[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-4.1-testing] xsm/flask: fix resource list range checks



# HG changeset patch
# User Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
# Date 1321969068 0
# Node ID 4f4763690d74ae4fb34aa8914f713812b1b19389
# Parent  db87ad0b5391b4b77643f6b095f445aca95ef705
xsm/flask: fix resource list range checks

The FLASK security checks for resource ranges were not implemented
correctly - only the permissions on the endpoints of a range were
checked, instead of all items contained in the range. This would allow
certain resources (I/O ports, I/O memory) to be used by domains in
contravention to security policy.

This also corrects a bug where adding overlapping resource ranges did
not trigger an error.

Signed-off-by: Daniel De Graaf <dgdegra@xxxxxxxxxxxxx>
Committed-by: Keir Fraser <keir@xxxxxxx>
xen-unstable changeset:   24177:d3859e348951
xen-unstable date:        Tue Nov 22 13:29:48 2011 +0000
---


diff -r db87ad0b5391 -r 4f4763690d74 xen/xsm/flask/hooks.c
--- a/xen/xsm/flask/hooks.c     Tue Nov 22 13:37:26 2011 +0000
+++ b/xen/xsm/flask/hooks.c     Tue Nov 22 13:37:48 2011 +0000
@@ -683,14 +683,32 @@
         return rc;
 }
 
-static int iomem_has_perm(struct domain *d, unsigned long mfn, uint8_t access)
+struct iomem_has_perm_data {
+    struct domain_security_struct *ssec, *tsec;
+    u32 perm;
+};
+
+static int _iomem_has_perm(void *v, u32 sid, unsigned long start, unsigned 
long end)
 {
-    u32 perm;
-    u32 rsid;
+    struct iomem_has_perm_data *data = v;
+    struct avc_audit_data ad;
     int rc = -EPERM;
 
-    struct domain_security_struct *ssec, *tsec;
-    struct avc_audit_data ad;
+    AVC_AUDIT_DATA_INIT(&ad, DEV);
+    ad.device = start;
+
+    rc = avc_has_perm(data->ssec->sid, sid, SECCLASS_RESOURCE, data->perm, 
&ad);
+
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(data->tsec->sid, sid, SECCLASS_RESOURCE, 
RESOURCE__USE, &ad);
+}
+
+static int iomem_has_perm(struct domain *d, unsigned long start, unsigned long 
end, uint8_t access)
+{
+    struct iomem_has_perm_data data;
+    int rc;
 
     rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
                          resource_to_perm(access));
@@ -698,27 +716,14 @@
         return rc;
 
     if ( access )
-        perm = RESOURCE__ADD_IOMEM;
+        data.perm = RESOURCE__ADD_IOMEM;
     else
-        perm = RESOURCE__REMOVE_IOMEM;
+        data.perm = RESOURCE__REMOVE_IOMEM;
 
-    ssec = current->domain->ssid;
-    tsec = d->ssid;
+    data.ssec = current->domain->ssid;
+    data.tsec = d->ssid;
 
-    rc = security_iomem_sid(mfn, &rsid);
-    if ( rc )
-        return rc;
-
-    AVC_AUDIT_DATA_INIT(&ad, DEV);
-    ad.device = mfn;
-
-    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
-
-    if ( rc )
-        return rc;
-
-    return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
-                        RESOURCE__USE, &ad);
+    return security_iterate_iomem_sids(start, end, _iomem_has_perm, &data);
 }
 
 static int flask_perfcontrol(void)
@@ -755,14 +760,33 @@
     return domain_has_perm(current->domain, d, SECCLASS_SHADOW, perm);
 }
 
-static int ioport_has_perm(struct domain *d, uint32_t ioport, uint8_t access)
+struct ioport_has_perm_data {
+    struct domain_security_struct *ssec, *tsec;
+    u32 perm;
+};
+
+static int _ioport_has_perm(void *v, u32 sid, unsigned long start, unsigned 
long end)
 {
-    u32 perm;
-    u32 rsid;
-    int rc = -EPERM;
+    struct ioport_has_perm_data *data = v;
+    struct avc_audit_data ad;
+    int rc;
 
-    struct avc_audit_data ad;
-    struct domain_security_struct *ssec, *tsec;
+    AVC_AUDIT_DATA_INIT(&ad, DEV);
+    ad.device = start;
+
+    rc = avc_has_perm(data->ssec->sid, sid, SECCLASS_RESOURCE, data->perm, 
&ad);
+
+    if ( rc )
+        return rc;
+
+    return avc_has_perm(data->tsec->sid, sid, SECCLASS_RESOURCE, 
RESOURCE__USE, &ad);
+}
+
+
+static int ioport_has_perm(struct domain *d, uint32_t start, uint32_t end, 
uint8_t access)
+{
+    int rc;
+    struct ioport_has_perm_data data;
 
     rc = domain_has_perm(current->domain, d, SECCLASS_RESOURCE,
                          resource_to_perm(access));
@@ -771,29 +795,14 @@
         return rc;
 
     if ( access )
-        perm = RESOURCE__ADD_IOPORT;
+        data.perm = RESOURCE__ADD_IOPORT;
     else
-        perm = RESOURCE__REMOVE_IOPORT;
+        data.perm = RESOURCE__REMOVE_IOPORT;
 
-    ssec = current->domain->ssid;
-    tsec = d->ssid;
+    data.ssec = current->domain->ssid;
+    data.tsec = d->ssid;
 
-    rc = security_ioport_sid(ioport, &rsid);
-    if ( rc )
-        return rc;
-
-    AVC_AUDIT_DATA_INIT(&ad, DEV);
-    ad.device = ioport;
-
-    rc = avc_has_perm(ssec->sid, rsid, SECCLASS_RESOURCE, perm, &ad);
-    if ( rc )
-        return rc;
-
-    if ( access )
-        return avc_has_perm(tsec->sid, rsid, SECCLASS_RESOURCE, 
-                            RESOURCE__USE, &ad);
-    else
-        return rc;
+    return security_iterate_ioport_sids(start, end, _ioport_has_perm, &data);
 }
 
 static int flask_getpageframeinfo(struct page_info *page)
@@ -1208,31 +1217,25 @@
 
     if ( strcmp(name, "I/O Memory") == 0 )
     {
-        rc = iomem_has_perm(d, s, access);
+        rc = iomem_has_perm(d, s, e, access);
         if ( rc )
             return rc;
-
-        if ( s != e )
-            rc = iomem_has_perm(d, e, access);
     }
     else if ( strcmp(name, "Interrupts") == 0 )
     {
-        rc = irq_has_perm(d, s, access);
-        if ( rc )
-            return rc;
-
-        if ( s != e )
-            rc = irq_has_perm(d, e, access);
+        while (s <= e) {
+            rc = irq_has_perm(d, s, access);
+            if ( rc )
+                return rc;
+            s++;
+        }
     }
 #ifdef CONFIG_X86
     else if ( strcmp(name, "I/O Ports") == 0 )
     {
-        rc = ioport_has_perm(d, s, access);
+        rc = ioport_has_perm(d, s, e, access);
         if ( rc )
             return rc;
-
-        if ( s != e )
-            rc = ioport_has_perm(d, e, access);
     }
 #endif
 
diff -r db87ad0b5391 -r 4f4763690d74 xen/xsm/flask/include/security.h
--- a/xen/xsm/flask/include/security.h  Tue Nov 22 13:37:26 2011 +0000
+++ b/xen/xsm/flask/include/security.h  Tue Nov 22 13:37:48 2011 +0000
@@ -82,6 +82,14 @@
 int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
                                                                     u16 
tclass);
 
+typedef int (*security_iterate_fn)(void *data, u32 sid, unsigned long start,
+                                                        unsigned long end);
+int security_iterate_iomem_sids(unsigned long start, unsigned long end,
+                                security_iterate_fn fn, void *data);
+
+int security_iterate_ioport_sids(u32 start, u32 end,
+                                security_iterate_fn fn, void *data);
+
 int security_ocontext_add(char *ocontext, unsigned long low,
                            unsigned long high, u32 sid);
 
diff -r db87ad0b5391 -r 4f4763690d74 xen/xsm/flask/ss/services.c
--- a/xen/xsm/flask/ss/services.c       Tue Nov 22 13:37:26 2011 +0000
+++ b/xen/xsm/flask/ss/services.c       Tue Nov 22 13:37:48 2011 +0000
@@ -1594,6 +1594,53 @@
     return rc;
 }
 
+int security_iterate_iomem_sids(unsigned long start, unsigned long end,
+                                security_iterate_fn fn, void *data)
+{
+    struct ocontext *c;
+    int rc = 0;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_IOMEM];
+    while (c && c->u.iomem.high_iomem < start)
+        c = c->next;
+
+    while (c && c->u.iomem.low_iomem <= end) {
+        if (!c->sid[0])
+        {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if ( rc )
+                goto out;
+        }
+        if (start < c->u.iomem.low_iomem) {
+            /* found a gap */
+            rc = fn(data, SECINITSID_IOMEM, start, c->u.iomem.low_iomem - 1);
+            if (rc)
+                goto out;
+            start = c->u.iomem.low_iomem;
+        }
+        if (end <= c->u.iomem.high_iomem) {
+            /* iteration ends in the middle of this range */
+            rc = fn(data, c->sid[0], start, end);
+            goto out;
+        }
+
+        rc = fn(data, c->sid[0], start, c->u.iomem.high_iomem);
+        if (rc)
+            goto out;
+        start = c->u.iomem.high_iomem + 1;
+
+        c = c->next;
+    }
+
+    rc = fn(data, SECINITSID_IOMEM, start, end);
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
 /**
  * security_ioport_sid - Obtain the SID for an ioport.
  * @ioport: ioport
@@ -1635,6 +1682,53 @@
     return rc;
 }
 
+int security_iterate_ioport_sids(u32 start, u32 end,
+                                security_iterate_fn fn, void *data)
+{
+    struct ocontext *c;
+    int rc = 0;
+
+    POLICY_RDLOCK;
+
+    c = policydb.ocontexts[OCON_IOPORT];
+    while (c && c->u.ioport.high_ioport < start)
+        c = c->next;
+
+    while (c && c->u.ioport.low_ioport <= end) {
+        if (!c->sid[0])
+        {
+            rc = sidtab_context_to_sid(&sidtab, &c->context[0], &c->sid[0]);
+            if ( rc )
+                goto out;
+        }
+        if (start < c->u.ioport.low_ioport) {
+            /* found a gap */
+            rc = fn(data, SECINITSID_IOPORT, start, c->u.ioport.low_ioport - 
1);
+            if (rc)
+                goto out;
+            start = c->u.ioport.low_ioport;
+        }
+        if (end <= c->u.ioport.high_ioport) {
+            /* iteration ends in the middle of this range */
+            rc = fn(data, c->sid[0], start, end);
+            goto out;
+        }
+
+        rc = fn(data, c->sid[0], start, c->u.ioport.high_ioport);
+        if (rc)
+            goto out;
+        start = c->u.ioport.high_ioport + 1;
+
+        c = c->next;
+    }
+
+    rc = fn(data, SECINITSID_IOPORT, start, end);
+
+out:
+    POLICY_RDUNLOCK;
+    return rc;
+}
+
 /**
  * security_device_sid - Obtain the SID for a PCI device.
  * @ioport: device
@@ -1963,6 +2057,7 @@
     int ret = 0;
     int ocon = 0;
     struct ocontext *c;
+    struct ocontext *prev;
     struct ocontext *add;
 
     if ( (ocon = determine_ocontext(ocontext)) < 0 )
@@ -2006,23 +2101,27 @@
         add->u.ioport.low_ioport = low;
         add->u.ioport.high_ioport = high;
 
+        prev = NULL;
         c = policydb.ocontexts[OCON_IOPORT];
-        while ( c )
-        {
-            if ( c->u.ioport.low_ioport <= add->u.ioport.high_ioport &&
-                 add->u.ioport.low_ioport <= c->u.ioport.high_ioport )
-            {
-                printk("%s: IO Port overlap with entry 0x%x - 0x%x\n",
-                       __FUNCTION__, c->u.ioport.low_ioport,
-                       c->u.ioport.high_ioport);
-                ret = -EINVAL;
-                break;
-            }
+
+        while ( c && c->u.ioport.high_ioport < low ) {
+            prev = c;
             c = c->next;
         }
 
-        if ( ret == 0 )
+        if (c && c->u.ioport.low_ioport <= high)
         {
+            printk("%s: IO Port overlap with entry 0x%x - 0x%x\n",
+                   __FUNCTION__, c->u.ioport.low_ioport,
+                   c->u.ioport.high_ioport);
+            ret = -EINVAL;
+            break;
+        }
+
+        if (prev) {
+            add->next = prev->next;
+            prev->next = add;
+        } else {
             add->next = policydb.ocontexts[OCON_IOPORT];
             policydb.ocontexts[OCON_IOPORT] = add;
         }
@@ -2032,23 +2131,27 @@
         add->u.iomem.low_iomem = low;
         add->u.iomem.high_iomem = high;
 
+        prev = NULL;
         c = policydb.ocontexts[OCON_IOMEM];
-        while ( c )
-        {
-            if ( c->u.iomem.low_iomem <= add->u.iomem.high_iomem &&
-                 add->u.iomem.low_iomem <= c->u.iomem.high_iomem )
-            {
-                printk("%s: IO Memory overlap with entry 0x%x - 0x%x\n",
-                       __FUNCTION__, c->u.iomem.low_iomem,
-                       c->u.iomem.high_iomem);
-                ret = -EINVAL;
-                break;
-            }
+
+        while ( c && c->u.iomem.high_iomem < low ) {
+            prev = c;
             c = c->next;
         }
 
-        if ( ret == 0 )
+        if (c && c->u.iomem.low_iomem <= high)
         {
+            printk("%s: IO Memory overlap with entry 0x%x - 0x%x\n",
+                   __FUNCTION__, c->u.iomem.low_iomem,
+                   c->u.iomem.high_iomem);
+            ret = -EINVAL;
+            break;
+        }
+
+        if (prev) {
+            add->next = prev->next;
+            prev->next = add;
+        } else {
             add->next = policydb.ocontexts[OCON_IOMEM];
             policydb.ocontexts[OCON_IOMEM] = add;
         }

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.