ia64/xen-unstable

view xen/acm/acm_simple_type_enforcement_hooks.c @ 15452:f152e44325a7

xenconsoled: improve robustness of logfile handling

Check the 'log_reload' on every iteration of the select() loop, not just when
select() returns EINTR. This is because the log reload signal may have
iterrupted a syscall other than select & thus without this change we
might miss the reload signal. The second change makes us process the
hypervisor logs on every iteration of the loop, not just upon timeouts.
This is because if a guest VM were consistently sending some log message
and < 1 second period, the select() would never hit the 1 second timeout
and thus never process the HV logs.

Thanks to Markus Armbruster for pointing out both these edge cases

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Wed Jun 27 21:05:54 2007 +0100 (2007-06-27)
parents 4677ee247aa9
children 4a8dbbc16d48
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>
34 #include <acm/acm_core.h>
36 ssidref_t dom0_ste_ssidref = 0x0001;
38 /* local cache structures for STE policy */
39 struct ste_binary_policy ste_bin_pol;
41 static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
42 int i;
43 for(i=0; i< ste_bin_pol.max_types; i++)
44 if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
45 ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i]) {
46 printkd("%s: common type #%02x.\n", __func__, i);
47 return 1;
48 }
49 return 0;
50 }
52 /* Helper function: return = (subj and obj share a common type) */
53 static int share_common_type(struct domain *subj, struct domain *obj)
54 {
55 ssidref_t ref_s, ref_o;
56 int ret;
58 if ((subj == NULL) || (obj == NULL) || (subj->ssid == NULL) || (obj->ssid == NULL))
59 return 0;
60 read_lock(&acm_bin_pol_rwlock);
61 /* lookup the policy-local ssids */
62 ref_s = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
63 (struct acm_ssid_domain *)subj->ssid)))->ste_ssidref;
64 ref_o = ((struct ste_ssid *)(GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
65 (struct acm_ssid_domain *)obj->ssid)))->ste_ssidref;
66 /* check whether subj and obj share a common ste type */
67 ret = have_common_type(ref_s, ref_o);
68 read_unlock(&acm_bin_pol_rwlock);
69 return ret;
70 }
72 /*
73 * Initializing STE policy (will be filled by policy partition
74 * using setpolicy command)
75 */
76 int acm_init_ste_policy(void)
77 {
78 /* minimal startup policy; policy write-locked already */
79 ste_bin_pol.max_types = 1;
80 ste_bin_pol.max_ssidrefs = 1 + dom0_ste_ssidref;
81 ste_bin_pol.ssidrefs =
82 (domaintype_t *)xmalloc_array(domaintype_t,
83 ste_bin_pol.max_types *
84 ste_bin_pol.max_ssidrefs);
86 if (ste_bin_pol.ssidrefs == NULL)
87 return ACM_INIT_SSID_ERROR;
89 memset(ste_bin_pol.ssidrefs, 0, sizeof(domaintype_t) *
90 ste_bin_pol.max_types *
91 ste_bin_pol.max_ssidrefs);
93 /* initialize state so that dom0 can start up and communicate with itself */
94 ste_bin_pol.ssidrefs[ste_bin_pol.max_types * dom0_ste_ssidref] = 1;
96 /* init stats */
97 atomic_set(&(ste_bin_pol.ec_eval_count), 0);
98 atomic_set(&(ste_bin_pol.ec_denied_count), 0);
99 atomic_set(&(ste_bin_pol.ec_cachehit_count), 0);
100 atomic_set(&(ste_bin_pol.gt_eval_count), 0);
101 atomic_set(&(ste_bin_pol.gt_denied_count), 0);
102 atomic_set(&(ste_bin_pol.gt_cachehit_count), 0);
103 return ACM_OK;
104 }
107 /* ste initialization function hooks */
108 static int
109 ste_init_domain_ssid(void **ste_ssid, ssidref_t ssidref)
110 {
111 int i;
112 struct ste_ssid *ste_ssidp = xmalloc(struct ste_ssid);
113 traceprintk("%s.\n", __func__);
115 if (ste_ssidp == NULL)
116 return ACM_INIT_SSID_ERROR;
118 /* get policy-local ssid reference */
119 ste_ssidp->ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
120 if ((ste_ssidp->ste_ssidref >= ste_bin_pol.max_ssidrefs) ||
121 (ste_ssidp->ste_ssidref == ACM_DEFAULT_LOCAL_SSID)) {
122 printkd("%s: ERROR ste_ssidref (%x) undefined or unset (0).\n",
123 __func__, ste_ssidp->ste_ssidref);
124 xfree(ste_ssidp);
125 return ACM_INIT_SSID_ERROR;
126 }
127 /* clean ste cache */
128 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
129 ste_ssidp->ste_cache[i].valid = ACM_STE_free;
131 (*ste_ssid) = ste_ssidp;
132 printkd("%s: determined ste_ssidref to %x.\n",
133 __func__, ste_ssidp->ste_ssidref);
134 return ACM_OK;
135 }
138 static void
139 ste_free_domain_ssid(void *ste_ssid)
140 {
141 traceprintk("%s.\n", __func__);
142 xfree(ste_ssid);
143 return;
144 }
146 /* dump type enforcement cache; policy read-locked already */
147 static int
148 ste_dump_policy(u8 *buf, u32 buf_size) {
149 struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
150 int ret = 0;
152 if (buf_size < sizeof(struct acm_ste_policy_buffer))
153 return -EINVAL;
155 ste_buf->ste_max_types = cpu_to_be32(ste_bin_pol.max_types);
156 ste_buf->ste_max_ssidrefs = cpu_to_be32(ste_bin_pol.max_ssidrefs);
157 ste_buf->policy_code = cpu_to_be32(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY);
158 ste_buf->ste_ssid_offset = cpu_to_be32(sizeof(struct acm_ste_policy_buffer));
159 ret = be32_to_cpu(ste_buf->ste_ssid_offset) +
160 sizeof(domaintype_t)*ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types;
162 ret = (ret + 7) & ~7;
164 if (buf_size < ret)
165 return -EINVAL;
167 /* now copy buffer over */
168 arrcpy(buf + be32_to_cpu(ste_buf->ste_ssid_offset),
169 ste_bin_pol.ssidrefs,
170 sizeof(domaintype_t),
171 ste_bin_pol.max_ssidrefs*ste_bin_pol.max_types);
173 return ret;
174 }
176 /* ste_init_state is called when a policy is changed to detect violations (return != 0).
177 * from a security point of view, we simulate that all running domains are re-started and
178 * all sharing decisions are replayed to detect violations or current sharing behavior
179 * (right now: event_channels, future: also grant_tables)
180 */
181 static int
182 ste_init_state(struct acm_sized_buffer *errors)
183 {
184 int violation = 1;
185 struct ste_ssid *ste_ssid, *ste_rssid;
186 ssidref_t ste_ssidref, ste_rssidref;
187 struct domain *d, *rdom;
188 domid_t rdomid;
189 struct active_grant_entry *act;
190 int port, i;
192 rcu_read_lock(&domlist_read_lock);
193 read_lock(&ssid_list_rwlock);
194 /* go through all domains and adjust policy as if this domain was started now */
195 for_each_domain ( d )
196 {
197 struct evtchn *ports;
198 unsigned int bucket;
199 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
200 (struct acm_ssid_domain *)d->ssid);
201 ste_ssidref = ste_ssid->ste_ssidref;
202 traceprintk("%s: validating policy for eventch domain %x (ste-Ref=%x).\n",
203 __func__, d->domain_id, ste_ssidref);
204 /* a) check for event channel conflicts */
205 for (bucket = 0; bucket < NR_EVTCHN_BUCKETS; bucket++) {
206 spin_lock(&d->evtchn_lock);
207 ports = d->evtchn[bucket];
208 if (ports == NULL) {
209 spin_unlock(&d->evtchn_lock);
210 break;
211 }
213 for (port=0; port < EVTCHNS_PER_BUCKET; port++) {
214 if (ports[port].state == ECS_INTERDOMAIN) {
215 rdom = ports[port].u.interdomain.remote_dom;
216 rdomid = rdom->domain_id;
217 } else {
218 continue; /* port unused */
219 }
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) --> "
226 "domain %x (rssidref %x) used (port %x).\n",
227 __func__, d->domain_id, ste_ssidref,
228 rdom->domain_id, ste_rssidref, port);
229 /* check whether on subj->ssid, obj->ssid share a common type*/
230 if (!have_common_type(ste_ssidref, ste_rssidref)) {
231 printkd("%s: Policy violation in event channel domain "
232 "%x -> domain %x.\n",
233 __func__, d->domain_id, rdomid);
234 spin_unlock(&d->evtchn_lock);
236 acm_array_append_tuple(errors,
237 ACM_EVTCHN_SHARING_VIOLATION,
238 d->domain_id << 16 | rdomid);
239 goto out;
240 }
241 }
242 spin_unlock(&d->evtchn_lock);
243 }
246 /* b) check for grant table conflicts on shared pages */
247 spin_lock(&d->grant_table->lock);
248 for ( i = 0; i < nr_active_grant_frames(d->grant_table); i++ ) {
249 #define APP (PAGE_SIZE / sizeof(struct active_grant_entry))
250 act = &d->grant_table->active[i/APP][i%APP];
251 if ( act->pin != 0 ) {
252 printkd("%s: grant dom (%hu) SHARED (%d) pin (%d) "
253 "dom:(%hu) frame:(%lx)\n",
254 __func__, d->domain_id, i, act->pin,
255 act->domid, (unsigned long)act->frame);
256 rdomid = act->domid;
257 if ((rdom = rcu_lock_domain_by_id(rdomid)) == NULL) {
258 spin_unlock(&d->grant_table->lock);
259 printkd("%s: domain not found ERROR!\n", __func__);
261 acm_array_append_tuple(errors,
262 ACM_DOMAIN_LOOKUP,
263 rdomid);
264 goto out;
265 }
266 /* rdom now has remote domain */
267 ste_rssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
268 (struct acm_ssid_domain *)(rdom->ssid));
269 ste_rssidref = ste_rssid->ste_ssidref;
270 rcu_unlock_domain(rdom);
271 if (!have_common_type(ste_ssidref, ste_rssidref)) {
272 spin_unlock(&d->grant_table->lock);
273 printkd("%s: Policy violation in grant table "
274 "sharing domain %x -> domain %x.\n",
275 __func__, d->domain_id, rdomid);
277 acm_array_append_tuple(errors,
278 ACM_GNTTAB_SHARING_VIOLATION,
279 d->domain_id << 16 | rdomid);
280 goto out;
281 }
282 }
283 }
284 spin_unlock(&d->grant_table->lock);
285 }
286 violation = 0;
287 out:
288 read_unlock(&ssid_list_rwlock);
289 rcu_read_unlock(&domlist_read_lock);
290 return violation;
291 /* returning "violation != 0" means that existing sharing between domains would not
292 * have been allowed if the new policy had been enforced before the sharing; for ste,
293 * this means that there are at least 2 domains that have established sharing through
294 * event-channels or grant-tables but these two domains don't have no longer a common
295 * type in their typesets referenced by their ssidrefs */
296 }
299 /*
300 * Call ste_init_state with the current policy.
301 */
302 int
303 do_ste_init_state_curr(struct acm_sized_buffer *errors)
304 {
305 return ste_init_state(errors);
306 }
309 /* set new policy; policy write-locked already */
310 static int
311 _ste_update_policy(u8 *buf, u32 buf_size, int test_only,
312 struct acm_sized_buffer *errors)
313 {
314 int rc = -EFAULT;
315 struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
316 void *ssidrefsbuf;
317 struct ste_ssid *ste_ssid;
318 struct acm_ssid_domain *rawssid;
319 int i;
322 /* 1. create and copy-in new ssidrefs buffer */
323 ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
324 if (ssidrefsbuf == NULL) {
325 return -ENOMEM;
326 }
327 if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
328 goto error_free;
330 arrcpy(ssidrefsbuf,
331 buf + ste_buf->ste_ssid_offset,
332 sizeof(domaintype_t),
333 ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
336 /* 3. in test mode: re-calculate sharing decisions based on running domains;
337 * this can fail if new policy is conflicting with sharing of running domains
338 * now: reject violating new policy; future: adjust sharing through revoking sharing */
340 if (test_only) {
341 /* temporarily replace old policy with new one for the testing */
342 struct ste_binary_policy orig_ste_bin_pol = ste_bin_pol;
343 ste_bin_pol.max_types = ste_buf->ste_max_types;
344 ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
345 ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
347 if (ste_init_state(NULL)) {
348 /* new policy conflicts with sharing of running domains */
349 printk("%s: New policy conflicts with running domains. "
350 "Policy load aborted.\n", __func__);
351 } else {
352 rc = ACM_OK;
353 }
354 /* revert changes, no matter whether testing was successful or not */
355 ste_bin_pol = orig_ste_bin_pol;
356 goto error_free;
357 }
359 /* 3. replace old policy (activate new policy) */
360 ste_bin_pol.max_types = ste_buf->ste_max_types;
361 ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
362 xfree(ste_bin_pol.ssidrefs);
363 ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
365 /* clear all ste caches */
366 read_lock(&ssid_list_rwlock);
368 for_each_acmssid( rawssid ) {
369 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, rawssid);
370 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
371 ste_ssid->ste_cache[i].valid = ACM_STE_free;
372 }
374 read_unlock(&ssid_list_rwlock);
376 return ACM_OK;
378 error_free:
379 if (!test_only) printk("%s: ERROR setting policy.\n", __func__);
380 xfree(ssidrefsbuf);
381 return rc;
382 }
384 static int
385 ste_test_policy(u8 *buf, u32 buf_size, int is_bootpolicy,
386 struct acm_sized_buffer *errors)
387 {
388 struct acm_ste_policy_buffer *ste_buf =
389 (struct acm_ste_policy_buffer *)buf;
391 if (buf_size < sizeof(struct acm_ste_policy_buffer))
392 return -EINVAL;
394 /* Convert endianess of policy */
395 ste_buf->policy_code = be32_to_cpu(ste_buf->policy_code);
396 ste_buf->policy_version = be32_to_cpu(ste_buf->policy_version);
397 ste_buf->ste_max_types = be32_to_cpu(ste_buf->ste_max_types);
398 ste_buf->ste_max_ssidrefs = be32_to_cpu(ste_buf->ste_max_ssidrefs);
399 ste_buf->ste_ssid_offset = be32_to_cpu(ste_buf->ste_ssid_offset);
401 /* policy type and version checks */
402 if ((ste_buf->policy_code != ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY) ||
403 (ste_buf->policy_version != ACM_STE_VERSION))
404 return -EINVAL;
406 /* during boot dom0_chwall_ssidref is set */
407 if (is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs))
408 return -EINVAL;
410 return _ste_update_policy(buf, buf_size, 1, errors);
411 }
413 static int
414 ste_set_policy(u8 *buf, u32 buf_size)
415 {
416 return _ste_update_policy(buf, buf_size, 0, NULL);
417 }
419 static int
420 ste_dump_stats(u8 *buf, u16 buf_len)
421 {
422 struct acm_ste_stats_buffer stats;
424 /* now send the hook counts to user space */
425 stats.ec_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_eval_count));
426 stats.gt_eval_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_eval_count));
427 stats.ec_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_denied_count));
428 stats.gt_denied_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_denied_count));
429 stats.ec_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.ec_cachehit_count));
430 stats.gt_cachehit_count = cpu_to_be32(atomic_read(&ste_bin_pol.gt_cachehit_count));
432 if (buf_len < sizeof(struct acm_ste_stats_buffer))
433 return -ENOMEM;
435 memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
436 return sizeof(struct acm_ste_stats_buffer);
437 }
439 static int
440 ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
441 {
442 int i;
444 /* fill in buffer */
445 if (ste_bin_pol.max_types > len)
446 return -EFAULT;
448 if (ssidref >= ste_bin_pol.max_ssidrefs)
449 return -EFAULT;
451 /* read types for chwall ssidref */
452 for(i=0; i< ste_bin_pol.max_types; i++) {
453 if (ste_bin_pol.ssidrefs[ssidref * ste_bin_pol.max_types + i])
454 buf[i] = 1;
455 else
456 buf[i] = 0;
457 }
458 return ste_bin_pol.max_types;
459 }
461 /* we need to go through this before calling the hooks,
462 * returns 1 == cache hit */
463 static int inline
464 check_cache(struct domain *dom, domid_t rdom) {
465 struct ste_ssid *ste_ssid;
466 int i;
468 printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
470 if (dom->ssid == NULL)
471 return 0;
472 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
473 (struct acm_ssid_domain *)(dom->ssid));
475 for(i=0; i< ACM_TE_CACHE_SIZE; i++) {
476 if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) &&
477 (ste_ssid->ste_cache[i].id == rdom)) {
478 printkd("cache hit (entry %x, id= %x!\n", i, ste_ssid->ste_cache[i].id);
479 return 1;
480 }
481 }
482 return 0;
483 }
486 /* we only get here if there is NO entry yet; no duplication check! */
487 static void inline
488 cache_result(struct domain *subj, struct domain *obj) {
489 struct ste_ssid *ste_ssid;
490 int i;
491 printkd("caching from doms: %x --> %x.\n", subj->domain_id, obj->domain_id);
492 if (subj->ssid == NULL)
493 return;
494 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
495 (struct acm_ssid_domain *)(subj)->ssid);
496 for(i=0; i< ACM_TE_CACHE_SIZE; i++)
497 if (ste_ssid->ste_cache[i].valid == ACM_STE_free)
498 break;
499 if (i< ACM_TE_CACHE_SIZE) {
500 ste_ssid->ste_cache[i].valid = ACM_STE_valid;
501 ste_ssid->ste_cache[i].id = obj->domain_id;
502 } else
503 printk ("Cache of dom %x is full!\n", subj->domain_id);
504 }
506 /* deletes entries for domain 'id' from all caches (re-use) */
507 static void inline
508 clean_id_from_cache(domid_t id)
509 {
510 struct ste_ssid *ste_ssid;
511 int i;
512 struct acm_ssid_domain *rawssid;
514 printkd("deleting cache for dom %x.\n", id);
515 read_lock(&ssid_list_rwlock);
516 /* look through caches of all domains */
518 for_each_acmssid ( rawssid ) {
520 ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, rawssid);
521 if (!ste_ssid) {
522 printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n",
523 __func__);
524 goto out;
525 }
526 for (i=0; i<ACM_TE_CACHE_SIZE; i++)
527 if ((ste_ssid->ste_cache[i].valid == ACM_STE_valid) &&
528 (ste_ssid->ste_cache[i].id == id))
529 ste_ssid->ste_cache[i].valid = ACM_STE_free;
530 }
532 out:
533 read_unlock(&ssid_list_rwlock);
534 }
536 /***************************
537 * Authorization functions
538 **************************/
539 static int
540 ste_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
541 {
542 /* check for ssidref in range for policy */
543 ssidref_t ste_ssidref;
544 traceprintk("%s.\n", __func__);
546 read_lock(&acm_bin_pol_rwlock);
547 ste_ssidref = GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref);
548 if (ste_ssidref == ACM_DEFAULT_LOCAL_SSID) {
549 printk("%s: ERROR STE SSID is NOT SET but policy enforced.\n", __func__);
550 read_unlock(&acm_bin_pol_rwlock);
551 return ACM_ACCESS_DENIED; /* catching and indicating config error */
552 }
553 if (ste_ssidref >= ste_bin_pol.max_ssidrefs) {
554 printk("%s: ERROR ste_ssidref > max(%x).\n",
555 __func__, ste_bin_pol.max_ssidrefs-1);
556 read_unlock(&acm_bin_pol_rwlock);
557 return ACM_ACCESS_DENIED;
558 }
559 read_unlock(&acm_bin_pol_rwlock);
560 return ACM_ACCESS_PERMITTED;
561 }
563 static int
564 ste_domain_create(void *subject_ssid, ssidref_t ssidref, domid_t domid)
565 {
566 return ste_pre_domain_create(subject_ssid, ssidref);
567 }
570 static void
571 ste_domain_destroy(void *subject_ssid, struct domain *d)
572 {
573 /* clean all cache entries for destroyed domain (might be re-used) */
574 clean_id_from_cache(d->domain_id);
575 }
577 /* -------- EVENTCHANNEL OPERATIONS -----------*/
578 static int
579 ste_pre_eventchannel_unbound(domid_t id1, domid_t id2) {
580 struct domain *subj, *obj;
581 int ret;
582 traceprintk("%s: dom%x-->dom%x.\n", __func__,
583 (id1 == DOMID_SELF) ? current->domain->domain_id : id1,
584 (id2 == DOMID_SELF) ? current->domain->domain_id : id2);
586 if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
587 if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
589 subj = rcu_lock_domain_by_id(id1);
590 obj = rcu_lock_domain_by_id(id2);
591 if ((subj == NULL) || (obj == NULL)) {
592 ret = ACM_ACCESS_DENIED;
593 goto out;
594 }
595 /* cache check late */
596 if (check_cache(subj, obj->domain_id)) {
597 atomic_inc(&ste_bin_pol.ec_cachehit_count);
598 ret = ACM_ACCESS_PERMITTED;
599 goto out;
600 }
601 atomic_inc(&ste_bin_pol.ec_eval_count);
603 if (share_common_type(subj, obj)) {
604 cache_result(subj, obj);
605 ret = ACM_ACCESS_PERMITTED;
606 } else {
607 atomic_inc(&ste_bin_pol.ec_denied_count);
608 ret = ACM_ACCESS_DENIED;
609 }
610 out:
611 if (obj != NULL)
612 rcu_unlock_domain(obj);
613 if (subj != NULL)
614 rcu_unlock_domain(subj);
615 return ret;
616 }
618 static int
619 ste_pre_eventchannel_interdomain(domid_t id)
620 {
621 struct domain *subj=NULL, *obj=NULL;
622 int ret;
624 traceprintk("%s: dom%x-->dom%x.\n", __func__,
625 current->domain->domain_id,
626 (id == DOMID_SELF) ? current->domain->domain_id : id);
628 /* following is a bit longer but ensures that we
629 * "put" only domains that we where "find"-ing
630 */
631 if (id == DOMID_SELF) id = current->domain->domain_id;
633 subj = current->domain;
634 obj = rcu_lock_domain_by_id(id);
635 if (obj == NULL) {
636 ret = ACM_ACCESS_DENIED;
637 goto out;
638 }
640 /* cache check late, but evtchn is not on performance critical path */
641 if (check_cache(subj, obj->domain_id)) {
642 atomic_inc(&ste_bin_pol.ec_cachehit_count);
643 ret = ACM_ACCESS_PERMITTED;
644 goto out;
645 }
647 atomic_inc(&ste_bin_pol.ec_eval_count);
649 if (share_common_type(subj, obj)) {
650 cache_result(subj, obj);
651 ret = ACM_ACCESS_PERMITTED;
652 } else {
653 atomic_inc(&ste_bin_pol.ec_denied_count);
654 ret = ACM_ACCESS_DENIED;
655 }
656 out:
657 if (obj != NULL)
658 rcu_unlock_domain(obj);
659 return ret;
660 }
662 /* -------- SHARED MEMORY OPERATIONS -----------*/
664 static int
665 ste_pre_grant_map_ref (domid_t id) {
666 struct domain *obj, *subj;
667 int ret;
668 traceprintk("%s: dom%x-->dom%x.\n", __func__,
669 current->domain->domain_id, id);
671 if (check_cache(current->domain, id)) {
672 atomic_inc(&ste_bin_pol.gt_cachehit_count);
673 return ACM_ACCESS_PERMITTED;
674 }
675 atomic_inc(&ste_bin_pol.gt_eval_count);
676 subj = current->domain;
677 obj = rcu_lock_domain_by_id(id);
679 if (share_common_type(subj, obj)) {
680 cache_result(subj, obj);
681 ret = ACM_ACCESS_PERMITTED;
682 } else {
683 atomic_inc(&ste_bin_pol.gt_denied_count);
684 printkd("%s: ACCESS DENIED!\n", __func__);
685 ret = ACM_ACCESS_DENIED;
686 }
687 if (obj != NULL)
688 rcu_unlock_domain(obj);
689 return ret;
690 }
693 /* since setting up grant tables involves some implicit information
694 flow from the creating domain to the domain that is setup, we
695 check types in addition to the general authorization */
696 static int
697 ste_pre_grant_setup (domid_t id) {
698 struct domain *obj, *subj;
699 int ret;
700 traceprintk("%s: dom%x-->dom%x.\n", __func__,
701 current->domain->domain_id, id);
703 if (check_cache(current->domain, id)) {
704 atomic_inc(&ste_bin_pol.gt_cachehit_count);
705 return ACM_ACCESS_PERMITTED;
706 }
707 atomic_inc(&ste_bin_pol.gt_eval_count);
708 /* a) check authorization (eventually use specific capabilities) */
709 if (!IS_PRIV(current->domain)) {
710 printk("%s: Grant table management authorization denied ERROR!\n", __func__);
711 return ACM_ACCESS_DENIED;
712 }
713 /* b) check types */
714 subj = current->domain;
715 obj = rcu_lock_domain_by_id(id);
717 if (share_common_type(subj, obj)) {
718 cache_result(subj, obj);
719 ret = ACM_ACCESS_PERMITTED;
720 } else {
721 atomic_inc(&ste_bin_pol.gt_denied_count);
722 ret = ACM_ACCESS_DENIED;
723 }
724 if (obj != NULL)
725 rcu_unlock_domain(obj);
726 return ret;
727 }
729 /* -------- DOMAIN-Requested Decision hooks -----------*/
731 static int
732 ste_sharing(ssidref_t ssidref1, ssidref_t ssidref2) {
733 if (have_common_type (
734 GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
735 GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2)
736 ))
737 return ACM_ACCESS_PERMITTED;
738 else
739 return ACM_ACCESS_DENIED;
740 }
743 /* now define the hook structure similarly to LSM */
744 struct acm_operations acm_simple_type_enforcement_ops = {
746 /* policy management services */
747 .init_domain_ssid = ste_init_domain_ssid,
748 .free_domain_ssid = ste_free_domain_ssid,
749 .dump_binary_policy = ste_dump_policy,
750 .test_binary_policy = ste_test_policy,
751 .set_binary_policy = ste_set_policy,
752 .dump_statistics = ste_dump_stats,
753 .dump_ssid_types = ste_dump_ssid_types,
755 /* domain management control hooks */
756 .domain_create = ste_domain_create,
757 .domain_destroy = ste_domain_destroy,
759 /* event channel control hooks */
760 .pre_eventchannel_unbound = ste_pre_eventchannel_unbound,
761 .fail_eventchannel_unbound = NULL,
762 .pre_eventchannel_interdomain = ste_pre_eventchannel_interdomain,
763 .fail_eventchannel_interdomain = NULL,
765 /* grant table control hooks */
766 .pre_grant_map_ref = ste_pre_grant_map_ref,
767 .fail_grant_map_ref = NULL,
768 .pre_grant_setup = ste_pre_grant_setup,
769 .fail_grant_setup = NULL,
770 .sharing = ste_sharing,
771 };
773 /*
774 * Local variables:
775 * mode: C
776 * c-set-style: "BSD"
777 * c-basic-offset: 4
778 * tab-width: 4
779 * indent-tabs-mode: nil
780 * End:
781 */