source: trunk/packages/xen-common/xen-common/xen/acm/acm_chinesewall_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.4 KB
Line 
1/****************************************************************
2 * acm_chinesewall_hooks.c
3 *
4 * Copyright (C) 2005 IBM Corporation
5 *
6 * Author:
7 * Reiner Sailer <sailer@watson.ibm.com>
8 *
9 * Contributions:
10 * Stefan Berger <stefanb@watson.ibm.com>
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License as
14 * published by the Free Software Foundation, version 2 of the
15 * License.
16 *
17 * sHype Chinese Wall Policy for Xen
18 *    This code implements the hooks that are called
19 *    throughout Xen operations and decides authorization
20 *    based on domain types and Chinese Wall conflict type
21 *    sets. The CHWALL policy decides if a new domain can be started
22 *    based on the types of running domains and the type of the
23 *    new domain to be started. If the new domain's type is in
24 *    conflict with types of running domains, then this new domain
25 *    is not allowed to be created. A domain can have multiple types,
26 *    in which case all types of a new domain must be conflict-free
27 *    with all types of already running domains.
28 *
29 * indent -i4 -kr -nut
30 *
31 */
32
33#include <xen/config.h>
34#include <xen/errno.h>
35#include <xen/types.h>
36#include <xen/lib.h>
37#include <xen/delay.h>
38#include <xen/sched.h>
39#include <public/acm.h>
40#include <asm/atomic.h>
41#include <acm/acm_core.h>
42#include <acm/acm_hooks.h>
43#include <acm/acm_endian.h>
44#include <acm/acm_core.h>
45
46ssidref_t dom0_chwall_ssidref = 0x0001;
47
48/* local cache structures for chinese wall policy */
49struct chwall_binary_policy chwall_bin_pol;
50
51/*
52 * Initializing chinese wall policy (will be filled by policy partition
53 * using setpolicy command)
54 */
55int acm_init_chwall_policy(void)
56{
57    /* minimal startup policy; policy write-locked already */
58    chwall_bin_pol.max_types = 1;
59    chwall_bin_pol.max_ssidrefs = 1 + dom0_chwall_ssidref;
60    chwall_bin_pol.max_conflictsets = 1;
61    chwall_bin_pol.ssidrefs =
62        (domaintype_t *) xmalloc_array(domaintype_t,
63                                       chwall_bin_pol.max_ssidrefs *
64                                       chwall_bin_pol.max_types);
65    chwall_bin_pol.conflict_sets =
66        (domaintype_t *) xmalloc_array(domaintype_t,
67                                       chwall_bin_pol.max_conflictsets *
68                                       chwall_bin_pol.max_types);
69    chwall_bin_pol.running_types =
70        (domaintype_t *) xmalloc_array(domaintype_t,
71                                       chwall_bin_pol.max_types);
72    chwall_bin_pol.conflict_aggregate_set =
73        (domaintype_t *) xmalloc_array(domaintype_t,
74                                       chwall_bin_pol.max_types);
75
76    if ((chwall_bin_pol.conflict_sets == NULL)
77        || (chwall_bin_pol.running_types == NULL)
78        || (chwall_bin_pol.ssidrefs == NULL)
79        || (chwall_bin_pol.conflict_aggregate_set == NULL))
80        return ACM_INIT_SSID_ERROR;
81
82    /* initialize state */
83    memset((void *) chwall_bin_pol.ssidrefs, 0,
84           chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types *
85           sizeof(domaintype_t));
86    memset((void *) chwall_bin_pol.conflict_sets, 0,
87           chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types *
88           sizeof(domaintype_t));
89    memset((void *) chwall_bin_pol.running_types, 0,
90           chwall_bin_pol.max_types * sizeof(domaintype_t));
91    memset((void *) chwall_bin_pol.conflict_aggregate_set, 0,
92           chwall_bin_pol.max_types * sizeof(domaintype_t));
93    return ACM_OK;
94}
95
96static int chwall_init_domain_ssid(void **chwall_ssid, ssidref_t ssidref)
97{
98    struct chwall_ssid *chwall_ssidp = xmalloc(struct chwall_ssid);
99    traceprintk("%s.\n", __func__);
100    if (chwall_ssidp == NULL)
101        return ACM_INIT_SSID_ERROR;
102
103    chwall_ssidp->chwall_ssidref =
104        GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
105
106    if ((chwall_ssidp->chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
107        || (chwall_ssidp->chwall_ssidref == ACM_DEFAULT_LOCAL_SSID))
108    {
109        printkd("%s: ERROR chwall_ssidref(%x) undefined (>max) or unset (0).\n",
110                __func__, chwall_ssidp->chwall_ssidref);
111        xfree(chwall_ssidp);
112        return ACM_INIT_SSID_ERROR;
113    }
114    (*chwall_ssid) = chwall_ssidp;
115    printkd("%s: determined chwall_ssidref to %x.\n",
116            __func__, chwall_ssidp->chwall_ssidref);
117    return ACM_OK;
118}
119
120static void chwall_free_domain_ssid(void *chwall_ssid)
121{
122    traceprintk("%s.\n", __func__);
123    xfree(chwall_ssid);
124    return;
125}
126
127
128/* dump chinese wall cache; policy read-locked already */
129static int chwall_dump_policy(u8 * buf, u32 buf_size)
130{
131    struct acm_chwall_policy_buffer *chwall_buf =
132        (struct acm_chwall_policy_buffer *) buf;
133    int ret = 0;
134
135    if (buf_size < sizeof(struct acm_chwall_policy_buffer))
136        return -EINVAL;
137
138    chwall_buf->chwall_max_types = cpu_to_be32(chwall_bin_pol.max_types);
139    chwall_buf->chwall_max_ssidrefs = cpu_to_be32(chwall_bin_pol.max_ssidrefs);
140    chwall_buf->policy_code = cpu_to_be32(ACM_CHINESE_WALL_POLICY);
141    chwall_buf->chwall_ssid_offset =
142        cpu_to_be32(sizeof(struct acm_chwall_policy_buffer));
143    chwall_buf->chwall_max_conflictsets =
144        cpu_to_be32(chwall_bin_pol.max_conflictsets);
145    chwall_buf->chwall_conflict_sets_offset =
146        cpu_to_be32(be32_to_cpu(chwall_buf->chwall_ssid_offset) +
147              sizeof(domaintype_t) * chwall_bin_pol.max_ssidrefs *
148              chwall_bin_pol.max_types);
149    chwall_buf->chwall_running_types_offset =
150        cpu_to_be32(be32_to_cpu(chwall_buf->chwall_conflict_sets_offset) +
151              sizeof(domaintype_t) * chwall_bin_pol.max_conflictsets *
152              chwall_bin_pol.max_types);
153    chwall_buf->chwall_conflict_aggregate_offset =
154        cpu_to_be32(be32_to_cpu(chwall_buf->chwall_running_types_offset) +
155              sizeof(domaintype_t) * chwall_bin_pol.max_types);
156
157    ret = be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset) +
158        sizeof(domaintype_t) * chwall_bin_pol.max_types;
159
160    ret = (ret + 7) & ~7;
161
162    if (buf_size < ret)
163        return -EINVAL;
164
165    /* now copy buffers over */
166    arrcpy16((u16 *) (buf + be32_to_cpu(chwall_buf->chwall_ssid_offset)),
167             chwall_bin_pol.ssidrefs,
168             chwall_bin_pol.max_ssidrefs * chwall_bin_pol.max_types);
169
170    arrcpy16((u16 *) (buf +
171                      be32_to_cpu(chwall_buf->chwall_conflict_sets_offset)),
172             chwall_bin_pol.conflict_sets,
173             chwall_bin_pol.max_conflictsets * chwall_bin_pol.max_types);
174
175    arrcpy16((u16 *) (buf +
176                      be32_to_cpu(chwall_buf->chwall_running_types_offset)),
177             chwall_bin_pol.running_types, chwall_bin_pol.max_types);
178
179    arrcpy16((u16 *) (buf +
180                      be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset)),
181             chwall_bin_pol.conflict_aggregate_set,
182             chwall_bin_pol.max_types);
183    return ret;
184}
185
186/*
187 * Adapt security state (running_types and conflict_aggregate_set) to all
188 * running domains; chwall_init_state is called when a policy is changed
189 * to bring the security information into a consistent state and to detect
190 * violations (return != 0) from a security point of view, we simulate
191 * that all running domains are re-started
192 */
193static int
194chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
195                  domaintype_t * ssidrefs,
196                  domaintype_t * conflict_sets,
197                  domaintype_t * running_types,
198                  domaintype_t * conflict_aggregate_set,
199                  struct acm_sized_buffer *errors /* may be NULL */)
200{
201    int violation = 0, i, j;
202    struct chwall_ssid *chwall_ssid;
203    ssidref_t chwall_ssidref;
204    struct acm_ssid_domain *rawssid;
205
206    read_lock(&ssid_list_rwlock);
207
208    /* go through all domains and adjust policy as if this domain was started now */
209    for_each_acmssid( rawssid )
210    {
211        chwall_ssid =
212            GET_SSIDP(ACM_CHINESE_WALL_POLICY, rawssid);
213        chwall_ssidref = chwall_ssid->chwall_ssidref;
214        traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
215                    __func__, d->domain_id, chwall_ssidref);
216        /* a) adjust types ref-count for running domains */
217        for (i = 0; i < chwall_buf->chwall_max_types; i++)
218            running_types[i] +=
219                ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i];
220
221        /* b) check for conflict */
222        for (i = 0; i < chwall_buf->chwall_max_types; i++)
223            if (conflict_aggregate_set[i] &&
224                ssidrefs[chwall_ssidref * chwall_buf->chwall_max_types + i])
225            {
226                printk("%s: CHINESE WALL CONFLICT in type %02x.\n",
227                       __func__, i);
228                violation = 1;
229
230                acm_array_append_tuple(errors, ACM_CHWALL_CONFLICT, i);
231
232                goto out;
233            }
234        /* set violation and break out of the loop */
235        /* c) adapt conflict aggregate set for this domain (notice conflicts) */
236        for (i = 0; i < chwall_buf->chwall_max_conflictsets; i++)
237        {
238            int common = 0;
239            /* check if conflict_set_i and ssidref have common types */
240            for (j = 0; j < chwall_buf->chwall_max_types; j++)
241                if (conflict_sets[i * chwall_buf->chwall_max_types + j] &&
242                    ssidrefs[chwall_ssidref *
243                            chwall_buf->chwall_max_types + j])
244                {
245                    common = 1;
246                    break;
247                }
248            if (common == 0)
249                continue;       /* try next conflict set */
250            /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
251            for (j = 0; j < chwall_buf->chwall_max_types; j++)
252                if (conflict_sets[i * chwall_buf->chwall_max_types + j] &&
253                    !ssidrefs[chwall_ssidref *
254                             chwall_buf->chwall_max_types + j])
255                    conflict_aggregate_set[j]++;
256        }
257    }
258 out:
259    read_unlock(&ssid_list_rwlock);
260    return violation;
261    /* returning "violation != 0" means that the currently running set of domains would
262     * not be possible if the new policy had been enforced before starting them; for chinese
263     * wall, this means that the new policy includes at least one conflict set of which
264     * more than one type is currently running */
265}
266
267
268int
269do_chwall_init_state_curr(struct acm_sized_buffer *errors)
270{
271    struct acm_chwall_policy_buffer chwall_buf = {
272         /* only these two are important */
273         .chwall_max_types        = chwall_bin_pol.max_types,
274         .chwall_max_conflictsets = chwall_bin_pol.max_conflictsets,
275    };
276    /* reset running_types and aggregate set for recalculation */
277    memset(chwall_bin_pol.running_types,
278           0x0,
279           sizeof(domaintype_t) * chwall_bin_pol.max_types);
280    memset(chwall_bin_pol.conflict_aggregate_set,
281           0x0,
282           sizeof(domaintype_t) * chwall_bin_pol.max_types);
283    return chwall_init_state(&chwall_buf,
284                             chwall_bin_pol.ssidrefs,
285                             chwall_bin_pol.conflict_sets,
286                             chwall_bin_pol.running_types,
287                             chwall_bin_pol.conflict_aggregate_set,
288                             errors);
289}
290
291/*
292 * Attempt to set the policy. This function must be called in test_only
293 * mode first to only perform checks. A second call then does the
294 * actual changes.
295 */
296static int _chwall_update_policy(u8 *buf, u32 buf_size, int test_only,
297                                 struct acm_sized_buffer *errors)
298{
299    int rc = -EFAULT;
300    /* policy write-locked already */
301    struct acm_chwall_policy_buffer *chwall_buf =
302        (struct acm_chwall_policy_buffer *) buf;
303    void *ssids = NULL, *conflict_sets = NULL, *running_types =
304        NULL, *conflict_aggregate_set = NULL;
305
306    /* 1. allocate new buffers */
307    ssids =
308        xmalloc_array(domaintype_t,
309                      chwall_buf->chwall_max_types *
310                      chwall_buf->chwall_max_ssidrefs);
311    conflict_sets =
312        xmalloc_array(domaintype_t,
313                      chwall_buf->chwall_max_conflictsets *
314                      chwall_buf->chwall_max_types);
315    running_types =
316        xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
317    conflict_aggregate_set =
318        xmalloc_array(domaintype_t, chwall_buf->chwall_max_types);
319
320    if ((ssids == NULL) || (conflict_sets == NULL)
321        || (running_types == NULL) || (conflict_aggregate_set == NULL))
322        goto error_free;
323
324    /* 2. set new policy */
325    if (chwall_buf->chwall_ssid_offset + sizeof(domaintype_t) *
326        chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs >
327        buf_size)
328        goto error_free;
329
330    arrcpy(ssids, buf + chwall_buf->chwall_ssid_offset,
331           sizeof(domaintype_t),
332           chwall_buf->chwall_max_types * chwall_buf->chwall_max_ssidrefs);
333
334    if (chwall_buf->chwall_conflict_sets_offset + sizeof(domaintype_t) *
335        chwall_buf->chwall_max_types *
336        chwall_buf->chwall_max_conflictsets > buf_size)
337        goto error_free;
338
339    arrcpy(conflict_sets, buf + chwall_buf->chwall_conflict_sets_offset,
340           sizeof(domaintype_t),
341           chwall_buf->chwall_max_types *
342           chwall_buf->chwall_max_conflictsets);
343
344    /* we also use new state buffers since max_types can change */
345    memset(running_types, 0,
346           sizeof(domaintype_t) * chwall_buf->chwall_max_types);
347    memset(conflict_aggregate_set, 0,
348           sizeof(domaintype_t) * chwall_buf->chwall_max_types);
349
350    /* 3. now re-calculate the state for the new policy based on running domains;
351     *    this can fail if new policy is conflicting with running domains */
352    if (chwall_init_state(chwall_buf, ssids,
353                          conflict_sets, running_types,
354                          conflict_aggregate_set,
355                          errors))
356    {
357        printk("%s: New policy conflicts with running domains. Policy load aborted.\n",
358               __func__);
359        goto error_free;        /* new policy conflicts with running domains */
360    }
361
362    /* if this was only a test run, exit with ACM_OK */
363    if (test_only) {
364        rc = ACM_OK;
365        goto error_free;
366    }
367
368    /* 4. free old policy buffers, replace with new ones */
369    chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
370    chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
371    chwall_bin_pol.max_conflictsets = chwall_buf->chwall_max_conflictsets;
372    xfree(chwall_bin_pol.ssidrefs);
373    xfree(chwall_bin_pol.conflict_aggregate_set);
374    xfree(chwall_bin_pol.running_types);
375    xfree(chwall_bin_pol.conflict_sets);
376    chwall_bin_pol.ssidrefs = ssids;
377    chwall_bin_pol.conflict_aggregate_set = conflict_aggregate_set;
378    chwall_bin_pol.running_types = running_types;
379    chwall_bin_pol.conflict_sets = conflict_sets;
380    return ACM_OK;
381
382 error_free:
383    if (!test_only) printk("%s: ERROR setting policy.\n", __func__);
384    xfree(ssids);
385    xfree(conflict_sets);
386    xfree(running_types);
387    xfree(conflict_aggregate_set);
388    return rc;
389}
390
391/*
392 * This function MUST be called before the chwall_ste_policy function!
393 */
394static int chwall_test_policy(u8 *buf, u32 buf_size, int is_bootpolicy,
395                              struct acm_sized_buffer *errors)
396{
397    struct acm_chwall_policy_buffer *chwall_buf =
398        (struct acm_chwall_policy_buffer *) buf;
399
400    if (buf_size < sizeof(struct acm_chwall_policy_buffer))
401        return -EINVAL;
402
403    /* rewrite the policy due to endianess */
404    chwall_buf->policy_code = be32_to_cpu(chwall_buf->policy_code);
405    chwall_buf->policy_version = be32_to_cpu(chwall_buf->policy_version);
406    chwall_buf->chwall_max_types =
407        be32_to_cpu(chwall_buf->chwall_max_types);
408    chwall_buf->chwall_max_ssidrefs =
409        be32_to_cpu(chwall_buf->chwall_max_ssidrefs);
410    chwall_buf->chwall_max_conflictsets =
411        be32_to_cpu(chwall_buf->chwall_max_conflictsets);
412    chwall_buf->chwall_ssid_offset =
413        be32_to_cpu(chwall_buf->chwall_ssid_offset);
414    chwall_buf->chwall_conflict_sets_offset =
415        be32_to_cpu(chwall_buf->chwall_conflict_sets_offset);
416    chwall_buf->chwall_running_types_offset =
417        be32_to_cpu(chwall_buf->chwall_running_types_offset);
418    chwall_buf->chwall_conflict_aggregate_offset =
419        be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset);
420
421    /* policy type and version checks */
422    if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) ||
423        (chwall_buf->policy_version != ACM_CHWALL_VERSION))
424        return -EINVAL;
425
426    /* during boot dom0_chwall_ssidref is set */
427    if (is_bootpolicy &&
428        (dom0_chwall_ssidref >= chwall_buf->chwall_max_ssidrefs))
429        return -EINVAL;
430
431
432    return _chwall_update_policy(buf, buf_size, 1, errors);
433}
434
435static int chwall_set_policy(u8 *buf, u32 buf_size)
436{
437    return _chwall_update_policy(buf, buf_size, 0, NULL);
438}
439
440static int chwall_dump_stats(u8 * buf, u16 len)
441{
442    /* no stats for Chinese Wall Policy */
443    return 0;
444}
445
446static int chwall_dump_ssid_types(ssidref_t ssidref, u8 * buf, u16 len)
447{
448    int i;
449
450    /* fill in buffer */
451    if (chwall_bin_pol.max_types > len)
452        return -EFAULT;
453
454    if (ssidref >= chwall_bin_pol.max_ssidrefs)
455        return -EFAULT;
456
457    /* read types for chwall ssidref */
458    for (i = 0; i < chwall_bin_pol.max_types; i++)
459    {
460        if (chwall_bin_pol.
461            ssidrefs[ssidref * chwall_bin_pol.max_types + i])
462            buf[i] = 1;
463        else
464            buf[i] = 0;
465    }
466    return chwall_bin_pol.max_types;
467}
468
469/***************************
470 * Authorization functions
471 ***************************/
472
473/* -------- DOMAIN OPERATION HOOKS -----------*/
474
475static int _chwall_pre_domain_create(void *subject_ssid, ssidref_t ssidref)
476{
477    ssidref_t chwall_ssidref;
478    int i, j;
479    traceprintk("%s.\n", __func__);
480
481    chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
482    if (chwall_ssidref == ACM_DEFAULT_LOCAL_SSID)
483    {
484        printk("%s: ERROR CHWALL SSID is NOT SET but policy enforced.\n",
485               __func__);
486        return ACM_ACCESS_DENIED;       /* catching and indicating config error */
487    }
488    if (chwall_ssidref >= chwall_bin_pol.max_ssidrefs)
489    {
490        printk("%s: ERROR chwall_ssidref > max(%x).\n",
491               __func__, chwall_bin_pol.max_ssidrefs - 1);
492        return ACM_ACCESS_DENIED;
493    }
494    /* A: chinese wall check for conflicts */
495    for (i = 0; i < chwall_bin_pol.max_types; i++)
496        if (chwall_bin_pol.conflict_aggregate_set[i] &&
497            chwall_bin_pol.ssidrefs[chwall_ssidref *
498                                   chwall_bin_pol.max_types + i])
499        {
500            printk("%s: CHINESE WALL CONFLICT in type %02x.\n", __func__, i);
501            return ACM_ACCESS_DENIED;
502        }
503
504    /* B: chinese wall conflict set adjustment (so that other
505     *      other domains simultaneously created are evaluated against this new set)*/
506    for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
507    {
508        int common = 0;
509        /* check if conflict_set_i and ssidref have common types */
510        for (j = 0; j < chwall_bin_pol.max_types; j++)
511            if (chwall_bin_pol.
512                conflict_sets[i * chwall_bin_pol.max_types + j]
513                && chwall_bin_pol.ssidrefs[chwall_ssidref *
514                                          chwall_bin_pol.max_types + j])
515            {
516                common = 1;
517                break;
518            }
519        if (common == 0)
520            continue;           /* try next conflict set */
521        /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
522        for (j = 0; j < chwall_bin_pol.max_types; j++)
523            if (chwall_bin_pol.
524                conflict_sets[i * chwall_bin_pol.max_types + j]
525                && !chwall_bin_pol.ssidrefs[chwall_ssidref *
526                                           chwall_bin_pol.max_types + j])
527                chwall_bin_pol.conflict_aggregate_set[j]++;
528    }
529    return ACM_ACCESS_PERMITTED;
530}
531
532
533static void _chwall_post_domain_create(domid_t domid, ssidref_t ssidref)
534{
535    int i, j;
536    ssidref_t chwall_ssidref;
537    traceprintk("%s.\n", __func__);
538
539    chwall_ssidref = GET_SSIDREF(ACM_CHINESE_WALL_POLICY, ssidref);
540    /* adjust types ref-count for running domains */
541    for (i = 0; i < chwall_bin_pol.max_types; i++)
542        chwall_bin_pol.running_types[i] +=
543            chwall_bin_pol.ssidrefs[chwall_ssidref *
544                                   chwall_bin_pol.max_types + i];
545    if (domid)
546    {
547        return;
548    }
549    /* Xen does not call pre-create hook for DOM0;
550     * to consider type conflicts of any domain with DOM0, we need
551     * to adjust the conflict_aggregate for DOM0 here the same way it
552     * is done for non-DOM0 domains in the pre-hook */
553    printkd("%s: adjusting security state for DOM0 (ssidref=%x, chwall_ssidref=%x).\n",
554            __func__, ssidref, chwall_ssidref);
555
556    /* chinese wall conflict set adjustment (so that other
557     *      other domains simultaneously created are evaluated against this new set)*/
558    for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
559    {
560        int common = 0;
561        /* check if conflict_set_i and ssidref have common types */
562        for (j = 0; j < chwall_bin_pol.max_types; j++)
563            if (chwall_bin_pol.
564                conflict_sets[i * chwall_bin_pol.max_types + j]
565                && chwall_bin_pol.ssidrefs[chwall_ssidref *
566                                          chwall_bin_pol.max_types + j])
567            {
568                common = 1;
569                break;
570            }
571        if (common == 0)
572            continue;           /* try next conflict set */
573        /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
574        for (j = 0; j < chwall_bin_pol.max_types; j++)
575            if (chwall_bin_pol.
576                conflict_sets[i * chwall_bin_pol.max_types + j]
577                && !chwall_bin_pol.ssidrefs[chwall_ssidref *
578                                           chwall_bin_pol.max_types + j])
579                chwall_bin_pol.conflict_aggregate_set[j]++;
580    }
581    return;
582}
583
584
585/*
586 * To be called when creating a domain. If this call is unsuccessful,
587 * no state changes have occurred (adjustments of counters etc.). If it
588 * was successful, state was changed and can be undone using
589 * chwall_domain_destroy.
590 */
591static int chwall_domain_create(void *subject_ssid, ssidref_t ssidref,
592                                domid_t domid)
593{
594    int rc;
595    read_lock(&acm_bin_pol_rwlock);
596    rc = _chwall_pre_domain_create(subject_ssid, ssidref);
597    if (rc == ACM_ACCESS_PERMITTED) {
598        _chwall_post_domain_create(domid, ssidref);
599    }
600    read_unlock(&acm_bin_pol_rwlock);
601    return rc;
602}
603
604/*
605 * This function undoes everything a successful call to
606 * chwall_domain_create has done.
607 */
608static void chwall_domain_destroy(void *object_ssid, struct domain *d)
609{
610    int i, j;
611    struct chwall_ssid *chwall_ssidp = GET_SSIDP(ACM_CHINESE_WALL_POLICY,
612                                                 (struct acm_ssid_domain *)
613                                                 object_ssid);
614    ssidref_t chwall_ssidref = chwall_ssidp->chwall_ssidref;
615
616    traceprintk("%s.\n", __func__);
617
618    read_lock(&acm_bin_pol_rwlock);
619    /* adjust running types set */
620    for (i = 0; i < chwall_bin_pol.max_types; i++)
621        chwall_bin_pol.running_types[i] -=
622            chwall_bin_pol.ssidrefs[chwall_ssidref *
623                                   chwall_bin_pol.max_types + i];
624
625    /* roll-back: re-adjust conflicting types aggregate */
626    for (i = 0; i < chwall_bin_pol.max_conflictsets; i++)
627    {
628        int common = 0;
629        /* check if conflict_set_i and ssidref have common types */
630        for (j = 0; j < chwall_bin_pol.max_types; j++)
631            if (chwall_bin_pol.
632                conflict_sets[i * chwall_bin_pol.max_types + j]
633                && chwall_bin_pol.ssidrefs[chwall_ssidref *
634                                          chwall_bin_pol.max_types + j])
635            {
636                common = 1;
637                break;
638            }
639        if (common == 0)
640            continue;           /* try next conflict set, this one does not include any type of chwall_ssidref */
641        /* now add types of the conflict set to conflict_aggregate_set (except types in chwall_ssidref) */
642        for (j = 0; j < chwall_bin_pol.max_types; j++)
643            if (chwall_bin_pol.
644                conflict_sets[i * chwall_bin_pol.max_types + j]
645                && !chwall_bin_pol.ssidrefs[chwall_ssidref *
646                                           chwall_bin_pol.max_types + j])
647                chwall_bin_pol.conflict_aggregate_set[j]--;
648    }
649    read_unlock(&acm_bin_pol_rwlock);
650    return;
651}
652
653struct acm_operations acm_chinesewall_ops = {
654    /* policy management services */
655    .init_domain_ssid = chwall_init_domain_ssid,
656    .free_domain_ssid = chwall_free_domain_ssid,
657    .dump_binary_policy = chwall_dump_policy,
658    .test_binary_policy = chwall_test_policy,
659    .set_binary_policy = chwall_set_policy,
660    .dump_statistics = chwall_dump_stats,
661    .dump_ssid_types = chwall_dump_ssid_types,
662    /* domain management control hooks */
663    .domain_create = chwall_domain_create,
664    .domain_destroy = chwall_domain_destroy,
665    /* event channel control hooks */
666    .pre_eventchannel_unbound = NULL,
667    .fail_eventchannel_unbound = NULL,
668    .pre_eventchannel_interdomain = NULL,
669    .fail_eventchannel_interdomain = NULL,
670    /* grant table control hooks */
671    .pre_grant_map_ref = NULL,
672    .fail_grant_map_ref = NULL,
673    .pre_grant_setup = NULL,
674    .fail_grant_setup = NULL,
675    /* generic domain-requested decision hooks */
676    .sharing = NULL,
677};
678
679/*
680 * Local variables:
681 * mode: C
682 * c-set-style: "BSD"
683 * c-basic-offset: 4
684 * tab-width: 4
685 * indent-tabs-mode: nil
686 * End:
687 */
Note: See TracBrowser for help on using the repository browser.