ia64/xen-unstable

view xen/acm/acm_core.c @ 14858:249de074617f

Added documentation, C bindings, and test for VM_metrics.VCPUs_flags.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author Ewan Mellor <ewan@xensource.com>
date Fri Apr 13 18:14:06 2007 +0100 (2007-04-13)
parents 4434d1039a65
children b43bd71ee65b
line source
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 */
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>
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 */
45 /* function prototypes */
46 void acm_init_chwall_policy(void);
47 void acm_init_ste_policy(void);
49 extern struct acm_operations acm_chinesewall_ops,
50 acm_simple_type_enforcement_ops, acm_null_ops;
52 /* global ACM policy (now dynamically determined at boot time) */
53 u16 acm_active_security_policy = ACM_POLICY_UNDEFINED;
55 /* global ops structs called by the hooks */
56 struct acm_operations *acm_primary_ops = NULL;
57 /* called in hook if-and-only-if primary succeeds */
58 struct acm_operations *acm_secondary_ops = NULL;
60 /* acm global binary policy (points to 'local' primary and secondary policies */
61 struct acm_binary_policy acm_bin_pol;
62 /* acm binary policy lock */
63 DEFINE_RWLOCK(acm_bin_pol_rwlock);
65 /* ACM's only accepted policy name */
66 char polname[80];
67 char *acm_accepted_boot_policy_name = NULL;
69 static void __init set_dom0_ssidref(const char *val)
70 {
71 /* expected format:
72 ssidref=<hex number>:<policy name>
73 Policy name must not have a 'space'.
74 */
75 const char *c;
76 int lo, hi;
77 int i;
78 int dom0_ssidref = simple_strtoull(val, &c, 0);
80 if (!strncmp(&c[0],":sHype:", 7)) {
81 lo = dom0_ssidref & 0xffff;
82 if (lo < ACM_MAX_NUM_TYPES && lo >= 1)
83 dom0_chwall_ssidref = lo;
84 hi = dom0_ssidref >> 16;
85 if (hi < ACM_MAX_NUM_TYPES && hi >= 1)
86 dom0_ste_ssidref = hi;
87 for (i = 0; i < sizeof(polname); i++) {
88 polname[i] = c[7+i];
89 if (polname[i] == '\0' || polname[i] == '\t' ||
90 polname[i] == '\n' || polname[i] == ' ' ||
91 polname[i] == ':') {
92 break;
93 }
94 }
95 polname[i] = 0;
96 acm_accepted_boot_policy_name = polname;
97 }
98 }
100 custom_param("ssidref", set_dom0_ssidref);
102 int
103 acm_set_policy_reference(u8 *buf, u32 buf_size)
104 {
105 char *name = (char *)(buf + sizeof(struct acm_policy_reference_buffer));
106 struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf;
108 if (acm_accepted_boot_policy_name != NULL) {
109 if (strcmp(acm_accepted_boot_policy_name, name)) {
110 printk("Policy's name '%s' is not the expected one '%s'.\n",
111 name, acm_accepted_boot_policy_name);
112 return ACM_ERROR;
113 }
114 }
116 acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len));
118 if (!acm_bin_pol.policy_reference_name)
119 return -ENOMEM;
120 strlcpy(acm_bin_pol.policy_reference_name, name, be32_to_cpu(pr->len));
122 printk("%s: Activating policy %s\n", __func__,
123 acm_bin_pol.policy_reference_name);
124 return 0;
125 }
127 int
128 acm_dump_policy_reference(u8 *buf, u32 buf_size)
129 {
130 struct acm_policy_reference_buffer *pr_buf = (struct acm_policy_reference_buffer *)buf;
131 int ret = sizeof(struct acm_policy_reference_buffer) + strlen(acm_bin_pol.policy_reference_name) + 1;
133 ret = (ret + 7) & ~7;
134 if (buf_size < ret)
135 return -EINVAL;
137 memset(buf, 0, ret);
138 pr_buf->len = cpu_to_be32(strlen(acm_bin_pol.policy_reference_name) + 1); /* including stringend '\0' */
139 strlcpy((char *)(buf + sizeof(struct acm_policy_reference_buffer)),
140 acm_bin_pol.policy_reference_name,
141 be32_to_cpu(pr_buf->len));
142 return ret;
143 }
145 int
146 acm_init_binary_policy(u32 policy_code)
147 {
148 int ret = ACM_OK;
150 acm_bin_pol.primary_policy_code = (policy_code & 0x0f);
151 acm_bin_pol.secondary_policy_code = (policy_code >> 4) & 0x0f;
153 write_lock(&acm_bin_pol_rwlock);
155 /* set primary policy component */
156 switch ((policy_code) & 0x0f)
157 {
159 case ACM_CHINESE_WALL_POLICY:
160 acm_init_chwall_policy();
161 acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
162 acm_primary_ops = &acm_chinesewall_ops;
163 break;
165 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
166 acm_init_ste_policy();
167 acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
168 acm_primary_ops = &acm_simple_type_enforcement_ops;
169 break;
171 case ACM_NULL_POLICY:
172 acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
173 acm_primary_ops = &acm_null_ops;
174 break;
176 default:
177 /* Unknown policy not allowed primary */
178 ret = -EINVAL;
179 goto out;
180 }
182 /* secondary policy component part */
183 switch ((policy_code) >> 4)
184 {
186 case ACM_NULL_POLICY:
187 acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
188 acm_secondary_ops = &acm_null_ops;
189 break;
191 case ACM_CHINESE_WALL_POLICY:
192 if (acm_bin_pol.primary_policy_code == ACM_CHINESE_WALL_POLICY)
193 { /* not a valid combination */
194 ret = -EINVAL;
195 goto out;
196 }
197 acm_init_chwall_policy();
198 acm_bin_pol.secondary_policy_code = ACM_CHINESE_WALL_POLICY;
199 acm_secondary_ops = &acm_chinesewall_ops;
200 break;
202 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
203 if (acm_bin_pol.primary_policy_code == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY)
204 { /* not a valid combination */
205 ret = -EINVAL;
206 goto out;
207 }
208 acm_init_ste_policy();
209 acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
210 acm_secondary_ops = &acm_simple_type_enforcement_ops;
211 break;
213 default:
214 ret = -EINVAL;
215 goto out;
216 }
218 out:
219 write_unlock(&acm_bin_pol_rwlock);
220 return ret;
221 }
223 int
224 acm_is_policy(char *buf, unsigned long len)
225 {
226 struct acm_policy_buffer *pol;
228 if (buf == NULL || len < sizeof(struct acm_policy_buffer))
229 return 0;
231 pol = (struct acm_policy_buffer *)buf;
232 return be32_to_cpu(pol->magic) == ACM_MAGIC;
233 }
236 static int
237 acm_setup(char *policy_start,
238 unsigned long policy_len,
239 int is_bootpolicy)
240 {
241 int rc = ACM_OK;
242 struct acm_policy_buffer *pol;
244 if (policy_start == NULL || policy_len < sizeof(struct acm_policy_buffer))
245 return rc;
247 pol = (struct acm_policy_buffer *)policy_start;
248 if (be32_to_cpu(pol->magic) != ACM_MAGIC)
249 return rc;
251 rc = do_acm_set_policy((void *)policy_start, (u32)policy_len,
252 is_bootpolicy);
253 if (rc == ACM_OK)
254 {
255 printkd("Policy len 0x%lx, start at %p.\n",policy_len,policy_start);
256 }
257 else
258 {
259 printk("Invalid policy.\n");
260 /* load default policy later */
261 acm_active_security_policy = ACM_POLICY_UNDEFINED;
262 }
263 return rc;
264 }
267 int
268 acm_init(char *policy_start,
269 unsigned long policy_len)
270 {
271 int ret = ACM_OK;
273 /* first try to load the boot policy (uses its own locks) */
274 acm_setup(policy_start, policy_len, 1);
276 /* a user-provided policy may have any name; only matched during boot */
277 acm_accepted_boot_policy_name = NULL;
279 if (acm_active_security_policy != ACM_POLICY_UNDEFINED)
280 {
281 printk("%s: Enforcing %s boot policy.\n", __func__,
282 ACM_POLICY_NAME(acm_active_security_policy));
283 goto out;
284 }
285 /* else continue with the minimal hardcoded default startup policy */
286 printk("%s: Loading default policy (%s).\n",
287 __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY));
289 /* (re-)set dom-0 ssidref to default */
290 dom0_ste_ssidref = dom0_chwall_ssidref = 0x0001;
292 if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) {
293 ret = -EINVAL;
294 goto out;
295 }
296 acm_active_security_policy = ACM_DEFAULT_SECURITY_POLICY;
297 if (acm_active_security_policy != ACM_NULL_POLICY)
298 acm_bin_pol.policy_reference_name = "DEFAULT";
299 else
300 acm_bin_pol.policy_reference_name = "NULL";
302 out:
303 if (ret != ACM_OK)
304 {
305 printk("%s: Error initializing policies.\n", __func__);
306 /* here one could imagine a clean panic */
307 return -EINVAL;
308 }
309 return ret;
310 }
312 int
313 acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
314 {
315 struct acm_ssid_domain *ssid;
316 struct domain *subj = rcu_lock_domain_by_id(id);
317 int ret1, ret2;
319 if (subj == NULL)
320 {
321 printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
322 return ACM_NULL_POINTER_ERROR;
323 }
324 if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
325 {
326 rcu_unlock_domain(subj);
327 return ACM_INIT_SSID_ERROR;
328 }
330 ssid->datatype = ACM_DATATYPE_domain;
331 ssid->subject = subj;
332 ssid->domainid = subj->domain_id;
333 ssid->primary_ssid = NULL;
334 ssid->secondary_ssid = NULL;
336 if (acm_active_security_policy != ACM_NULL_POLICY)
337 ssid->ssidref = ssidref;
338 else
339 ssid->ssidref = ACM_DEFAULT_SSID;
341 subj->ssid = ssid;
342 /* now fill in primary and secondary parts; we only get here through hooks */
343 if (acm_primary_ops->init_domain_ssid != NULL)
344 ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
345 else
346 ret1 = ACM_OK;
348 if (acm_secondary_ops->init_domain_ssid != NULL)
349 ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
350 else
351 ret2 = ACM_OK;
353 if ((ret1 != ACM_OK) || (ret2 != ACM_OK))
354 {
355 printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
356 __func__, subj->domain_id);
357 acm_free_domain_ssid(ssid);
358 rcu_unlock_domain(subj);
359 return ACM_INIT_SSID_ERROR;
360 }
361 printkd("%s: assigned domain %x the ssidref=%x.\n",
362 __func__, id, ssid->ssidref);
363 rcu_unlock_domain(subj);
364 return ACM_OK;
365 }
368 void
369 acm_free_domain_ssid(struct acm_ssid_domain *ssid)
370 {
371 /* domain is already gone, just ssid is left */
372 if (ssid == NULL)
373 return;
375 ssid->subject = NULL;
376 if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
377 acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
378 ssid->primary_ssid = NULL;
379 if (acm_secondary_ops->free_domain_ssid != NULL)
380 acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
381 ssid->secondary_ssid = NULL;
382 xfree(ssid);
383 printkd("%s: Freed individual domain ssid (domain=%02x).\n",
384 __func__, id);
385 }
387 /*
388 * Local variables:
389 * mode: C
390 * c-set-style: "BSD"
391 * c-basic-offset: 4
392 * tab-width: 4
393 * indent-tabs-mode: nil
394 * End:
395 */