ia64/xen-unstable

view xen/acm/acm_policy.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 f8fd9afd2aad
children 4a8dbbc16d48
line source
1 /****************************************************************
2 * acm_policy.c
3 *
4 * Copyright (C) 2005-2007 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 policy management for Xen.
18 * This interface allows policy tools in authorized
19 * domains to interact with the Xen access control module
20 *
21 */
23 #include <xen/config.h>
24 #include <xen/errno.h>
25 #include <xen/types.h>
26 #include <xen/lib.h>
27 #include <xen/delay.h>
28 #include <xen/sched.h>
29 #include <xen/guest_access.h>
30 #include <public/xen.h>
31 #include <acm/acm_core.h>
32 #include <public/acm_ops.h>
33 #include <acm/acm_hooks.h>
34 #include <acm/acm_endian.h>
35 #include <asm/current.h>
37 static int acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,
38 struct acm_sized_buffer *errors);
39 static void acm_doms_change_ssidref(ssidref_t (*translator)
40 (const struct acm_ssid_domain *,
41 const struct acm_sized_buffer *),
42 struct acm_sized_buffer *translation_map);
43 static void acm_doms_restore_ssidref(void);
44 static ssidref_t oldssid_to_newssid(const struct acm_ssid_domain *,
45 const struct acm_sized_buffer *map);
48 int
49 acm_set_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size)
50 {
51 u8 *policy_buffer = NULL;
52 int ret = -EFAULT;
54 if (buf_size < sizeof(struct acm_policy_buffer))
55 return -EFAULT;
57 /* copy buffer from guest domain */
58 if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
59 return -ENOMEM;
61 if (copy_from_guest(policy_buffer, buf, buf_size))
62 {
63 printk("%s: Error copying!\n",__func__);
64 goto error_free;
65 }
66 ret = do_acm_set_policy(policy_buffer, buf_size, 0,
67 NULL, NULL, NULL);
69 error_free:
70 xfree(policy_buffer);
71 return ret;
72 }
75 /*
76 * Update the policy of the running system by:
77 * - deleting ssidrefs that are not in the new policy anymore
78 * -> no running domain may use such an ssidref
79 * - assign new ssidrefs to domains based on their old ssidrefs
80 *
81 */
82 static int
83 _acm_update_policy(void *buf, u32 buf_size, int is_bootpolicy,
84 struct acm_policy_buffer *pol,
85 struct acm_sized_buffer *deletions,
86 struct acm_sized_buffer *ssidchanges,
87 struct acm_sized_buffer *errors)
88 {
89 uint32_t offset, length;
91 write_lock(&acm_bin_pol_rwlock);
93 /*
94 first some tests to check compatibility of new policy with
95 current state of system/domains
96 */
98 /* if ssidrefs are to be deleted, make sure no domain is using them */
99 if (deletions != NULL) {
100 if (acm_check_deleted_ssidrefs(deletions, errors))
101 goto error_lock_free;
102 }
104 if ((ssidchanges != NULL) && (ssidchanges->num_items > 0)) {
105 /* assign all running domains new ssidrefs as requested */
106 acm_doms_change_ssidref(oldssid_to_newssid, ssidchanges);
107 }
109 /* test primary policy data with the new ssidrefs */
110 offset = be32_to_cpu(pol->primary_buffer_offset);
111 length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
113 if ( (offset + length) > buf_size ||
114 acm_primary_ops->test_binary_policy(buf + offset, length,
115 is_bootpolicy,
116 errors))
117 goto error_lock_free;
119 /* test secondary policy data with the new ssidrefs */
120 offset = be32_to_cpu(pol->secondary_buffer_offset);
121 length = be32_to_cpu(pol->len) - offset;
122 if ( (offset + length) > buf_size ||
123 acm_secondary_ops->test_binary_policy(buf + offset, length,
124 is_bootpolicy,
125 errors)) {
126 goto error_lock_free;
127 }
129 /* end of testing --- now real updates */
131 offset = be32_to_cpu(pol->policy_reference_offset);
132 length = be32_to_cpu(pol->primary_buffer_offset) - offset;
134 /* set label reference name */
135 if ( (offset + length) > buf_size ||
136 acm_set_policy_reference(buf + offset, length) )
137 goto error_lock_free;
139 /* set primary policy data */
140 offset = be32_to_cpu(pol->primary_buffer_offset);
141 length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
143 if ( acm_primary_ops->set_binary_policy(buf + offset, length) )
144 goto error_lock_free;
146 /* set secondary policy data */
147 offset = be32_to_cpu(pol->secondary_buffer_offset);
148 length = be32_to_cpu(pol->len) - offset;
149 if ( acm_secondary_ops->set_binary_policy(buf + offset, length) )
150 goto error_lock_free;
152 memcpy(&acm_bin_pol.xml_pol_version,
153 &pol->xml_pol_version,
154 sizeof(acm_bin_pol.xml_pol_version));
156 write_unlock(&acm_bin_pol_rwlock);
157 return ACM_OK;
159 error_lock_free:
160 if ((ssidchanges != NULL) && (ssidchanges->num_items > 0)) {
161 acm_doms_restore_ssidref();
162 }
163 do_chwall_init_state_curr(NULL);
164 write_unlock(&acm_bin_pol_rwlock);
166 return -EFAULT;
167 }
170 int
171 do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy,
172 struct acm_sized_buffer *deletions,
173 struct acm_sized_buffer *ssidchanges,
174 struct acm_sized_buffer *errors)
175 {
176 struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
178 /* some sanity checking */
179 if ((be32_to_cpu(pol->magic) != ACM_MAGIC) ||
180 (buf_size != be32_to_cpu(pol->len)) ||
181 (be32_to_cpu(pol->policy_version) != ACM_POLICY_VERSION))
182 {
183 printk("%s: ERROR in Magic, Version, or buf size.\n", __func__);
184 goto error_free;
185 }
187 if (acm_active_security_policy == ACM_POLICY_UNDEFINED) {
188 /* setup the policy with the boot policy */
189 if (acm_init_binary_policy((be32_to_cpu(pol->secondary_policy_code) << 4) |
190 be32_to_cpu(pol->primary_policy_code))) {
191 goto error_free;
192 }
193 acm_active_security_policy = (acm_bin_pol.secondary_policy_code << 4) |
194 acm_bin_pol.primary_policy_code;
195 }
197 /* once acm_active_security_policy is set, it cannot be changed */
198 if ((be32_to_cpu(pol->primary_policy_code) != acm_bin_pol.primary_policy_code) ||
199 (be32_to_cpu(pol->secondary_policy_code) != acm_bin_pol.secondary_policy_code))
200 {
201 printkd("%s: Wrong policy type in boot policy!\n", __func__);
202 goto error_free;
203 }
205 return _acm_update_policy(buf, buf_size, is_bootpolicy,
206 pol,
207 deletions, ssidchanges,
208 errors);
210 error_free:
211 printk("%s: Error setting policy.\n", __func__);
212 return -EFAULT;
213 }
215 int
216 acm_get_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size)
217 {
218 u8 *policy_buffer;
219 int ret;
220 struct acm_policy_buffer *bin_pol;
222 if (buf_size < sizeof(struct acm_policy_buffer))
223 return -EFAULT;
225 if ((policy_buffer = xmalloc_array(u8, buf_size)) == NULL)
226 return -ENOMEM;
228 read_lock(&acm_bin_pol_rwlock);
230 bin_pol = (struct acm_policy_buffer *)policy_buffer;
231 bin_pol->magic = cpu_to_be32(ACM_MAGIC);
232 bin_pol->primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code);
233 bin_pol->secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code);
235 bin_pol->len = cpu_to_be32(sizeof(struct acm_policy_buffer));
236 bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
237 bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
238 bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
240 memcpy(&bin_pol->xml_pol_version,
241 &acm_bin_pol.xml_pol_version,
242 sizeof(struct acm_policy_version));
244 ret = acm_dump_policy_reference(policy_buffer + be32_to_cpu(bin_pol->policy_reference_offset),
245 buf_size - be32_to_cpu(bin_pol->policy_reference_offset));
246 if (ret < 0)
247 goto error_free_unlock;
249 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
250 bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
252 ret = acm_primary_ops->dump_binary_policy (policy_buffer + be32_to_cpu(bin_pol->primary_buffer_offset),
253 buf_size - be32_to_cpu(bin_pol->primary_buffer_offset));
254 if (ret < 0)
255 goto error_free_unlock;
257 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
258 bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
260 ret = acm_secondary_ops->dump_binary_policy(policy_buffer + be32_to_cpu(bin_pol->secondary_buffer_offset),
261 buf_size - be32_to_cpu(bin_pol->secondary_buffer_offset));
262 if (ret < 0)
263 goto error_free_unlock;
265 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
266 if (copy_to_guest(buf, policy_buffer, be32_to_cpu(bin_pol->len)))
267 goto error_free_unlock;
269 read_unlock(&acm_bin_pol_rwlock);
270 xfree(policy_buffer);
271 return ACM_OK;
273 error_free_unlock:
274 read_unlock(&acm_bin_pol_rwlock);
275 printk("%s: Error getting policy.\n", __func__);
276 xfree(policy_buffer);
277 return -EFAULT;
278 }
280 int
281 acm_dump_statistics(XEN_GUEST_HANDLE_64(void) buf, u16 buf_size)
282 {
283 /* send stats to user space */
284 u8 *stats_buffer;
285 int len1, len2;
286 struct acm_stats_buffer acm_stats;
288 if ((stats_buffer = xmalloc_array(u8, buf_size)) == NULL)
289 return -ENOMEM;
291 read_lock(&acm_bin_pol_rwlock);
293 len1 = acm_primary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer),
294 buf_size - sizeof(struct acm_stats_buffer));
295 if (len1 < 0)
296 goto error_lock_free;
298 len2 = acm_secondary_ops->dump_statistics(stats_buffer + sizeof(struct acm_stats_buffer) + len1,
299 buf_size - sizeof(struct acm_stats_buffer) - len1);
300 if (len2 < 0)
301 goto error_lock_free;
303 acm_stats.magic = cpu_to_be32(ACM_MAGIC);
304 acm_stats.primary_policy_code = cpu_to_be32(acm_bin_pol.primary_policy_code);
305 acm_stats.secondary_policy_code = cpu_to_be32(acm_bin_pol.secondary_policy_code);
306 acm_stats.primary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer));
307 acm_stats.secondary_stats_offset = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1);
308 acm_stats.len = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1 + len2);
310 memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
312 if (copy_to_guest(buf, stats_buffer, sizeof(struct acm_stats_buffer) + len1 + len2))
313 goto error_lock_free;
315 read_unlock(&acm_bin_pol_rwlock);
316 xfree(stats_buffer);
317 return ACM_OK;
319 error_lock_free:
320 read_unlock(&acm_bin_pol_rwlock);
321 xfree(stats_buffer);
322 return -EFAULT;
323 }
326 int
327 acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE_64(void) buf, u16 buf_size)
328 {
329 /* send stats to user space */
330 u8 *ssid_buffer;
331 int ret;
332 struct acm_ssid_buffer *acm_ssid;
333 if (buf_size < sizeof(struct acm_ssid_buffer))
334 return -EFAULT;
336 if ((ssid_buffer = xmalloc_array(u8, buf_size)) == NULL)
337 return -ENOMEM;
339 read_lock(&acm_bin_pol_rwlock);
341 acm_ssid = (struct acm_ssid_buffer *)ssid_buffer;
342 acm_ssid->len = sizeof(struct acm_ssid_buffer);
343 acm_ssid->ssidref = ssidref;
344 acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code;
345 acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code;
347 acm_ssid->policy_reference_offset = acm_ssid->len;
348 ret = acm_dump_policy_reference(ssid_buffer + acm_ssid->policy_reference_offset,
349 buf_size - acm_ssid->policy_reference_offset);
350 if (ret < 0)
351 goto error_free_unlock;
353 acm_ssid->len += ret;
354 acm_ssid->primary_types_offset = acm_ssid->len;
356 /* ret >= 0 --> ret == max_types */
357 ret = acm_primary_ops->dump_ssid_types(ACM_PRIMARY(ssidref),
358 ssid_buffer + acm_ssid->primary_types_offset,
359 buf_size - acm_ssid->primary_types_offset);
360 if (ret < 0)
361 goto error_free_unlock;
363 acm_ssid->len += ret;
364 acm_ssid->primary_max_types = ret;
365 acm_ssid->secondary_types_offset = acm_ssid->len;
367 ret = acm_secondary_ops->dump_ssid_types(ACM_SECONDARY(ssidref),
368 ssid_buffer + acm_ssid->secondary_types_offset,
369 buf_size - acm_ssid->secondary_types_offset);
370 if (ret < 0)
371 goto error_free_unlock;
373 acm_ssid->len += ret;
374 acm_ssid->secondary_max_types = ret;
376 if (copy_to_guest(buf, ssid_buffer, acm_ssid->len))
377 goto error_free_unlock;
379 read_unlock(&acm_bin_pol_rwlock);
380 xfree(ssid_buffer);
381 return ACM_OK;
383 error_free_unlock:
384 read_unlock(&acm_bin_pol_rwlock);
385 printk("%s: Error getting ssid.\n", __func__);
386 xfree(ssid_buffer);
387 return -ENOMEM;
388 }
390 int
391 acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook)
392 {
393 int ret = ACM_ACCESS_DENIED;
394 switch (hook) {
396 case ACMHOOK_sharing:
397 /* Sharing hook restricts access in STE policy only */
398 ret = acm_sharing(ssidref1, ssidref2);
399 break;
401 default:
402 /* deny */
403 break;
404 }
406 printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n",
407 __func__, ssidref1, ssidref2,
408 (ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED");
410 return ret;
411 }
415 /*
416 Check if an ssidref of the current policy type is being used by any
417 domain.
418 */
419 static int
420 acm_check_used_ssidref(uint32_t policy_type, uint32_t search_ssidref,
421 struct acm_sized_buffer *errors)
422 {
423 int rc = 0;
424 struct acm_ssid_domain *rawssid;
426 read_lock(&ssid_list_rwlock);
428 for_each_acmssid( rawssid ) {
429 ssidref_t ssidref;
430 void *s = GET_SSIDP(policy_type, rawssid);
432 if (policy_type == ACM_CHINESE_WALL_POLICY) {
433 ssidref = ((struct chwall_ssid *)s)->chwall_ssidref;
434 } else {
435 ssidref = ((struct ste_ssid *)s)->ste_ssidref;
436 }
437 gdprintk(XENLOG_INFO,"domid=%d: search ssidref=%d, ssidref=%d\n",
438 rawssid->domainid,search_ssidref,ssidref);
439 if (ssidref == search_ssidref) {
440 /* one is enough */
441 acm_array_append_tuple(errors, ACM_SSIDREF_IN_USE, search_ssidref);
442 rc = 1;
443 break;
444 }
445 }
447 read_unlock(&ssid_list_rwlock);
449 return rc;
450 }
453 /*
454 * Translate a current ssidref into its future representation under
455 * the new policy.
456 * The map provides translation of ssidrefs from old to new in tuples
457 * of (old ssidref, new ssidref).
458 */
459 static ssidref_t
460 oldssid_to_newssid(const struct acm_ssid_domain *rawssid,
461 const struct acm_sized_buffer *map)
462 {
463 uint i;
465 if (rawssid != NULL) {
466 ssidref_t ssid = rawssid->ssidref & 0xffff;
467 for (i = 0; i+1 < map->num_items; i += 2) {
468 if (map->array[i] == ssid) {
469 return (map->array[i+1] << 16 | map->array[i+1]);
470 }
471 }
472 }
473 return ACM_INVALID_SSIDREF;
474 }
477 /*
478 * Assign an ssidref to the CHWALL policy component of the domain
479 */
480 static void
481 acm_pri_policy_assign_ssidref(struct acm_ssid_domain *rawssid, ssidref_t new_ssid)
482 {
483 struct chwall_ssid *chwall = (struct chwall_ssid *)rawssid->primary_ssid;
484 chwall->chwall_ssidref = new_ssid;
485 }
488 /*
489 * Assign an ssidref to the STE policy component of the domain
490 */
491 static void
492 acm_sec_policy_assign_ssidref(struct acm_ssid_domain *rawssid, ssidref_t new_ssid)
493 {
494 struct ste_ssid *ste = (struct ste_ssid *)rawssid->secondary_ssid;
495 ste->ste_ssidref = new_ssid;
496 }
498 /*
499 Change the ssidrefs on each domain using a passed translation function;
500 */
501 static void
502 acm_doms_change_ssidref(ssidref_t (*translator_fn)
503 (const struct acm_ssid_domain *,
504 const struct acm_sized_buffer *),
505 struct acm_sized_buffer *translation_map)
506 {
507 struct acm_ssid_domain *rawssid;
509 write_lock(&ssid_list_rwlock);
511 for_each_acmssid( rawssid ) {
512 ssidref_t new_ssid;
514 rawssid->old_ssidref = rawssid->ssidref;
516 new_ssid = translator_fn(rawssid, translation_map);
517 if (new_ssid == ACM_INVALID_SSIDREF) {
518 /* means no mapping found, so no change -- old = new */
519 continue;
520 }
522 acm_pri_policy_assign_ssidref(rawssid, ACM_PRIMARY (new_ssid) );
523 acm_sec_policy_assign_ssidref(rawssid, ACM_SECONDARY(new_ssid) );
525 rawssid->ssidref = new_ssid;
526 }
528 write_unlock(&ssid_list_rwlock);
529 }
531 /*
532 * Restore the previous ssidref values on all domains
533 */
534 static void
535 acm_doms_restore_ssidref(void)
536 {
537 struct acm_ssid_domain *rawssid;
539 write_lock(&ssid_list_rwlock);
541 for_each_acmssid( rawssid ) {
542 ssidref_t old_ssid;
544 if (rawssid->old_ssidref == rawssid->ssidref)
545 continue;
547 old_ssid = rawssid->old_ssidref & 0xffff;
548 rawssid->ssidref = rawssid->old_ssidref;
550 acm_pri_policy_assign_ssidref(rawssid, old_ssid);
551 acm_sec_policy_assign_ssidref(rawssid, old_ssid);
552 }
554 write_unlock(&ssid_list_rwlock);
555 }
558 /*
559 Check the list of domains whether either one of them uses a
560 to-be-deleted ssidref.
561 */
562 static int
563 acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,
564 struct acm_sized_buffer *errors)
565 {
566 int rc = 0;
567 uint idx;
568 /* check for running domains that should not be there anymore */
569 for (idx = 0; idx < dels->num_items; idx++) {
570 if (acm_check_used_ssidref(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
571 dels->array[idx],
572 errors) > 0 ||
573 acm_check_used_ssidref(ACM_CHINESE_WALL_POLICY,
574 dels->array[idx],
575 errors) > 0) {
576 rc = ACM_ERROR;
577 break;
578 }
579 }
580 return rc;
581 }
584 /*
585 * Change the policy of the system.
586 */
587 int
588 acm_change_policy(struct acm_change_policy *chgpolicy)
589 {
590 int rc = 0;
591 u8 *binpolicy = NULL;
592 struct acm_sized_buffer dels = {
593 .array = NULL,
594 };
595 struct acm_sized_buffer ssidmap = {
596 .array = NULL,
597 };
598 struct acm_sized_buffer errors = {
599 .array = NULL,
600 };
602 gdprintk(XENLOG_INFO, "change policy operation\n");
604 if ((chgpolicy->delarray_size > 4096) ||
605 (chgpolicy->chgarray_size > 4096) ||
606 (chgpolicy->errarray_size > 4096)) {
607 return ACM_ERROR;
608 }
610 dels.num_items = chgpolicy->delarray_size / sizeof(uint32_t);
611 if (dels.num_items > 0) {
612 dels.array = xmalloc_array(uint32_t, dels.num_items);
613 if (dels.array == NULL) {
614 rc = -ENOMEM;
615 goto acm_chg_policy_exit;
616 }
617 }
619 ssidmap.num_items = chgpolicy->chgarray_size / sizeof(uint32_t);
620 if (ssidmap.num_items > 0) {
621 ssidmap.array = xmalloc_array(uint32_t, ssidmap.num_items);
622 if (ssidmap.array == NULL) {
623 rc = -ENOMEM;
624 goto acm_chg_policy_exit;
625 }
626 }
628 errors.num_items = chgpolicy->errarray_size / sizeof(uint32_t);
629 if (errors.num_items > 0) {
630 errors.array = xmalloc_array(uint32_t, errors.num_items);
631 if (errors.array == NULL) {
632 rc = -ENOMEM;
633 goto acm_chg_policy_exit;
634 }
635 memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
636 }
638 binpolicy = xmalloc_array(u8,
639 chgpolicy->policy_pushcache_size);
640 if (binpolicy == NULL) {
641 rc = -ENOMEM;
642 goto acm_chg_policy_exit;
643 }
645 if ( copy_from_guest(dels.array,
646 chgpolicy->del_array,
647 chgpolicy->delarray_size) ||
648 copy_from_guest(ssidmap.array,
649 chgpolicy->chg_array,
650 chgpolicy->chgarray_size) ||
651 copy_from_guest(binpolicy,
652 chgpolicy->policy_pushcache,
653 chgpolicy->policy_pushcache_size )) {
654 rc = -EFAULT;
655 goto acm_chg_policy_exit;
656 }
658 rc = do_acm_set_policy(binpolicy,
659 chgpolicy->policy_pushcache_size,
660 0,
661 &dels, &ssidmap, &errors);
663 if ( (errors.num_items > 0) &&
664 copy_to_guest(chgpolicy->err_array,
665 errors.array,
666 errors.num_items ) ) {
667 rc = -EFAULT;
668 goto acm_chg_policy_exit;
669 }
672 acm_chg_policy_exit:
673 xfree(dels.array);
674 xfree(ssidmap.array);
675 xfree(errors.array);
676 xfree(binpolicy);
678 return rc;
679 }
682 /*
683 * Lookup the new ssidref given the domain's id.
684 * The translation map provides a list of tuples in the format
685 * (domid, new ssidref).
686 */
687 static ssidref_t
688 domid_to_newssid(const struct acm_ssid_domain *rawssid,
689 const struct acm_sized_buffer *map)
690 {
691 domid_t domid = rawssid->domainid;
692 uint i;
693 for (i = 0; (i+1) < map->num_items; i += 2) {
694 if (map->array[i] == domid) {
695 return (ssidref_t)map->array[i+1];
696 }
697 }
698 return ACM_INVALID_SSIDREF;
699 }
702 int
703 do_acm_relabel_doms(struct acm_sized_buffer *relabel_map,
704 struct acm_sized_buffer *errors)
705 {
706 int rc = 0, irc;
708 write_lock(&acm_bin_pol_rwlock);
710 acm_doms_change_ssidref(domid_to_newssid, relabel_map);
712 /* run tests; collect as much error info as possible */
713 irc = do_chwall_init_state_curr(errors);
714 irc += do_ste_init_state_curr(errors);
715 if (irc != 0) {
716 rc = -EFAULT;
717 goto acm_relabel_doms_lock_err_exit;
718 }
720 write_unlock(&acm_bin_pol_rwlock);
722 return rc;
724 acm_relabel_doms_lock_err_exit:
725 /* revert the new ssidref assignment */
726 acm_doms_restore_ssidref();
727 do_chwall_init_state_curr(NULL);
729 write_unlock(&acm_bin_pol_rwlock);
731 return rc;
732 }
735 int
736 acm_relabel_domains(struct acm_relabel_doms *relabel)
737 {
738 int rc = ACM_OK;
739 struct acm_sized_buffer relabels = {
740 .array = NULL,
741 };
742 struct acm_sized_buffer errors = {
743 .array = NULL,
744 };
746 if (relabel->relabel_map_size > 4096) {
747 return ACM_ERROR;
748 }
750 relabels.num_items = relabel->relabel_map_size / sizeof(uint32_t);
751 if (relabels.num_items > 0) {
752 relabels.array = xmalloc_array(uint32_t, relabels.num_items);
753 if (relabels.array == NULL) {
754 rc = -ENOMEM;
755 goto acm_relabel_doms_exit;
756 }
757 }
759 errors.num_items = relabel->errarray_size / sizeof(uint32_t);
760 if (errors.num_items > 0) {
761 errors.array = xmalloc_array(uint32_t, errors.num_items);
762 if (errors.array == NULL) {
763 rc = -ENOMEM;
764 goto acm_relabel_doms_exit;
765 }
766 memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
767 }
769 if ( copy_from_guest(relabels.array,
770 relabel->relabel_map,
771 relabel->relabel_map_size) ) {
772 rc = -EFAULT;
773 goto acm_relabel_doms_exit;
774 }
776 rc = do_acm_relabel_doms(&relabels, &errors);
778 if ( copy_to_guest(relabel->err_array,
779 errors.array,
780 errors.num_items ) ) {
781 rc = -EFAULT;
782 goto acm_relabel_doms_exit;
783 }
785 acm_relabel_doms_exit:
786 xfree(relabels.array);
787 xfree(errors.array);
788 return rc;
789 }
791 /*
792 * Local variables:
793 * mode: C
794 * c-set-style: "BSD"
795 * c-basic-offset: 4
796 * tab-width: 4
797 * indent-tabs-mode: nil
798 * End:
799 */