ia64/xen-unstable

changeset 14925:4677ee247aa9

acm: Updating a policy on a running system.

Allow a policy to be updated on a running system and domains to be
relabeled. The updating of a policy is happening in several steps:
relabeling the domains, testing whether the system would be in a valid
state after the relabeling (according to the policy), committing the
changes if state is determined to be valid.

I have followed Keir's suggestion of building a 2nd linked list
parallel to the domain list. That 2nd list holds security information
related to the running domains. Each entry is pointed to by its domain
structure. The list is protected by its own read/write-lock. I have
moved nearly all ACM-related code that was traversing the domain list
previously to traverse this list instead and not hold onto the domain
list lock.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Wed Apr 25 09:40:02 2007 +0100 (2007-04-25)
parents d5d6d2a8d10c
children 8ca89a9e54a7
files xen/acm/acm_chinesewall_hooks.c xen/acm/acm_core.c xen/acm/acm_null_hooks.c xen/acm/acm_policy.c xen/acm/acm_simple_type_enforcement_hooks.c xen/common/acm_ops.c xen/include/acm/acm_core.h xen/include/acm/acm_hooks.h xen/include/public/acm.h xen/include/public/acm_ops.h
line diff
     1.1 --- a/xen/acm/acm_chinesewall_hooks.c	Wed Apr 25 09:31:52 2007 +0100
     1.2 +++ b/xen/acm/acm_chinesewall_hooks.c	Wed Apr 25 09:40:02 2007 +0100
     1.3 @@ -183,29 +183,33 @@ static int chwall_dump_policy(u8 * buf, 
     1.4      return ret;
     1.5  }
     1.6  
     1.7 -/* adapt security state (running_types and conflict_aggregate_set) to all running
     1.8 - * domains; chwall_init_state is called when a policy is changed to bring the security
     1.9 - * information into a consistent state and to detect violations (return != 0).
    1.10 - * from a security point of view, we simulate that all running domains are re-started
    1.11 +/*
    1.12 + * Adapt security state (running_types and conflict_aggregate_set) to all
    1.13 + * running domains; chwall_init_state is called when a policy is changed
    1.14 + * to bring the security information into a consistent state and to detect
    1.15 + * violations (return != 0) from a security point of view, we simulate
    1.16 + * that all running domains are re-started
    1.17   */
    1.18  static int
    1.19  chwall_init_state(struct acm_chwall_policy_buffer *chwall_buf,
    1.20 -                  domaintype_t * ssidrefs, domaintype_t * conflict_sets,
    1.21 +                  domaintype_t * ssidrefs,
    1.22 +                  domaintype_t * conflict_sets,
    1.23                    domaintype_t * running_types,
    1.24 -                  domaintype_t * conflict_aggregate_set)
    1.25 +                  domaintype_t * conflict_aggregate_set,
    1.26 +                  struct acm_sized_buffer *errors /* may be NULL */)
    1.27  {
    1.28      int violation = 0, i, j;
    1.29      struct chwall_ssid *chwall_ssid;
    1.30      ssidref_t chwall_ssidref;
    1.31 -    struct domain *d;
    1.32 +    struct acm_ssid_domain *rawssid;
    1.33  
    1.34 -    spin_lock(&domlist_update_lock);
    1.35 +    read_lock(&ssid_list_rwlock);
    1.36 +
    1.37      /* go through all domains and adjust policy as if this domain was started now */
    1.38 -    for_each_domain ( d )
    1.39 +    for_each_acmssid( rawssid )
    1.40      {
    1.41          chwall_ssid =
    1.42 -            GET_SSIDP(ACM_CHINESE_WALL_POLICY,
    1.43 -                      (struct acm_ssid_domain *)d->ssid);
    1.44 +            GET_SSIDP(ACM_CHINESE_WALL_POLICY, rawssid);
    1.45          chwall_ssidref = chwall_ssid->chwall_ssidref;
    1.46          traceprintk("%s: validating policy for domain %x (chwall-REF=%x).\n",
    1.47                      __func__, d->domain_id, chwall_ssidref);
    1.48 @@ -222,6 +226,9 @@ chwall_init_state(struct acm_chwall_poli
    1.49                  printk("%s: CHINESE WALL CONFLICT in type %02x.\n",
    1.50                         __func__, i);
    1.51                  violation = 1;
    1.52 +
    1.53 +                acm_array_append_tuple(errors, ACM_CHWALL_CONFLICT, i);
    1.54 +
    1.55                  goto out;
    1.56              }
    1.57          /* set violation and break out of the loop */
    1.58 @@ -249,7 +256,7 @@ chwall_init_state(struct acm_chwall_poli
    1.59          }
    1.60      }
    1.61   out:
    1.62 -    spin_unlock(&domlist_update_lock);
    1.63 +    read_unlock(&ssid_list_rwlock);
    1.64      return violation;
    1.65      /* returning "violation != 0" means that the currently running set of domains would
    1.66       * not be possible if the new policy had been enforced before starting them; for chinese
    1.67 @@ -257,44 +264,45 @@ chwall_init_state(struct acm_chwall_poli
    1.68       * more than one type is currently running */
    1.69  }
    1.70  
    1.71 -static int chwall_set_policy(u8 * buf, u32 buf_size, int is_bootpolicy)
    1.72 +
    1.73 +int
    1.74 +do_chwall_init_state_curr(struct acm_sized_buffer *errors)
    1.75  {
    1.76 +    struct acm_chwall_policy_buffer chwall_buf = {
    1.77 +         /* only these two are important */
    1.78 +         .chwall_max_types        = chwall_bin_pol.max_types,
    1.79 +         .chwall_max_conflictsets = chwall_bin_pol.max_conflictsets,
    1.80 +    };
    1.81 +    /* reset running_types and aggregate set for recalculation */
    1.82 +    memset(chwall_bin_pol.running_types,
    1.83 +           0x0,
    1.84 +           sizeof(domaintype_t) * chwall_bin_pol.max_types);
    1.85 +    memset(chwall_bin_pol.conflict_aggregate_set,
    1.86 +           0x0,
    1.87 +           sizeof(domaintype_t) * chwall_bin_pol.max_types);
    1.88 +    return chwall_init_state(&chwall_buf,
    1.89 +                             chwall_bin_pol.ssidrefs,
    1.90 +                             chwall_bin_pol.conflict_sets,
    1.91 +                             chwall_bin_pol.running_types,
    1.92 +                             chwall_bin_pol.conflict_aggregate_set,
    1.93 +                             errors);
    1.94 +}
    1.95 +
    1.96 +/*
    1.97 + * Attempt to set the policy. This function must be called in test_only
    1.98 + * mode first to only perform checks. A second call then does the
    1.99 + * actual changes.
   1.100 + */
   1.101 +static int _chwall_update_policy(u8 *buf, u32 buf_size, int test_only,
   1.102 +                                 struct acm_sized_buffer *errors)
   1.103 +{
   1.104 +    int rc = -EFAULT;
   1.105      /* policy write-locked already */
   1.106      struct acm_chwall_policy_buffer *chwall_buf =
   1.107          (struct acm_chwall_policy_buffer *) buf;
   1.108      void *ssids = NULL, *conflict_sets = NULL, *running_types =
   1.109          NULL, *conflict_aggregate_set = NULL;
   1.110  
   1.111 -    if (buf_size < sizeof(struct acm_chwall_policy_buffer))
   1.112 -        return -EINVAL;
   1.113 -
   1.114 -    /* rewrite the policy due to endianess */
   1.115 -    chwall_buf->policy_code = be32_to_cpu(chwall_buf->policy_code);
   1.116 -    chwall_buf->policy_version = be32_to_cpu(chwall_buf->policy_version);
   1.117 -    chwall_buf->chwall_max_types = be32_to_cpu(chwall_buf->chwall_max_types);
   1.118 -    chwall_buf->chwall_max_ssidrefs =
   1.119 -        be32_to_cpu(chwall_buf->chwall_max_ssidrefs);
   1.120 -    chwall_buf->chwall_max_conflictsets =
   1.121 -        be32_to_cpu(chwall_buf->chwall_max_conflictsets);
   1.122 -    chwall_buf->chwall_ssid_offset = be32_to_cpu(chwall_buf->chwall_ssid_offset);
   1.123 -    chwall_buf->chwall_conflict_sets_offset =
   1.124 -        be32_to_cpu(chwall_buf->chwall_conflict_sets_offset);
   1.125 -    chwall_buf->chwall_running_types_offset =
   1.126 -        be32_to_cpu(chwall_buf->chwall_running_types_offset);
   1.127 -    chwall_buf->chwall_conflict_aggregate_offset =
   1.128 -        be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset);
   1.129 -
   1.130 -    /* policy type and version checks */
   1.131 -    if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) ||
   1.132 -        (chwall_buf->policy_version != ACM_CHWALL_VERSION))
   1.133 -        return -EINVAL;
   1.134 -
   1.135 -    /* during boot dom0_chwall_ssidref is set */
   1.136 -    if (is_bootpolicy &&
   1.137 -        (dom0_chwall_ssidref >= chwall_buf->chwall_max_ssidrefs)) {
   1.138 -        goto error_free;
   1.139 -    }
   1.140 -
   1.141      /* 1. allocate new buffers */
   1.142      ssids =
   1.143          xmalloc_array(domaintype_t,
   1.144 @@ -343,12 +351,20 @@ static int chwall_set_policy(u8 * buf, u
   1.145       *    this can fail if new policy is conflicting with running domains */
   1.146      if (chwall_init_state(chwall_buf, ssids,
   1.147                            conflict_sets, running_types,
   1.148 -                          conflict_aggregate_set))
   1.149 +                          conflict_aggregate_set,
   1.150 +                          errors))
   1.151      {
   1.152          printk("%s: New policy conflicts with running domains. Policy load aborted.\n",
   1.153                 __func__);
   1.154          goto error_free;        /* new policy conflicts with running domains */
   1.155      }
   1.156 +
   1.157 +    /* if this was only a test run, exit with ACM_OK */
   1.158 +    if (test_only) {
   1.159 +        rc = ACM_OK;
   1.160 +        goto error_free;
   1.161 +    }
   1.162 +
   1.163      /* 4. free old policy buffers, replace with new ones */
   1.164      chwall_bin_pol.max_types = chwall_buf->chwall_max_types;
   1.165      chwall_bin_pol.max_ssidrefs = chwall_buf->chwall_max_ssidrefs;
   1.166 @@ -364,12 +380,61 @@ static int chwall_set_policy(u8 * buf, u
   1.167      return ACM_OK;
   1.168  
   1.169   error_free:
   1.170 -    printk("%s: ERROR setting policy.\n", __func__);
   1.171 +    if (!test_only) printk("%s: ERROR setting policy.\n", __func__);
   1.172      xfree(ssids);
   1.173      xfree(conflict_sets);
   1.174      xfree(running_types);
   1.175      xfree(conflict_aggregate_set);
   1.176 -    return -EFAULT;
   1.177 +    return rc;
   1.178 +}
   1.179 +
   1.180 +/*
   1.181 + * This function MUST be called before the chwall_ste_policy function!
   1.182 + */
   1.183 +static int chwall_test_policy(u8 *buf, u32 buf_size, int is_bootpolicy,
   1.184 +                              struct acm_sized_buffer *errors)
   1.185 +{
   1.186 +    struct acm_chwall_policy_buffer *chwall_buf =
   1.187 +        (struct acm_chwall_policy_buffer *) buf;
   1.188 +
   1.189 +    if (buf_size < sizeof(struct acm_chwall_policy_buffer))
   1.190 +        return -EINVAL;
   1.191 +
   1.192 +    /* rewrite the policy due to endianess */
   1.193 +    chwall_buf->policy_code = be32_to_cpu(chwall_buf->policy_code);
   1.194 +    chwall_buf->policy_version = be32_to_cpu(chwall_buf->policy_version);
   1.195 +    chwall_buf->chwall_max_types =
   1.196 +        be32_to_cpu(chwall_buf->chwall_max_types);
   1.197 +    chwall_buf->chwall_max_ssidrefs =
   1.198 +        be32_to_cpu(chwall_buf->chwall_max_ssidrefs);
   1.199 +    chwall_buf->chwall_max_conflictsets =
   1.200 +        be32_to_cpu(chwall_buf->chwall_max_conflictsets);
   1.201 +    chwall_buf->chwall_ssid_offset =
   1.202 +        be32_to_cpu(chwall_buf->chwall_ssid_offset);
   1.203 +    chwall_buf->chwall_conflict_sets_offset =
   1.204 +        be32_to_cpu(chwall_buf->chwall_conflict_sets_offset);
   1.205 +    chwall_buf->chwall_running_types_offset =
   1.206 +        be32_to_cpu(chwall_buf->chwall_running_types_offset);
   1.207 +    chwall_buf->chwall_conflict_aggregate_offset =
   1.208 +        be32_to_cpu(chwall_buf->chwall_conflict_aggregate_offset);
   1.209 +
   1.210 +    /* policy type and version checks */
   1.211 +    if ((chwall_buf->policy_code != ACM_CHINESE_WALL_POLICY) ||
   1.212 +        (chwall_buf->policy_version != ACM_CHWALL_VERSION))
   1.213 +        return -EINVAL;
   1.214 +
   1.215 +    /* during boot dom0_chwall_ssidref is set */
   1.216 +    if (is_bootpolicy &&
   1.217 +        (dom0_chwall_ssidref >= chwall_buf->chwall_max_ssidrefs))
   1.218 +        return -EINVAL;
   1.219 +
   1.220 +
   1.221 +    return _chwall_update_policy(buf, buf_size, 1, errors);
   1.222 +}
   1.223 +
   1.224 +static int chwall_set_policy(u8 *buf, u32 buf_size)
   1.225 +{
   1.226 +    return _chwall_update_policy(buf, buf_size, 0, NULL);
   1.227  }
   1.228  
   1.229  static int chwall_dump_stats(u8 * buf, u16 len)
   1.230 @@ -590,6 +655,7 @@ struct acm_operations acm_chinesewall_op
   1.231      .init_domain_ssid = chwall_init_domain_ssid,
   1.232      .free_domain_ssid = chwall_free_domain_ssid,
   1.233      .dump_binary_policy = chwall_dump_policy,
   1.234 +    .test_binary_policy = chwall_test_policy,
   1.235      .set_binary_policy = chwall_set_policy,
   1.236      .dump_statistics = chwall_dump_stats,
   1.237      .dump_ssid_types = chwall_dump_ssid_types,
     2.1 --- a/xen/acm/acm_core.c	Wed Apr 25 09:31:52 2007 +0100
     2.2 +++ b/xen/acm/acm_core.c	Wed Apr 25 09:40:02 2007 +0100
     2.3 @@ -62,10 +62,14 @@ struct acm_binary_policy acm_bin_pol;
     2.4  /* acm binary policy lock */
     2.5  DEFINE_RWLOCK(acm_bin_pol_rwlock);
     2.6  
     2.7 -/* ACM's only accepted policy name */
     2.8 +/* ACM's only accepted policy name during boot */
     2.9  char polname[80];
    2.10  char *acm_accepted_boot_policy_name = NULL;
    2.11  
    2.12 +/* a lits of all chained ssid structures */
    2.13 +LIST_HEAD(ssid_list);
    2.14 +DEFINE_RWLOCK(ssid_list_rwlock);
    2.15 +
    2.16  static void __init set_dom0_ssidref(const char *val)
    2.17  {
    2.18      /* expected format:
    2.19 @@ -77,7 +81,7 @@ static void __init set_dom0_ssidref(cons
    2.20      int i;
    2.21      int dom0_ssidref = simple_strtoull(val, &c, 0);
    2.22  
    2.23 -    if (!strncmp(&c[0],":sHype:", 7)) {
    2.24 +    if (!strncmp(&c[0],":ACM:", 5)) {
    2.25          lo = dom0_ssidref & 0xffff;
    2.26          if (lo < ACM_MAX_NUM_TYPES && lo >= 1)
    2.27              dom0_chwall_ssidref = lo;
    2.28 @@ -249,7 +253,8 @@ acm_setup(char *policy_start,
    2.29          return rc;
    2.30  
    2.31      rc = do_acm_set_policy((void *)policy_start, (u32)policy_len,
    2.32 -                           is_bootpolicy);
    2.33 +                           is_bootpolicy,
    2.34 +                           NULL, NULL, NULL);
    2.35      if (rc == ACM_OK)
    2.36      {
    2.37          printkd("Policy len  0x%lx, start at %p.\n",policy_len,policy_start);
    2.38 @@ -337,9 +342,10 @@ int acm_init_domain_ssid_new(struct doma
    2.39          return ACM_INIT_SSID_ERROR;
    2.40      }
    2.41  
    2.42 +    INIT_LIST_HEAD(&ssid->node);
    2.43      ssid->datatype       = ACM_DATATYPE_domain;
    2.44      ssid->subject        = subj;
    2.45 -    ssid->domainid      = subj->domain_id;
    2.46 +    ssid->domainid       = subj->domain_id;
    2.47      ssid->primary_ssid   = NULL;
    2.48      ssid->secondary_ssid = NULL;
    2.49  
    2.50 @@ -367,6 +373,11 @@ int acm_init_domain_ssid_new(struct doma
    2.51          acm_free_domain_ssid(ssid);
    2.52          return ACM_INIT_SSID_ERROR;
    2.53      }
    2.54 +
    2.55 +    write_lock(&ssid_list_rwlock);
    2.56 +    list_add(&ssid->node, &ssid_list);
    2.57 +    write_unlock(&ssid_list_rwlock);
    2.58 +
    2.59      printkd("%s: assigned domain %x the ssidref=%x.\n",
    2.60             __func__, subj->domain_id, ssid->ssidref);
    2.61      return ACM_OK;
    2.62 @@ -387,6 +398,11 @@ acm_free_domain_ssid(struct acm_ssid_dom
    2.63      if (acm_secondary_ops->free_domain_ssid != NULL)
    2.64          acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
    2.65      ssid->secondary_ssid = NULL;
    2.66 +
    2.67 +    write_lock(&ssid_list_rwlock);
    2.68 +    list_del(&ssid->node);
    2.69 +    write_unlock(&ssid_list_rwlock);
    2.70 +
    2.71      xfree(ssid);
    2.72      printkd("%s: Freed individual domain ssid (domain=%02x).\n",
    2.73              __func__, id);
     3.1 --- a/xen/acm/acm_null_hooks.c	Wed Apr 25 09:31:52 2007 +0100
     3.2 +++ b/xen/acm/acm_null_hooks.c	Wed Apr 25 09:40:02 2007 +0100
     3.3 @@ -33,7 +33,14 @@ null_dump_binary_policy(u8 *buf, u32 buf
     3.4  }
     3.5  
     3.6  static int
     3.7 -null_set_binary_policy(u8 *buf, u32 buf_size, int is_bootpolicy)
     3.8 +null_test_binary_policy(u8 *buf, u32 buf_size, int is_bootpolicy,
     3.9 +                        struct acm_sized_buffer *errors)
    3.10 +{
    3.11 +    return ACM_OK;
    3.12 +}
    3.13 +
    3.14 +static int
    3.15 +null_set_binary_policy(u8 *buf, u32 buf_size)
    3.16  { 
    3.17      return ACM_OK;
    3.18  }
    3.19 @@ -58,6 +65,7 @@ struct acm_operations acm_null_ops = {
    3.20      .init_domain_ssid = null_init_domain_ssid,
    3.21      .free_domain_ssid = null_free_domain_ssid,
    3.22      .dump_binary_policy = null_dump_binary_policy,
    3.23 +    .test_binary_policy = null_test_binary_policy,
    3.24      .set_binary_policy = null_set_binary_policy,
    3.25      .dump_statistics = null_dump_stats,
    3.26      .dump_ssid_types = null_dump_ssid_types,
     4.1 --- a/xen/acm/acm_policy.c	Wed Apr 25 09:31:52 2007 +0100
     4.2 +++ b/xen/acm/acm_policy.c	Wed Apr 25 09:40:02 2007 +0100
     4.3 @@ -1,7 +1,7 @@
     4.4  /****************************************************************
     4.5   * acm_policy.c
     4.6   * 
     4.7 - * Copyright (C) 2005 IBM Corporation
     4.8 + * Copyright (C) 2005-2007 IBM Corporation
     4.9   *
    4.10   * Author:
    4.11   * Reiner Sailer <sailer@watson.ibm.com>
    4.12 @@ -27,10 +27,23 @@
    4.13  #include <xen/delay.h>
    4.14  #include <xen/sched.h>
    4.15  #include <xen/guest_access.h>
    4.16 +#include <public/xen.h>
    4.17  #include <acm/acm_core.h>
    4.18  #include <public/acm_ops.h>
    4.19  #include <acm/acm_hooks.h>
    4.20  #include <acm/acm_endian.h>
    4.21 +#include <asm/current.h>
    4.22 +
    4.23 +static int acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,
    4.24 +                                      struct acm_sized_buffer *errors);
    4.25 +static void acm_doms_change_ssidref(ssidref_t (*translator)
    4.26 +                                     (const struct acm_ssid_domain *,
    4.27 +                                      const struct acm_sized_buffer *),
    4.28 +                                      struct acm_sized_buffer *translation_map);
    4.29 +static void acm_doms_restore_ssidref(void);
    4.30 +static ssidref_t oldssid_to_newssid(const struct acm_ssid_domain *,
    4.31 +                                    const struct acm_sized_buffer *map);
    4.32 +
    4.33  
    4.34  int
    4.35  acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size)
    4.36 @@ -50,7 +63,8 @@ acm_set_policy(XEN_GUEST_HANDLE(void) bu
    4.37          printk("%s: Error copying!\n",__func__);
    4.38          goto error_free;
    4.39      }
    4.40 -    ret = do_acm_set_policy(policy_buffer, buf_size, 0);
    4.41 +    ret = do_acm_set_policy(policy_buffer, buf_size, 0,
    4.42 +                            NULL, NULL, NULL);
    4.43  
    4.44   error_free:
    4.45      xfree(policy_buffer);
    4.46 @@ -58,11 +72,109 @@ acm_set_policy(XEN_GUEST_HANDLE(void) bu
    4.47  }
    4.48  
    4.49  
    4.50 +/*
    4.51 + * Update the policy of the running system by:
    4.52 + * - deleting ssidrefs that are not in the new policy anymore
    4.53 + *   -> no running domain may use such an ssidref
    4.54 + * - assign new ssidrefs to domains based on their old ssidrefs
    4.55 + *
    4.56 + */
    4.57 +static int
    4.58 +_acm_update_policy(void *buf, u32 buf_size, int is_bootpolicy,
    4.59 +                   struct acm_policy_buffer *pol,
    4.60 +                   struct acm_sized_buffer *deletions,
    4.61 +                   struct acm_sized_buffer *ssidchanges,
    4.62 +                   struct acm_sized_buffer *errors)
    4.63 +{
    4.64 +    uint32_t offset, length;
    4.65 +
    4.66 +    write_lock(&acm_bin_pol_rwlock);
    4.67 +
    4.68 +    /*
    4.69 +       first some tests to check compatibility of new policy with
    4.70 +       current state of system/domains
    4.71 +     */
    4.72 +
    4.73 +    /* if ssidrefs are to be deleted, make sure no domain is using them */
    4.74 +    if (deletions != NULL) {
    4.75 +        if (acm_check_deleted_ssidrefs(deletions, errors))
    4.76 +            goto error_lock_free;
    4.77 +    }
    4.78 +
    4.79 +    if ((ssidchanges != NULL) && (ssidchanges->num_items > 0)) {
    4.80 +        /* assign all running domains new ssidrefs as requested */
    4.81 +        acm_doms_change_ssidref(oldssid_to_newssid, ssidchanges);
    4.82 +    }
    4.83 +
    4.84 +    /* test primary policy data with the new ssidrefs */
    4.85 +    offset = be32_to_cpu(pol->primary_buffer_offset);
    4.86 +    length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
    4.87 +
    4.88 +    if ( (offset + length) > buf_size ||
    4.89 +         acm_primary_ops->test_binary_policy(buf + offset, length,
    4.90 +                                             is_bootpolicy,
    4.91 +                                             errors))
    4.92 +        goto error_lock_free;
    4.93 +
    4.94 +    /* test secondary policy data with the new ssidrefs */
    4.95 +    offset = be32_to_cpu(pol->secondary_buffer_offset);
    4.96 +    length = be32_to_cpu(pol->len) - offset;
    4.97 +    if ( (offset + length) > buf_size ||
    4.98 +         acm_secondary_ops->test_binary_policy(buf + offset, length,
    4.99 +                                               is_bootpolicy,
   4.100 +                                               errors)) {
   4.101 +        goto error_lock_free;
   4.102 +    }
   4.103 +
   4.104 +    /* end of testing --- now real updates */
   4.105 +
   4.106 +    offset = be32_to_cpu(pol->policy_reference_offset);
   4.107 +    length = be32_to_cpu(pol->primary_buffer_offset) - offset;
   4.108 +
   4.109 +    /* set label reference name */
   4.110 +    if ( (offset + length) > buf_size ||
   4.111 +        acm_set_policy_reference(buf + offset, length) )
   4.112 +        goto error_lock_free;
   4.113 +
   4.114 +    /* set primary policy data */
   4.115 +    offset = be32_to_cpu(pol->primary_buffer_offset);
   4.116 +    length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
   4.117 +
   4.118 +    if ( acm_primary_ops->set_binary_policy(buf + offset, length) )
   4.119 +        goto error_lock_free;
   4.120 +
   4.121 +    /* set secondary policy data */
   4.122 +    offset = be32_to_cpu(pol->secondary_buffer_offset);
   4.123 +    length = be32_to_cpu(pol->len) - offset;
   4.124 +    if ( acm_secondary_ops->set_binary_policy(buf + offset, length) )
   4.125 +        goto error_lock_free;
   4.126 +
   4.127 +    memcpy(&acm_bin_pol.xml_pol_version,
   4.128 +           &pol->xml_pol_version,
   4.129 +           sizeof(acm_bin_pol.xml_pol_version));
   4.130 +
   4.131 +    write_unlock(&acm_bin_pol_rwlock);
   4.132 +    return ACM_OK;
   4.133 +
   4.134 +error_lock_free:
   4.135 +    if ((ssidchanges != NULL) && (ssidchanges->num_items > 0)) {
   4.136 +        acm_doms_restore_ssidref();
   4.137 +    }
   4.138 +    do_chwall_init_state_curr(NULL);
   4.139 +    write_unlock(&acm_bin_pol_rwlock);
   4.140 +
   4.141 +    return -EFAULT;
   4.142 +}
   4.143 +
   4.144 +
   4.145  int
   4.146 -do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy)
   4.147 +do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy,
   4.148 +                  struct acm_sized_buffer *deletions,
   4.149 +                  struct acm_sized_buffer *ssidchanges,
   4.150 +                  struct acm_sized_buffer *errors)
   4.151  {
   4.152      struct acm_policy_buffer *pol = (struct acm_policy_buffer *)buf;
   4.153 -    uint32_t offset, length;
   4.154 +
   4.155      /* some sanity checking */
   4.156      if ((be32_to_cpu(pol->magic) != ACM_MAGIC) ||
   4.157          (buf_size != be32_to_cpu(pol->len)) ||
   4.158 @@ -78,8 +190,8 @@ do_acm_set_policy(void *buf, u32 buf_siz
   4.159                                     be32_to_cpu(pol->primary_policy_code))) {
   4.160              goto error_free;
   4.161          }
   4.162 -        acm_active_security_policy =
   4.163 -            (acm_bin_pol.secondary_policy_code << 4) | acm_bin_pol.primary_policy_code;
   4.164 +        acm_active_security_policy = (acm_bin_pol.secondary_policy_code << 4) |
   4.165 +                                      acm_bin_pol.primary_policy_code;
   4.166      }
   4.167  
   4.168      /* once acm_active_security_policy is set, it cannot be changed */
   4.169 @@ -90,43 +202,11 @@ do_acm_set_policy(void *buf, u32 buf_siz
   4.170          goto error_free;
   4.171      }
   4.172  
   4.173 -    /* get bin_policy lock and rewrite policy (release old one) */
   4.174 -    write_lock(&acm_bin_pol_rwlock);
   4.175 -
   4.176 -    offset = be32_to_cpu(pol->policy_reference_offset);
   4.177 -    length = be32_to_cpu(pol->primary_buffer_offset) - offset;
   4.178 -
   4.179 -    /* set label reference name */
   4.180 -    if ( (offset + length) > buf_size ||
   4.181 -         acm_set_policy_reference(buf + offset, length))
   4.182 -        goto error_lock_free;
   4.183 -
   4.184 -    /* set primary policy data */
   4.185 -    offset = be32_to_cpu(pol->primary_buffer_offset);
   4.186 -    length = be32_to_cpu(pol->secondary_buffer_offset) - offset;
   4.187 +    return _acm_update_policy(buf, buf_size, is_bootpolicy,
   4.188 +                              pol,
   4.189 +                              deletions, ssidchanges,
   4.190 +                              errors);
   4.191  
   4.192 -    if ( (offset + length) > buf_size ||
   4.193 -         acm_primary_ops->set_binary_policy(buf + offset, length,
   4.194 -                                            is_bootpolicy))
   4.195 -        goto error_lock_free;
   4.196 -
   4.197 -    /* set secondary policy data */
   4.198 -    offset = be32_to_cpu(pol->secondary_buffer_offset);
   4.199 -    length = be32_to_cpu(pol->len) - offset;
   4.200 -    if ( (offset + length) > buf_size ||
   4.201 -         acm_secondary_ops->set_binary_policy(buf + offset, length,
   4.202 -                                              is_bootpolicy))
   4.203 -        goto error_lock_free;
   4.204 -
   4.205 -    memcpy(&acm_bin_pol.xml_pol_version,
   4.206 -           &pol->xml_pol_version,
   4.207 -           sizeof(acm_bin_pol.xml_pol_version));
   4.208 -
   4.209 -    write_unlock(&acm_bin_pol_rwlock);
   4.210 -    return ACM_OK;
   4.211 -
   4.212 - error_lock_free:
   4.213 -    write_unlock(&acm_bin_pol_rwlock);
   4.214   error_free:
   4.215      printk("%s: Error setting policy.\n", __func__);
   4.216      return -EFAULT;
   4.217 @@ -156,7 +236,7 @@ acm_get_policy(XEN_GUEST_HANDLE(void) bu
   4.218      bin_pol->policy_reference_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
   4.219      bin_pol->primary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
   4.220      bin_pol->secondary_buffer_offset = cpu_to_be32(be32_to_cpu(bin_pol->len));
   4.221 -     
   4.222 +
   4.223      memcpy(&bin_pol->xml_pol_version,
   4.224             &acm_bin_pol.xml_pol_version,
   4.225             sizeof(struct acm_policy_version));
   4.226 @@ -330,6 +410,384 @@ acm_get_decision(ssidref_t ssidref1, ssi
   4.227      return ret;
   4.228  }
   4.229  
   4.230 +
   4.231 +
   4.232 +/*
   4.233 +   Check if an ssidref of the current policy type is being used by any
   4.234 +   domain.
   4.235 + */
   4.236 +static int
   4.237 +acm_check_used_ssidref(uint32_t policy_type, uint32_t search_ssidref,
   4.238 +                       struct acm_sized_buffer *errors)
   4.239 +{
   4.240 +    int rc = 0;
   4.241 +    struct acm_ssid_domain *rawssid;
   4.242 +
   4.243 +    read_lock(&ssid_list_rwlock);
   4.244 +
   4.245 +    for_each_acmssid( rawssid ) {
   4.246 +        ssidref_t ssidref;
   4.247 +        void *s = GET_SSIDP(policy_type, rawssid);
   4.248 +
   4.249 +        if (policy_type == ACM_CHINESE_WALL_POLICY) {
   4.250 +            ssidref = ((struct chwall_ssid *)s)->chwall_ssidref;
   4.251 +        } else {
   4.252 +            ssidref = ((struct ste_ssid *)s)->ste_ssidref;
   4.253 +        }
   4.254 +        gdprintk(XENLOG_INFO,"domid=%d: search ssidref=%d, ssidref=%d\n",
   4.255 +                 rawssid->domainid,search_ssidref,ssidref);
   4.256 +        if (ssidref == search_ssidref) {
   4.257 +            /* one is enough */
   4.258 +            acm_array_append_tuple(errors, ACM_SSIDREF_IN_USE, search_ssidref);
   4.259 +            rc = 1;
   4.260 +            break;
   4.261 +        }
   4.262 +    }
   4.263 +
   4.264 +    read_unlock(&ssid_list_rwlock);
   4.265 +
   4.266 +    return rc;
   4.267 +}
   4.268 +
   4.269 +
   4.270 +/*
   4.271 + * Translate a current ssidref into its future representation under
   4.272 + * the new policy.
   4.273 + * The map provides translation of ssidrefs from old to new in tuples
   4.274 + * of (old ssidref, new ssidref).
   4.275 + */
   4.276 +static ssidref_t
   4.277 +oldssid_to_newssid(const struct acm_ssid_domain *rawssid,
   4.278 +                   const struct acm_sized_buffer *map)
   4.279 +{
   4.280 +    uint i;
   4.281 +
   4.282 +    if (rawssid != NULL) {
   4.283 +        ssidref_t ssid = rawssid->ssidref & 0xffff;
   4.284 +        for (i = 0; i+1 < map->num_items; i += 2) {
   4.285 +            if (map->array[i] == ssid) {
   4.286 +                return (map->array[i+1] << 16 | map->array[i+1]);
   4.287 +            }
   4.288 +        }
   4.289 +    }
   4.290 +    return ACM_INVALID_SSIDREF;
   4.291 +}
   4.292 +
   4.293 +
   4.294 +/*
   4.295 + * Assign an ssidref to the CHWALL policy component of the domain
   4.296 + */
   4.297 +static void
   4.298 +acm_pri_policy_assign_ssidref(struct acm_ssid_domain *rawssid, ssidref_t new_ssid)
   4.299 +{
   4.300 +    struct chwall_ssid *chwall = (struct chwall_ssid *)rawssid->primary_ssid;
   4.301 +    chwall->chwall_ssidref = new_ssid;
   4.302 +}
   4.303 +
   4.304 +
   4.305 +/*
   4.306 + * Assign an ssidref to the STE policy component of the domain
   4.307 + */
   4.308 +static void
   4.309 +acm_sec_policy_assign_ssidref(struct acm_ssid_domain *rawssid, ssidref_t new_ssid)
   4.310 +{
   4.311 +    struct ste_ssid *ste = (struct ste_ssid *)rawssid->secondary_ssid;
   4.312 +    ste->ste_ssidref = new_ssid;
   4.313 +}
   4.314 +
   4.315 +/*
   4.316 +   Change the ssidrefs on each domain using a passed translation function;
   4.317 + */
   4.318 +static void
   4.319 +acm_doms_change_ssidref(ssidref_t (*translator_fn)
   4.320 +                          (const struct acm_ssid_domain *,
   4.321 +                           const struct acm_sized_buffer *),
   4.322 +                        struct acm_sized_buffer *translation_map)
   4.323 +{
   4.324 +    struct acm_ssid_domain *rawssid;
   4.325 +
   4.326 +    write_lock(&ssid_list_rwlock);
   4.327 +
   4.328 +    for_each_acmssid( rawssid ) {
   4.329 +        ssidref_t new_ssid;
   4.330 +
   4.331 +        rawssid->old_ssidref = rawssid->ssidref;
   4.332 +
   4.333 +        new_ssid = translator_fn(rawssid, translation_map);
   4.334 +        if (new_ssid == ACM_INVALID_SSIDREF) {
   4.335 +            /* means no mapping found, so no change -- old = new */
   4.336 +            continue;
   4.337 +        }
   4.338 +
   4.339 +        acm_pri_policy_assign_ssidref(rawssid, ACM_PRIMARY  (new_ssid) );
   4.340 +        acm_sec_policy_assign_ssidref(rawssid, ACM_SECONDARY(new_ssid) );
   4.341 +
   4.342 +        rawssid->ssidref = new_ssid;
   4.343 +    }
   4.344 +
   4.345 +    write_unlock(&ssid_list_rwlock);
   4.346 +}
   4.347 +
   4.348 +/*
   4.349 + * Restore the previous ssidref values on all domains
   4.350 + */
   4.351 +static void
   4.352 +acm_doms_restore_ssidref(void)
   4.353 +{
   4.354 +    struct acm_ssid_domain *rawssid;
   4.355 +
   4.356 +    write_lock(&ssid_list_rwlock);
   4.357 +
   4.358 +    for_each_acmssid( rawssid ) {
   4.359 +        ssidref_t old_ssid;
   4.360 +
   4.361 +        if (rawssid->old_ssidref == rawssid->ssidref)
   4.362 +            continue;
   4.363 +
   4.364 +        old_ssid = rawssid->old_ssidref & 0xffff;
   4.365 +        rawssid->ssidref = rawssid->old_ssidref;
   4.366 +
   4.367 +        acm_pri_policy_assign_ssidref(rawssid, old_ssid);
   4.368 +        acm_sec_policy_assign_ssidref(rawssid, old_ssid);
   4.369 +    }
   4.370 +
   4.371 +    write_unlock(&ssid_list_rwlock);
   4.372 +}
   4.373 +
   4.374 +
   4.375 +/*
   4.376 +   Check the list of domains whether either one of them uses a
   4.377 +   to-be-deleted ssidref.
   4.378 + */
   4.379 +static int
   4.380 +acm_check_deleted_ssidrefs(struct acm_sized_buffer *dels,
   4.381 +                           struct acm_sized_buffer *errors)
   4.382 +{
   4.383 +    int rc = 0;
   4.384 +    uint idx;
   4.385 +    /* check for running domains that should not be there anymore */
   4.386 +    for (idx = 0; idx < dels->num_items; idx++) {
   4.387 +        if (acm_check_used_ssidref(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY,
   4.388 +                                   dels->array[idx],
   4.389 +                                   errors) > 0 ||
   4.390 +            acm_check_used_ssidref(ACM_CHINESE_WALL_POLICY,
   4.391 +                                   dels->array[idx],
   4.392 +                                   errors) > 0) {
   4.393 +            rc = ACM_ERROR;
   4.394 +            break;
   4.395 +        }
   4.396 +    }
   4.397 +    return rc;
   4.398 +}
   4.399 +
   4.400 +
   4.401 +/*
   4.402 + * Change the policy of the system.
   4.403 + */
   4.404 +int
   4.405 +acm_change_policy(struct acm_change_policy *chgpolicy)
   4.406 +{
   4.407 +    int rc = 0;
   4.408 +    u8 *binpolicy = NULL;
   4.409 +    struct acm_sized_buffer dels = {
   4.410 +        .array = NULL,
   4.411 +    };
   4.412 +    struct acm_sized_buffer ssidmap = {
   4.413 +        .array = NULL,
   4.414 +    };
   4.415 +    struct acm_sized_buffer errors = {
   4.416 +        .array = NULL,
   4.417 +    };
   4.418 +
   4.419 +    gdprintk(XENLOG_INFO, "change policy operation\n");
   4.420 +
   4.421 +    if ((chgpolicy->delarray_size > 4096) ||
   4.422 +        (chgpolicy->chgarray_size > 4096) ||
   4.423 +        (chgpolicy->errarray_size > 4096)) {
   4.424 +        return ACM_ERROR;
   4.425 +    }
   4.426 +
   4.427 +    dels.num_items = chgpolicy->delarray_size / sizeof(uint32_t);
   4.428 +    if (dels.num_items > 0) {
   4.429 +        dels.array = xmalloc_array(uint32_t, dels.num_items);
   4.430 +        if (dels.array == NULL) {
   4.431 +            rc = -ENOMEM;
   4.432 +            goto acm_chg_policy_exit;
   4.433 +        }
   4.434 +    }
   4.435 +
   4.436 +    ssidmap.num_items = chgpolicy->chgarray_size / sizeof(uint32_t);
   4.437 +    if (ssidmap.num_items > 0) {
   4.438 +        ssidmap.array = xmalloc_array(uint32_t, ssidmap.num_items);
   4.439 +        if (ssidmap.array == NULL) {
   4.440 +            rc = -ENOMEM;
   4.441 +            goto acm_chg_policy_exit;
   4.442 +        }
   4.443 +    }
   4.444 +
   4.445 +    errors.num_items = chgpolicy->errarray_size / sizeof(uint32_t);
   4.446 +    if (errors.num_items > 0) {
   4.447 +        errors.array = xmalloc_array(uint32_t, errors.num_items);
   4.448 +        if (errors.array == NULL) {
   4.449 +            rc = -ENOMEM;
   4.450 +            goto acm_chg_policy_exit;
   4.451 +        }
   4.452 +        memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
   4.453 +    }
   4.454 +
   4.455 +    binpolicy = xmalloc_array(u8,
   4.456 +                              chgpolicy->policy_pushcache_size);
   4.457 +    if (binpolicy == NULL) {
   4.458 +        rc = -ENOMEM;
   4.459 +        goto acm_chg_policy_exit;
   4.460 +    }
   4.461 +
   4.462 +    if ( copy_from_guest(dels.array,
   4.463 +                         chgpolicy->del_array,
   4.464 +                         chgpolicy->delarray_size) ||
   4.465 +         copy_from_guest(ssidmap.array,
   4.466 +                         chgpolicy->chg_array,
   4.467 +                         chgpolicy->chgarray_size) ||
   4.468 +         copy_from_guest(binpolicy,
   4.469 +                         chgpolicy->policy_pushcache,
   4.470 +                         chgpolicy->policy_pushcache_size )) {
   4.471 +        rc = -EFAULT;
   4.472 +        goto acm_chg_policy_exit;
   4.473 +    }
   4.474 +
   4.475 +    rc = do_acm_set_policy(binpolicy,
   4.476 +                           chgpolicy->policy_pushcache_size,
   4.477 +                           0,
   4.478 +                           &dels, &ssidmap, &errors);
   4.479 +
   4.480 +    if ( (errors.num_items > 0) &&
   4.481 +         copy_to_guest(chgpolicy->err_array,
   4.482 +                       errors.array,
   4.483 +                       errors.num_items ) ) {
   4.484 +        rc = -EFAULT;
   4.485 +        goto acm_chg_policy_exit;
   4.486 +    }
   4.487 +
   4.488 +
   4.489 +acm_chg_policy_exit:
   4.490 +    xfree(dels.array);
   4.491 +    xfree(ssidmap.array);
   4.492 +    xfree(errors.array);
   4.493 +    xfree(binpolicy);
   4.494 +
   4.495 +    return rc;
   4.496 +}
   4.497 +
   4.498 +
   4.499 +/*
   4.500 + * Lookup the new ssidref given the domain's id.
   4.501 + * The translation map provides a list of tuples in the format
   4.502 + * (domid, new ssidref).
   4.503 + */
   4.504 +static ssidref_t
   4.505 +domid_to_newssid(const struct acm_ssid_domain *rawssid,
   4.506 +                 const struct acm_sized_buffer *map)
   4.507 +{
   4.508 +    domid_t domid = rawssid->domainid;
   4.509 +    uint i;
   4.510 +    for (i = 0; (i+1) < map->num_items; i += 2) {
   4.511 +        if (map->array[i] == domid) {
   4.512 +            return (ssidref_t)map->array[i+1];
   4.513 +        }
   4.514 +    }
   4.515 +    return ACM_INVALID_SSIDREF;
   4.516 +}
   4.517 +
   4.518 +
   4.519 +int
   4.520 +do_acm_relabel_doms(struct acm_sized_buffer *relabel_map,
   4.521 +                    struct acm_sized_buffer *errors)
   4.522 +{
   4.523 +    int rc = 0, irc;
   4.524 +
   4.525 +    write_lock(&acm_bin_pol_rwlock);
   4.526 +
   4.527 +    acm_doms_change_ssidref(domid_to_newssid, relabel_map);
   4.528 +
   4.529 +    /* run tests; collect as much error info as possible */
   4.530 +    irc =  do_chwall_init_state_curr(errors);
   4.531 +    irc += do_ste_init_state_curr(errors);
   4.532 +    if (irc != 0) {
   4.533 +        rc = -EFAULT;
   4.534 +        goto acm_relabel_doms_lock_err_exit;
   4.535 +    }
   4.536 +
   4.537 +    write_unlock(&acm_bin_pol_rwlock);
   4.538 +
   4.539 +    return rc;
   4.540 +
   4.541 +acm_relabel_doms_lock_err_exit:
   4.542 +    /* revert the new ssidref assignment */
   4.543 +    acm_doms_restore_ssidref();
   4.544 +    do_chwall_init_state_curr(NULL);
   4.545 +
   4.546 +    write_unlock(&acm_bin_pol_rwlock);
   4.547 +
   4.548 +    return rc;
   4.549 +}
   4.550 +
   4.551 +
   4.552 +int
   4.553 +acm_relabel_domains(struct acm_relabel_doms *relabel)
   4.554 +{
   4.555 +    int rc = ACM_OK;
   4.556 +    struct acm_sized_buffer relabels = {
   4.557 +        .array = NULL,
   4.558 +    };
   4.559 +    struct acm_sized_buffer errors = {
   4.560 +        .array = NULL,
   4.561 +    };
   4.562 +
   4.563 +    if (relabel->relabel_map_size > 4096) {
   4.564 +        return ACM_ERROR;
   4.565 +    }
   4.566 +
   4.567 +    relabels.num_items = relabel->relabel_map_size / sizeof(uint32_t);
   4.568 +    if (relabels.num_items > 0) {
   4.569 +        relabels.array = xmalloc_array(uint32_t, relabels.num_items);
   4.570 +        if (relabels.array == NULL) {
   4.571 +            rc = -ENOMEM;
   4.572 +            goto acm_relabel_doms_exit;
   4.573 +        }
   4.574 +    }
   4.575 +
   4.576 +    errors.num_items = relabel->errarray_size / sizeof(uint32_t);
   4.577 +    if (errors.num_items > 0) {
   4.578 +        errors.array = xmalloc_array(uint32_t, errors.num_items);
   4.579 +        if (errors.array == NULL) {
   4.580 +            rc = -ENOMEM;
   4.581 +            goto acm_relabel_doms_exit;
   4.582 +        }
   4.583 +        memset(errors.array, 0x0, sizeof(uint32_t) * errors.num_items);
   4.584 +    }
   4.585 +
   4.586 +    if ( copy_from_guest(relabels.array,
   4.587 +                         relabel->relabel_map,
   4.588 +                         relabel->relabel_map_size) ) {
   4.589 +        rc = -EFAULT;
   4.590 +        goto acm_relabel_doms_exit;
   4.591 +    }
   4.592 +
   4.593 +    rc = do_acm_relabel_doms(&relabels, &errors);
   4.594 +
   4.595 +    if ( copy_to_guest(relabel->err_array,
   4.596 +                       errors.array,
   4.597 +                       errors.num_items ) ) {
   4.598 +        rc = -EFAULT;
   4.599 +        goto acm_relabel_doms_exit;
   4.600 +    }
   4.601 +
   4.602 +acm_relabel_doms_exit:
   4.603 +    xfree(relabels.array);
   4.604 +    xfree(errors.array);
   4.605 +    return rc;
   4.606 +}
   4.607 +
   4.608  /*
   4.609   * Local variables:
   4.610   * mode: C
     5.1 --- a/xen/acm/acm_simple_type_enforcement_hooks.c	Wed Apr 25 09:31:52 2007 +0100
     5.2 +++ b/xen/acm/acm_simple_type_enforcement_hooks.c	Wed Apr 25 09:40:02 2007 +0100
     5.3 @@ -179,7 +179,7 @@ ste_dump_policy(u8 *buf, u32 buf_size) {
     5.4   * (right now: event_channels, future: also grant_tables)
     5.5   */ 
     5.6  static int
     5.7 -ste_init_state(struct acm_ste_policy_buffer *ste_buf, domaintype_t *ssidrefs)
     5.8 +ste_init_state(struct acm_sized_buffer *errors)
     5.9  {
    5.10      int violation = 1;
    5.11      struct ste_ssid *ste_ssid, *ste_rssid;
    5.12 @@ -190,7 +190,7 @@ ste_init_state(struct acm_ste_policy_buf
    5.13      int port, i;
    5.14  
    5.15      rcu_read_lock(&domlist_read_lock);
    5.16 -    /* go by domain? or directly by global? event/grant list */
    5.17 +    read_lock(&ssid_list_rwlock);
    5.18      /* go through all domains and adjust policy as if this domain was started now */
    5.19      for_each_domain ( d )
    5.20      {
    5.21 @@ -232,12 +232,17 @@ ste_init_state(struct acm_ste_policy_buf
    5.22                              "%x -> domain %x.\n",
    5.23                              __func__, d->domain_id, rdomid);
    5.24                      spin_unlock(&d->evtchn_lock);
    5.25 +
    5.26 +                    acm_array_append_tuple(errors,
    5.27 +                                           ACM_EVTCHN_SHARING_VIOLATION,
    5.28 +                                           d->domain_id << 16 | rdomid);
    5.29                      goto out;
    5.30                  }
    5.31              }
    5.32              spin_unlock(&d->evtchn_lock);
    5.33          } 
    5.34  
    5.35 +
    5.36          /* b) check for grant table conflicts on shared pages */
    5.37          spin_lock(&d->grant_table->lock);
    5.38          for ( i = 0; i < nr_active_grant_frames(d->grant_table); i++ ) {
    5.39 @@ -252,6 +257,10 @@ ste_init_state(struct acm_ste_policy_buf
    5.40                  if ((rdom = rcu_lock_domain_by_id(rdomid)) == NULL) {
    5.41                      spin_unlock(&d->grant_table->lock);
    5.42                      printkd("%s: domain not found ERROR!\n", __func__);
    5.43 +
    5.44 +                    acm_array_append_tuple(errors,
    5.45 +                                           ACM_DOMAIN_LOOKUP,
    5.46 +                                           rdomid);
    5.47                      goto out;
    5.48                  }
    5.49                  /* rdom now has remote domain */
    5.50 @@ -264,6 +273,10 @@ ste_init_state(struct acm_ste_policy_buf
    5.51                      printkd("%s: Policy violation in grant table "
    5.52                              "sharing domain %x -> domain %x.\n",
    5.53                              __func__, d->domain_id, rdomid);
    5.54 +
    5.55 +                    acm_array_append_tuple(errors,
    5.56 +                                           ACM_GNTTAB_SHARING_VIOLATION,
    5.57 +                                           d->domain_id << 16 | rdomid);
    5.58                      goto out;
    5.59                  }
    5.60              }
    5.61 @@ -272,6 +285,7 @@ ste_init_state(struct acm_ste_policy_buf
    5.62      }
    5.63      violation = 0;
    5.64   out:
    5.65 +    read_unlock(&ssid_list_rwlock);
    5.66      rcu_read_unlock(&domlist_read_lock);
    5.67      return violation;
    5.68      /* returning "violation != 0" means that existing sharing between domains would not 
    5.69 @@ -281,16 +295,99 @@ ste_init_state(struct acm_ste_policy_buf
    5.70       * type in their typesets referenced by their ssidrefs */
    5.71  }
    5.72  
    5.73 +
    5.74 +/*
    5.75 + * Call ste_init_state with the current policy.
    5.76 + */
    5.77 +int
    5.78 +do_ste_init_state_curr(struct acm_sized_buffer *errors)
    5.79 +{
    5.80 +    return ste_init_state(errors);
    5.81 +}
    5.82 +
    5.83 +
    5.84  /* set new policy; policy write-locked already */
    5.85  static int
    5.86 -ste_set_policy(u8 *buf, u32 buf_size, int is_bootpolicy)
    5.87 +_ste_update_policy(u8 *buf, u32 buf_size, int test_only,
    5.88 +                   struct acm_sized_buffer *errors)
    5.89  {
    5.90 +    int rc = -EFAULT;
    5.91      struct acm_ste_policy_buffer *ste_buf = (struct acm_ste_policy_buffer *)buf;
    5.92      void *ssidrefsbuf;
    5.93      struct ste_ssid *ste_ssid;
    5.94 -    struct domain *d;
    5.95 +    struct acm_ssid_domain *rawssid;
    5.96      int i;
    5.97  
    5.98 +
    5.99 +    /* 1. create and copy-in new ssidrefs buffer */
   5.100 +    ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
   5.101 +    if (ssidrefsbuf == NULL) {
   5.102 +        return -ENOMEM;
   5.103 +    }
   5.104 +    if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
   5.105 +        goto error_free;
   5.106 +
   5.107 +    arrcpy(ssidrefsbuf, 
   5.108 +           buf + ste_buf->ste_ssid_offset,
   5.109 +           sizeof(domaintype_t),
   5.110 +           ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
   5.111 +
   5.112 +
   5.113 +    /* 3. in test mode: re-calculate sharing decisions based on running domains;
   5.114 +     *    this can fail if new policy is conflicting with sharing of running domains 
   5.115 +     *    now: reject violating new policy; future: adjust sharing through revoking sharing */
   5.116 +
   5.117 +    if (test_only) {
   5.118 +        /* temporarily replace old policy with new one for the testing */
   5.119 +        struct ste_binary_policy orig_ste_bin_pol = ste_bin_pol;
   5.120 +        ste_bin_pol.max_types = ste_buf->ste_max_types;
   5.121 +        ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
   5.122 +        ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
   5.123 +
   5.124 +        if (ste_init_state(NULL)) {
   5.125 +            /* new policy conflicts with sharing of running domains */
   5.126 +            printk("%s: New policy conflicts with running domains. "
   5.127 +                   "Policy load aborted.\n", __func__);
   5.128 +        } else {
   5.129 +            rc = ACM_OK;
   5.130 +        }
   5.131 +        /* revert changes, no matter whether testing was successful or not */
   5.132 +        ste_bin_pol = orig_ste_bin_pol;
   5.133 +        goto error_free;
   5.134 +    }
   5.135 +
   5.136 +    /* 3. replace old policy (activate new policy) */
   5.137 +    ste_bin_pol.max_types = ste_buf->ste_max_types;
   5.138 +    ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
   5.139 +    xfree(ste_bin_pol.ssidrefs);
   5.140 +    ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
   5.141 +
   5.142 +    /* clear all ste caches */
   5.143 +    read_lock(&ssid_list_rwlock);
   5.144 +
   5.145 +    for_each_acmssid( rawssid ) {
   5.146 +        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, rawssid);
   5.147 +        for (i=0; i<ACM_TE_CACHE_SIZE; i++)
   5.148 +            ste_ssid->ste_cache[i].valid = ACM_STE_free;
   5.149 +    }
   5.150 +
   5.151 +    read_unlock(&ssid_list_rwlock);
   5.152 +
   5.153 +    return ACM_OK;
   5.154 +
   5.155 + error_free:
   5.156 +    if (!test_only) printk("%s: ERROR setting policy.\n", __func__);
   5.157 +    xfree(ssidrefsbuf);
   5.158 +    return rc;
   5.159 +}
   5.160 +
   5.161 +static int
   5.162 +ste_test_policy(u8 *buf, u32 buf_size, int is_bootpolicy,
   5.163 +                struct acm_sized_buffer *errors)
   5.164 +{
   5.165 +    struct acm_ste_policy_buffer *ste_buf =
   5.166 +             (struct acm_ste_policy_buffer *)buf;
   5.167 +
   5.168      if (buf_size < sizeof(struct acm_ste_policy_buffer))
   5.169          return -EINVAL;
   5.170  
   5.171 @@ -306,52 +403,17 @@ ste_set_policy(u8 *buf, u32 buf_size, in
   5.172          (ste_buf->policy_version != ACM_STE_VERSION))
   5.173          return -EINVAL;
   5.174  
   5.175 -    /* 1. create and copy-in new ssidrefs buffer */
   5.176 -    ssidrefsbuf = xmalloc_array(u8, sizeof(domaintype_t)*ste_buf->ste_max_types*ste_buf->ste_max_ssidrefs);
   5.177 -    if (ssidrefsbuf == NULL) {
   5.178 -        return -ENOMEM;
   5.179 -    }
   5.180 -    if (ste_buf->ste_ssid_offset + sizeof(domaintype_t) * ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types > buf_size)
   5.181 -        goto error_free;
   5.182 -
   5.183      /* during boot dom0_chwall_ssidref is set */
   5.184 -    if (is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs)) {
   5.185 -        goto error_free;
   5.186 -    }
   5.187 -
   5.188 -    arrcpy(ssidrefsbuf, 
   5.189 -           buf + ste_buf->ste_ssid_offset,
   5.190 -           sizeof(domaintype_t),
   5.191 -           ste_buf->ste_max_ssidrefs*ste_buf->ste_max_types);
   5.192 +    if (is_bootpolicy && (dom0_ste_ssidref >= ste_buf->ste_max_ssidrefs))
   5.193 +        return -EINVAL;
   5.194  
   5.195 -    /* 2. now re-calculate sharing decisions based on running domains;
   5.196 -     *    this can fail if new policy is conflicting with sharing of running domains 
   5.197 -     *    now: reject violating new policy; future: adjust sharing through revoking sharing */
   5.198 -    if (ste_init_state(ste_buf, (domaintype_t *)ssidrefsbuf)) {
   5.199 -        printk("%s: New policy conflicts with running domains. Policy load aborted.\n", __func__);
   5.200 -        goto error_free; /* new policy conflicts with sharing of running domains */
   5.201 -    }
   5.202 -    /* 3. replace old policy (activate new policy) */
   5.203 -    ste_bin_pol.max_types = ste_buf->ste_max_types;
   5.204 -    ste_bin_pol.max_ssidrefs = ste_buf->ste_max_ssidrefs;
   5.205 -    xfree(ste_bin_pol.ssidrefs);
   5.206 -    ste_bin_pol.ssidrefs = (domaintype_t *)ssidrefsbuf;
   5.207 +    return _ste_update_policy(buf, buf_size, 1, errors);
   5.208 +}
   5.209  
   5.210 -    /* clear all ste caches */
   5.211 -    rcu_read_lock(&domlist_read_lock);
   5.212 -    for_each_domain ( d ) {
   5.213 -        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, 
   5.214 -                             (struct acm_ssid_domain *)(d)->ssid);
   5.215 -        for (i=0; i<ACM_TE_CACHE_SIZE; i++)
   5.216 -            ste_ssid->ste_cache[i].valid = ACM_STE_free;
   5.217 -    }
   5.218 -    rcu_read_unlock(&domlist_read_lock);
   5.219 -    return ACM_OK;
   5.220 -
   5.221 - error_free:
   5.222 -    printk("%s: ERROR setting policy.\n", __func__);
   5.223 -    xfree(ssidrefsbuf);
   5.224 -    return -EFAULT;
   5.225 +static int
   5.226 +ste_set_policy(u8 *buf, u32 buf_size)
   5.227 +{
   5.228 +    return _ste_update_policy(buf, buf_size, 0, NULL);
   5.229  }
   5.230  
   5.231  static int 
   5.232 @@ -447,18 +509,15 @@ clean_id_from_cache(domid_t id)
   5.233  {
   5.234      struct ste_ssid *ste_ssid;
   5.235      int i;
   5.236 -    struct domain *d;
   5.237 -    struct acm_ssid_domain *ssid;
   5.238 +    struct acm_ssid_domain *rawssid;
   5.239  
   5.240      printkd("deleting cache for dom %x.\n", id);
   5.241 -    rcu_read_lock(&domlist_read_lock);
   5.242 +    read_lock(&ssid_list_rwlock);
   5.243      /* look through caches of all domains */
   5.244 -    for_each_domain ( d ) {
   5.245 -        ssid = (struct acm_ssid_domain *)(d->ssid);
   5.246  
   5.247 -        if (ssid == NULL)
   5.248 -            continue; /* hanging domain structure, no ssid any more ... */
   5.249 -        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssid);
   5.250 +    for_each_acmssid ( rawssid ) {
   5.251 +
   5.252 +        ste_ssid = GET_SSIDP(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, rawssid);
   5.253          if (!ste_ssid) {
   5.254              printk("%s: deleting ID from cache ERROR (no ste_ssid)!\n",
   5.255                     __func__);
   5.256 @@ -469,8 +528,9 @@ clean_id_from_cache(domid_t id)
   5.257                  (ste_ssid->ste_cache[i].id == id))
   5.258                  ste_ssid->ste_cache[i].valid = ACM_STE_free;
   5.259      }
   5.260 +
   5.261   out:
   5.262 -    rcu_read_unlock(&domlist_read_lock);
   5.263 +    read_unlock(&ssid_list_rwlock);
   5.264  }
   5.265  
   5.266  /***************************
   5.267 @@ -687,6 +747,7 @@ struct acm_operations acm_simple_type_en
   5.268      .init_domain_ssid  = ste_init_domain_ssid,
   5.269      .free_domain_ssid  = ste_free_domain_ssid,
   5.270      .dump_binary_policy     = ste_dump_policy,
   5.271 +    .test_binary_policy     = ste_test_policy,
   5.272      .set_binary_policy      = ste_set_policy,
   5.273      .dump_statistics  = ste_dump_stats,
   5.274      .dump_ssid_types        = ste_dump_ssid_types,
     6.1 --- a/xen/common/acm_ops.c	Wed Apr 25 09:31:52 2007 +0100
     6.2 +++ b/xen/common/acm_ops.c	Wed Apr 25 09:40:02 2007 +0100
     6.3 @@ -216,6 +216,42 @@ ret_t do_acm_op(int cmd, XEN_GUEST_HANDL
     6.4          break;
     6.5      }
     6.6  
     6.7 +    case ACMOP_chgpolicy: {
     6.8 +        struct acm_change_policy chgpolicy;
     6.9 +
    6.10 +        if (copy_from_guest(&chgpolicy, arg, 1) != 0)
    6.11 +            return -EFAULT;
    6.12 +        if (chgpolicy.interface_version != ACM_INTERFACE_VERSION)
    6.13 +            return -EACCES;
    6.14 +
    6.15 +        rc = acm_change_policy(&chgpolicy);
    6.16 +
    6.17 +        if (rc == 0) {
    6.18 +            if (copy_to_guest(arg, &chgpolicy, 1) != 0) {
    6.19 +                rc = -EFAULT;
    6.20 +            }
    6.21 +        }
    6.22 +        break;
    6.23 +    }
    6.24 +
    6.25 +    case ACMOP_relabeldoms: {
    6.26 +        struct acm_relabel_doms relabeldoms;
    6.27 +
    6.28 +        if (copy_from_guest(&relabeldoms, arg, 1) != 0)
    6.29 +            return -EFAULT;
    6.30 +        if (relabeldoms.interface_version != ACM_INTERFACE_VERSION)
    6.31 +            return -EACCES;
    6.32 +
    6.33 +        rc = acm_relabel_domains(&relabeldoms);
    6.34 +
    6.35 +        if (rc == 0) {
    6.36 +            if (copy_to_guest(arg, &relabeldoms, 1) != 0) {
    6.37 +                rc = -EFAULT;
    6.38 +            }
    6.39 +        }
    6.40 +        break;
    6.41 +    }
    6.42 +
    6.43      default:
    6.44          rc = -ENOSYS;
    6.45          break;
     7.1 --- a/xen/include/acm/acm_core.h	Wed Apr 25 09:31:52 2007 +0100
     7.2 +++ b/xen/include/acm/acm_core.h	Wed Apr 25 09:40:02 2007 +0100
     7.3 @@ -20,9 +20,11 @@
     7.4  #define _ACM_CORE_H
     7.5  
     7.6  #include <xen/spinlock.h>
     7.7 +#include <xen/list.h>
     7.8  #include <public/acm.h>
     7.9  #include <xen/acm_policy.h>
    7.10  #include <public/acm_ops.h>
    7.11 +#include <acm/acm_endian.h>
    7.12  
    7.13  /* Xen-internal representation of the binary policy */
    7.14  struct acm_binary_policy {
    7.15 @@ -58,6 +60,7 @@ extern struct chwall_binary_policy chwal
    7.16  extern struct ste_binary_policy ste_bin_pol;
    7.17  /* use the lock when reading / changing binary policy ! */
    7.18  extern rwlock_t acm_bin_pol_rwlock;
    7.19 +extern rwlock_t ssid_list_rwlock;
    7.20  
    7.21  /* subject and object type definitions */
    7.22  #define ACM_DATATYPE_domain 1
    7.23 @@ -80,12 +83,14 @@ struct acm_ste_cache_line {
    7.24  
    7.25  /* general definition of a subject security id */
    7.26  struct acm_ssid_domain {
    7.27 -    int datatype; /* type of subject (e.g., partition): ACM_DATATYPE_* */
    7.28 -    ssidref_t ssidref;   /* combined security reference */
    7.29 -    void *primary_ssid;   /* primary policy ssid part (e.g. chinese wall) */
    7.30 -    void *secondary_ssid;    /* secondary policy ssid part (e.g. type enforcement) */
    7.31 -    struct domain *subject;     /* backpointer to subject structure */
    7.32 -    domid_t domainid;   /* replicate id */
    7.33 +    struct list_head node; /* all are chained together */
    7.34 +    int datatype;          /* type of subject (e.g., partition): ACM_DATATYPE_* */
    7.35 +    ssidref_t ssidref;     /* combined security reference */
    7.36 +    ssidref_t old_ssidref; /* holds previous value of ssidref during relabeling */
    7.37 +    void *primary_ssid;    /* primary policy ssid part (e.g. chinese wall) */
    7.38 +    void *secondary_ssid;  /* secondary policy ssid part (e.g. type enforcement) */
    7.39 +    struct domain *subject;/* backpointer to subject structure */
    7.40 +    domid_t domainid;      /* replicate id */
    7.41  };
    7.42  
    7.43  /* chinese wall ssid type */
    7.44 @@ -118,26 +123,65 @@ struct ste_ssid {
    7.45   ((POLICY) == acm_bin_pol.primary_policy_code) ? \
    7.46   ((ssid)->primary_ssid) : ((ssid)->secondary_ssid)
    7.47  
    7.48 +#define ACM_INVALID_SSIDREF  (0xffffffff)
    7.49 +
    7.50 +struct acm_sized_buffer
    7.51 +{
    7.52 +    uint32_t *array;
    7.53 +    uint num_items;
    7.54 +    uint position;
    7.55 +};
    7.56 +
    7.57 +static inline int acm_array_append_tuple(struct acm_sized_buffer *buf,
    7.58 +                                         uint32_t a, uint32_t b)
    7.59 +{
    7.60 +    uint i;
    7.61 +    if (buf == NULL)
    7.62 +        return 0;
    7.63 +
    7.64 +    i = buf->position;
    7.65 +
    7.66 +    if ((i + 2) > buf->num_items)
    7.67 +        return 0;
    7.68 +
    7.69 +    buf->array[i]   = cpu_to_be32(a);
    7.70 +    buf->array[i+1] = cpu_to_be32(b);
    7.71 +    buf->position += 2;
    7.72 +    return 1;
    7.73 +}
    7.74 +
    7.75  /* protos */
    7.76  int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
    7.77  int acm_init_domain_ssid_new(struct domain *, ssidref_t ssidref);
    7.78  void acm_free_domain_ssid(struct acm_ssid_domain *ssid);
    7.79  int acm_init_binary_policy(u32 policy_code);
    7.80  int acm_set_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size);
    7.81 -int do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy);
    7.82 +int do_acm_set_policy(void *buf, u32 buf_size, int is_bootpolicy,
    7.83 +                      struct acm_sized_buffer *, struct acm_sized_buffer *,
    7.84 +                      struct acm_sized_buffer *);
    7.85  int acm_get_policy(XEN_GUEST_HANDLE(void) buf, u32 buf_size);
    7.86  int acm_dump_statistics(XEN_GUEST_HANDLE(void) buf, u16 buf_size);
    7.87  int acm_get_ssid(ssidref_t ssidref, XEN_GUEST_HANDLE(void) buf, u16 buf_size);
    7.88  int acm_get_decision(ssidref_t ssidref1, ssidref_t ssidref2, u32 hook);
    7.89  int acm_set_policy_reference(u8 * buf, u32 buf_size);
    7.90  int acm_dump_policy_reference(u8 *buf, u32 buf_size);
    7.91 -
    7.92 +int acm_change_policy(struct acm_change_policy *);
    7.93 +int acm_relabel_domains(struct acm_relabel_doms *);
    7.94 +int do_chwall_init_state_curr(struct acm_sized_buffer *);
    7.95 +int do_ste_init_state_curr(struct acm_sized_buffer *);
    7.96  
    7.97  /* variables */
    7.98  extern ssidref_t dom0_chwall_ssidref;
    7.99  extern ssidref_t dom0_ste_ssidref;
   7.100  #define ACM_MAX_NUM_TYPES   (256)
   7.101  
   7.102 +/* traversing the list of ssids */
   7.103 +extern struct list_head ssid_list;
   7.104 +#define for_each_acmssid( N )                               \
   7.105 +   for ( N =  (struct acm_ssid_domain *)ssid_list.next;     \
   7.106 +         N != (struct acm_ssid_domain *)&ssid_list;         \
   7.107 +         N =  (struct acm_ssid_domain *)N->node.next     )
   7.108 +
   7.109  #endif
   7.110  
   7.111  /*
     8.1 --- a/xen/include/acm/acm_hooks.h	Wed Apr 25 09:31:52 2007 +0100
     8.2 +++ b/xen/include/acm/acm_hooks.h	Wed Apr 25 09:40:02 2007 +0100
     8.3 @@ -91,8 +91,10 @@ struct acm_operations {
     8.4      int  (*init_domain_ssid)           (void **ssid, ssidref_t ssidref);
     8.5      void (*free_domain_ssid)           (void *ssid);
     8.6      int  (*dump_binary_policy)         (u8 *buffer, u32 buf_size);
     8.7 -    int  (*set_binary_policy)          (u8 *buffer, u32 buf_size,
     8.8 -                                        int is_bootpolicy);
     8.9 +    int  (*test_binary_policy)         (u8 *buffer, u32 buf_size,
    8.10 +                                        int is_bootpolicy,
    8.11 +                                        struct acm_sized_buffer *);
    8.12 +    int  (*set_binary_policy)          (u8 *buffer, u32 buf_size);
    8.13      int  (*dump_statistics)            (u8 *buffer, u16 buf_size);
    8.14      int  (*dump_ssid_types)            (ssidref_t ssidref, u8 *buffer, u16 buf_size);
    8.15      /* domain management control hooks (can be NULL) */
    8.16 @@ -228,37 +230,6 @@ static inline int acm_pre_grant_setup(do
    8.17  }
    8.18  
    8.19  
    8.20 -static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
    8.21 -{
    8.22 -    void *subject_ssid = current->domain->ssid;
    8.23 -    domid_t domid = d->domain_id;
    8.24 -    int rc;
    8.25 -
    8.26 -    /*
    8.27 -       To be called when a domain is created; returns '0' if the
    8.28 -       domain is allowed to be created, != '0' if not.
    8.29 -     */
    8.30 -    rc = acm_init_domain_ssid_new(d, ssidref);
    8.31 -    if (rc != ACM_OK)
    8.32 -        return rc;
    8.33 -
    8.34 -    if ((acm_primary_ops->domain_create != NULL) &&
    8.35 -        acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
    8.36 -        return ACM_ACCESS_DENIED;
    8.37 -    } else if ((acm_secondary_ops->domain_create != NULL) &&
    8.38 -                acm_secondary_ops->domain_create(subject_ssid, ssidref,
    8.39 -                                                 domid)) {
    8.40 -        /* roll-back primary */
    8.41 -        if (acm_primary_ops->domain_destroy != NULL)
    8.42 -            acm_primary_ops->domain_destroy(d->ssid, d);
    8.43 -        acm_free_domain_ssid(d->ssid);
    8.44 -        return ACM_ACCESS_DENIED;
    8.45 -    }
    8.46 -
    8.47 -    return 0;
    8.48 -}
    8.49 -
    8.50 -
    8.51  static inline void acm_domain_destroy(struct domain *d)
    8.52  {
    8.53      void *ssid = d->ssid;
    8.54 @@ -273,6 +244,44 @@ static inline void acm_domain_destroy(st
    8.55  }
    8.56  
    8.57  
    8.58 +static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
    8.59 +{
    8.60 +    void *subject_ssid = current->domain->ssid;
    8.61 +    domid_t domid = d->domain_id;
    8.62 +    int rc = 0;
    8.63 +
    8.64 +    read_lock(&acm_bin_pol_rwlock);
    8.65 +    /*
    8.66 +       To be called when a domain is created; returns '0' if the
    8.67 +       domain is allowed to be created, != '0' if not.
    8.68 +     */
    8.69 +
    8.70 +    if ((acm_primary_ops->domain_create != NULL) &&
    8.71 +        acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
    8.72 +        rc = ACM_ACCESS_DENIED;
    8.73 +    } else if ((acm_secondary_ops->domain_create != NULL) &&
    8.74 +                acm_secondary_ops->domain_create(subject_ssid, ssidref,
    8.75 +                                                 domid)) {
    8.76 +        /* roll-back primary */
    8.77 +        if (acm_primary_ops->domain_destroy != NULL)
    8.78 +            acm_primary_ops->domain_destroy(d->ssid, d);
    8.79 +        acm_free_domain_ssid(d->ssid);
    8.80 +        rc = ACM_ACCESS_DENIED;
    8.81 +    }
    8.82 +
    8.83 +    if (rc == 0) {
    8.84 +        rc = acm_init_domain_ssid_new(d, ssidref);
    8.85 +
    8.86 +        if (rc != ACM_OK) {
    8.87 +            acm_domain_destroy(d);
    8.88 +        }
    8.89 +    }
    8.90 +
    8.91 +    read_unlock(&acm_bin_pol_rwlock);
    8.92 +    return rc;
    8.93 +}
    8.94 +
    8.95 +
    8.96  static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
    8.97  {
    8.98      if ((acm_primary_ops->sharing != NULL) &&
     9.1 --- a/xen/include/public/acm.h	Wed Apr 25 09:31:52 2007 +0100
     9.2 +++ b/xen/include/public/acm.h	Wed Apr 25 09:40:02 2007 +0100
     9.3 @@ -56,6 +56,19 @@
     9.4  #define ACM_ACCESS_DENIED           -111
     9.5  #define ACM_NULL_POINTER_ERROR      -200
     9.6  
     9.7 +/*
     9.8 +   Error codes reported in when trying to test for a new policy
     9.9 +   These error codes are reported in an array of tuples where
    9.10 +   each error code is followed by a parameter describing the error
    9.11 +   more closely, such as a domain id.
    9.12 +*/
    9.13 +#define ACM_EVTCHN_SHARING_VIOLATION       0x100
    9.14 +#define ACM_GNTTAB_SHARING_VIOLATION       0x101
    9.15 +#define ACM_DOMAIN_LOOKUP                  0x102
    9.16 +#define ACM_CHWALL_CONFLICT                0x103
    9.17 +#define ACM_SSIDREF_IN_USE                 0x104
    9.18 +
    9.19 +
    9.20  /* primary policy in lower 4 bits */
    9.21  #define ACM_NULL_POLICY 0
    9.22  #define ACM_CHINESE_WALL_POLICY 1
    10.1 --- a/xen/include/public/acm_ops.h	Wed Apr 25 09:31:52 2007 +0100
    10.2 +++ b/xen/include/public/acm_ops.h	Wed Apr 25 09:40:02 2007 +0100
    10.3 @@ -34,7 +34,7 @@
    10.4   * This makes sure that old versions of acm tools will stop working in a
    10.5   * well-defined way (rather than crashing the machine, for instance).
    10.6   */
    10.7 -#define ACM_INTERFACE_VERSION   0xAAAA0008
    10.8 +#define ACM_INTERFACE_VERSION   0xAAAA0009
    10.9  
   10.10  /************************************************************************/
   10.11  
   10.12 @@ -50,7 +50,7 @@
   10.13  struct acm_setpolicy {
   10.14      /* IN */
   10.15      uint32_t interface_version;
   10.16 -    XEN_GUEST_HANDLE(void) pushcache;
   10.17 +    XEN_GUEST_HANDLE_64(void) pushcache;
   10.18      uint32_t pushcache_size;
   10.19  };
   10.20  
   10.21 @@ -59,7 +59,7 @@ struct acm_setpolicy {
   10.22  struct acm_getpolicy {
   10.23      /* IN */
   10.24      uint32_t interface_version;
   10.25 -    XEN_GUEST_HANDLE(void) pullcache;
   10.26 +    XEN_GUEST_HANDLE_64(void) pullcache;
   10.27      uint32_t pullcache_size;
   10.28  };
   10.29  
   10.30 @@ -68,7 +68,7 @@ struct acm_getpolicy {
   10.31  struct acm_dumpstats {
   10.32      /* IN */
   10.33      uint32_t interface_version;
   10.34 -    XEN_GUEST_HANDLE(void) pullcache;
   10.35 +    XEN_GUEST_HANDLE_64(void) pullcache;
   10.36      uint32_t pullcache_size;
   10.37  };
   10.38  
   10.39 @@ -84,7 +84,7 @@ struct acm_getssid {
   10.40          domaintype_t domainid;
   10.41          ssidref_t    ssidref;
   10.42      } id;
   10.43 -    XEN_GUEST_HANDLE(void) ssidbuf;
   10.44 +    XEN_GUEST_HANDLE_64(void) ssidbuf;
   10.45      uint32_t ssidbuf_size;
   10.46  };
   10.47  
   10.48 @@ -107,6 +107,52 @@ struct acm_getdecision {
   10.49      uint32_t acm_decision;
   10.50  };
   10.51  
   10.52 +
   10.53 +#define ACMOP_chgpolicy        6
   10.54 +struct acm_change_policy {
   10.55 +    /* IN */
   10.56 +    uint32_t interface_version;
   10.57 +    XEN_GUEST_HANDLE_64(void) policy_pushcache;
   10.58 +    uint32_t policy_pushcache_size;
   10.59 +    XEN_GUEST_HANDLE_64(void) del_array;
   10.60 +    uint32_t delarray_size;
   10.61 +    XEN_GUEST_HANDLE_64(void) chg_array;
   10.62 +    uint32_t chgarray_size;
   10.63 +    /* OUT */
   10.64 +    /* array with error code */
   10.65 +    XEN_GUEST_HANDLE_64(void) err_array;
   10.66 +    uint32_t errarray_size;
   10.67 +};
   10.68 +
   10.69 +#define ACMOP_relabeldoms       7
   10.70 +struct acm_relabel_doms {
   10.71 +    /* IN */
   10.72 +    uint32_t interface_version;
   10.73 +    XEN_GUEST_HANDLE_64(void) relabel_map;
   10.74 +    uint32_t relabel_map_size;
   10.75 +    /* OUT */
   10.76 +    XEN_GUEST_HANDLE_64(void) err_array;
   10.77 +    uint32_t errarray_size;
   10.78 +};
   10.79 +
   10.80 +/* future interface to Xen */
   10.81 +struct xen_acmctl {
   10.82 +    uint32_t cmd;
   10.83 +    uint32_t interface_version;
   10.84 +    union {
   10.85 +        struct acm_setpolicy     setpolicy;
   10.86 +        struct acm_getpolicy     getpolicy;
   10.87 +        struct acm_dumpstats     dumpstats;
   10.88 +        struct acm_getssid       getssid;
   10.89 +        struct acm_getdecision   getdecision;
   10.90 +        struct acm_change_policy change_policy;
   10.91 +        struct acm_relabel_doms  relabel_doms;
   10.92 +    } u;
   10.93 +};
   10.94 +
   10.95 +typedef struct xen_acmctl xen_acmctl_t;
   10.96 +DEFINE_XEN_GUEST_HANDLE(xen_acmctl_t);
   10.97 +
   10.98  #endif /* __XEN_PUBLIC_ACM_OPS_H__ */
   10.99  
  10.100  /*