ia64/xen-unstable

view xen/acm/acm_simple_type_enforcement_hooks.c @ 14167:d4cd2c70cdea

[XEN] [ACM] Simplify the event channel scanning

This patch simplifies the scanning of a domain's event channels
considering that an 'ECS_UNBOUND' event channel is not connected and
can be skipped.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Tue Feb 27 20:22:36 2007 +0000 (2007-02-27)
parents 97826d77bd4d
children 09a9b6d6c356
line source
1 /****************************************************************
2 * acm_simple_type_enforcement_hooks.c
3 *
4 * Copyright (C) 2005 IBM Corporation
5 *
6 * Author:
7 * Reiner Sailer <sailer@watson.ibm.com>
8 *
9 * Contributors:
10 * Stefan Berger <stefanb@watson.ibm.com>
11 * support for network order binary policies
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License as
15 * published by the Free Software Foundation, version 2 of the
16 * License.
17 *
18 * sHype Simple Type Enforcement for Xen
19 * STE allows to control which domains can setup sharing
20 * (eventchannels right now) with which other domains. Hooks
21 * are defined and called throughout Xen when domains bind to
22 * shared resources (setup eventchannels) and a domain is allowed
23 * to setup sharing with another domain if and only if both domains
24 * share at least on common type.
25 *
26 */
28 #include <xen/lib.h>
29 #include <asm/types.h>
30 #include <asm/current.h>
31 #include <acm/acm_hooks.h>
32 #include <asm/atomic.h>
33 #include <acm/acm_endian.h>
35 /* local cache structures for STE policy */
36 struct ste_binary_policy ste_bin_pol;
38 static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
39 int i;
40 for(i=0; i< ste_bin_pol.max_types; i++)
41 if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
42 ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
43 printkd("%s: common type #%02x.\n", __func__, i);
44 return 1;
45 }
46 return 0;
47 }
49 /* Helper function: return = (subj and obj share a common type) */
50 static int share_common_type(struct domain *subj, struct domain *obj)
51 {
52 ssidref_t ref_s, ref_o;
53 int ret;
55 if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
56 return 0;
57 read_lock(&acm_bin_pol_rwlock);
58 /* lookup the policy-local ssids */
59 ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
60 (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
61 ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
62 (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
63 /* check whether subj and obj share a common ste type */
64 ret = have_common_type(ref_s, ref_o);
65 read_unlock(&acm_bin_pol_rwlock);
66 return ret;
67 }
69 /*
70 * Initializing STE policy (will be filled by policy partition
71 * using setpolicy command)
72 */
73 int acm_init_ste_policy(void)
74 {
75 /* minimal startup policy; policy write-locked already */
76 ste_bin_pol.max_types = 1;
77 ste_bin_pol.max_ssidrefs = 2;
78 ste_bin_pol.ssidrefs = (domaintype_t *)xmalloc_array(domaintype_t, 2);
79 memset(ste_bin_pol.ssidrefs, 0, 2);
81 if (ste_bin_pol.ssidrefs == NULL)
82 return ACM_INIT_SSID_ERROR;
84 /* initialize state so that dom0 can start up and communicate with itself */
85 ste_bin_pol.ssidrefs[1] = 1;
87 /* init stats */
88 atomic_set(&(ste_bin_pol.ec_eval_count), 0);
89 atomic_set(&(ste_bin_pol.ec_denied_count), 0);
90 atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
91 atomic_set(&(ste_bin_pol.gt_eval_count), 0);
92 atomic_set(&(ste_bin_pol.gt_denied_count), 0);
93 atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
94 return ACM_OK;
95 }
98 /* ste initialization function hooks */
99 static int
100 ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref)
101 {
102 int i;
103 struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);
104 traceprintk("%s.\n", __func__);
106 if (ste_ssidp == NULL)
107 return ACM_INIT_SSID_ERROR;
109 /* get policy-local ssid reference */
110 ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
111 if ((ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) ||
112 (ste_ssidp->ste_ssidref == ACM_DEFAULT_LOCAL_SSID)) {
113 printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n",
114 __func__, ste_ssidp->ste_ssidref);
115 xfree(ste_ssidp);
116 return ACM_INIT_SSID_ERROR;
117 }
118 /* clean ste cache */
119 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
120 ste_ssidp->ste_cache[i].valid = ACM_STE_free;
122 (*ste_ssid) = ste_ssidp;
123 printkd("%s: determined ste_ssidref to %x.\n",
124 __func__, ste_ssidp->ste_ssidref);
125 return ACM_OK;
126 }
129 static void
130 ste_free_domain_ssid(void *ste_ssid)
131 {
132 traceprintk("%s.\n", __func__);
133 xfree(ste_ssid);
134 return;
135 }
137 /* dump type enforcement cache; policy read-locked already */
138 static int
139 ste_dump_policy(u8 *buf, u32 buf_size) {
140 struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
141 int ret = 0;
143 if (buf_size < sizeof(struct acm_ste_policy_buffer))
144 return -EINVAL;
146 ste_buf->ste_max_types = cpu_to_be32(ste_bin_pol.max_types);
147 ste_buf->ste_max_ssidrefs = cpu_to_be32(ste_bin_pol.max_ssidrefs);
148 ste_buf->policy_code = cpu_to_be32(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
149 ste_buf->ste_ssid_offset = cpu_to_be32(sizeof(struct acm_ste_policy_buffer));
150 ret = be32_to_cpu(ste_buf->ste_ssid_offset) +
151 sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
153 ret = (ret + 7) & ~7;
155 if (buf_size < ret)
156 return -EINVAL;
158 /* now copy buffer over */
159 arrcpy(buf + be32_to_cpu(ste_buf->ste_ssid_offset),
160 ste_bin_pol.ssidrefs,
161 sizeof(domaintype_t),
162 ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
164 return ret;
165 }
167 /* ste_init_state is called when a policy is changed to detect violations (return != 0).
168 * from a security point of view, we simulate that all running domains are re-started and
169 * all sharing decisions are replayed to detect violations or current sharing behavior
170 * (right now: event_channels, future: also grant_tables)
171 */
172 static int
173 ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
174 {
175 int violation = 1;
176 struct ste_ssid *ste_ssid, *ste_rssid;
177 ssidref_t ste_ssidref, ste_rssidref;
178 struct domain *d, *rdom;
179 domid_t rdomid;
180 struct grant_entry sha_copy;
181 int port, i;
183 rcu_read_lock(&domlist_read_lock);
184 /* go by domain? or directly by global? event/grant list */
185 /* go through all domains and adjust policy as if this domain was started now */
186 for_each_domain ( d )
187 {
188 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
189 (struct acm_ssid_domain *)d->ssid);
190 ste_ssidref = ste_ssid->ste_ssidref;
191 traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
192 __func__, d->domain_id, ste_ssidref);
193 /* a) check for event channel conflicts */
194 for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
195 spin_lock(&d->evtchn_lock);
196 if (d->evtchn[port] == NULL ||
197 d->evtchn[port]->state == ECS_UNBOUND) {
198 spin_unlock(&d->evtchn_lock);
199 continue;
200 }
201 if (d->evtchn[port]->state == ECS_INTERDOMAIN) {
202 rdom = d->evtchn[port]->u.interdomain.remote_dom;
203 rdomid = rdom->domain_id;
204 } else {
205 spin_unlock(&d->evtchn_lock);
206 continue; /* port unused */
207 }
208 spin_unlock(&d->evtchn_lock);
210 /* rdom now has remote domain */
211 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
212 (struct acm_ssid_domain *)(rdom->ssid));
213 ste_rssidref = ste_rssid->ste_ssidref;
214 traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n",
215 __func__, d->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);
216 /* check whether on subj->ssid, obj->ssid share a common type*/
217 if (!have_common_type(ste_ssidref, ste_rssidref)) {
218 printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
219 __func__, d->domain_id, rdomid);
220 goto out;
221 }
222 }
223 /* b) check for grant table conflicts on shared pages */
224 spin_lock(&d->grant_table->lock);
225 for ( i = 0; i < nr_grant_entries(d->grant_table); i++ ) {
226 #define SPP (PAGE_SIZE / sizeof(struct grant_entry))
227 sha_copy = d->grant_table->shared[i/SPP][i%SPP];
228 if ( sha_copy.flags ) {
229 printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
230 __func__, d->domain_id, i, sha_copy.flags, sha_copy.domid,
231 (unsigned long)sha_copy.frame);
232 rdomid = sha_copy.domid;
233 if ((rdom = get_domain_by_id(rdomid)) == NULL) {
234 spin_unlock(&d->grant_table->lock);
235 printkd("%s: domain not found ERROR!\n", __func__);
236 goto out;
237 };
238 /* rdom now has remote domain */
239 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
240 (struct acm_ssid_domain *)(rdom->ssid));
241 ste_rssidref = ste_rssid->ste_ssidref;
242 put_domain(rdom);
243 if (!have_common_type(ste_ssidref, ste_rssidref)) {
244 spin_unlock(&d->grant_table->lock);
245 printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
246 __func__, d->domain_id, rdomid);
247 goto out;
248 }
249 }
250 }
251 spin_unlock(&d->grant_table->lock);
252 }
253 violation = 0;
254 out:
255 rcu_read_unlock(&domlist_read_lock);
256 return violation;
257 /* returning "violation != 0" means that existing sharing between domains would not
258 * have been allowed if the new policy had been enforced before the sharing; for ste,
259 * this means that there are at least 2 domains that have established sharing through
260 * event-channels or grant-tables but these two domains don't have no longer a common
261 * type in their typesets referenced by their ssidrefs */
262 }
264 /* set new policy; policy write-locked already */
265 static int
266 ste_set_policy(u8 *buf, u32 buf_size)
267 {
268 struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
269 void *ssidrefsbuf;
270 struct ste_ssid *ste_ssid;
271 struct domain *d;
272 int i;
274 if (buf_size < sizeof(struct acm_ste_policy_buffer))
275 return -EINVAL;
277 /* Convert endianess of policy */
278 ste_buf->policy_code = be32_to_cpu(ste_buf->policy_code);
279 ste_buf->policy_version = be32_to_cpu(ste_buf->policy_version);
280 ste_buf->ste_max_types = be32_to_cpu(ste_buf->ste_max_types);
281 ste_buf->ste_max_ssidrefs = be32_to_cpu(ste_buf->ste_max_ssidrefs);
282 ste_buf->ste_ssid_offset = be32_to_cpu(ste_buf->ste_ssid_offset);
284 /* policy type and version checks */
285 if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ||
286 (ste_buf->policy_version != ACM_STE_VERSION))
287 return -EINVAL;
289 /* 1. create and copy-in new ssidrefs buffer */
290 ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
291 if (ssidrefsbuf == NULL) {
292 return -ENOMEM;
293 }
294 if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
295 goto error_free;
297 arrcpy(ssidrefsbuf,
298 buf + ste_buf->ste_ssid_offset,
299 sizeof(domaintype_t),
300 ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
302 /* 2. now re-calculate sharing decisions based on running domains;
303 * this can fail if new policy is conflicting with sharing of running domains
304 * now: reject violating new policy; future: adjust sharing through revoking sharing */
305 if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
306 printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
307 goto error_free; /* new policy conflicts with sharing of running domains */
308 }
309 /* 3. replace old policy (activate new policy) */
310 ste_bin_pol.max_types = ste_buf->ste_max_types;
311 ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
312 xfree(ste_bin_pol.ssidrefs);
313 ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
315 /* clear all ste caches */
316 rcu_read_lock(&domlist_read_lock);
317 for_each_domain ( d ) {
318 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
319 (struct acm_ssid_domain *)(d)->ssid);
320 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
321 ste_ssid->ste_cache[i].valid = ACM_STE_free;
322 }
323 rcu_read_unlock(&domlist_read_lock);
324 return ACM_OK;
326 error_free:
327 printk("%s: ERROR setting policy.\n", __func__);
328 xfree(ssidrefsbuf);
329 return -EFAULT;
330 }
332 static int
333 ste_dump_stats(u8 *buf, u16 buf_len)
334 {
335 struct acm_ste_stats_buffer stats;
337 /* now send the hook counts to user space */
338 stats.ec_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_eval_count));
339 stats.gt_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_eval_count));
340 stats.ec_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_denied_count));
341 stats.gt_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_denied_count));
342 stats.ec_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_cachehit_count));
343 stats.gt_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_cachehit_count));
345 if (buf_len < sizeof(struct acm_ste_stats_buffer))
346 return -ENOMEM;
348 memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
349 return sizeof(struct acm_ste_stats_buffer);
350 }
352 static int
353 ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
354 {
355 int i;
357 /* fill in buffer */
358 if (ste_bin_pol.max_types > len)
359 return -EFAULT;
361 if (ssidref >= ste_bin_pol.max_ssidrefs)
362 return -EFAULT;
364 /* read types for chwall ssidref */
365 for(i=0; i< ste_bin_pol.max_types; i++) {
366 if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i])
367 buf[i] = 1;
368 else
369 buf[i] = 0;
370 }
371 return ste_bin_pol.max_types;
372 }
374 /* we need to go through this before calling the hooks,
375 * returns 1 == cache hit */
376 static int inline
377 check_cache(struct domain *dom, domid_t rdom) {
378 struct ste_ssid *ste_ssid;
379 int i;
381 printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
383 if (dom->ssid == NULL)
384 return 0;
385 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
386 (struct acm_ssid_domain *)(dom->ssid));
388 for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
389 if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) &&
390 (ste_ssid->ste_cache[i].id == rdom)) {
391 printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
392 return 1;
393 }
394 }
395 return 0;
396 }
399 /* we only get here if there is NO entry yet; no duplication check! */
400 static void inline
401 cache_result(struct domain *subj, struct domain *obj) {
402 struct ste_ssid *ste_ssid;
403 int i;
404 printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
405 if (subj->ssid == NULL)
406 return;
407 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
408 (struct acm_ssid_domain *)(subj)->ssid);
409 for(i=0; i< ACM_TE_CACHE_SIZE; i++)
410 if (ste_ssid->ste_cache[i].valid == ACM_STE_free)
411 break;
412 if (i< ACM_TE_CACHE_SIZE) {
413 ste_ssid->ste_cache[i].valid = ACM_STE_valid;
414 ste_ssid->ste_cache[i].id = obj->domain_id;
415 } else
416 printk ("Cache of dom %x is full!\n", subj->domain_id);
417 }
419 /* deletes entries for domain 'id' from all caches (re-use) */
420 static void inline
421 clean_id_from_cache(domid_t id)
422 {
423 struct ste_ssid *ste_ssid;
424 int i;
425 struct domain *d;
426 struct acm_ssid_domain *ssid;
428 printkd("deleting cache for dom %x.\n", id);
429 rcu_read_lock(&domlist_read_lock);
430 /* look through caches of all domains */
431 for_each_domain ( d ) {
432 ssid = (struct acm_ssid_domain *)(d->ssid);
434 if (ssid == NULL)
435 continue; /* hanging domain structure, no ssid any more ... */
436 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssid);
437 if (!ste_ssid) {
438 printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n",
439 __func__);
440 goto out;
441 }
442 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
443 if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) &&
444 (ste_ssid->ste_cache[i].id == id))
445 ste_ssid->ste_cache[i].valid = ACM_STE_free;
446 }
447 out:
448 rcu_read_unlock(&domlist_read_lock);
449 }
451 /***************************
452 * Authorization functions
453 **************************/
454 static int
455 ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
456 {
457 /* check for ssidref in range for policy */
458 ssidref_t ste_ssidref;
459 traceprintk("%s.\n", __func__);
461 read_lock(&acm_bin_pol_rwlock);
462 ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
463 if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
464 printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
465 read_unlock(&acm_bin_pol_rwlock);
466 return ACM_ACCESS_DENIED; /* catching and indicating config error */
467 }
468 if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
469 printk("%s: ERROR ste_ssidref > max(%x).\n",
470 __func__, ste_bin_pol.max_ssidrefs-1);
471 read_unlock(&acm_bin_pol_rwlock);
472 return ACM_ACCESS_DENIED;
473 }
474 read_unlock(&acm_bin_pol_rwlock);
475 return ACM_ACCESS_PERMITTED;
476 }
478 static void
479 ste_post_domain_destroy(void *subject_ssid, domid_t id)
480 {
481 /* clean all cache entries for destroyed domain (might be re-used) */
482 clean_id_from_cache(id);
483 }
485 /* -------- EVENTCHANNEL OPERATIONS -----------*/
486 static int
487 ste_pre_eventchannel_unbound(domid_t id1, domid_t id2) {
488 struct domain *subj, *obj;
489 int ret;
490 traceprintk("%s: dom%x-->dom%x.\n", __func__,
491 (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
492 (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
494 if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
495 if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
497 subj = get_domain_by_id(id1);
498 obj = get_domain_by_id(id2);
499 if ((subj == NULL) || (obj == NULL)) {
500 ret = ACM_ACCESS_DENIED;
501 goto out;
502 }
503 /* cache check late */
504 if (check_cache(subj, obj->domain_id)) {
505 atomic_inc(&ste_bin_pol.ec_cachehit_count);
506 ret = ACM_ACCESS_PERMITTED;
507 goto out;
508 }
509 atomic_inc(&ste_bin_pol.ec_eval_count);
511 if (share_common_type(subj, obj)) {
512 cache_result(subj, obj);
513 ret = ACM_ACCESS_PERMITTED;
514 } else {
515 atomic_inc(&ste_bin_pol.ec_denied_count);
516 ret = ACM_ACCESS_DENIED;
517 }
518 out:
519 if (obj != NULL)
520 put_domain(obj);
521 if (subj != NULL)
522 put_domain(subj);
523 return ret;
524 }
526 static int
527 ste_pre_eventchannel_interdomain(domid_t id)
528 {
529 struct domain *subj=NULL, *obj=NULL;
530 int ret;
532 traceprintk("%s: dom%x-->dom%x.\n", __func__,
533 current->domain->domain_id,
534 (id == DOMID_SELF) ? current->domain->domain_id : id);
536 /* following is a bit longer but ensures that we
537 * "put" only domains that we where "find"-ing
538 */
539 if (id == DOMID_SELF) id = current->domain->domain_id;
541 subj = current->domain;
542 obj = get_domain_by_id(id);
543 if (obj == NULL) {
544 ret = ACM_ACCESS_DENIED;
545 goto out;
546 }
548 /* cache check late, but evtchn is not on performance critical path */
549 if (check_cache(subj, obj->domain_id)) {
550 atomic_inc(&ste_bin_pol.ec_cachehit_count);
551 ret = ACM_ACCESS_PERMITTED;
552 goto out;
553 }
555 atomic_inc(&ste_bin_pol.ec_eval_count);
557 if (share_common_type(subj, obj)) {
558 cache_result(subj, obj);
559 ret = ACM_ACCESS_PERMITTED;
560 } else {
561 atomic_inc(&ste_bin_pol.ec_denied_count);
562 ret = ACM_ACCESS_DENIED;
563 }
564 out:
565 if (obj != NULL)
566 put_domain(obj);
567 return ret;
568 }
570 /* -------- SHARED MEMORY OPERATIONS -----------*/
572 static int
573 ste_pre_grant_map_ref (domid_t id) {
574 struct domain *obj, *subj;
575 int ret;
576 traceprintk("%s: dom%x-->dom%x.\n", __func__,
577 current->domain->domain_id, id);
579 if (check_cache(current->domain, id)) {
580 atomic_inc(&ste_bin_pol.gt_cachehit_count);
581 return ACM_ACCESS_PERMITTED;
582 }
583 atomic_inc(&ste_bin_pol.gt_eval_count);
584 subj = current->domain;
585 obj = get_domain_by_id(id);
587 if (share_common_type(subj, obj)) {
588 cache_result(subj, obj);
589 ret = ACM_ACCESS_PERMITTED;
590 } else {
591 atomic_inc(&ste_bin_pol.gt_denied_count);
592 printkd("%s: ACCESS DENIED!\n", __func__);
593 ret = ACM_ACCESS_DENIED;
594 }
595 if (obj != NULL)
596 put_domain(obj);
597 return ret;
598 }
601 /* since setting up grant tables involves some implicit information
602 flow from the creating domain to the domain that is setup, we
603 check types in addition to the general authorization */
604 static int
605 ste_pre_grant_setup (domid_t id) {
606 struct domain *obj, *subj;
607 int ret;
608 traceprintk("%s: dom%x-->dom%x.\n", __func__,
609 current->domain->domain_id, id);
611 if (check_cache(current->domain, id)) {
612 atomic_inc(&ste_bin_pol.gt_cachehit_count);
613 return ACM_ACCESS_PERMITTED;
614 }
615 atomic_inc(&ste_bin_pol.gt_eval_count);
616 /* a) check authorization (eventually use specific capabilities) */
617 if (!IS_PRIV(current->domain)) {
618 printk("%s: Grant table management authorization denied ERROR!\n", __func__);
619 return ACM_ACCESS_DENIED;
620 }
621 /* b) check types */
622 subj = current->domain;
623 obj = get_domain_by_id(id);
625 if (share_common_type(subj, obj)) {
626 cache_result(subj, obj);
627 ret = ACM_ACCESS_PERMITTED;
628 } else {
629 atomic_inc(&ste_bin_pol.gt_denied_count);
630 ret = ACM_ACCESS_DENIED;
631 }
632 if (obj != NULL)
633 put_domain(obj);
634 return ret;
635 }
637 /* -------- DOMAIN-Requested Decision hooks -----------*/
639 static int
640 ste_sharing(ssidref_t ssidref1, ssidref_t ssidref2) {
641 if (have_common_type (
642 GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
643 GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2)
644 ))
645 return ACM_ACCESS_PERMITTED;
646 else
647 return ACM_ACCESS_DENIED;
648 }
651 /* now define the hook structure similarly to LSM */
652 struct acm_operations acm_simple_type_enforcement_ops = {
654 /* policy management services */
655 .init_domain_ssid = ste_init_domain_ssid,
656 .free_domain_ssid = ste_free_domain_ssid,
657 .dump_binary_policy = ste_dump_policy,
658 .set_binary_policy = ste_set_policy,
659 .dump_statistics = ste_dump_stats,
660 .dump_ssid_types = ste_dump_ssid_types,
662 /* domain management control hooks */
663 .pre_domain_create = ste_pre_domain_create,
664 .post_domain_create = NULL,
665 .fail_domain_create = NULL,
666 .post_domain_destroy = ste_post_domain_destroy,
668 /* event channel control hooks */
669 .pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
670 .fail_eventchannel_unbound = NULL,
671 .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
672 .fail_eventchannel_interdomain = NULL,
674 /* grant table control hooks */
675 .pre_grant_map_ref = ste_pre_grant_map_ref,
676 .fail_grant_map_ref = NULL,
677 .pre_grant_setup = ste_pre_grant_setup,
678 .fail_grant_setup = NULL,
679 .sharing = ste_sharing,
680 };
682 /*
683 * Local variables:
684 * mode: C
685 * c-set-style: "BSD"
686 * c-basic-offset: 4
687 * tab-width: 4
688 * indent-tabs-mode: nil
689 * End:
690 */