ia64/xen-unstable

view xen/acm/acm_simple_type_enforcement_hooks.c @ 11624:f5fd563bcc84

[XEN] Small clean up.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Mon Sep 25 17:45:28 2006 +0100 (2006-09-25)
parents 58a3a7849216
children d088aec406c0
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 = htonl(ste_bin_pol.max_types);
147 ste_buf->ste_max_ssidrefs = htonl(ste_bin_pol.max_ssidrefs);
148 ste_buf->policy_code = htonl(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
149 ste_buf->ste_ssid_offset = htonl(sizeof(struct acm_ste_policy_buffer));
150 ret = ntohl(ste_buf->ste_ssid_offset) +
151 sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
153 if (buf_size < ret)
154 return -EINVAL;
156 /* now copy buffer over */
157 arrcpy(buf + ntohl(ste_buf->ste_ssid_offset),
158 ste_bin_pol.ssidrefs,
159 sizeof(domaintype_t),
160 ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
162 return ret;
163 }
165 /* ste_init_state is called when a policy is changed to detect violations (return != 0).
166 * from a security point of view, we simulate that all running domains are re-started and
167 * all sharing decisions are replayed to detect violations or current sharing behavior
168 * (right now: event_channels, future: also grant_tables)
169 */
170 static int
171 ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
172 {
173 int violation = 1;
174 struct ste_ssid *ste_ssid, *ste_rssid;
175 ssidref_t ste_ssidref, ste_rssidref;
176 struct domain **pd, *rdom;
177 domid_t rdomid;
178 grant_entry_t sha_copy;
179 int port, i;
181 read_lock(&domlist_lock); /* go by domain? or directly by global? event/grant list */
182 /* go through all domains and adjust policy as if this domain was started now */
183 pd = &domain_list;
184 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
185 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
186 (struct acm_ssid_domain *)(*pd)->ssid);
187 ste_ssidref = ste_ssid->ste_ssidref;
188 traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
189 __func__, (*pd)->domain_id, ste_ssidref);
190 /* a) check for event channel conflicts */
191 for (port=0; port < NR_EVTCHN_BUCKETS; port++) {
192 spin_lock(&(*pd)->evtchn_lock);
193 if ((*pd)->evtchn[port] == NULL) {
194 spin_unlock(&(*pd)->evtchn_lock);
195 continue;
196 }
197 if ((*pd)->evtchn[port]->state == ECS_INTERDOMAIN) {
198 rdom = (*pd)->evtchn[port]->u.interdomain.remote_dom;
199 rdomid = rdom->domain_id;
200 /* rdom now has remote domain */
201 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
202 (struct acm_ssid_domain *)(rdom->ssid));
203 ste_rssidref = ste_rssid->ste_ssidref;
204 } else if ((*pd)->evtchn[port]->state == ECS_UNBOUND) {
205 rdomid = (*pd)->evtchn[port]->u.unbound.remote_domid;
206 if ((rdom = find_domain_by_id(rdomid)) == NULL) {
207 printk("%s: Error finding domain to id %x!\n", __func__, rdomid);
208 goto out;
209 }
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 put_domain(rdom);
215 } else {
216 spin_unlock(&(*pd)->evtchn_lock);
217 continue; /* port unused */
218 }
219 spin_unlock(&(*pd)->evtchn_lock);
221 /* rdom now has remote domain */
222 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
223 (struct acm_ssid_domain *)(rdom->ssid));
224 ste_rssidref = ste_rssid->ste_ssidref;
225 traceprintk("%s: eventch: domain %x (ssidref %x) --> domain %x (rssidref %x) used (port %x).\n",
226 __func__, (*pd)->domain_id, ste_ssidref, rdom->domain_id, ste_rssidref, port);
227 /* check whether on subj->ssid, obj->ssid share a common type*/
228 if (!have_common_type(ste_ssidref, ste_rssidref)) {
229 printkd("%s: Policy violation in event channel domain %x -> domain %x.\n",
230 __func__, (*pd)->domain_id, rdomid);
231 goto out;
232 }
233 }
234 /* b) check for grant table conflicts on shared pages */
235 if ((*pd)->grant_table->shared == NULL) {
236 printkd("%s: Grant ... sharing for domain %x not setup!\n", __func__, (*pd)->domain_id);
237 continue;
238 }
239 for ( i = 0; i < NR_GRANT_ENTRIES; i++ ) {
240 sha_copy = (*pd)->grant_table->shared[i];
241 if ( sha_copy.flags ) {
242 printkd("%s: grant dom (%hu) SHARED (%d) flags:(%hx) dom:(%hu) frame:(%lx)\n",
243 __func__, (*pd)->domain_id, i, sha_copy.flags, sha_copy.domid,
244 (unsigned long)sha_copy.frame);
245 rdomid = sha_copy.domid;
246 if ((rdom = find_domain_by_id(rdomid)) == NULL) {
247 printkd("%s: domain not found ERROR!\n", __func__);
248 goto out;
249 };
250 /* rdom now has remote domain */
251 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
252 (struct acm_ssid_domain *)(rdom->ssid));
253 ste_rssidref = ste_rssid->ste_ssidref;
254 put_domain(rdom);
255 if (!have_common_type(ste_ssidref, ste_rssidref)) {
256 printkd("%s: Policy violation in grant table sharing domain %x -> domain %x.\n",
257 __func__, (*pd)->domain_id, rdomid);
258 goto out;
259 }
260 }
261 }
262 }
263 violation = 0;
264 out:
265 read_unlock(&domlist_lock);
266 return violation;
267 /* returning "violation != 0" means that existing sharing between domains would not
268 * have been allowed if the new policy had been enforced before the sharing; for ste,
269 * this means that there are at least 2 domains that have established sharing through
270 * event-channels or grant-tables but these two domains don't have no longer a common
271 * type in their typesets referenced by their ssidrefs */
272 }
274 /* set new policy; policy write-locked already */
275 static int
276 ste_set_policy(u8 *buf, u32 buf_size)
277 {
278 struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
279 void *ssidrefsbuf;
280 struct ste_ssid *ste_ssid;
281 struct domain **pd;
282 int i;
284 if (buf_size < sizeof(struct acm_ste_policy_buffer))
285 return -EINVAL;
287 /* Convert endianess of policy */
288 ste_buf->policy_code = ntohl(ste_buf->policy_code);
289 ste_buf->policy_version = ntohl(ste_buf->policy_version);
290 ste_buf->ste_max_types = ntohl(ste_buf->ste_max_types);
291 ste_buf->ste_max_ssidrefs = ntohl(ste_buf->ste_max_ssidrefs);
292 ste_buf->ste_ssid_offset = ntohl(ste_buf->ste_ssid_offset);
294 /* policy type and version checks */
295 if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ||
296 (ste_buf->policy_version != ACM_STE_VERSION))
297 return -EINVAL;
299 /* 1. create and copy-in new ssidrefs buffer */
300 ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
301 if (ssidrefsbuf == NULL) {
302 return -ENOMEM;
303 }
304 if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
305 goto error_free;
307 arrcpy(ssidrefsbuf,
308 buf + ste_buf->ste_ssid_offset,
309 sizeof(domaintype_t),
310 ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
312 /* 2. now re-calculate sharing decisions based on running domains;
313 * this can fail if new policy is conflicting with sharing of running domains
314 * now: reject violating new policy; future: adjust sharing through revoking sharing */
315 if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
316 printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
317 goto error_free; /* new policy conflicts with sharing of running domains */
318 }
319 /* 3. replace old policy (activate new policy) */
320 ste_bin_pol.max_types = ste_buf->ste_max_types;
321 ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
322 xfree(ste_bin_pol.ssidrefs);
323 ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
325 /* clear all ste caches */
326 read_lock(&domlist_lock);
327 pd = &domain_list;
328 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
329 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
330 (struct acm_ssid_domain *)(*pd)->ssid);
331 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
332 ste_ssid->ste_cache[i].valid = ACM_STE_free;
333 }
334 read_unlock(&domlist_lock);
335 return ACM_OK;
337 error_free:
338 printk("%s: ERROR setting policy.\n", __func__);
339 xfree(ssidrefsbuf);
340 return -EFAULT;
341 }
343 static int
344 ste_dump_stats(u8 *buf, u16 buf_len)
345 {
346 struct acm_ste_stats_buffer stats;
348 /* now send the hook counts to user space */
349 stats.ec_eval_count = htonl(atomic_read(&ste_bin_pol.ec_eval_count));
350 stats.gt_eval_count = htonl(atomic_read(&ste_bin_pol.gt_eval_count));
351 stats.ec_denied_count = htonl(atomic_read(&ste_bin_pol.ec_denied_count));
352 stats.gt_denied_count = htonl(atomic_read(&ste_bin_pol.gt_denied_count));
353 stats.ec_cachehit_count = htonl(atomic_read(&ste_bin_pol.ec_cachehit_count));
354 stats.gt_cachehit_count = htonl(atomic_read(&ste_bin_pol.gt_cachehit_count));
356 if (buf_len < sizeof(struct acm_ste_stats_buffer))
357 return -ENOMEM;
359 memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
360 return sizeof(struct acm_ste_stats_buffer);
361 }
363 static int
364 ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
365 {
366 int i;
368 /* fill in buffer */
369 if (ste_bin_pol.max_types > len)
370 return -EFAULT;
372 if (ssidref >= ste_bin_pol.max_ssidrefs)
373 return -EFAULT;
375 /* read types for chwall ssidref */
376 for(i=0; i< ste_bin_pol.max_types; i++) {
377 if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i])
378 buf[i] = 1;
379 else
380 buf[i] = 0;
381 }
382 return ste_bin_pol.max_types;
383 }
385 /* we need to go through this before calling the hooks,
386 * returns 1 == cache hit */
387 static int inline
388 check_cache(struct domain *dom, domid_t rdom) {
389 struct ste_ssid *ste_ssid;
390 int i;
392 printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
394 if (dom->ssid == NULL)
395 return 0;
396 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
397 (struct acm_ssid_domain *)(dom->ssid));
399 for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
400 if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) &&
401 (ste_ssid->ste_cache[i].id == rdom)) {
402 printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
403 return 1;
404 }
405 }
406 return 0;
407 }
410 /* we only get here if there is NO entry yet; no duplication check! */
411 static void inline
412 cache_result(struct domain *subj, struct domain *obj) {
413 struct ste_ssid *ste_ssid;
414 int i;
415 printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
416 if (subj->ssid == NULL)
417 return;
418 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
419 (struct acm_ssid_domain *)(subj)->ssid);
420 for(i=0; i< ACM_TE_CACHE_SIZE; i++)
421 if (ste_ssid->ste_cache[i].valid == ACM_STE_free)
422 break;
423 if (i< ACM_TE_CACHE_SIZE) {
424 ste_ssid->ste_cache[i].valid = ACM_STE_valid;
425 ste_ssid->ste_cache[i].id = obj->domain_id;
426 } else
427 printk ("Cache of dom %x is full!\n", subj->domain_id);
428 }
430 /* deletes entries for domain 'id' from all caches (re-use) */
431 static void inline
432 clean_id_from_cache(domid_t id)
433 {
434 struct ste_ssid *ste_ssid;
435 int i;
436 struct domain **pd;
437 struct acm_ssid_domain *ssid;
439 printkd("deleting cache for dom %x.\n", id);
440 read_lock(&domlist_lock); /* look through caches of all domains */
441 pd = &domain_list;
442 for ( pd = &domain_list; *pd != NULL; pd = &(*pd)->next_in_list ) {
443 ssid = (struct acm_ssid_domain *)((*pd)->ssid);
445 if (ssid == NULL)
446 continue; /* hanging domain structure, no ssid any more ... */
447 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssid);
448 if (!ste_ssid) {
449 printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n",
450 __func__);
451 goto out;
452 }
453 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
454 if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) &&
455 (ste_ssid->ste_cache[i].id == id))
456 ste_ssid->ste_cache[i].valid = ACM_STE_free;
457 }
458 out:
459 read_unlock(&domlist_lock);
460 }
462 /***************************
463 * Authorization functions
464 **************************/
465 static int
466 ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
467 {
468 /* check for ssidref in range for policy */
469 ssidref_t ste_ssidref;
470 traceprintk("%s.\n", __func__);
472 read_lock(&acm_bin_pol_rwlock);
473 ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
474 if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
475 printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
476 read_unlock(&acm_bin_pol_rwlock);
477 return ACM_ACCESS_DENIED; /* catching and indicating config error */
478 }
479 if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
480 printk("%s: ERROR ste_ssidref > max(%x).\n",
481 __func__, ste_bin_pol.max_ssidrefs-1);
482 read_unlock(&acm_bin_pol_rwlock);
483 return ACM_ACCESS_DENIED;
484 }
485 read_unlock(&acm_bin_pol_rwlock);
486 return ACM_ACCESS_PERMITTED;
487 }
489 static void
490 ste_post_domain_destroy(void *subject_ssid, domid_t id)
491 {
492 /* clean all cache entries for destroyed domain (might be re-used) */
493 clean_id_from_cache(id);
494 }
496 /* -------- EVENTCHANNEL OPERATIONS -----------*/
497 static int
498 ste_pre_eventchannel_unbound(domid_t id1, domid_t id2) {
499 struct domain *subj, *obj;
500 int ret;
501 traceprintk("%s: dom%x-->dom%x.\n", __func__,
502 (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
503 (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
505 if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
506 if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
508 subj = find_domain_by_id(id1);
509 obj = find_domain_by_id(id2);
510 if ((subj == NULL) || (obj == NULL)) {
511 ret = ACM_ACCESS_DENIED;
512 goto out;
513 }
514 /* cache check late */
515 if (check_cache(subj, obj->domain_id)) {
516 atomic_inc(&ste_bin_pol.ec_cachehit_count);
517 ret = ACM_ACCESS_PERMITTED;
518 goto out;
519 }
520 atomic_inc(&ste_bin_pol.ec_eval_count);
522 if (share_common_type(subj, obj)) {
523 cache_result(subj, obj);
524 ret = ACM_ACCESS_PERMITTED;
525 } else {
526 atomic_inc(&ste_bin_pol.ec_denied_count);
527 ret = ACM_ACCESS_DENIED;
528 }
529 out:
530 if (obj != NULL)
531 put_domain(obj);
532 if (subj != NULL)
533 put_domain(subj);
534 return ret;
535 }
537 static int
538 ste_pre_eventchannel_interdomain(domid_t id)
539 {
540 struct domain *subj=NULL, *obj=NULL;
541 int ret;
543 traceprintk("%s: dom%x-->dom%x.\n", __func__,
544 current->domain->domain_id,
545 (id == DOMID_SELF) ? current->domain->domain_id : id);
547 /* following is a bit longer but ensures that we
548 * "put" only domains that we where "find"-ing
549 */
550 if (id == DOMID_SELF) id = current->domain->domain_id;
552 subj = current->domain;
553 obj = find_domain_by_id(id);
554 if (obj == NULL) {
555 ret = ACM_ACCESS_DENIED;
556 goto out;
557 }
559 /* cache check late, but evtchn is not on performance critical path */
560 if (check_cache(subj, obj->domain_id)) {
561 atomic_inc(&ste_bin_pol.ec_cachehit_count);
562 ret = ACM_ACCESS_PERMITTED;
563 goto out;
564 }
566 atomic_inc(&ste_bin_pol.ec_eval_count);
568 if (share_common_type(subj, obj)) {
569 cache_result(subj, obj);
570 ret = ACM_ACCESS_PERMITTED;
571 } else {
572 atomic_inc(&ste_bin_pol.ec_denied_count);
573 ret = ACM_ACCESS_DENIED;
574 }
575 out:
576 if (obj != NULL)
577 put_domain(obj);
578 return ret;
579 }
581 /* -------- SHARED MEMORY OPERATIONS -----------*/
583 static int
584 ste_pre_grant_map_ref (domid_t id) {
585 struct domain *obj, *subj;
586 int ret;
587 traceprintk("%s: dom%x-->dom%x.\n", __func__,
588 current->domain->domain_id, id);
590 if (check_cache(current->domain, id)) {
591 atomic_inc(&ste_bin_pol.gt_cachehit_count);
592 return ACM_ACCESS_PERMITTED;
593 }
594 atomic_inc(&ste_bin_pol.gt_eval_count);
595 subj = current->domain;
596 obj = find_domain_by_id(id);
598 if (share_common_type(subj, obj)) {
599 cache_result(subj, obj);
600 ret = ACM_ACCESS_PERMITTED;
601 } else {
602 atomic_inc(&ste_bin_pol.gt_denied_count);
603 printkd("%s: ACCESS DENIED!\n", __func__);
604 ret = ACM_ACCESS_DENIED;
605 }
606 if (obj != NULL)
607 put_domain(obj);
608 return ret;
609 }
612 /* since setting up grant tables involves some implicit information
613 flow from the creating domain to the domain that is setup, we
614 check types in addition to the general authorization */
615 static int
616 ste_pre_grant_setup (domid_t id) {
617 struct domain *obj, *subj;
618 int ret;
619 traceprintk("%s: dom%x-->dom%x.\n", __func__,
620 current->domain->domain_id, id);
622 if (check_cache(current->domain, id)) {
623 atomic_inc(&ste_bin_pol.gt_cachehit_count);
624 return ACM_ACCESS_PERMITTED;
625 }
626 atomic_inc(&ste_bin_pol.gt_eval_count);
627 /* a) check authorization (eventually use specific capabilities) */
628 if (!IS_PRIV(current->domain)) {
629 printk("%s: Grant table management authorization denied ERROR!\n", __func__);
630 return ACM_ACCESS_DENIED;
631 }
632 /* b) check types */
633 subj = current->domain;
634 obj = find_domain_by_id(id);
636 if (share_common_type(subj, obj)) {
637 cache_result(subj, obj);
638 ret = ACM_ACCESS_PERMITTED;
639 } else {
640 atomic_inc(&ste_bin_pol.gt_denied_count);
641 ret = ACM_ACCESS_DENIED;
642 }
643 if (obj != NULL)
644 put_domain(obj);
645 return ret;
646 }
648 /* -------- DOMAIN-Requested Decision hooks -----------*/
650 static int
651 ste_sharing(ssidref_t ssidref1, ssidref_t ssidref2) {
652 if (have_common_type (
653 GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
654 GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2)
655 ))
656 return ACM_ACCESS_PERMITTED;
657 else
658 return ACM_ACCESS_DENIED;
659 }
662 /* now define the hook structure similarly to LSM */
663 struct acm_operations acm_simple_type_enforcement_ops = {
665 /* policy management services */
666 .init_domain_ssid = ste_init_domain_ssid,
667 .free_domain_ssid = ste_free_domain_ssid,
668 .dump_binary_policy = ste_dump_policy,
669 .set_binary_policy = ste_set_policy,
670 .dump_statistics = ste_dump_stats,
671 .dump_ssid_types = ste_dump_ssid_types,
673 /* domain management control hooks */
674 .pre_domain_create = ste_pre_domain_create,
675 .post_domain_create = NULL,
676 .fail_domain_create = NULL,
677 .post_domain_destroy = ste_post_domain_destroy,
679 /* event channel control hooks */
680 .pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
681 .fail_eventchannel_unbound = NULL,
682 .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
683 .fail_eventchannel_interdomain = NULL,
685 /* grant table control hooks */
686 .pre_grant_map_ref = ste_pre_grant_map_ref,
687 .fail_grant_map_ref = NULL,
688 .pre_grant_setup = ste_pre_grant_setup,
689 .fail_grant_setup = NULL,
690 .sharing = ste_sharing,
691 };
693 /*
694 * Local variables:
695 * mode: C
696 * c-set-style: "BSD"
697 * c-basic-offset: 4
698 * tab-width: 4
699 * indent-tabs-mode: nil
700 * End:
701 */