ia64/xen-unstable

view xen/acm/acm_core.c @ 10411:4f0bc5744557

[LINUX] Network buffers do not need to be multi-page contiguous
for unprivileged domains (in any case, can fall back to swiotlb).
On non-privileged domain of Xen/IA64, this caused some trouble.
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author kaf24@firebug.cl.cam.ac.uk
date Thu Jun 15 13:19:04 2006 +0100 (2006-06-15)
parents 96b1479305ce
children 21e6625a6c01
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 rwlock_t acm_bin_pol_rwlock = RW_LOCK_UNLOCKED;
65 /* until we have endian support in Xen, we discover it at runtime */
66 u8 little_endian = 1;
67 void
68 acm_set_endian(void)
69 {
70 u32 test = 1;
71 if (*((u8 *)&test) == 1)
72 {
73 printkd("ACM module running in LITTLE ENDIAN.\n");
74 little_endian = 1;
75 }
76 else
77 {
78 printkd("ACM module running in BIG ENDIAN.\n");
79 little_endian = 0;
80 }
81 }
83 int
84 acm_set_policy_reference(u8 * buf, u32 buf_size)
85 {
86 struct acm_policy_reference_buffer *pr = (struct acm_policy_reference_buffer *)buf;
87 acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, ntohl(pr->len));
89 if (!acm_bin_pol.policy_reference_name)
90 return -ENOMEM;
92 strcpy(acm_bin_pol.policy_reference_name, (char *)(buf + sizeof(struct acm_policy_reference_buffer)));
93 printk("%s: Activating policy %s\n", __func__, acm_bin_pol.policy_reference_name);
94 return 0;
95 }
97 int
98 acm_dump_policy_reference(u8 *buf, u32 buf_size)
99 {
100 struct acm_policy_reference_buffer *pr_buf = (struct acm_policy_reference_buffer *)buf;
101 int ret = sizeof(struct acm_policy_reference_buffer) + strlen(acm_bin_pol.policy_reference_name) + 1;
103 if (buf_size < ret)
104 return -EINVAL;
106 pr_buf->len = htonl(strlen(acm_bin_pol.policy_reference_name) + 1); /* including stringend '\0' */
107 strcpy((char *)(buf + sizeof(struct acm_policy_reference_buffer)),
108 acm_bin_pol.policy_reference_name);
109 return ret;
110 }
112 int
113 acm_init_binary_policy(u32 policy_code)
114 {
115 int ret = ACM_OK;
117 acm_bin_pol.primary_policy_code = (policy_code & 0x0f);
118 acm_bin_pol.secondary_policy_code = (policy_code >> 4) & 0x0f;
120 write_lock(&acm_bin_pol_rwlock);
122 /* set primary policy component */
123 switch ((policy_code) & 0x0f)
124 {
126 case ACM_CHINESE_WALL_POLICY:
127 acm_init_chwall_policy();
128 acm_bin_pol.primary_policy_code = ACM_CHINESE_WALL_POLICY;
129 acm_primary_ops = &acm_chinesewall_ops;
130 break;
132 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
133 acm_init_ste_policy();
134 acm_bin_pol.primary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
135 acm_primary_ops = &acm_simple_type_enforcement_ops;
136 break;
138 case ACM_NULL_POLICY:
139 acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
140 acm_primary_ops = &acm_null_ops;
141 break;
143 default:
144 /* Unknown policy not allowed primary */
145 ret = -EINVAL;
146 goto out;
147 }
149 /* secondary policy component part */
150 switch ((policy_code) >> 4)
151 {
153 case ACM_NULL_POLICY:
154 acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
155 acm_secondary_ops = &acm_null_ops;
156 break;
158 case ACM_CHINESE_WALL_POLICY:
159 if (acm_bin_pol.primary_policy_code == ACM_CHINESE_WALL_POLICY)
160 { /* not a valid combination */
161 ret = -EINVAL;
162 goto out;
163 }
164 acm_init_chwall_policy();
165 acm_bin_pol.secondary_policy_code = ACM_CHINESE_WALL_POLICY;
166 acm_secondary_ops = &acm_chinesewall_ops;
167 break;
169 case ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY:
170 if (acm_bin_pol.primary_policy_code == ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY)
171 { /* not a valid combination */
172 ret = -EINVAL;
173 goto out;
174 }
175 acm_init_ste_policy();
176 acm_bin_pol.secondary_policy_code = ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY;
177 acm_secondary_ops = &acm_simple_type_enforcement_ops;
178 break;
180 default:
181 ret = -EINVAL;
182 goto out;
183 }
185 out:
186 write_unlock(&acm_bin_pol_rwlock);
187 return ret;
188 }
190 static int
191 acm_setup(unsigned int *initrdidx,
192 const multiboot_info_t *mbi,
193 unsigned long initial_images_start)
194 {
195 int i;
196 module_t *mod = (module_t *)__va(mbi->mods_addr);
197 int rc = ACM_OK;
199 if (mbi->mods_count > 1)
200 *initrdidx = 1;
202 /*
203 * Try all modules and see whichever could be the binary policy.
204 * Adjust the initrdidx if module[1] is the binary policy.
205 */
206 for (i = mbi->mods_count-1; i >= 1; i--)
207 {
208 struct acm_policy_buffer *pol;
209 char *_policy_start;
210 unsigned long _policy_len;
211 #if defined(__i386__)
212 _policy_start = (char *)(initial_images_start + (mod[i].mod_start-mod[0].mod_start));
213 #elif defined(__x86_64__)
214 _policy_start = __va(initial_images_start + (mod[i].mod_start-mod[0].mod_start));
215 #else
216 #error Architecture unsupported by sHype
217 #endif
218 _policy_len = mod[i].mod_end - mod[i].mod_start;
219 if (_policy_len < sizeof(struct acm_policy_buffer))
220 continue; /* not a policy */
222 pol = (struct acm_policy_buffer *)_policy_start;
223 if (ntohl(pol->magic) == ACM_MAGIC)
224 {
225 rc = acm_set_policy((void *)_policy_start,
226 (u32)_policy_len,
227 0);
228 if (rc == ACM_OK)
229 {
230 printkd("Policy len 0x%lx, start at %p.\n",_policy_len,_policy_start);
231 if (i == 1)
232 {
233 if (mbi->mods_count > 2)
234 {
235 *initrdidx = 2;
236 }
237 else {
238 *initrdidx = 0;
239 }
240 }
241 else
242 {
243 *initrdidx = 1;
244 }
245 break;
246 }
247 else
248 {
249 printk("Invalid policy. %d.th module line.\n", i+1);
250 /* load default policy later */
251 acm_active_security_policy = ACM_POLICY_UNDEFINED;
252 }
253 } /* end if a binary policy definition, i.e., (ntohl(pol->magic) == ACM_MAGIC ) */
254 }
255 return rc;
256 }
259 int
260 acm_init(unsigned int *initrdidx,
261 const multiboot_info_t *mbi,
262 unsigned long initial_images_start)
263 {
264 int ret = ACM_OK;
266 acm_set_endian();
268 /* first try to load the boot policy (uses its own locks) */
269 acm_setup(initrdidx, mbi, initial_images_start);
271 if (acm_active_security_policy != ACM_POLICY_UNDEFINED)
272 {
273 printk("%s: Enforcing %s boot policy.\n", __func__,
274 ACM_POLICY_NAME(acm_active_security_policy));
275 goto out;
276 }
277 /* else continue with the minimal hardcoded default startup policy */
278 printk("%s: Loading default policy (%s).\n",
279 __func__, ACM_POLICY_NAME(ACM_DEFAULT_SECURITY_POLICY));
281 if (acm_init_binary_policy(ACM_DEFAULT_SECURITY_POLICY)) {
282 ret = -EINVAL;
283 goto out;
284 }
285 acm_active_security_policy = ACM_DEFAULT_SECURITY_POLICY;
286 if (acm_active_security_policy != ACM_NULL_POLICY)
287 acm_bin_pol.policy_reference_name = "DEFAULT";
288 else
289 acm_bin_pol.policy_reference_name = "NULL";
291 out:
292 if (ret != ACM_OK)
293 {
294 printk("%s: Error initializing policies.\n", __func__);
295 /* here one could imagine a clean panic */
296 return -EINVAL;
297 }
298 return ret;
299 }
301 int
302 acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
303 {
304 struct acm_ssid_domain *ssid;
305 struct domain *subj = find_domain_by_id(id);
306 int ret1, ret2;
308 if (subj == NULL)
309 {
310 printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
311 return ACM_NULL_POINTER_ERROR;
312 }
313 if ((ssid = xmalloc(struct acm_ssid_domain)) == NULL)
314 {
315 put_domain(subj);
316 return ACM_INIT_SSID_ERROR;
317 }
319 ssid->datatype = ACM_DATATYPE_domain;
320 ssid->subject = subj;
321 ssid->domainid = subj->domain_id;
322 ssid->primary_ssid = NULL;
323 ssid->secondary_ssid = NULL;
325 if (acm_active_security_policy != ACM_NULL_POLICY)
326 ssid->ssidref = ssidref;
327 else
328 ssid->ssidref = ACM_DEFAULT_SSID;
330 subj->ssid = ssid;
331 /* now fill in primary and secondary parts; we only get here through hooks */
332 if (acm_primary_ops->init_domain_ssid != NULL)
333 ret1 = acm_primary_ops->init_domain_ssid(&(ssid->primary_ssid), ssidref);
334 else
335 ret1 = ACM_OK;
337 if (acm_secondary_ops->init_domain_ssid != NULL)
338 ret2 = acm_secondary_ops->init_domain_ssid(&(ssid->secondary_ssid), ssidref);
339 else
340 ret2 = ACM_OK;
342 if ((ret1 != ACM_OK) || (ret2 != ACM_OK))
343 {
344 printk("%s: ERROR instantiating individual ssids for domain 0x%02x.\n",
345 __func__, subj->domain_id);
346 acm_free_domain_ssid(ssid);
347 put_domain(subj);
348 return ACM_INIT_SSID_ERROR;
349 }
350 printkd("%s: assigned domain %x the ssidref=%x.\n",
351 __func__, id, ssid->ssidref);
352 put_domain(subj);
353 return ACM_OK;
354 }
357 void
358 acm_free_domain_ssid(struct acm_ssid_domain *ssid)
359 {
360 /* domain is already gone, just ssid is left */
361 if (ssid == NULL)
362 return;
364 ssid->subject = NULL;
365 if (acm_primary_ops->free_domain_ssid != NULL) /* null policy */
366 acm_primary_ops->free_domain_ssid(ssid->primary_ssid);
367 ssid->primary_ssid = NULL;
368 if (acm_secondary_ops->free_domain_ssid != NULL)
369 acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
370 ssid->secondary_ssid = NULL;
371 xfree(ssid);
372 printkd("%s: Freed individual domain ssid (domain=%02x).\n",
373 __func__, id);
374 }
376 /*
377 * Local variables:
378 * mode: C
379 * c-set-style: "BSD"
380 * c-basic-offset: 4
381 * tab-width: 4
382 * indent-tabs-mode: nil
383 * End:
384 */