ia64/xen-unstable

view xen/acm/acm_policy.c @ 15738:918e04a982b8

acm: Cleaner use of copy_from_guest().
Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Thu Aug 09 10:03:59 2007 +0100 (2007-08-09)
parents 007a11317ce8
children
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;
90 static int require_update = 0;
92 write_lock(&acm_bin_pol_rwlock);
94 if ( require_update != 0 &&
95 ( deletions == NULL || ssidchanges == NULL ) )
96 goto error_lock_free;
98 require_update = 1;
99 /*
100 first some tests to check compatibility of new policy with
101 current state of system/domains
102 */
104 /* if ssidrefs are to be deleted, make sure no domain is using them */
105 if ( deletions != NULL )
106 if ( acm_check_deleted_ssidrefs(deletions, errors) )
107 goto error_lock_free;
109 if ( (ssidchanges != NULL) && (ssidchanges->num_items > 0) )
110 /* assign all running domains new ssidrefs as requested */
111 acm_doms_change_ssidref(oldssid_to_newssid, ssidchanges);
113 /* test primary policy data with the new ssidrefs */
114 offset = be32_to_cpu(pol->primary_buffer_offset);
115 length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
117 if ( (offset + length) > buf_size ||
118 acm_primary_ops->test_binary_policy(buf + offset, length,
119 is_bootpolicy,
120 errors))
121 goto error_lock_free;
123 /* test secondary policy data with the new ssidrefs */
124 offset = be32_to_cpu(pol->secondary_buffer_offset);
125 length = be32_to_cpu(pol->len) - offset;
126 if ( (offset + length) > buf_size ||
127 acm_secondary_ops->test_binary_policy(buf + offset, length,
128 is_bootpolicy,
129 errors))
130 goto error_lock_free;
132 /* end of testing --- now real updates */
134 offset = be32_to_cpu(pol->policy_reference_offset);
135 length = be32_to_cpu(pol->primary_buffer_offset) - offset;
137 /* set label reference name */
138 if ( (offset + length) > buf_size ||
139 acm_set_policy_reference(buf + offset, length) )
140 goto error_lock_free;
142 /* set primary policy data */
143 offset = be32_to_cpu(pol->primary_buffer_offset);
144 length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
146 if ( acm_primary_ops->set_binary_policy(buf + offset, length) )
147 goto error_lock_free;
149 /* set secondary policy data */
150 offset = be32_to_cpu(pol->secondary_buffer_offset);
151 length = be32_to_cpu(pol->len) - offset;
152 if ( acm_secondary_ops->set_binary_policy(buf + offset, length) )
153 goto error_lock_free;
155 memcpy(&acm_bin_pol.xml_pol_version,
156 &pol->xml_pol_version,
157 sizeof(acm_bin_pol.xml_pol_version));
159 if ( acm_primary_ops->is_default_policy() &&
160 acm_secondary_ops->is_default_policy() )
161 require_update = 0;
163 write_unlock(&acm_bin_pol_rwlock);
165 return ACM_OK;
167 error_lock_free:
168 if ( (ssidchanges != NULL) && (ssidchanges->num_items > 0) )
169 {
170 acm_doms_restore_ssidref();
171 }
172 do_chwall_init_state_curr(NULL);
173 write_unlock(&acm_bin_pol_rwlock);
175 return -EFAULT;
176 }
179 int
180 do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy,
181 struct acm_sized_buffer *deletions,
182 struct acm_sized_buffer *ssidchanges,
183 struct acm_sized_buffer *errors)
184 {
185 struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
187 /* some sanity checking */
188 if ( (be32_to_cpu(pol->magic) != ACM_MAGIC) ||
189 (buf_size != be32_to_cpu(pol->len)) ||
190 (be32_to_cpu(pol->policy_version) != ACM_POLICY_VERSION) )
191 {
192 printk("%s: ERROR in Magic, Version, or buf size.\n", __func__);
193 goto error_free;
194 }
196 if ( acm_active_security_policy == ACM_POLICY_UNDEFINED )
197 {
198 /* setup the policy with the boot policy */
199 if ( acm_init_binary_policy(
200 (be32_to_cpu(pol->secondary_policy_code) << 4) |
201 be32_to_cpu(pol->primary_policy_code)) )
202 {
203 goto error_free;
204 }
205 acm_active_security_policy = (acm_bin_pol.secondary_policy_code << 4) |
206 acm_bin_pol.primary_policy_code;
207 }
209 /* once acm_active_security_policy is set, it cannot be changed */
210 if ( (be32_to_cpu(pol->primary_policy_code) !=
211 acm_bin_pol.primary_policy_code) ||
212 (be32_to_cpu(pol->secondary_policy_code) !=
213 acm_bin_pol.secondary_policy_code) )
214 {
215 printkd("%s: Wrong policy type in boot policy!\n", __func__);
216 goto error_free;
217 }
219 return _acm_update_policy(buf, buf_size, is_bootpolicy,
220 pol,
221 deletions, ssidchanges,
222 errors);
224 error_free:
225 printk("%s: Error setting policy.\n", __func__);
226 return -EFAULT;
227 }
229 int
230 acm_get_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size)
231 {
232 u8 *policy_buffer;
233 int ret;
234 struct acm_policy_buffer *bin_pol;
236 if ( buf_size < sizeof(struct acm_policy_buffer) )
237 return -EFAULT;
239 if ( (policy_buffer = xmalloc_array(u8, buf_size)) == NULL )
240 return -ENOMEM;
242 read_lock(&acm_bin_pol_rwlock);
244 bin_pol = (struct acm_policy_buffer *)policy_buffer;
245 bin_pol->magic = cpu_to_be32(ACM_MAGIC);
246 bin_pol->primary_policy_code =
247 cpu_to_be32(acm_bin_pol.primary_policy_code);
248 bin_pol->secondary_policy_code =
249 cpu_to_be32(acm_bin_pol.secondary_policy_code);
251 bin_pol->len = cpu_to_be32(sizeof(struct acm_policy_buffer));
252 bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
253 bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
254 bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
256 memcpy(&bin_pol->xml_pol_version,
257 &acm_bin_pol.xml_pol_version,
258 sizeof(struct acm_policy_version));
260 ret = acm_dump_policy_reference(
261 policy_buffer + be32_to_cpu(bin_pol->policy_reference_offset),
262 buf_size - be32_to_cpu(bin_pol->policy_reference_offset));
264 if ( ret < 0 )
265 goto error_free_unlock;
267 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
268 bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
270 ret = acm_primary_ops->dump_binary_policy(
271 policy_buffer + be32_to_cpu(bin_pol->primary_buffer_offset),
272 buf_size - be32_to_cpu(bin_pol->primary_buffer_offset));
274 if ( ret < 0 )
275 goto error_free_unlock;
277 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
278 bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
280 ret = acm_secondary_ops->dump_binary_policy(
281 policy_buffer + be32_to_cpu(bin_pol->secondary_buffer_offset),
282 buf_size - be32_to_cpu(bin_pol->secondary_buffer_offset));
284 if ( ret < 0 )
285 goto error_free_unlock;
287 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
288 if ( copy_to_guest(buf, policy_buffer, be32_to_cpu(bin_pol->len)) )
289 goto error_free_unlock;
291 read_unlock(&acm_bin_pol_rwlock);
292 xfree(policy_buffer);
294 return ACM_OK;
296 error_free_unlock:
297 read_unlock(&acm_bin_pol_rwlock);
298 printk("%s: Error getting policy.\n", __func__);
299 xfree(policy_buffer);
301 return -EFAULT;
302 }
304 int
305 acm_dump_statistics(XEN_GUEST_HANDLE_64(void) buf, u16 buf_size)
306 {
307 /* send stats to user space */
308 u8 *stats_buffer;
309 int len1, len2;
310 struct acm_stats_buffer acm_stats;
312 if ( (stats_buffer = xmalloc_array(u8, buf_size)) == NULL )
313 return -ENOMEM;
315 read_lock(&acm_bin_pol_rwlock);
317 len1 = acm_primary_ops->dump_statistics(
318 stats_buffer + sizeof(struct acm_stats_buffer),
319 buf_size - sizeof(struct acm_stats_buffer));
320 if ( len1 < 0 )
321 goto error_lock_free;
323 len2 = acm_secondary_ops->dump_statistics(
324 stats_buffer + sizeof(struct acm_stats_buffer) + len1,
325 buf_size - sizeof(struct acm_stats_buffer) - len1);
326 if ( len2 < 0 )
327 goto error_lock_free;
329 acm_stats.magic = cpu_to_be32(ACM_MAGIC);
330 acm_stats.primary_policy_code =
331 cpu_to_be32(acm_bin_pol.primary_policy_code);
332 acm_stats.secondary_policy_code =
333 cpu_to_be32(acm_bin_pol.secondary_policy_code);
334 acm_stats.primary_stats_offset =
335 cpu_to_be32(sizeof(struct acm_stats_buffer));
336 acm_stats.secondary_stats_offset =
337 cpu_to_be32(sizeof(struct acm_stats_buffer) + len1);
338 acm_stats.len = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1 + len2);
340 memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
342 if ( copy_to_guest(buf,
343 stats_buffer,
344 sizeof(struct acm_stats_buffer) + len1 + len2) )
345 goto error_lock_free;
347 read_unlock(&acm_bin_pol_rwlock);
348 xfree(stats_buffer);
350 return ACM_OK;
352 error_lock_free:
353 read_unlock(&acm_bin_pol_rwlock);
354 xfree(stats_buffer);
356 return -EFAULT;
357 }
360 int
361 acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE_64(void) buf, u16 buf_size)
362 {
363 /* send stats to user space */
364 u8 *ssid_buffer;
365 int ret;
366 struct acm_ssid_buffer *acm_ssid;
367 if ( buf_size < sizeof(struct acm_ssid_buffer) )
368 return -EFAULT;
370 if ( (ssid_buffer = xmalloc_array(u8, buf_size)) == NULL )
371 return -ENOMEM;
373 read_lock(&acm_bin_pol_rwlock);
375 acm_ssid = (struct acm_ssid_buffer *)ssid_buffer;
376 acm_ssid->len = sizeof(struct acm_ssid_buffer);
377 acm_ssid->ssidref = ssidref;
378 acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code;
379 acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code;
381 acm_ssid->policy_reference_offset = acm_ssid->len;
382 ret = acm_dump_policy_reference(
383 ssid_buffer + acm_ssid->policy_reference_offset,
384 buf_size - acm_ssid->policy_reference_offset);
385 if ( ret < 0 )
386 goto error_free_unlock;
388 acm_ssid->len += ret;
389 acm_ssid->primary_types_offset = acm_ssid->len;
391 /* ret >= 0 --> ret == max_types */
392 ret = acm_primary_ops->dump_ssid_types(
393 ACM_PRIMARY(ssidref),
394 ssid_buffer + acm_ssid->primary_types_offset,
395 buf_size - acm_ssid->primary_types_offset);
396 if ( ret < 0 )
397 goto error_free_unlock;
399 acm_ssid->len += ret;
400 acm_ssid->primary_max_types = ret;
401 acm_ssid->secondary_types_offset = acm_ssid->len;
403 ret = acm_secondary_ops->dump_ssid_types(
404 ACM_SECONDARY(ssidref),
405 ssid_buffer + acm_ssid->secondary_types_offset,
406 buf_size - acm_ssid->secondary_types_offset);
407 if ( ret < 0 )
408 goto error_free_unlock;
410 acm_ssid->len += ret;
411 acm_ssid->secondary_max_types = ret;
413 if ( copy_to_guest(buf, ssid_buffer, acm_ssid->len) )
414 goto error_free_unlock;
416 read_unlock(&acm_bin_pol_rwlock);
417 xfree(ssid_buffer);
419 return ACM_OK;
421 error_free_unlock:
422 read_unlock(&acm_bin_pol_rwlock);
423 printk("%s: Error getting ssid.\n", __func__);
424 xfree(ssid_buffer);
426 return -ENOMEM;
427 }
429 int
430 acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook)
431 {
432 int ret = ACM_ACCESS_DENIED;
433 switch ( hook )
434 {
436 case ACMHOOK_sharing:
437 /* Sharing hook restricts access in STE policy only */
438 ret = acm_sharing(ssidref1, ssidref2);
439 break;
441 case ACMHOOK_authorization:
442 ret = acm_authorization(ssidref1, ssidref2);
443 break;
445 default:
446 /* deny */
447 break;
448 }
450 printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n",
451 __func__, ssidref1, ssidref2,
452 (ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED");
454 return ret;
455 }
459 /*
460 Check if an ssidref of the current policy type is being used by any
461 domain.
462 */
463 static int
464 acm_check_used_ssidref(uint32_t policy_type, uint32_t search_ssidref,
465 struct acm_sized_buffer *errors)
466 {
467 int rc = 0;
468 struct acm_ssid_domain *rawssid;
470 read_lock(&ssid_list_rwlock);
472 for_each_acmssid( rawssid )
473 {
474 ssidref_t ssidref;
475 void *s = GET_SSIDP(policy_type, rawssid);
477 if ( policy_type == ACM_CHINESE_WALL_POLICY )
478 {
479 ssidref = ((struct chwall_ssid *)s)->chwall_ssidref;
480 } else {
481 ssidref = ((struct ste_ssid *)s)->ste_ssidref;
482 }
483 gdprintk(XENLOG_INFO,"domid=%d: search ssidref=%d, ssidref=%d\n",
484 rawssid->domainid,search_ssidref,ssidref);
485 if ( ssidref == search_ssidref )
486 {
487 /* one is enough */
488 acm_array_append_tuple(errors, ACM_SSIDREF_IN_USE, search_ssidref);
489 rc = 1;
490 break;
491 }
492 }
494 read_unlock(&ssid_list_rwlock);
496 return rc;
497 }
500 /*
501 * Translate a current ssidref into its future representation under
502 * the new policy.
503 * The map provides translation of ssidrefs from old to new in tuples
504 * of (old ssidref, new ssidref).
505 */
506 static ssidref_t
507 oldssid_to_newssid(const struct acm_ssid_domain *rawssid,
508 const struct acm_sized_buffer *map)
509 {
510 uint i;
512 if ( rawssid != NULL )
513 {
514 ssidref_t ssid = rawssid->ssidref & 0xffff;
515 for ( i = 0; i + 1 < map->num_items; i += 2 )
516 {
517 if ( map->array[i] == ssid )
518 {
519 return (map->array[i+1] << 16 | map->array[i+1]);
520 }
521 }
522 }
523 return ACM_INVALID_SSIDREF;
524 }
527 /*
528 * Assign an ssidref to the CHWALL policy component of the domain
529 */
530 static void
531 acm_pri_policy_assign_ssidref(struct acm_ssid_domain *rawssid,
532 ssidref_t new_ssid)
533 {
534 struct chwall_ssid *chwall = (struct chwall_ssid *)rawssid->primary_ssid;
535 chwall->chwall_ssidref = new_ssid;
536 }
539 /*
540 * Assign an ssidref to the STE policy component of the domain
541 */
542 static void
543 acm_sec_policy_assign_ssidref(struct acm_ssid_domain *rawssid,
544 ssidref_t new_ssid)
545 {
546 struct ste_ssid *ste = (struct ste_ssid *)rawssid->secondary_ssid;
547 ste->ste_ssidref = new_ssid;
548 }
550 /*
551 Change the ssidrefs on each domain using a passed translation function;
552 */
553 static void
554 acm_doms_change_ssidref(ssidref_t (*translator_fn)
555 (const struct acm_ssid_domain *,
556 const struct acm_sized_buffer *),
557 struct acm_sized_buffer *translation_map)
558 {
559 struct acm_ssid_domain *rawssid;
561 write_lock(&ssid_list_rwlock);
563 for_each_acmssid( rawssid )
564 {
565 ssidref_t new_ssid;
567 rawssid->old_ssidref = rawssid->ssidref;
569 new_ssid = translator_fn(rawssid, translation_map);
570 if ( new_ssid == ACM_INVALID_SSIDREF )
571 {
572 /* means no mapping found, so no change -- old = new */
573 continue;
574 }
576 acm_pri_policy_assign_ssidref(rawssid, ACM_PRIMARY (new_ssid) );
577 acm_sec_policy_assign_ssidref(rawssid, ACM_SECONDARY(new_ssid) );
579 rawssid->ssidref = new_ssid;
580 }
582 write_unlock(&ssid_list_rwlock);
583 }
585 /*
586 * Restore the previous ssidref values on all domains
587 */
588 static void
589 acm_doms_restore_ssidref(void)
590 {
591 struct acm_ssid_domain *rawssid;
593 write_lock(&ssid_list_rwlock);
595 for_each_acmssid( rawssid )
596 {
597 ssidref_t old_ssid;
599 if ( rawssid->old_ssidref == rawssid->ssidref )
600 continue;
602 old_ssid = rawssid->old_ssidref & 0xffff;
603 rawssid->ssidref = rawssid->old_ssidref;
605 acm_pri_policy_assign_ssidref(rawssid, old_ssid);
606 acm_sec_policy_assign_ssidref(rawssid, old_ssid);
607 }
609 write_unlock(&ssid_list_rwlock);
610 }
613 /*
614 Check the list of domains whether either one of them uses a
615 to-be-deleted ssidref.
616 */
617 static int
618 acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,
619 struct acm_sized_buffer *errors)
620 {
621 int rc = 0;
622 uint idx;
623 /* check for running domains that should not be there anymore */
624 for ( idx = 0; idx < dels->num_items; idx++ )
625 {
626 if ( acm_check_used_ssidref(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
627 dels->array[idx],
628 errors) > 0 ||
629 acm_check_used_ssidref(ACM_CHINESE_WALL_POLICY,
630 dels->array[idx],
631 errors) > 0)
632 {
633 rc = ACM_ERROR;
634 break;
635 }
636 }
637 return rc;
638 }
641 /*
642 * Change the policy of the system.
643 */
644 int
645 acm_change_policy(struct acm_change_policy *chgpolicy)
646 {
647 int rc = 0;
648 u8 *binpolicy = NULL;
649 struct acm_sized_buffer dels =
650 {
651 .array = NULL,
652 };
653 struct acm_sized_buffer ssidmap =
654 {
655 .array = NULL,
656 };
657 struct acm_sized_buffer errors =
658 {
659 .array = NULL,
660 };
662 gdprintk(XENLOG_INFO, "change policy operation\n");
664 if ( (chgpolicy->delarray_size > 4096) ||
665 (chgpolicy->chgarray_size > 4096) ||
666 (chgpolicy->errarray_size > 4096))
667 {
668 return ACM_ERROR;
669 }
671 dels.num_items = chgpolicy->delarray_size / sizeof(uint32_t);
672 if ( dels.num_items > 0 )
673 {
674 dels.array = xmalloc_array(uint32_t, dels.num_items);
675 if ( dels.array == NULL )
676 {
677 rc = -ENOMEM;
678 goto acm_chg_policy_exit;
679 }
680 }
682 ssidmap.num_items = chgpolicy->chgarray_size / sizeof(uint32_t);
683 if ( ssidmap.num_items > 0 )
684 {
685 ssidmap.array = xmalloc_array(uint32_t, ssidmap.num_items);
686 if ( ssidmap.array == NULL )
687 {
688 rc = -ENOMEM;
689 goto acm_chg_policy_exit;
690 }
691 }
693 errors.num_items = chgpolicy->errarray_size / sizeof(uint32_t);
694 if ( errors.num_items > 0 )
695 {
696 errors.array = xmalloc_array(uint32_t, errors.num_items);
697 if ( errors.array == NULL )
698 {
699 rc = -ENOMEM;
700 goto acm_chg_policy_exit;
701 }
702 memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
703 }
705 binpolicy = xmalloc_array(u8,
706 chgpolicy->policy_pushcache_size);
707 if ( binpolicy == NULL )
708 {
709 rc = -ENOMEM;
710 goto acm_chg_policy_exit;
711 }
713 if ( copy_from_guest(dels.array,
714 chgpolicy->del_array,
715 dels.num_items) ||
716 copy_from_guest(ssidmap.array,
717 chgpolicy->chg_array,
718 ssidmap.num_items) ||
719 copy_from_guest(binpolicy,
720 chgpolicy->policy_pushcache,
721 chgpolicy->policy_pushcache_size ))
722 {
723 rc = -EFAULT;
724 goto acm_chg_policy_exit;
725 }
727 rc = do_acm_set_policy(binpolicy,
728 chgpolicy->policy_pushcache_size,
729 0,
730 &dels, &ssidmap, &errors);
732 if ( (errors.num_items > 0) &&
733 copy_to_guest(chgpolicy->err_array,
734 errors.array,
735 errors.num_items ) )
736 {
737 rc = -EFAULT;
738 goto acm_chg_policy_exit;
739 }
742 acm_chg_policy_exit:
743 xfree(dels.array);
744 xfree(ssidmap.array);
745 xfree(errors.array);
746 xfree(binpolicy);
748 return rc;
749 }
752 /*
753 * Lookup the new ssidref given the domain's id.
754 * The translation map provides a list of tuples in the format
755 * (domid, new ssidref).
756 */
757 static ssidref_t
758 domid_to_newssid(const struct acm_ssid_domain *rawssid,
759 const struct acm_sized_buffer *map)
760 {
761 domid_t domid = rawssid->domainid;
762 uint i;
763 for ( i = 0; (i+1) < map->num_items; i += 2 )
764 {
765 if ( map->array[i] == domid )
766 return (ssidref_t)map->array[i+1];
767 }
768 return ACM_INVALID_SSIDREF;
769 }
772 int
773 do_acm_relabel_doms(struct acm_sized_buffer *relabel_map,
774 struct acm_sized_buffer *errors)
775 {
776 int rc = 0, irc;
778 write_lock(&acm_bin_pol_rwlock);
780 acm_doms_change_ssidref(domid_to_newssid, relabel_map);
782 /* run tests; collect as much error info as possible */
783 irc = do_chwall_init_state_curr(errors);
784 irc += do_ste_init_state_curr(errors);
785 if ( irc != 0 )
786 {
787 rc = -EFAULT;
788 goto acm_relabel_doms_lock_err_exit;
789 }
791 write_unlock(&acm_bin_pol_rwlock);
793 return rc;
795 acm_relabel_doms_lock_err_exit:
796 /* revert the new ssidref assignment */
797 acm_doms_restore_ssidref();
798 do_chwall_init_state_curr(NULL);
800 write_unlock(&acm_bin_pol_rwlock);
802 return rc;
803 }
806 int
807 acm_relabel_domains(struct acm_relabel_doms *relabel)
808 {
809 int rc = ACM_OK;
810 struct acm_sized_buffer relabels =
811 {
812 .array = NULL,
813 };
814 struct acm_sized_buffer errors =
815 {
816 .array = NULL,
817 };
819 if ( relabel->relabel_map_size > 4096 )
820 {
821 return ACM_ERROR;
822 }
824 relabels.num_items = relabel->relabel_map_size / sizeof(uint32_t);
825 if ( relabels.num_items > 0 )
826 {
827 relabels.array = xmalloc_array(uint32_t, relabels.num_items);
828 if ( relabels.array == NULL )
829 {
830 rc = -ENOMEM;
831 goto acm_relabel_doms_exit;
832 }
833 }
835 errors.num_items = relabel->errarray_size / sizeof(uint32_t);
836 if ( errors.num_items > 0 )
837 {
838 errors.array = xmalloc_array(uint32_t, errors.num_items);
839 if ( errors.array == NULL )
840 {
841 rc = -ENOMEM;
842 goto acm_relabel_doms_exit;
843 }
844 memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
845 }
847 if ( copy_from_guest(relabels.array,
848 relabel->relabel_map,
849 relabels.num_items) )
850 {
851 rc = -EFAULT;
852 goto acm_relabel_doms_exit;
853 }
855 rc = do_acm_relabel_doms(&relabels, &errors);
857 if ( copy_to_guest(relabel->err_array,
858 errors.array,
859 errors.num_items ) )
860 rc = -EFAULT;
862 acm_relabel_doms_exit:
863 xfree(relabels.array);
864 xfree(errors.array);
865 return rc;
866 }
868 /*
869 * Local variables:
870 * mode: C
871 * c-set-style: "BSD"
872 * c-basic-offset: 4
873 * tab-width: 4
874 * indent-tabs-mode: nil
875 * End:
876 */