source: trunk/packages/xen-common/xen-common/xen/acm/acm_core.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: 11.7 KB
Line 
1/****************************************************************
2 * acm_core.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 *
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 access control module (ACM)
18 *       This file handles initialization of the ACM
19 *       as well as initializing/freeing security
20 *       identifiers for domains (it calls on active
21 *       policy hook functions).
22 *
23 */
24
25#include <xen/config.h>
26#include <xen/errno.h>
27#include <xen/types.h>
28#include <xen/lib.h>
29#include <xen/delay.h>
30#include <xen/sched.h>
31#include <xen/multiboot.h>
32#include <acm/acm_hooks.h>
33#include <acm/acm_endian.h>
34
35/* debug:
36 *   include/acm/acm_hooks.h defines a constant ACM_TRACE_MODE;
37 *   define/undefine this constant to receive / suppress any
38 *   security hook debug output of sHype
39 *
40 *   include/public/acm.h defines a constant ACM_DEBUG
41 *   define/undefine this constant to receive non-hook-related
42 *   debug output.
43 */
44
45/* function prototypes */
46void acm_init_chwall_policy(void);
47void acm_init_ste_policy(void);
48
49extern struct acm_operations acm_chinesewall_ops, 
50    acm_simple_type_enforcement_ops, acm_null_ops;
51
52/* global ACM policy  (now dynamically determined at boot time) */
53u16 acm_active_security_policy = ACM_POLICY_UNDEFINED;
54
55/* global ops structs called by the hooks */
56struct acm_operations *acm_primary_ops = NULL;
57/* called in hook if-and-only-if primary succeeds */
58struct acm_operations *acm_secondary_ops = NULL;
59
60/* acm global binary policy (points to 'local' primary and secondary policies */
61struct acm_binary_policy acm_bin_pol;
62/* acm binary policy lock */
63DEFINE_RWLOCK(acm_bin_pol_rwlock);
64
65/* ACM's only accepted policy name during boot */
66char polname[80];
67char *acm_accepted_boot_policy_name = NULL;
68
69/* a lits of all chained ssid structures */
70LIST_HEAD(ssid_list);
71DEFINE_RWLOCK(ssid_list_rwlock);
72
73static void __init set_dom0_ssidref(const char *val)
74{
75    /* expected format:
76         ssidref=<hex number>:<policy name>
77         Policy name must not have a 'space'.
78     */
79    const char *c;
80    int lo, hi;
81    int i;
82    int dom0_ssidref = simple_strtoull(val, &c, 0);
83
84    if (!strncmp(&c[0],":ACM:", 5)) {
85        lo = dom0_ssidref & 0xffff;
86        if (lo < ACM_MAX_NUM_TYPES && lo >= 1)
87            dom0_chwall_ssidref = lo;
88        hi = dom0_ssidref >> 16;
89        if (hi < ACM_MAX_NUM_TYPES && hi >= 1)
90            dom0_ste_ssidref = hi;
91        for (i = 0; i < sizeof(polname); i++) {
92            polname[i] = c[7+i];
93            if (polname[i] == '\0' || polname[i] == '\t' ||
94                polname[i] == '\n' || polname[i] == ' '  ||
95                polname[i] == ':') {
96                break;
97            }
98        }
99        polname[i] = 0;
100        acm_accepted_boot_policy_name = polname;
101    }
102}
103
104custom_param("ssidref", set_dom0_ssidref);
105
106int
107acm_set_policy_reference(u8 *buf, u32 buf_size)
108{
109    char *name = (char *)(buf + sizeof(struct acm_policy_reference_buffer));
110    struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf;
111
112    if (acm_accepted_boot_policy_name != NULL) {
113        if (strcmp(acm_accepted_boot_policy_name, name)) {
114            printk("Policy's name '%s' is not the expected one '%s'.\n",
115                   name, acm_accepted_boot_policy_name);
116            return ACM_ERROR;
117        }
118    }
119
120    acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len));
121
122    if (!acm_bin_pol.policy_reference_name)
123        return -ENOMEM;
124    strlcpy(acm_bin_pol.policy_reference_name, name, be32_to_cpu(pr->len));
125
126    printk("%s: Activating policy %s\n", __func__,
127           acm_bin_pol.policy_reference_name);
128    return 0;
129}
130
131int
132acm_dump_policy_reference(u8 *buf, u32 buf_size)
133{
134    struct acm_policy_reference_buffer *pr_buf = (struct acm_policy_reference_buffer *)buf;
135    int ret = sizeof(struct acm_policy_reference_buffer) + strlen(acm_bin_pol.policy_reference_name) + 1;
136
137    ret = (ret + 7) & ~7;
138    if (buf_size < ret)
139        return -EINVAL;
140
141    memset(buf, 0, ret);
142    pr_buf->len = cpu_to_be32(strlen(acm_bin_pol.policy_reference_name) + 1); /* including stringend '\0' */
143    strlcpy((char *)(buf + sizeof(struct acm_policy_reference_buffer)),
144            acm_bin_pol.policy_reference_name,
145            be32_to_cpu(pr_buf->len));
146    return ret;
147}
148
149int
150acm_init_binary_policy(u32 policy_code)
151{
152    int ret = ACM_OK;
153
154    acm_bin_pol.primary_policy_code = (policy_code & 0x0f);
155    acm_bin_pol.secondary_policy_code = (policy_code >> 4) & 0x0f;
156
157    write_lock(&acm_bin_pol_rwlock);
158
159    /* set primary policy component */
160    switch ((policy_code) & 0x0f)
161    {
162
163    case ACM_CHINESE_WALL_POLICY:
164        acm_init_chwall_policy();
165        acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
166        acm_primary_ops = &acm_chinesewall_ops;
167        break;
168
169    case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
170        acm_init_ste_policy();
171        acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
172        acm_primary_ops = &acm_simple_type_enforcement_ops;
173        break;
174
175    case ACM_NULL_POLICY:
176        acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
177        acm_primary_ops = &acm_null_ops;
178        break;
179
180    default:
181        /* Unknown policy not allowed primary */
182        ret = -EINVAL;
183        goto out;
184    }
185
186    /* secondary policy component part */
187    switch ((policy_code) >> 4)
188    {
189
190    case ACM_NULL_POLICY:
191        acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
192        acm_secondary_ops = &acm_null_ops;
193        break;
194
195    case ACM_CHINESE_WALL_POLICY:
196        if (acm_bin_pol.primary_policy_code == ACM_CHINESE_WALL_POLICY)
197        {   /* not a valid combination */
198            ret = -EINVAL;
199            goto out;
200        }
201        acm_init_chwall_policy();
202        acm_bin_pol.secondary_policy_code = ACM_CHINESE_WALL_POLICY;
203        acm_secondary_ops = &acm_chinesewall_ops;
204        break;
205
206    case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
207        if (acm_bin_pol.primary_policy_code == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY)
208        {   /* not a valid combination */
209            ret = -EINVAL;
210            goto out;
211        }
212        acm_init_ste_policy();
213        acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
214        acm_secondary_ops = &acm_simple_type_enforcement_ops;
215        break;
216
217    default:
218        ret = -EINVAL;
219        goto out;
220    }
221
222 out:
223    write_unlock(&acm_bin_pol_rwlock);
224    return ret;
225}
226
227int
228acm_is_policy(char *buf, unsigned long len)
229{
230    struct acm_policy_buffer *pol;
231
232    if (buf == NULL || len < sizeof(struct acm_policy_buffer))
233        return 0;
234
235    pol = (struct acm_policy_buffer *)buf;
236    return be32_to_cpu(pol->magic) == ACM_MAGIC;
237}
238
239
240static int
241acm_setup(char *policy_start,
242          unsigned long policy_len,
243          int is_bootpolicy)
244{
245    int rc = ACM_OK;
246    struct acm_policy_buffer *pol;
247
248    if (policy_start == NULL || policy_len < sizeof(struct acm_policy_buffer))
249        return rc;
250
251    pol = (struct acm_policy_buffer *)policy_start;
252    if (be32_to_cpu(pol->magic) != ACM_MAGIC)
253        return rc;
254
255    rc = do_acm_set_policy((void *)policy_start, (u32)policy_len,
256                           is_bootpolicy,
257                           NULL, NULL, NULL);
258    if (rc == ACM_OK)
259    {
260        printkd("Policy len  0x%lx, start at %p.\n",policy_len,policy_start);
261    }
262    else
263    {
264        printk("Invalid policy.\n");
265        /* load default policy later */
266        acm_active_security_policy = ACM_POLICY_UNDEFINED;
267    }
268    return rc;
269}
270
271
272int
273acm_init(char *policy_start,
274         unsigned long policy_len)
275{
276    int ret = ACM_OK;
277
278    /* first try to load the boot policy (uses its own locks) */
279    acm_setup(policy_start, policy_len, 1);
280
281    /* a user-provided policy may have any name; only matched during boot */
282    acm_accepted_boot_policy_name = NULL;
283
284    if (acm_active_security_policy != ACM_POLICY_UNDEFINED)
285    {
286        printk("%s: Enforcing %s boot policy.\n", __func__,
287               ACM_POLICY_NAME(acm_active_security_policy));
288        goto out;
289    }
290    /* else continue with the minimal hardcoded default startup policy */
291    printk("%s: Loading default policy (%s).\n",
292           __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY));
293
294    /* (re-)set dom-0 ssidref to default */
295    dom0_ste_ssidref = dom0_chwall_ssidref = 0x0001;
296
297    if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) {
298        ret = -EINVAL;
299        goto out;
300    }
301    acm_active_security_policy = ACM_DEFAULT_SECURITY_POLICY;
302    if (acm_active_security_policy != ACM_NULL_POLICY)
303        acm_bin_pol.policy_reference_name = "DEFAULT";
304    else
305        acm_bin_pol.policy_reference_name = "NULL";
306
307 out:
308    if (ret != ACM_OK)
309    {
310        printk("%s: Error initializing policies.\n", __func__);
311        /* here one could imagine a clean panic */
312        return -EINVAL;
313    }
314    return ret;
315}
316
317int
318acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
319{
320    struct domain *subj = rcu_lock_domain_by_id(id);
321    int ret;
322 
323    if (subj == NULL)
324    {
325        printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
326        return ACM_NULL_POINTER_ERROR;
327    }
328
329    ret = acm_init_domain_ssid_new(subj, ssidref);
330
331    rcu_unlock_domain(subj);
332
333    return ret;
334}
335
336int acm_init_domain_ssid_new(struct domain *subj, ssidref_t ssidref)
337{
338    struct acm_ssid_domain *ssid;
339    int ret1, ret2;
340    if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
341    {
342        return ACM_INIT_SSID_ERROR;
343    }
344
345    INIT_LIST_HEAD(&ssid->node);
346    ssid->datatype       = ACM_DATATYPE_domain;
347    ssid->subject        = subj;
348    ssid->domainid       = subj->domain_id;
349    ssid->primary_ssid   = NULL;
350    ssid->secondary_ssid = NULL;
351
352    if (acm_active_security_policy != ACM_NULL_POLICY)
353        ssid->ssidref = ssidref;
354    else
355        ssid->ssidref = ACM_DEFAULT_SSID;
356
357    subj->ssid           = ssid;
358    /* now fill in primary and secondary parts; we only get here through hooks */
359    if (acm_primary_ops->init_domain_ssid != NULL)
360        ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
361    else
362        ret1 = ACM_OK;
363
364    if (acm_secondary_ops->init_domain_ssid != NULL)
365        ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
366    else
367        ret2 = ACM_OK;
368
369    if ((ret1 != ACM_OK) || (ret2 != ACM_OK))
370    {
371        printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
372               __func__, subj->domain_id);
373        acm_free_domain_ssid(ssid);
374        return ACM_INIT_SSID_ERROR;
375    }
376
377    write_lock(&ssid_list_rwlock);
378    list_add(&ssid->node, &ssid_list);
379    write_unlock(&ssid_list_rwlock);
380
381    printkd("%s: assigned domain %x the ssidref=%x.\n",
382           __func__, subj->domain_id, ssid->ssidref);
383    return ACM_OK;
384}
385
386
387void
388acm_free_domain_ssid(struct acm_ssid_domain *ssid)
389{
390    /* domain is already gone, just ssid is left */
391    if (ssid == NULL)
392        return;
393
394    ssid->subject = NULL;
395    if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
396        acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
397    ssid->primary_ssid = NULL;
398    if (acm_secondary_ops->free_domain_ssid != NULL)
399        acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
400    ssid->secondary_ssid = NULL;
401
402    write_lock(&ssid_list_rwlock);
403    list_del(&ssid->node);
404    write_unlock(&ssid_list_rwlock);
405
406    xfree(ssid);
407    printkd("%s: Freed individual domain ssid (domain=%02x).\n",
408            __func__, id);
409}
410
411/*
412 * Local variables:
413 * mode: C
414 * c-set-style: "BSD"
415 * c-basic-offset: 4
416 * tab-width: 4
417 * indent-tabs-mode: nil
418 * End:
419 */
Note: See TracBrowser for help on using the repository browser.