ia64/xen-unstable

view xen/xsm/acm/acm_policy.c @ 16426:ae087a0fa2c9

acm: Fix an exit label.

Jump to a different error exit label if error occurs early in the
policy update process.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Nov 22 17:44:51 2007 +0000 (2007-11-22)
parents 2022cbc842af
children 05ac689a9473
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 <xsm/acm/acm_core.h>
32 #include <public/xsm/acm_ops.h>
33 #include <xsm/acm/acm_hooks.h>
34 #include <xsm/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_nossidchange;
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 error_lock_free_nossidchange:
173 do_chwall_init_state_curr(NULL);
174 write_unlock(&acm_bin_pol_rwlock);
176 return -EFAULT;
177 }
180 int
181 do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy,
182 struct acm_sized_buffer *deletions,
183 struct acm_sized_buffer *ssidchanges,
184 struct acm_sized_buffer *errors)
185 {
186 struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
188 /* some sanity checking */
189 if ( (be32_to_cpu(pol->magic) != ACM_MAGIC) ||
190 (buf_size != be32_to_cpu(pol->len)) ||
191 (be32_to_cpu(pol->policy_version) != ACM_POLICY_VERSION) )
192 {
193 printk("%s: ERROR in Magic, Version, or buf size.\n", __func__);
194 goto error_free;
195 }
197 if ( acm_active_security_policy == ACM_POLICY_UNDEFINED )
198 {
199 /* setup the policy with the boot policy */
200 if ( acm_init_binary_policy(
201 (be32_to_cpu(pol->secondary_policy_code) << 4) |
202 be32_to_cpu(pol->primary_policy_code)) )
203 {
204 goto error_free;
205 }
206 acm_active_security_policy = (acm_bin_pol.secondary_policy_code << 4) |
207 acm_bin_pol.primary_policy_code;
208 }
210 /* once acm_active_security_policy is set, it cannot be changed */
211 if ( (be32_to_cpu(pol->primary_policy_code) !=
212 acm_bin_pol.primary_policy_code) ||
213 (be32_to_cpu(pol->secondary_policy_code) !=
214 acm_bin_pol.secondary_policy_code) )
215 {
216 printkd("%s: Wrong policy type in boot policy!\n", __func__);
217 goto error_free;
218 }
220 return _acm_update_policy(buf, buf_size, is_bootpolicy,
221 pol,
222 deletions, ssidchanges,
223 errors);
225 error_free:
226 printk("%s: Error setting policy.\n", __func__);
227 return -EFAULT;
228 }
230 int
231 acm_get_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size)
232 {
233 u8 *policy_buffer;
234 int ret;
235 struct acm_policy_buffer *bin_pol;
237 if ( buf_size < sizeof(struct acm_policy_buffer) )
238 return -EFAULT;
240 if ( (policy_buffer = xmalloc_array(u8, buf_size)) == NULL )
241 return -ENOMEM;
243 read_lock(&acm_bin_pol_rwlock);
245 bin_pol = (struct acm_policy_buffer *)policy_buffer;
246 bin_pol->magic = cpu_to_be32(ACM_MAGIC);
247 bin_pol->primary_policy_code =
248 cpu_to_be32(acm_bin_pol.primary_policy_code);
249 bin_pol->secondary_policy_code =
250 cpu_to_be32(acm_bin_pol.secondary_policy_code);
252 bin_pol->len = cpu_to_be32(sizeof(struct acm_policy_buffer));
253 bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
254 bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
255 bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
257 memcpy(&bin_pol->xml_pol_version,
258 &acm_bin_pol.xml_pol_version,
259 sizeof(struct acm_policy_version));
261 ret = acm_dump_policy_reference(
262 policy_buffer + be32_to_cpu(bin_pol->policy_reference_offset),
263 buf_size - be32_to_cpu(bin_pol->policy_reference_offset));
265 if ( ret < 0 )
266 goto error_free_unlock;
268 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
269 bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
271 ret = acm_primary_ops->dump_binary_policy(
272 policy_buffer + be32_to_cpu(bin_pol->primary_buffer_offset),
273 buf_size - be32_to_cpu(bin_pol->primary_buffer_offset));
275 if ( ret < 0 )
276 goto error_free_unlock;
278 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
279 bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
281 ret = acm_secondary_ops->dump_binary_policy(
282 policy_buffer + be32_to_cpu(bin_pol->secondary_buffer_offset),
283 buf_size - be32_to_cpu(bin_pol->secondary_buffer_offset));
285 if ( ret < 0 )
286 goto error_free_unlock;
288 bin_pol->len = cpu_to_be32(be32_to_cpu(bin_pol->len) + ret);
289 if ( copy_to_guest(buf, policy_buffer, be32_to_cpu(bin_pol->len)) )
290 goto error_free_unlock;
292 read_unlock(&acm_bin_pol_rwlock);
293 xfree(policy_buffer);
295 return ACM_OK;
297 error_free_unlock:
298 read_unlock(&acm_bin_pol_rwlock);
299 printk("%s: Error getting policy.\n", __func__);
300 xfree(policy_buffer);
302 return -EFAULT;
303 }
305 int
306 acm_dump_statistics(XEN_GUEST_HANDLE_64(void) buf, u16 buf_size)
307 {
308 /* send stats to user space */
309 u8 *stats_buffer;
310 int len1, len2;
311 struct acm_stats_buffer acm_stats;
313 if ( (stats_buffer = xmalloc_array(u8, buf_size)) == NULL )
314 return -ENOMEM;
316 read_lock(&acm_bin_pol_rwlock);
318 len1 = acm_primary_ops->dump_statistics(
319 stats_buffer + sizeof(struct acm_stats_buffer),
320 buf_size - sizeof(struct acm_stats_buffer));
321 if ( len1 < 0 )
322 goto error_lock_free;
324 len2 = acm_secondary_ops->dump_statistics(
325 stats_buffer + sizeof(struct acm_stats_buffer) + len1,
326 buf_size - sizeof(struct acm_stats_buffer) - len1);
327 if ( len2 < 0 )
328 goto error_lock_free;
330 acm_stats.magic = cpu_to_be32(ACM_MAGIC);
331 acm_stats.primary_policy_code =
332 cpu_to_be32(acm_bin_pol.primary_policy_code);
333 acm_stats.secondary_policy_code =
334 cpu_to_be32(acm_bin_pol.secondary_policy_code);
335 acm_stats.primary_stats_offset =
336 cpu_to_be32(sizeof(struct acm_stats_buffer));
337 acm_stats.secondary_stats_offset =
338 cpu_to_be32(sizeof(struct acm_stats_buffer) + len1);
339 acm_stats.len = cpu_to_be32(sizeof(struct acm_stats_buffer) + len1 + len2);
341 memcpy(stats_buffer, &acm_stats, sizeof(struct acm_stats_buffer));
343 if ( copy_to_guest(buf,
344 stats_buffer,
345 sizeof(struct acm_stats_buffer) + len1 + len2) )
346 goto error_lock_free;
348 read_unlock(&acm_bin_pol_rwlock);
349 xfree(stats_buffer);
351 return ACM_OK;
353 error_lock_free:
354 read_unlock(&acm_bin_pol_rwlock);
355 xfree(stats_buffer);
357 return -EFAULT;
358 }
361 int
362 acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE_64(void) buf, u16 buf_size)
363 {
364 /* send stats to user space */
365 u8 *ssid_buffer;
366 int ret;
367 struct acm_ssid_buffer *acm_ssid;
368 if ( buf_size < sizeof(struct acm_ssid_buffer) )
369 return -EFAULT;
371 if ( (ssid_buffer = xmalloc_array(u8, buf_size)) == NULL )
372 return -ENOMEM;
374 read_lock(&acm_bin_pol_rwlock);
376 acm_ssid = (struct acm_ssid_buffer *)ssid_buffer;
377 acm_ssid->len = sizeof(struct acm_ssid_buffer);
378 acm_ssid->ssidref = ssidref;
379 acm_ssid->primary_policy_code = acm_bin_pol.primary_policy_code;
380 acm_ssid->secondary_policy_code = acm_bin_pol.secondary_policy_code;
382 acm_ssid->policy_reference_offset = acm_ssid->len;
383 ret = acm_dump_policy_reference(
384 ssid_buffer + acm_ssid->policy_reference_offset,
385 buf_size - acm_ssid->policy_reference_offset);
386 if ( ret < 0 )
387 goto error_free_unlock;
389 acm_ssid->len += ret;
390 acm_ssid->primary_types_offset = acm_ssid->len;
392 /* ret >= 0 --> ret == max_types */
393 ret = acm_primary_ops->dump_ssid_types(
394 ACM_PRIMARY(ssidref),
395 ssid_buffer + acm_ssid->primary_types_offset,
396 buf_size - acm_ssid->primary_types_offset);
397 if ( ret < 0 )
398 goto error_free_unlock;
400 acm_ssid->len += ret;
401 acm_ssid->primary_max_types = ret;
402 acm_ssid->secondary_types_offset = acm_ssid->len;
404 ret = acm_secondary_ops->dump_ssid_types(
405 ACM_SECONDARY(ssidref),
406 ssid_buffer + acm_ssid->secondary_types_offset,
407 buf_size - acm_ssid->secondary_types_offset);
408 if ( ret < 0 )
409 goto error_free_unlock;
411 acm_ssid->len += ret;
412 acm_ssid->secondary_max_types = ret;
414 if ( copy_to_guest(buf, ssid_buffer, acm_ssid->len) )
415 goto error_free_unlock;
417 read_unlock(&acm_bin_pol_rwlock);
418 xfree(ssid_buffer);
420 return ACM_OK;
422 error_free_unlock:
423 read_unlock(&acm_bin_pol_rwlock);
424 printk("%s: Error getting ssid.\n", __func__);
425 xfree(ssid_buffer);
427 return -ENOMEM;
428 }
430 int
431 acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook)
432 {
433 int ret = ACM_ACCESS_DENIED;
435 read_lock(&acm_bin_pol_rwlock);
437 switch ( hook )
438 {
440 case ACMHOOK_sharing:
441 /* Sharing hook restricts access in STE policy only */
442 ret = acm_sharing(ssidref1, ssidref2);
443 break;
445 case ACMHOOK_authorization:
446 ret = acm_authorization(ssidref1, ssidref2);
447 break;
449 default:
450 /* deny */
451 break;
452 }
454 read_unlock(&acm_bin_pol_rwlock);
456 printkd("%s: ssid1=%x, ssid2=%x, decision=%s.\n",
457 __func__, ssidref1, ssidref2,
458 (ret == ACM_ACCESS_PERMITTED) ? "GRANTED" : "DENIED");
460 return ret;
461 }
465 /*
466 Check if an ssidref of the current policy type is being used by any
467 domain.
468 */
469 static int
470 acm_check_used_ssidref(uint32_t policy_type, uint32_t search_ssidref,
471 struct acm_sized_buffer *errors)
472 {
473 int rc = 0;
474 struct acm_ssid_domain *rawssid;
476 read_lock(&ssid_list_rwlock);
478 for_each_acmssid( rawssid )
479 {
480 ssidref_t ssidref;
481 void *s = GET_SSIDP(policy_type, rawssid);
483 if ( policy_type == ACM_CHINESE_WALL_POLICY )
484 {
485 ssidref = ((struct chwall_ssid *)s)->chwall_ssidref;
486 } else {
487 ssidref = ((struct ste_ssid *)s)->ste_ssidref;
488 }
489 gdprintk(XENLOG_INFO,"domid=%d: search ssidref=%d, ssidref=%d\n",
490 rawssid->domainid,search_ssidref,ssidref);
491 if ( ssidref == search_ssidref )
492 {
493 /* one is enough */
494 acm_array_append_tuple(errors, ACM_SSIDREF_IN_USE, search_ssidref);
495 rc = 1;
496 break;
497 }
498 }
500 read_unlock(&ssid_list_rwlock);
502 return rc;
503 }
506 /*
507 * Translate a current ssidref into its future representation under
508 * the new policy.
509 * The map provides translation of ssidrefs from old to new in tuples
510 * of (old ssidref, new ssidref).
511 */
512 static ssidref_t
513 oldssid_to_newssid(const struct acm_ssid_domain *rawssid,
514 const struct acm_sized_buffer *map)
515 {
516 uint i;
518 if ( rawssid != NULL )
519 {
520 ssidref_t ssid = rawssid->ssidref & 0xffff;
521 for ( i = 0; i + 1 < map->num_items; i += 2 )
522 {
523 if ( map->array[i] == ssid )
524 {
525 return (map->array[i+1] << 16 | map->array[i+1]);
526 }
527 }
528 }
529 return ACM_INVALID_SSIDREF;
530 }
533 /*
534 * Assign an ssidref to the CHWALL policy component of the domain
535 */
536 static void
537 acm_pri_policy_assign_ssidref(struct acm_ssid_domain *rawssid,
538 ssidref_t new_ssid)
539 {
540 struct chwall_ssid *chwall = (struct chwall_ssid *)rawssid->primary_ssid;
541 chwall->chwall_ssidref = new_ssid;
542 }
545 /*
546 * Assign an ssidref to the STE policy component of the domain
547 */
548 static void
549 acm_sec_policy_assign_ssidref(struct acm_ssid_domain *rawssid,
550 ssidref_t new_ssid)
551 {
552 struct ste_ssid *ste = (struct ste_ssid *)rawssid->secondary_ssid;
553 ste->ste_ssidref = new_ssid;
554 }
556 /*
557 Change the ssidrefs on each domain using a passed translation function;
558 */
559 static void
560 acm_doms_change_ssidref(ssidref_t (*translator_fn)
561 (const struct acm_ssid_domain *,
562 const struct acm_sized_buffer *),
563 struct acm_sized_buffer *translation_map)
564 {
565 struct acm_ssid_domain *rawssid;
567 write_lock(&ssid_list_rwlock);
569 for_each_acmssid( rawssid )
570 {
571 ssidref_t new_ssid;
573 rawssid->old_ssidref = rawssid->ssidref;
575 new_ssid = translator_fn(rawssid, translation_map);
576 if ( new_ssid == ACM_INVALID_SSIDREF )
577 {
578 /* means no mapping found, so no change -- old = new */
579 continue;
580 }
582 acm_pri_policy_assign_ssidref(rawssid, ACM_PRIMARY (new_ssid) );
583 acm_sec_policy_assign_ssidref(rawssid, ACM_SECONDARY(new_ssid) );
585 rawssid->ssidref = new_ssid;
586 }
588 write_unlock(&ssid_list_rwlock);
589 }
591 /*
592 * Restore the previous ssidref values on all domains
593 */
594 static void
595 acm_doms_restore_ssidref(void)
596 {
597 struct acm_ssid_domain *rawssid;
599 write_lock(&ssid_list_rwlock);
601 for_each_acmssid( rawssid )
602 {
603 ssidref_t old_ssid;
605 if ( rawssid->old_ssidref == rawssid->ssidref )
606 continue;
608 old_ssid = rawssid->old_ssidref & 0xffff;
609 rawssid->ssidref = rawssid->old_ssidref;
611 acm_pri_policy_assign_ssidref(rawssid, old_ssid);
612 acm_sec_policy_assign_ssidref(rawssid, old_ssid);
613 }
615 write_unlock(&ssid_list_rwlock);
616 }
619 /*
620 Check the list of domains whether either one of them uses a
621 to-be-deleted ssidref.
622 */
623 static int
624 acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,
625 struct acm_sized_buffer *errors)
626 {
627 int rc = 0;
628 uint idx;
629 /* check for running domains that should not be there anymore */
630 for ( idx = 0; idx < dels->num_items; idx++ )
631 {
632 if ( acm_check_used_ssidref(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
633 dels->array[idx],
634 errors) > 0 ||
635 acm_check_used_ssidref(ACM_CHINESE_WALL_POLICY,
636 dels->array[idx],
637 errors) > 0)
638 {
639 rc = ACM_ERROR;
640 break;
641 }
642 }
643 return rc;
644 }
647 /*
648 * Change the policy of the system.
649 */
650 int
651 acm_change_policy(struct acm_change_policy *chgpolicy)
652 {
653 int rc = 0;
654 u8 *binpolicy = NULL;
655 struct acm_sized_buffer dels =
656 {
657 .array = NULL,
658 };
659 struct acm_sized_buffer ssidmap =
660 {
661 .array = NULL,
662 };
663 struct acm_sized_buffer errors =
664 {
665 .array = NULL,
666 };
668 gdprintk(XENLOG_INFO, "change policy operation\n");
670 if ( (chgpolicy->delarray_size > 4096) ||
671 (chgpolicy->chgarray_size > 4096) ||
672 (chgpolicy->errarray_size > 4096))
673 {
674 return ACM_ERROR;
675 }
677 dels.num_items = chgpolicy->delarray_size / sizeof(uint32_t);
678 if ( dels.num_items > 0 )
679 {
680 dels.array = xmalloc_array(uint32_t, dels.num_items);
681 if ( dels.array == NULL )
682 {
683 rc = -ENOMEM;
684 goto acm_chg_policy_exit;
685 }
686 }
688 ssidmap.num_items = chgpolicy->chgarray_size / sizeof(uint32_t);
689 if ( ssidmap.num_items > 0 )
690 {
691 ssidmap.array = xmalloc_array(uint32_t, ssidmap.num_items);
692 if ( ssidmap.array == NULL )
693 {
694 rc = -ENOMEM;
695 goto acm_chg_policy_exit;
696 }
697 }
699 errors.num_items = chgpolicy->errarray_size / sizeof(uint32_t);
700 if ( errors.num_items > 0 )
701 {
702 errors.array = xmalloc_array(uint32_t, errors.num_items);
703 if ( errors.array == NULL )
704 {
705 rc = -ENOMEM;
706 goto acm_chg_policy_exit;
707 }
708 memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
709 }
711 binpolicy = xmalloc_array(u8,
712 chgpolicy->policy_pushcache_size);
713 if ( binpolicy == NULL )
714 {
715 rc = -ENOMEM;
716 goto acm_chg_policy_exit;
717 }
719 if ( copy_from_guest(dels.array,
720 chgpolicy->del_array,
721 dels.num_items) ||
722 copy_from_guest(ssidmap.array,
723 chgpolicy->chg_array,
724 ssidmap.num_items) ||
725 copy_from_guest(binpolicy,
726 chgpolicy->policy_pushcache,
727 chgpolicy->policy_pushcache_size ))
728 {
729 rc = -EFAULT;
730 goto acm_chg_policy_exit;
731 }
733 rc = do_acm_set_policy(binpolicy,
734 chgpolicy->policy_pushcache_size,
735 0,
736 &dels, &ssidmap, &errors);
738 if ( (errors.num_items > 0) &&
739 copy_to_guest(chgpolicy->err_array,
740 errors.array,
741 errors.num_items ) )
742 {
743 rc = -EFAULT;
744 goto acm_chg_policy_exit;
745 }
748 acm_chg_policy_exit:
749 xfree(dels.array);
750 xfree(ssidmap.array);
751 xfree(errors.array);
752 xfree(binpolicy);
754 return rc;
755 }
758 /*
759 * Lookup the new ssidref given the domain's id.
760 * The translation map provides a list of tuples in the format
761 * (domid, new ssidref).
762 */
763 static ssidref_t
764 domid_to_newssid(const struct acm_ssid_domain *rawssid,
765 const struct acm_sized_buffer *map)
766 {
767 domid_t domid = rawssid->domainid;
768 uint i;
769 for ( i = 0; (i+1) < map->num_items; i += 2 )
770 {
771 if ( map->array[i] == domid )
772 return (ssidref_t)map->array[i+1];
773 }
774 return ACM_INVALID_SSIDREF;
775 }
778 int
779 do_acm_relabel_doms(struct acm_sized_buffer *relabel_map,
780 struct acm_sized_buffer *errors)
781 {
782 int rc = 0, irc;
784 write_lock(&acm_bin_pol_rwlock);
786 acm_doms_change_ssidref(domid_to_newssid, relabel_map);
788 /* run tests; collect as much error info as possible */
789 irc = do_chwall_init_state_curr(errors);
790 irc += do_ste_init_state_curr(errors);
791 if ( irc != 0 )
792 {
793 rc = -EFAULT;
794 goto acm_relabel_doms_lock_err_exit;
795 }
797 write_unlock(&acm_bin_pol_rwlock);
799 return rc;
801 acm_relabel_doms_lock_err_exit:
802 /* revert the new ssidref assignment */
803 acm_doms_restore_ssidref();
804 do_chwall_init_state_curr(NULL);
806 write_unlock(&acm_bin_pol_rwlock);
808 return rc;
809 }
812 int
813 acm_relabel_domains(struct acm_relabel_doms *relabel)
814 {
815 int rc = ACM_OK;
816 struct acm_sized_buffer relabels =
817 {
818 .array = NULL,
819 };
820 struct acm_sized_buffer errors =
821 {
822 .array = NULL,
823 };
825 if ( relabel->relabel_map_size > 4096 )
826 {
827 return ACM_ERROR;
828 }
830 relabels.num_items = relabel->relabel_map_size / sizeof(uint32_t);
831 if ( relabels.num_items > 0 )
832 {
833 relabels.array = xmalloc_array(uint32_t, relabels.num_items);
834 if ( relabels.array == NULL )
835 {
836 rc = -ENOMEM;
837 goto acm_relabel_doms_exit;
838 }
839 }
841 errors.num_items = relabel->errarray_size / sizeof(uint32_t);
842 if ( errors.num_items > 0 )
843 {
844 errors.array = xmalloc_array(uint32_t, errors.num_items);
845 if ( errors.array == NULL )
846 {
847 rc = -ENOMEM;
848 goto acm_relabel_doms_exit;
849 }
850 memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
851 }
853 if ( copy_from_guest(relabels.array,
854 relabel->relabel_map,
855 relabels.num_items) )
856 {
857 rc = -EFAULT;
858 goto acm_relabel_doms_exit;
859 }
861 rc = do_acm_relabel_doms(&relabels, &errors);
863 if ( copy_to_guest(relabel->err_array,
864 errors.array,
865 errors.num_items ) )
866 rc = -EFAULT;
868 acm_relabel_doms_exit:
869 xfree(relabels.array);
870 xfree(errors.array);
871 return rc;
872 }
874 /*
875 * Local variables:
876 * mode: C
877 * c-set-style: "BSD"
878 * c-basic-offset: 4
879 * tab-width: 4
880 * indent-tabs-mode: nil
881 * End:
882 */