source: trunk/packages/xen-common/xen-common/xen/acm/acm_simple_type_enforcement_hooks.c @ 77

Last change on this file since 77 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 25.9 KB
Line 
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 */
27
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>
35
36ssidref_t dom0_ste_ssidref = 0x0001;
37
38/* local cache structures for STE policy */
39struct ste_binary_policy ste_bin_pol;
40
41static 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}
51
52/* Helper function: return = (subj and obj share a common type) */
53static int share_common_type(struct domain *subj, struct domain *obj)
54{
55    ssidref_t ref_s, ref_o;
56    int ret;
57
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}
71
72/*
73 * Initializing STE policy (will be filled by policy partition
74 * using setpolicy command)
75 */
76int 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);
85
86    if (ste_bin_pol.ssidrefs == NULL)
87        return ACM_INIT_SSID_ERROR;
88
89    memset(ste_bin_pol.ssidrefs, 0, sizeof(domaintype_t) *
90                                    ste_bin_pol.max_types *
91                                    ste_bin_pol.max_ssidrefs);
92
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;
95
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}
105
106
107/* ste initialization function hooks */
108static int
109ste_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__);
114
115    if (ste_ssidp == NULL)
116        return ACM_INIT_SSID_ERROR;
117
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;
130
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}
136
137
138static void
139ste_free_domain_ssid(void *ste_ssid)
140{
141    traceprintk("%s.\n", __func__);
142    xfree(ste_ssid);
143    return;
144}
145
146/* dump type enforcement cache; policy read-locked already */
147static int 
148ste_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;
151
152    if (buf_size < sizeof(struct acm_ste_policy_buffer))
153        return -EINVAL;
154
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;
161
162    ret = (ret + 7) & ~7;
163
164    if (buf_size < ret)
165        return -EINVAL;
166
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);
172
173    return ret;
174}
175
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 */ 
181static int
182ste_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;
191
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            }
212
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                }
220
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);
235
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        } 
244
245
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__);
260
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);
276
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}
297
298
299/*
300 * Call ste_init_state with the current policy.
301 */
302int
303do_ste_init_state_curr(struct acm_sized_buffer *errors)
304{
305    return ste_init_state(errors);
306}
307
308
309/* set new policy; policy write-locked already */
310static 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;
320
321
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;
329
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);
334
335
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 */
339
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;
346
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    }
358
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;
364
365    /* clear all ste caches */
366    read_lock(&ssid_list_rwlock);
367
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    }
373
374    read_unlock(&ssid_list_rwlock);
375
376    return ACM_OK;
377
378 error_free:
379    if (!test_only) printk("%s: ERROR setting policy.\n", __func__);
380    xfree(ssidrefsbuf);
381    return rc;
382}
383
384static int
385ste_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;
390
391    if (buf_size < sizeof(struct acm_ste_policy_buffer))
392        return -EINVAL;
393
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);
400
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;
405
406    /* during boot dom0_chwall_ssidref is set */
407    if (is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs))
408        return -EINVAL;
409
410    return _ste_update_policy(buf, buf_size, 1, errors);
411}
412
413static int
414ste_set_policy(u8 *buf, u32 buf_size)
415{
416    return _ste_update_policy(buf, buf_size, 0, NULL);
417}
418
419static int 
420ste_dump_stats(u8 *buf, u16 buf_len)
421{
422    struct acm_ste_stats_buffer stats;
423
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));
431
432    if (buf_len < sizeof(struct acm_ste_stats_buffer))
433        return -ENOMEM;
434
435    memcpy(buf, &stats, sizeof(struct acm_ste_stats_buffer));
436    return sizeof(struct acm_ste_stats_buffer);
437}
438
439static int
440ste_dump_ssid_types(ssidref_t ssidref, u8 *buf, u16 len)
441{
442    int i;
443
444    /* fill in buffer */
445    if (ste_bin_pol.max_types > len)
446        return -EFAULT;
447
448    if (ssidref >= ste_bin_pol.max_ssidrefs)
449        return -EFAULT;
450
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}
460
461/* we need to go through this before calling the hooks,
462 * returns 1 == cache hit */
463static int inline
464check_cache(struct domain *dom, domid_t rdom) {
465    struct ste_ssid *ste_ssid;
466    int i;
467
468    printkd("checking cache: %x --> %x.\n", dom->domain_id, rdom);
469
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));
474
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}
484
485
486/* we only get here if there is NO entry yet; no duplication check! */
487static void inline
488cache_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}
505
506/* deletes entries for domain 'id' from all caches (re-use) */
507static void inline
508clean_id_from_cache(domid_t id) 
509{
510    struct ste_ssid *ste_ssid;
511    int i;
512    struct acm_ssid_domain *rawssid;
513
514    printkd("deleting cache for dom %x.\n", id);
515    read_lock(&ssid_list_rwlock);
516    /* look through caches of all domains */
517
518    for_each_acmssid ( rawssid ) {
519
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    }
531
532 out:
533    read_unlock(&ssid_list_rwlock);
534}
535
536/***************************
537 * Authorization functions
538 **************************/
539static int 
540ste_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__);
545
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}
562
563static int
564ste_domain_create(void *subject_ssid, ssidref_t ssidref, domid_t  domid)
565{
566    return ste_pre_domain_create(subject_ssid, ssidref);
567}
568
569
570static void 
571ste_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}
576
577/* -------- EVENTCHANNEL OPERATIONS -----------*/
578static int
579ste_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);
585
586    if (id1 == DOMID_SELF) id1 = current->domain->domain_id;
587    if (id2 == DOMID_SELF) id2 = current->domain->domain_id;
588
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);
602
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}
617
618static int
619ste_pre_eventchannel_interdomain(domid_t id)
620{
621    struct domain *subj=NULL, *obj=NULL;
622    int ret;
623
624    traceprintk("%s: dom%x-->dom%x.\n", __func__,
625                current->domain->domain_id,
626                (id == DOMID_SELF) ? current->domain->domain_id : id);
627
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;
632
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    }
639
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    }
646
647    atomic_inc(&ste_bin_pol.ec_eval_count);
648
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}
661
662/* -------- SHARED MEMORY OPERATIONS -----------*/
663
664static int
665ste_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);
670
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);
678
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}
691
692
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 */
696static int
697ste_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);
702
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);
716
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}
728
729/* -------- DOMAIN-Requested Decision hooks -----------*/
730
731static int
732ste_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}
741
742
743/* now define the hook structure similarly to LSM */
744struct acm_operations acm_simple_type_enforcement_ops = {
745
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,
754
755    /* domain management control hooks */
756    .domain_create = ste_domain_create,
757    .domain_destroy    = ste_domain_destroy,
758
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,
764
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};
772
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 */
Note: See TracBrowser for help on using the repository browser.