ia64/xen-unstable

view xen/acm/acm_core.c @ 15452:f152e44325a7

xenconsoled: improve robustness of logfile handling

Check the 'log_reload' on every iteration of the select() loop, not just when
select() returns EINTR. This is because the log reload signal may have
iterrupted a syscall other than select & thus without this change we
might miss the reload signal. The second change makes us process the
hypervisor logs on every iteration of the loop, not just upon timeouts.
This is because if a guest VM were consistently sending some log message
and < 1 second period, the select() would never hit the 1 second timeout
and thus never process the HV logs.

Thanks to Markus Armbruster for pointing out both these edge cases

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Wed Jun 27 21:05:54 2007 +0100 (2007-06-27)
parents 759d924af6d8
children 6e8199e555a6
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 during boot */
66 char polname[80];
67 char *acm_accepted_boot_policy_name = NULL;
69 /* a lits of all chained ssid structures */
70 LIST_HEAD(ssid_list);
71 DEFINE_RWLOCK(ssid_list_rwlock);
73 static 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);
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 }
104 custom_param("ssidref", set_dom0_ssidref);
106 int
107 acm_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;
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 }
120 acm_bin_pol.policy_reference_name = (char *)xmalloc_array(u8, be32_to_cpu(pr->len));
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));
126 printk("%s: Activating policy %s\n", __func__,
127 acm_bin_pol.policy_reference_name);
128 return 0;
129 }
131 int
132 acm_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;
137 ret = (ret + 7) & ~7;
138 if (buf_size < ret)
139 return -EINVAL;
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 }
149 int
150 acm_init_binary_policy(u32 policy_code)
151 {
152 int ret = ACM_OK;
154 acm_bin_pol.primary_policy_code = (policy_code & 0x0f);
155 acm_bin_pol.secondary_policy_code = (policy_code >> 4) & 0x0f;
157 write_lock(&acm_bin_pol_rwlock);
159 /* set primary policy component */
160 switch ((policy_code) & 0x0f)
161 {
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;
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;
175 case ACM_NULL_POLICY:
176 acm_bin_pol.primary_policy_code = ACM_NULL_POLICY;
177 acm_primary_ops = &acm_null_ops;
178 break;
180 default:
181 /* Unknown policy not allowed primary */
182 ret = -EINVAL;
183 goto out;
184 }
186 /* secondary policy component part */
187 switch ((policy_code) >> 4)
188 {
190 case ACM_NULL_POLICY:
191 acm_bin_pol.secondary_policy_code = ACM_NULL_POLICY;
192 acm_secondary_ops = &acm_null_ops;
193 break;
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;
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;
217 default:
218 ret = -EINVAL;
219 goto out;
220 }
222 out:
223 write_unlock(&acm_bin_pol_rwlock);
224 return ret;
225 }
227 int
228 acm_is_policy(char *buf, unsigned long len)
229 {
230 struct acm_policy_buffer *pol;
232 if (buf == NULL || len < sizeof(struct acm_policy_buffer))
233 return 0;
235 pol = (struct acm_policy_buffer *)buf;
236 return be32_to_cpu(pol->magic) == ACM_MAGIC;
237 }
240 static int
241 acm_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;
248 if (policy_start == NULL || policy_len < sizeof(struct acm_policy_buffer))
249 return rc;
251 pol = (struct acm_policy_buffer *)policy_start;
252 if (be32_to_cpu(pol->magic) != ACM_MAGIC)
253 return rc;
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 }
272 int __init
273 acm_init(char *policy_start,
274 unsigned long policy_len)
275 {
276 int ret = ACM_OK;
278 /* first try to load the boot policy (uses its own locks) */
279 acm_setup(policy_start, policy_len, 1);
281 /* a user-provided policy may have any name; only matched during boot */
282 acm_accepted_boot_policy_name = NULL;
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));
294 /* (re-)set dom-0 ssidref to default */
295 dom0_ste_ssidref = dom0_chwall_ssidref = 0x0001;
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";
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 }
317 int
318 acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
319 {
320 struct domain *subj = rcu_lock_domain_by_id(id);
321 int ret;
323 if (subj == NULL)
324 {
325 printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
326 return ACM_NULL_POINTER_ERROR;
327 }
329 ret = acm_init_domain_ssid_new(subj, ssidref);
331 rcu_unlock_domain(subj);
333 return ret;
334 }
336 int 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 }
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;
352 if (acm_active_security_policy != ACM_NULL_POLICY)
353 ssid->ssidref = ssidref;
354 else
355 ssid->ssidref = ACM_DEFAULT_SSID;
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;
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;
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 }
377 write_lock(&ssid_list_rwlock);
378 list_add(&ssid->node, &ssid_list);
379 write_unlock(&ssid_list_rwlock);
381 printkd("%s: assigned domain %x the ssidref=%x.\n",
382 __func__, subj->domain_id, ssid->ssidref);
383 return ACM_OK;
384 }
387 void
388 acm_free_domain_ssid(struct acm_ssid_domain *ssid)
389 {
390 /* domain is already gone, just ssid is left */
391 if (ssid == NULL)
392 return;
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;
402 write_lock(&ssid_list_rwlock);
403 list_del(&ssid->node);
404 write_unlock(&ssid_list_rwlock);
406 xfree(ssid);
407 printkd("%s: Freed individual domain ssid (domain=%02x).\n",
408 __func__, id);
409 }
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 */