ia64/xen-unstable

changeset 15653:bf512fde6667

[ACM] Check a domain's authorization to run.

A domain is only authorized to run if it has a superset of Simple Type
Enforcement Types in its VM label compared to that of Domain-0, which
itself may not have all STEs available in a policy. This patch adds a
check for this into Xend and the necessary code support into Xen.

Signed-off-by: Stefan Berger <stefanb@us.ibm.com>
author kfraser@localhost.localdomain
date Fri Jul 27 09:01:15 2007 +0100 (2007-07-27)
parents 07655ed2fe58
children 68f0e623f6b0
files tools/python/xen/lowlevel/acm/acm.c tools/python/xen/util/security.py tools/python/xen/xend/XendDomainInfo.py xen/acm/acm_chinesewall_hooks.c xen/acm/acm_core.c xen/acm/acm_policy.c xen/acm/acm_simple_type_enforcement_hooks.c xen/include/acm/acm_core.h xen/include/acm/acm_hooks.h xen/include/public/acm.h
line diff
     1.1 --- a/tools/python/xen/lowlevel/acm/acm.c	Thu Jul 26 12:00:32 2007 +0100
     1.2 +++ b/tools/python/xen/lowlevel/acm/acm.c	Fri Jul 27 09:01:15 2007 +0100
     1.3 @@ -148,9 +148,10 @@ static PyObject *getdecision(PyObject * 
     1.4      char *arg1_name, *arg1, *arg2_name, *arg2, *decision = NULL;
     1.5      struct acm_getdecision getdecision;
     1.6      int xc_handle, rc;
     1.7 +    uint32_t hooktype;
     1.8  
     1.9 -    if (!PyArg_ParseTuple(args, "ssss", &arg1_name,
    1.10 -                          &arg1, &arg2_name, &arg2)) {
    1.11 +    if (!PyArg_ParseTuple(args, "ssssi", &arg1_name,
    1.12 +                          &arg1, &arg2_name, &arg2, &hooktype)) {
    1.13          return NULL;
    1.14      }
    1.15  
    1.16 @@ -163,7 +164,7 @@ static PyObject *getdecision(PyObject * 
    1.17      (strcmp(arg2_name, "domid") && strcmp(arg2_name, "ssidref")))
    1.18          return NULL;
    1.19  
    1.20 -    getdecision.hook = ACMHOOK_sharing;
    1.21 +    getdecision.hook = hooktype;
    1.22      if (!strcmp(arg1_name, "domid")) {
    1.23          getdecision.get_decision_by1 = ACM_GETBY_domainid;
    1.24          getdecision.id1.domainid = atoi(arg1);
     2.1 --- a/tools/python/xen/util/security.py	Thu Jul 26 12:00:32 2007 +0100
     2.2 +++ b/tools/python/xen/util/security.py	Fri Jul 27 09:01:15 2007 +0100
     2.3 @@ -62,6 +62,10 @@ empty_line_re = re.compile("^\s*$")
     2.4  binary_name_re = re.compile(".*[chwall|ste|chwall_ste].*\.bin", re.IGNORECASE)
     2.5  policy_name_re = re.compile(".*[chwall|ste|chwall_ste].*", re.IGNORECASE)
     2.6  
     2.7 +#decision hooks known to the hypervisor
     2.8 +ACMHOOK_sharing = 1
     2.9 +ACMHOOK_authorization = 2
    2.10 +
    2.11  #other global variables
    2.12  NULL_SSIDREF = 0
    2.13  
    2.14 @@ -453,7 +457,8 @@ def get_decision(arg1, arg2):
    2.15          err("Invalid id or ssidref type, string or int required")
    2.16  
    2.17      try:
    2.18 -        decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1])
    2.19 +        decision = acm.getdecision(arg1[0], arg1[1], arg2[0], arg2[1],
    2.20 +                                   ACMHOOK_sharing)
    2.21      except:
    2.22          err("Cannot determine decision.")
    2.23  
    2.24 @@ -463,6 +468,21 @@ def get_decision(arg1, arg2):
    2.25          err("Cannot determine decision (Invalid parameter).")
    2.26  
    2.27  
    2.28 +def has_authorization(ssidref):
    2.29 +    """ Check if the domain with the given ssidref has authorization to
    2.30 +        run on this system. To have authoriztion dom0's STE types must
    2.31 +        be a superset of that of the domain's given through its ssidref.
    2.32 +    """
    2.33 +    rc = True
    2.34 +    dom0_ssidref = int(acm.getssid(0)['ssidref'])
    2.35 +    decision = acm.getdecision('ssidref', str(dom0_ssidref),
    2.36 +                               'ssidref', str(ssidref),
    2.37 +                               ACMHOOK_authorization)
    2.38 +    if decision == "DENIED":
    2.39 +        rc = False
    2.40 +    return rc
    2.41 +
    2.42 +
    2.43  def hv_chg_policy(bin_pol, del_array, chg_array):
    2.44      """
    2.45          Change the binary policy in the hypervisor
     3.1 --- a/tools/python/xen/xend/XendDomainInfo.py	Thu Jul 26 12:00:32 2007 +0100
     3.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Jul 27 09:01:15 2007 +0100
     3.3 @@ -1460,9 +1460,13 @@ class XendDomainInfo:
     3.4          # allocation of 1MB. We free up 2MB here to be on the safe side.
     3.5          balloon.free(2*1024) # 2MB should be plenty
     3.6  
     3.7 -        ssidref = security.calc_dom_ssidref_from_info(self.info)
     3.8 -        if ssidref == 0 and security.on():
     3.9 -            raise VmError('VM is not properly labeled.')
    3.10 +        ssidref = 0
    3.11 +        if security.on():
    3.12 +            ssidref = security.calc_dom_ssidref_from_info(self.info)
    3.13 +            if ssidref == 0:
    3.14 +                raise VmError('VM is not properly labeled.')
    3.15 +            if security.has_authorization(ssidref) == False:
    3.16 +                raise VmError("VM is not authorized to run.")
    3.17  
    3.18          try:
    3.19              self.domid = xc.domain_create(
     4.1 --- a/xen/acm/acm_chinesewall_hooks.c	Thu Jul 26 12:00:32 2007 +0100
     4.2 +++ b/xen/acm/acm_chinesewall_hooks.c	Fri Jul 27 09:01:15 2007 +0100
     4.3 @@ -685,6 +685,7 @@ struct acm_operations acm_chinesewall_op
     4.4      .fail_grant_setup = NULL,
     4.5      /* generic domain-requested decision hooks */
     4.6      .sharing = NULL,
     4.7 +    .authorization = NULL,
     4.8  
     4.9      .is_default_policy = chwall_is_default_policy,
    4.10  };
     5.1 --- a/xen/acm/acm_core.c	Thu Jul 26 12:00:32 2007 +0100
     5.2 +++ b/xen/acm/acm_core.c	Fri Jul 27 09:01:15 2007 +0100
     5.3 @@ -314,26 +314,7 @@ acm_init(char *policy_start,
     5.4      return ret;
     5.5  }
     5.6  
     5.7 -int
     5.8 -acm_init_domain_ssid(domid_t id, ssidref_t ssidref)
     5.9 -{
    5.10 -    struct domain *subj = rcu_lock_domain_by_id(id);
    5.11 -    int ret;
    5.12 - 
    5.13 -    if (subj == NULL)
    5.14 -    {
    5.15 -        printk("%s: ACM_NULL_POINTER ERROR (id=%x).\n", __func__, id);
    5.16 -        return ACM_NULL_POINTER_ERROR;
    5.17 -    }
    5.18 -
    5.19 -    ret = acm_init_domain_ssid_new(subj, ssidref);
    5.20 -
    5.21 -    rcu_unlock_domain(subj);
    5.22 -
    5.23 -    return ret;
    5.24 -}
    5.25 -
    5.26 -int acm_init_domain_ssid_new(struct domain *subj, ssidref_t ssidref)
    5.27 +int acm_init_domain_ssid(struct domain *subj, ssidref_t ssidref)
    5.28  {
    5.29      struct acm_ssid_domain *ssid;
    5.30      int ret1, ret2;
    5.31 @@ -374,10 +355,6 @@ int acm_init_domain_ssid_new(struct doma
    5.32          return ACM_INIT_SSID_ERROR;
    5.33      }
    5.34  
    5.35 -    write_lock(&ssid_list_rwlock);
    5.36 -    list_add(&ssid->node, &ssid_list);
    5.37 -    write_unlock(&ssid_list_rwlock);
    5.38 -
    5.39      printkd("%s: assigned domain %x the ssidref=%x.\n",
    5.40             __func__, subj->domain_id, ssid->ssidref);
    5.41      return ACM_OK;
    5.42 @@ -399,10 +376,6 @@ acm_free_domain_ssid(struct acm_ssid_dom
    5.43          acm_secondary_ops->free_domain_ssid(ssid->secondary_ssid);
    5.44      ssid->secondary_ssid = NULL;
    5.45  
    5.46 -    write_lock(&ssid_list_rwlock);
    5.47 -    list_del(&ssid->node);
    5.48 -    write_unlock(&ssid_list_rwlock);
    5.49 -
    5.50      xfree(ssid);
    5.51      printkd("%s: Freed individual domain ssid (domain=%02x).\n",
    5.52              __func__, id);
     6.1 --- a/xen/acm/acm_policy.c	Thu Jul 26 12:00:32 2007 +0100
     6.2 +++ b/xen/acm/acm_policy.c	Fri Jul 27 09:01:15 2007 +0100
     6.3 @@ -438,6 +438,10 @@ acm_get_decision(ssidref_t ssidref1, ssi
     6.4          ret = acm_sharing(ssidref1, ssidref2);
     6.5          break;
     6.6  
     6.7 +    case ACMHOOK_authorization:
     6.8 +        ret = acm_authorization(ssidref1, ssidref2);
     6.9 +        break;
    6.10 +
    6.11      default:
    6.12          /* deny */
    6.13          break;
     7.1 --- a/xen/acm/acm_simple_type_enforcement_hooks.c	Thu Jul 26 12:00:32 2007 +0100
     7.2 +++ b/xen/acm/acm_simple_type_enforcement_hooks.c	Fri Jul 27 09:01:15 2007 +0100
     7.3 @@ -38,15 +38,16 @@ ssidref_t dom0_ste_ssidref = 0x0001;
     7.4  /* local cache structures for STE policy */
     7.5  struct ste_binary_policy ste_bin_pol;
     7.6  
     7.7 -static inline int have_common_type (ssidref_t ref1, ssidref_t ref2) {
     7.8 +static inline int have_common_type (ssidref_t ref1, ssidref_t ref2)
     7.9 +{
    7.10      int i;
    7.11  
    7.12      if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&
    7.13           ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )
    7.14      {
    7.15          for( i = 0; i< ste_bin_pol.max_types; i++ )
    7.16 -            if ( ste_bin_pol.ssidrefs[ref1*ste_bin_pol.max_types + i] &&
    7.17 -                 ste_bin_pol.ssidrefs[ref2*ste_bin_pol.max_types + i])
    7.18 +            if ( ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&
    7.19 +                 ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])
    7.20              {
    7.21                  printkd("%s: common type #%02x.\n", __func__, i);
    7.22                  return 1;
    7.23 @@ -55,6 +56,26 @@ static inline int have_common_type (ssid
    7.24      return 0;
    7.25  }
    7.26  
    7.27 +static inline int is_superset(ssidref_t ref1, ssidref_t ref2)
    7.28 +{
    7.29 +    int i;
    7.30 +
    7.31 +    if ( ref1 >= 0 && ref1 < ste_bin_pol.max_ssidrefs &&
    7.32 +         ref2 >= 0 && ref2 < ste_bin_pol.max_ssidrefs )
    7.33 +    {
    7.34 +        for( i = 0; i< ste_bin_pol.max_types; i++ )
    7.35 +            if (!ste_bin_pol.ssidrefs[ref1 * ste_bin_pol.max_types + i] &&
    7.36 +                 ste_bin_pol.ssidrefs[ref2 * ste_bin_pol.max_types + i])
    7.37 +            {
    7.38 +                return 0;
    7.39 +            }
    7.40 +    } else {
    7.41 +        return 0;
    7.42 +    }
    7.43 +    return 1;
    7.44 +}
    7.45 +
    7.46 +
    7.47  /* Helper function: return = (subj and obj share a common type) */
    7.48  static int share_common_type(struct domain *subj, struct domain *obj)
    7.49  {
    7.50 @@ -609,6 +630,7 @@ ste_pre_domain_create(void *subject_ssid
    7.51  {      
    7.52      /* check for ssidref in range for policy */
    7.53      ssidref_t ste_ssidref;
    7.54 +
    7.55      traceprintk("%s.\n", __func__);
    7.56  
    7.57      read_lock(&acm_bin_pol_rwlock);
    7.58 @@ -833,6 +855,15 @@ ste_sharing(ssidref_t ssidref1, ssidref_
    7.59  }
    7.60  
    7.61  static int
    7.62 +ste_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
    7.63 +{
    7.64 +    int iss = is_superset(
    7.65 +        GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref1),
    7.66 +        GET_SSIDREF(ACM_SIMPLE_TYPE_ENFORCEMENT_POLICY, ssidref2));
    7.67 +    return (iss ? ACM_ACCESS_PERMITTED : ACM_ACCESS_DENIED);
    7.68 +}
    7.69 +
    7.70 +static int
    7.71  ste_is_default_policy(void)
    7.72  {
    7.73      return ((ste_bin_pol.max_types    == 1) &&
    7.74 @@ -867,6 +898,7 @@ struct acm_operations acm_simple_type_en
    7.75      .pre_grant_setup        = ste_pre_grant_setup,
    7.76      .fail_grant_setup       = NULL,
    7.77      .sharing                = ste_sharing,
    7.78 +    .authorization          = ste_authorization,
    7.79  
    7.80      .is_default_policy      = ste_is_default_policy,
    7.81  };
     8.1 --- a/xen/include/acm/acm_core.h	Thu Jul 26 12:00:32 2007 +0100
     8.2 +++ b/xen/include/acm/acm_core.h	Fri Jul 27 09:01:15 2007 +0100
     8.3 @@ -153,8 +153,7 @@ static inline int acm_array_append_tuple
     8.4  }
     8.5  
     8.6  /* protos */
     8.7 -int acm_init_domain_ssid(domid_t id, ssidref_t ssidref);
     8.8 -int acm_init_domain_ssid_new(struct domain *, ssidref_t ssidref);
     8.9 +int acm_init_domain_ssid(struct domain *, ssidref_t ssidref);
    8.10  void acm_free_domain_ssid(struct acm_ssid_domain *ssid);
    8.11  int acm_init_binary_policy(u32 policy_code);
    8.12  int acm_set_policy(XEN_GUEST_HANDLE_64(void) buf, u32 buf_size);
     9.1 --- a/xen/include/acm/acm_hooks.h	Thu Jul 26 12:00:32 2007 +0100
     9.2 +++ b/xen/include/acm/acm_hooks.h	Fri Jul 27 09:01:15 2007 +0100
     9.3 @@ -112,7 +112,10 @@ struct acm_operations {
     9.4      int  (*pre_grant_setup)            (domid_t id);
     9.5      void (*fail_grant_setup)           (domid_t id);
     9.6      /* generic domain-requested decision hooks (can be NULL) */
     9.7 -    int (*sharing)                     (ssidref_t ssidref1, ssidref_t ssidref2);
     9.8 +    int (*sharing)                     (ssidref_t ssidref1,
     9.9 +                                        ssidref_t ssidref2);
    9.10 +    int (*authorization)               (ssidref_t ssidref1,
    9.11 +                                        ssidref_t ssidref2);
    9.12      /* determine whether the default policy is installed */
    9.13      int (*is_default_policy)           (void);
    9.14  };
    9.15 @@ -148,6 +151,8 @@ static inline int acm_is_policy(char *bu
    9.16  { return 0; }
    9.17  static inline int acm_sharing(ssidref_t ssidref1, ssidref_t ssidref2)
    9.18  { return 0; }
    9.19 +static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
    9.20 +{ return 0; }
    9.21  static inline int acm_domain_create(struct domain *d, ssidref_t ssidref)
    9.22  { return 0; }
    9.23  static inline void acm_domain_destroy(struct domain *d)
    9.24 @@ -157,6 +162,19 @@ static inline void acm_domain_destroy(st
    9.25  
    9.26  #else
    9.27  
    9.28 +static inline void acm_domain_ssid_onto_list(struct acm_ssid_domain *ssid)
    9.29 +{
    9.30 +    write_lock(&ssid_list_rwlock);
    9.31 +    list_add(&ssid->node, &ssid_list);
    9.32 +    write_unlock(&ssid_list_rwlock);
    9.33 +}
    9.34 +
    9.35 +static inline void acm_domain_ssid_off_list(struct acm_ssid_domain *ssid)
    9.36 +{
    9.37 +    write_lock(&ssid_list_rwlock);
    9.38 +    list_del(&ssid->node);
    9.39 +    write_unlock(&ssid_list_rwlock);
    9.40 +}
    9.41  
    9.42  static inline int acm_pre_eventchannel_unbound(domid_t id1, domid_t id2)
    9.43  {
    9.44 @@ -241,6 +259,7 @@ static inline void acm_domain_destroy(st
    9.45          if (acm_secondary_ops->domain_destroy != NULL)
    9.46              acm_secondary_ops->domain_destroy(ssid, d);
    9.47          /* free security ssid for the destroyed domain (also if null policy */
    9.48 +        acm_domain_ssid_off_list(ssid);
    9.49          acm_free_domain_ssid((struct acm_ssid_domain *)(ssid));
    9.50      }
    9.51  }
    9.52 @@ -250,13 +269,16 @@ static inline int acm_domain_create(stru
    9.53  {
    9.54      void *subject_ssid = current->domain->ssid;
    9.55      domid_t domid = d->domain_id;
    9.56 -    int rc = 0;
    9.57 +    int rc;
    9.58  
    9.59      read_lock(&acm_bin_pol_rwlock);
    9.60      /*
    9.61         To be called when a domain is created; returns '0' if the
    9.62         domain is allowed to be created, != '0' if not.
    9.63       */
    9.64 +    rc = acm_init_domain_ssid(d, ssidref);
    9.65 +    if (rc != ACM_OK)
    9.66 +        goto error_out;
    9.67  
    9.68      if ((acm_primary_ops->domain_create != NULL) &&
    9.69          acm_primary_ops->domain_create(subject_ssid, ssidref, domid)) {
    9.70 @@ -267,18 +289,17 @@ static inline int acm_domain_create(stru
    9.71          /* roll-back primary */
    9.72          if (acm_primary_ops->domain_destroy != NULL)
    9.73              acm_primary_ops->domain_destroy(d->ssid, d);
    9.74 -        acm_free_domain_ssid(d->ssid);
    9.75          rc = ACM_ACCESS_DENIED;
    9.76      }
    9.77  
    9.78 -    if (rc == 0) {
    9.79 -        rc = acm_init_domain_ssid_new(d, ssidref);
    9.80 -
    9.81 -        if (rc != ACM_OK) {
    9.82 -            acm_domain_destroy(d);
    9.83 -        }
    9.84 +    if ( rc == ACM_OK )
    9.85 +    {
    9.86 +        acm_domain_ssid_onto_list(d->ssid);
    9.87 +    } else {
    9.88 +        acm_free_domain_ssid(d->ssid);
    9.89      }
    9.90  
    9.91 +error_out:
    9.92      read_unlock(&acm_bin_pol_rwlock);
    9.93      return rc;
    9.94  }
    9.95 @@ -297,6 +318,19 @@ static inline int acm_sharing(ssidref_t 
    9.96  }
    9.97  
    9.98  
    9.99 +static inline int acm_authorization(ssidref_t ssidref1, ssidref_t ssidref2)
   9.100 +{
   9.101 +    if ((acm_primary_ops->authorization != NULL) &&
   9.102 +        acm_primary_ops->authorization(ssidref1, ssidref2))
   9.103 +        return ACM_ACCESS_DENIED;
   9.104 +    else if ((acm_secondary_ops->authorization != NULL) &&
   9.105 +             acm_secondary_ops->authorization(ssidref1, ssidref2)) {
   9.106 +        return ACM_ACCESS_DENIED;
   9.107 +    } else
   9.108 +        return ACM_ACCESS_PERMITTED;
   9.109 +}
   9.110 +
   9.111 +
   9.112  extern int acm_init(char *policy_start, unsigned long policy_len);
   9.113  
   9.114  /* Return true iff buffer has an acm policy magic number.  */
    10.1 --- a/xen/include/public/acm.h	Thu Jul 26 12:00:32 2007 +0100
    10.2 +++ b/xen/include/public/acm.h	Fri Jul 27 09:01:15 2007 +0100
    10.3 @@ -99,8 +99,9 @@
    10.4  typedef uint32_t ssidref_t;
    10.5  
    10.6  /* hooks that are known to domains */
    10.7 -#define ACMHOOK_none    0
    10.8 -#define ACMHOOK_sharing 1
    10.9 +#define ACMHOOK_none          0
   10.10 +#define ACMHOOK_sharing       1
   10.11 +#define ACMHOOK_authorization 2
   10.12  
   10.13  /* -------security policy relevant type definitions-------- */
   10.14