WARNING - OLD ARCHIVES

This is an archived copy of the Xen.org mailing list, which we have preserved to ensure that existing links to archives are not broken. The live archive, which contains the latest emails, can be found at http://lists.xen.org/
   
 
 
Xen 
 
Home Products Support Community News
 
   
 

xen-changelog

[Xen-changelog] [xen-unstable] [XSM][FLASK] Argument handling bugs in XS

To: xen-changelog@xxxxxxxxxxxxxxxxxxx
Subject: [Xen-changelog] [xen-unstable] [XSM][FLASK] Argument handling bugs in XSM:FLASK
From: Xen patchbot-unstable <patchbot-unstable@xxxxxxxxxxxxxxxxxxx>
Date: Wed, 23 Jul 2008 08:50:16 -0700
Delivery-date: Wed, 23 Jul 2008 08:50:55 -0700
Envelope-to: www-data@xxxxxxxxxxxxxxxxxxx
List-help: <mailto:xen-changelog-request@lists.xensource.com?subject=help>
List-id: BK change log <xen-changelog.lists.xensource.com>
List-post: <mailto:xen-changelog@lists.xensource.com>
List-subscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=subscribe>
List-unsubscribe: <http://lists.xensource.com/mailman/listinfo/xen-changelog>, <mailto:xen-changelog-request@lists.xensource.com?subject=unsubscribe>
Reply-to: xen-devel@xxxxxxxxxxxxxxxxxxx
Sender: xen-changelog-bounces@xxxxxxxxxxxxxxxxxxx
# HG changeset patch
# User Keir Fraser <keir.fraser@xxxxxxxxxx>
# Date 1216629696 -3600
# Node ID fa66b33f975a8f7940249e0eb4a45c87a978ba50
# Parent  dbeddb76c2b9069c9cf9b961c29081544a8f3686
[XSM][FLASK] Argument handling bugs in XSM:FLASK

Addresses a number of argument handling bugs in the flask_op hypercall
in the XSM:Flask module.  Thanks to Rafal Wojtczuk at McAfee for
reporting the issues and Tim Deegan at Citrix for providing an
initial patch.

This patch addresses the following issues:
 - bounds checking and validation on input arguments to flask_op
 - updated ABI/API, size and cmd are now uint32_t
 - updated userspace tools and libraries to account for ABI/API
 changes
 - implemented all copies using from/to guest, better portability
 - implemented upper bounds checking on op->cmd, op->size
 - implemented sanity checking on op->size and op->buf
 - implemented bit vector for checking from/to usage on op->cmd

Signed-off-by: George Coker <gscoker@xxxxxxxxxxxxxx>
---
 tools/flask/libflask/flask_op.c      |    6 
 tools/flask/libflask/include/flask.h |    6 
 xen/arch/x86/time.c                  |   54 ++
 xen/include/public/xsm/flask_op.h    |    8 
 xen/xsm/flask/avc.c                  |    4 
 xen/xsm/flask/flask_op.c             |  652 +++++++++++++----------------------
 xen/xsm/flask/include/avc.h          |    2 
 7 files changed, 322 insertions(+), 410 deletions(-)

diff -r dbeddb76c2b9 -r fa66b33f975a tools/flask/libflask/flask_op.c
--- a/tools/flask/libflask/flask_op.c   Mon Jul 21 09:40:37 2008 +0100
+++ b/tools/flask/libflask/flask_op.c   Mon Jul 21 09:41:36 2008 +0100
@@ -22,7 +22,7 @@
 #include <flask.h>
 #include <xenctrl.h>
 
-int flask_load(int xc_handle, char *buf, int size)
+int flask_load(int xc_handle, char *buf, uint32_t size)
 {
     int err;
     flask_op_t op;
@@ -37,7 +37,7 @@ int flask_load(int xc_handle, char *buf,
     return 0;
 }
 
-int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid)
+int flask_context_to_sid(int xc_handle, char *buf, uint32_t size, uint32_t 
*sid)
 {
     int err;
     flask_op_t op;
@@ -54,7 +54,7 @@ int flask_context_to_sid(int xc_handle, 
     return 0;
 }
 
-int flask_sid_to_context(int xc_handle, int sid, char *buf, int size)
+int flask_sid_to_context(int xc_handle, int sid, char *buf, uint32_t size)
 {
     int err;
     flask_op_t op;
diff -r dbeddb76c2b9 -r fa66b33f975a tools/flask/libflask/include/flask.h
--- a/tools/flask/libflask/include/flask.h      Mon Jul 21 09:40:37 2008 +0100
+++ b/tools/flask/libflask/include/flask.h      Mon Jul 21 09:41:36 2008 +0100
@@ -15,8 +15,8 @@
 #include <xen/xen.h>
 #include <xen/xsm/flask_op.h>
 
-int flask_load(int xc_handle, char *buf, int size);
-int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid);
-int flask_sid_to_context(int xc_handle, int sid, char *buf, int size);
+int flask_load(int xc_handle, char *buf, uint32_t size);
+int flask_context_to_sid(int xc_handle, char *buf, uint32_t size, uint32_t 
*sid);
+int flask_sid_to_context(int xc_handle, int sid, char *buf, uint32_t size);
 
 #endif /* __FLASK_H__ */
diff -r dbeddb76c2b9 -r fa66b33f975a xen/arch/x86/time.c
--- a/xen/arch/x86/time.c       Mon Jul 21 09:40:37 2008 +0100
+++ b/xen/arch/x86/time.c       Mon Jul 21 09:41:36 2008 +0100
@@ -481,6 +481,46 @@ static int init_pmtimer(struct platform_
 }
 
 /************************************************************
+ * PLATFORM TIMER 5: TSC
+ */
+
+#define platform_timer_is_tsc() (!strcmp(plt_src.name, "TSC"))
+static u64 tsc_freq;
+
+static u64 read_tsc_count(void)
+{
+    u64 tsc;
+    rdtscll(tsc);
+    return tsc;
+}
+
+static int init_tsctimer(struct platform_timesource *pts)
+{
+    unsigned int cpu;
+
+    /*
+     * TODO: evaluate stability of TSC here, return 0 if not stable.
+     * For now we assume all TSCs are synchronised and hence can all share
+     * CPU 0's calibration values.
+     */
+    for_each_cpu ( cpu )
+    {
+        if ( cpu == 0 )
+            continue;
+        memcpy(&per_cpu(cpu_time, cpu),
+               &per_cpu(cpu_time, 0),
+               sizeof(struct cpu_time));
+    }
+
+    pts->name = "TSC";
+    pts->frequency = tsc_freq;
+    pts->read_counter = read_tsc_count;
+    pts->counter_bits = 64;
+
+    return 1;
+}
+
+/************************************************************
  * GENERIC PLATFORM TIMER INFRASTRUCTURE
  */
 
@@ -565,6 +605,8 @@ static void init_platform_timer(void)
             rc = init_cyclone(pts);
         else if ( !strcmp(opt_clocksource, "acpi") )
             rc = init_pmtimer(pts);
+        else if ( !strcmp(opt_clocksource, "tsc") )
+            rc = init_tsctimer(pts);
 
         if ( rc <= 0 )
             printk("WARNING: %s clocksource '%s'.\n",
@@ -780,6 +822,10 @@ int cpu_frequency_change(u64 freq)
     struct cpu_time *t = &this_cpu(cpu_time);
     u64 curr_tsc;
 
+    /* Nothing to do if TSC is platform timer. Assume it is constant-rate. */
+    if ( platform_timer_is_tsc() )
+        return 0;
+
     /* Sanity check: CPU frequency allegedly dropping below 1MHz? */
     if ( freq < 1000000u )
     {
@@ -978,6 +1024,9 @@ void init_percpu_time(void)
     unsigned long flags;
     s_time_t now;
 
+    if ( platform_timer_is_tsc() )
+        return;
+
     local_irq_save(flags);
     rdtscll(t->local_tsc_stamp);
     now = !plt_src.read_counter ? 0 : read_platform_stime();
@@ -998,10 +1047,10 @@ int __init init_xen_time(void)
 
     local_irq_disable();
 
-    init_percpu_time();
-
     stime_platform_stamp = 0;
     init_platform_timer();
+
+    init_percpu_time();
 
     /* check if TSC is invariant during deep C state
        this is a new feature introduced by Nehalem*/
@@ -1019,6 +1068,7 @@ void __init early_time_init(void)
 {
     u64 tmp = init_pit_and_calibrate_tsc();
 
+    tsc_freq = tmp;
     set_time_scale(&this_cpu(cpu_time).tsc_scale, tmp);
 
     do_div(tmp, 1000);
diff -r dbeddb76c2b9 -r fa66b33f975a xen/include/public/xsm/flask_op.h
--- a/xen/include/public/xsm/flask_op.h Mon Jul 21 09:40:37 2008 +0100
+++ b/xen/include/public/xsm/flask_op.h Mon Jul 21 09:41:36 2008 +0100
@@ -32,10 +32,12 @@
 #define FLASK_AVC_CACHESTATS    19
 #define FLASK_MEMBER            20
 
+#define FLASK_LAST              FLASK_MEMBER
+
 typedef struct flask_op {
-    int   cmd;
-    int   size;
-    char *buf;
+    uint32_t  cmd;
+    uint32_t  size;
+    char      *buf;
 } flask_op_t;
 
 DEFINE_XEN_GUEST_HANDLE(flask_op_t);
diff -r dbeddb76c2b9 -r fa66b33f975a xen/xsm/flask/avc.c
--- a/xen/xsm/flask/avc.c       Mon Jul 21 09:40:37 2008 +0100
+++ b/xen/xsm/flask/avc.c       Mon Jul 21 09:41:36 2008 +0100
@@ -250,7 +250,7 @@ void __init avc_init(void)
     printk("AVC INITIALIZED\n");
 }
 
-int avc_get_hash_stats(char *page)
+int avc_get_hash_stats(char *buf, uint32_t size)
 {
     int i, chain_len, max_chain_len, slots_used;
     struct avc_node *node;
@@ -274,7 +274,7 @@ int avc_get_hash_stats(char *page)
 
     rcu_read_unlock();
     
-    return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
+    return snprintf(buf, size, "entries: %d\nbuckets used: %d/%d\n"
                                 "longest chain: %d\n",
                                 atomic_read(&avc_cache.active_nodes),
                                 slots_used, AVC_CACHE_SLOTS, max_chain_len);
diff -r dbeddb76c2b9 -r fa66b33f975a xen/xsm/flask/flask_op.c
--- a/xen/xsm/flask/flask_op.c  Mon Jul 21 09:40:37 2008 +0100
+++ b/xen/xsm/flask/flask_op.c  Mon Jul 21 09:41:36 2008 +0100
@@ -29,6 +29,43 @@ integer_param("flask_enabled", flask_ena
 integer_param("flask_enabled", flask_enabled);
 #endif
 
+#define MAX_POLICY_SIZE 0x4000000
+#define FLASK_COPY_IN \
+    ( \
+        1UL<<FLASK_LOAD | \
+        1UL<<FLASK_SETENFORCE | \
+        1UL<<FLASK_CONTEXT_TO_SID | \
+        1UL<<FLASK_SID_TO_CONTEXT | \
+        1UL<<FLASK_ACCESS | \
+        1UL<<FLASK_CREATE | \
+        1UL<<FLASK_RELABEL | \
+        1UL<<FLASK_USER | \
+        1UL<<FLASK_GETBOOL | \
+        1UL<<FLASK_SETBOOL | \
+        1UL<<FLASK_COMMITBOOLS | \
+        1UL<<FLASK_DISABLE | \
+        1UL<<FLASK_SETAVC_THRESHOLD | \
+        1UL<<FLASK_MEMBER \
+    )
+
+#define FLASK_COPY_OUT \
+    ( \
+        1UL<<FLASK_GETENFORCE | \
+        1UL<<FLASK_CONTEXT_TO_SID | \
+        1UL<<FLASK_SID_TO_CONTEXT | \
+        1UL<<FLASK_ACCESS | \
+        1UL<<FLASK_CREATE | \
+        1UL<<FLASK_RELABEL | \
+        1UL<<FLASK_USER | \
+        1UL<<FLASK_POLICYVERS | \
+        1UL<<FLASK_GETBOOL | \
+        1UL<<FLASK_MLS | \
+        1UL<<FLASK_GETAVC_THRESHOLD | \
+        1UL<<FLASK_AVC_HASHSTATS | \
+        1UL<<FLASK_AVC_CACHESTATS | \
+        1UL<<FLASK_MEMBER \
+    )
+
 static DEFINE_SPINLOCK(sel_sem);
 
 /* global data for booleans */
@@ -51,7 +88,7 @@ static int domain_has_security(struct do
                                                                 perms, NULL);
 }
 
-static int flask_security_user(char *buf, int size)
+static int flask_security_user(char *buf, uint32_t size)
 {
     char *page = NULL;
     char *con, *user, *ptr;
@@ -82,12 +119,8 @@ static int flask_security_user(char *buf
         goto out2;
     memset(page, 0, PAGE_SIZE);
 
-    length = -EFAULT;
-    if ( copy_from_user(page, buf, size) )
-        goto out2;
-        
     length = -EINVAL;
-    if ( sscanf(page, "%s %s", con, user) != 2 )
+    if ( sscanf(buf, "%s %s", con, user) != 2 )
         goto out2;
 
     length = security_context_to_sid(con, strlen(con)+1, &sid);
@@ -98,7 +131,6 @@ static int flask_security_user(char *buf
     if ( length < 0 )
         goto out2;
     
-    memset(page, 0, PAGE_SIZE);
     length = snprintf(page, PAGE_SIZE, "%u", nsids) + 1;
     ptr = page + length;
     for ( i = 0; i < nsids; i++ )
@@ -121,8 +153,16 @@ static int flask_security_user(char *buf
         length += len;
     }
     
-    if ( copy_to_user(buf, page, length) )
-        length = -EFAULT;
+    if ( length > size )
+    {
+        printk( "%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, length);
+        length = -ERANGE;
+        goto out3;
+    }
+
+    memset(buf, 0, size);
+    memcpy(buf, page, length);
         
 out3:
     xfree(sids);
@@ -135,7 +175,7 @@ out:
     return length;
 }
 
-static int flask_security_relabel(char *buf, int size)
+static int flask_security_relabel(char *buf, uint32_t size)
 {
     char *scon, *tcon;
     u32 ssid, tsid, newsid;
@@ -178,15 +218,81 @@ static int flask_security_relabel(char *
     if ( length < 0 )
         goto out2;
             
-    if ( len > PAGE_SIZE )
-    {
+    if ( len > size )
+    {
+        printk( "%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, len);
         length = -ERANGE;
         goto out3;
     }
-        
-    if ( copy_to_user(buf, newcon, len) )
-        len = -EFAULT;
-
+
+    memset(buf, 0, size);
+    memcpy(buf, newcon, len);
+    length = len;
+
+out3:
+    xfree(newcon);
+out2:
+    xfree(tcon);
+out:
+    xfree(scon);
+    return length;
+}
+
+static int flask_security_create(char *buf, uint32_t size)
+{
+    char *scon, *tcon;
+    u32 ssid, tsid, newsid;
+    u16 tclass;
+    int length;
+    char *newcon;
+    u32 len;
+
+    length = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
+    if ( length )
+        return length;
+
+    length = -ENOMEM;
+    scon = xmalloc_array(char, size+1);
+    if ( !scon )
+        return length;
+    memset(scon, 0, size+1);
+
+    tcon = xmalloc_array(char, size+1);
+    if ( !tcon )
+        goto out;
+    memset(tcon, 0, size+1);
+
+    length = -EINVAL;
+    if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
+        goto out2;
+
+    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_transition_sid(ssid, tsid, tclass, &newsid);
+    if ( length < 0 )
+        goto out2;
+
+    length = security_sid_to_context(newsid, &newcon, &len);
+    if ( length < 0 )    
+        goto out2;
+
+    if ( len > size )
+    {
+        printk( "%s:  context size (%u) exceeds payload "
+                "max\n", __FUNCTION__, len);
+        length = -ERANGE;
+        goto out3;
+    }
+
+    memset(buf, 0, size);
+    memcpy(buf, newcon, len);
     length = len;
         
 out3:
@@ -198,75 +304,8 @@ out:
     return length;
 }
 
-static int flask_security_create(char *buf, int size)
-{
-    char *scon, *tcon;
-    u32 ssid, tsid, newsid;
-    u16 tclass;
-    int length;
-    char *newcon;
-    u32 len;
-
-    length = domain_has_security(current->domain, SECURITY__COMPUTE_CREATE);
-    if ( length )
-        return length;
-
-    length = -ENOMEM;
-    scon = xmalloc_array(char, size+1);
-    if ( !scon )
-        return length;
-    memset(scon, 0, size+1);
-
-    tcon = xmalloc_array(char, size+1);
-    if ( !tcon )
-        goto out;
-    memset(tcon, 0, size+1);
-
-    length = -EINVAL;
-    if ( sscanf(buf, "%s %s %hu", scon, tcon, &tclass) != 3 )
-        goto out2;
-
-    length = security_context_to_sid(scon, strlen(scon)+1, &ssid);
-    if ( length < 0 )
-        goto out2;
-
-    length = security_context_to_sid(tcon, strlen(tcon)+1, &tsid);
-    if ( length < 0 )
-        goto out2;
-
-    length = security_transition_sid(ssid, tsid, tclass, &newsid);
-    if ( length < 0 )
-        goto out2;
-
-    length = security_sid_to_context(newsid, &newcon, &len);
-    if ( length < 0 )    
-        goto out2;
-
-    if ( len > PAGE_SIZE )
-    {
-        printk( "%s:  context size (%u) exceeds payload "
-                "max\n", __FUNCTION__, len);
-        length = -ERANGE;
-        goto out3;
-    }
-
-    if ( copy_to_user(buf, newcon, len) )
-        len = -EFAULT;
-
-    length = len;
-        
-out3:
-    xfree(newcon);
-out2:
-    xfree(tcon);
-out:
-    xfree(scon);
-    return length;
-}
-
-static int flask_security_access(char *buf, int size)
-{
-    char *page = NULL;
+static int flask_security_access(char *buf, uint32_t size)
+{
     char *scon, *tcon;
     u32 ssid, tsid;
     u16 tclass;
@@ -305,23 +344,12 @@ static int flask_security_access(char *b
     if ( length < 0 )
         goto out2;
 
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-    {
-        length = -ENOMEM;
-        goto out2;
-    }
-
-    memset(page, 0, PAGE_SIZE);
-
-    length = snprintf(page, PAGE_SIZE, "%x %x %x %x %u", 
+    memset(buf, 0, size);
+    length = snprintf(buf, size, "%x %x %x %x %u", 
                                         avd.allowed, avd.decided,
                                         avd.auditallow, avd.auditdeny, 
                                         avd.seqno);
                 
-    if ( copy_to_user(buf, page, length) )
-        length = -EFAULT;
-        
 out2:
     xfree(tcon);
 out:
@@ -329,7 +357,7 @@ out:
     return length;
 }
 
-static int flask_security_member(char *buf, int size)
+static int flask_security_member(char *buf, uint32_t size)
 {
     char *scon, *tcon;
     u32 ssid, tsid, newsid;
@@ -373,7 +401,7 @@ static int flask_security_member(char *b
     if ( length < 0 )
         goto out2;
 
-    if ( len > PAGE_SIZE )
+    if ( len > size )
     {
         printk("%s:  context size (%u) exceeds payload "
                 "max\n", __FUNCTION__, len);
@@ -381,9 +409,8 @@ static int flask_security_member(char *b
         goto out3;
     }
 
-    if ( copy_to_user(buf, newcon, len) )
-        len = -EFAULT;
-
+    memset(buf, 0, size);
+    memcpy(buf, newcon, len);
     length = len;
 
 out3:
@@ -395,26 +422,13 @@ out:
     return length;
 }
 
-static int flask_security_setenforce(char *buf, int count)
-{
-    char *page = NULL;
+static int flask_security_setenforce(char *buf, uint32_t count)
+{
     int length;
     int new_value;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-        return -ENOMEM;
-
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-        return -ENOMEM;
-    memset(page, 0, PAGE_SIZE);
-    length = -EFAULT;
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
-    length = -EINVAL;
-    if ( sscanf(page, "%d", &new_value) != 1 )
-        goto out;
+    if ( sscanf(buf, "%d", &new_value) != 1 )
+        return -EINVAL;
 
     if ( new_value != flask_enforcing )
     {
@@ -428,13 +442,11 @@ static int flask_security_setenforce(cha
     length = count;
 
 out:
-    xfree(page);
-    return length;
-}
-
-static int flask_security_context(char *buf, int count)
-{
-    char *page = NULL;
+    return length;
+}
+
+static int flask_security_context(char *buf, uint32_t count)
+{
     u32 sid;
     int length;
 
@@ -442,35 +454,19 @@ static int flask_security_context(char *
     if ( length )
         goto out;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-        return -ENOMEM;
-
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-        return -ENOMEM;
-    memset(page, 0, PAGE_SIZE);
-    length = -EFAULT;
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
-    length = security_context_to_sid(page, count, &sid);
-    if ( length < 0 )
-        goto out;
-
-    memset(page, 0, PAGE_SIZE);
-    length = snprintf(page, PAGE_SIZE, "%u", sid);
-
-    if ( copy_to_user(buf, page, count) )
-        length = -EFAULT;
-
-out:
-    xfree(page);
-    return length;
-}
-
-static int flask_security_sid(char *buf, int count)
-{
-    char *page = NULL;
+    length = security_context_to_sid(buf, count, &sid);
+    if ( length < 0 )
+        goto out;
+
+    memset(buf, 0, count);
+    length = snprintf(buf, count, "%u", sid);
+
+out:
+    return length;
+}
+
+static int flask_security_sid(char *buf, uint32_t count)
+{
     char *context;
     u32 sid;
     u32 len;
@@ -480,31 +476,20 @@ static int flask_security_sid(char *buf,
     if ( length )
         goto out;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-        return -ENOMEM;
-
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-        return -ENOMEM;
-    memset(page, 0, PAGE_SIZE);
-    length = -EFAULT;
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
-    if ( sscanf(page, "%u", &sid) != 1 )
+    if ( sscanf(buf, "%u", &sid) != 1 )
         goto out;
 
     length = security_sid_to_context(sid, &context, &len);
     if ( length < 0 )
         goto out;
 
-    if ( copy_to_user(buf, context, len) )
-        length = -EFAULT;
-    
+    memset(buf, 0, count);
+    memcpy(buf, context, len);
+    length = len;
+
     xfree(context);
 
 out:
-    xfree(page);
     return length;
 }
 
@@ -534,24 +519,13 @@ int flask_disable(void)
     return 0;
 }
 
-static int flask_security_disable(char *buf, int count)
-{
-    char *page = NULL;
+static int flask_security_disable(char *buf, uint32_t count)
+{
     int length;
     int new_value;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-        return -ENOMEM;
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-        return -ENOMEM;
-    memset(page, 0, PAGE_SIZE);
-    length = -EFAULT;
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
     length = -EINVAL;
-    if ( sscanf(page, "%d", &new_value) != 1 )
+    if ( sscanf(buf, "%d", &new_value) != 1 )
         goto out;
 
     if ( new_value )
@@ -564,57 +538,35 @@ static int flask_security_disable(char *
     length = count;
 
 out:
-    xfree(page);
-    return length;
-}
-
-static int flask_security_setavc_threshold(char *buf, int count)
-{
-    char *page = NULL;
+    return length;
+}
+
+static int flask_security_setavc_threshold(char *buf, uint32_t count)
+{
     int ret;
     int new_value;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-    {
-        ret = -ENOMEM;
-        goto out;
-    }
-
-    page = (char*)xmalloc_bytes(PAGE_SIZE);
-    if (!page)
-        return -ENOMEM;
-    memset(page, 0, PAGE_SIZE);
-
-    if ( copy_from_user(page, buf, count) )
-    {
-        ret = -EFAULT;
-        goto out_free;
-    }
-
-    if ( sscanf(page, "%u", &new_value) != 1 )
+    if ( sscanf(buf, "%u", &new_value) != 1 )
     {
         ret = -EINVAL;
-        goto out_free;
+        goto out;
     }
 
     if ( new_value != avc_cache_threshold )
     {
         ret = domain_has_security(current->domain, SECURITY__SETSECPARAM);
         if ( ret )
-            goto out_free;
+            goto out;
         avc_cache_threshold = new_value;
     }
     ret = count;
 
-out_free:
-    xfree(page);
 out:
     return ret;
 }
 
-static int flask_security_set_bool(char *buf, int count)
-{
-    char *page = NULL;
+static int flask_security_set_bool(char *buf, uint32_t count)
+{
     int length = -EFAULT;
     int i, new_value;
 
@@ -624,25 +576,8 @@ static int flask_security_set_bool(char 
     if ( length )
         goto out;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-    {
-        length = -ENOMEM;
-        goto out;
-    }
-
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-    {
-        length = -ENOMEM;
-        goto out;
-    }
-    memset(page, 0, PAGE_SIZE);
-
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
     length = -EINVAL;
-    if ( sscanf(page, "%d %d", &i, &new_value) != 2 )
+    if ( sscanf(buf, "%d %d", &i, &new_value) != 2 )
         goto out;
 
     if ( new_value )
@@ -655,14 +590,11 @@ static int flask_security_set_bool(char 
 
 out:
     spin_unlock(&sel_sem);
-    if ( page )
-        xfree(page);
-    return length;
-}
-
-static int flask_security_commit_bools(char *buf, int count)
-{
-    char *page = NULL;
+    return length;
+}
+
+static int flask_security_commit_bools(char *buf, uint32_t count)
+{
     int length = -EFAULT;
     int new_value;
 
@@ -672,25 +604,8 @@ static int flask_security_commit_bools(c
     if ( length )
         goto out;
 
-    if ( count < 0 || count >= PAGE_SIZE )
-    {
-        length = -ENOMEM;
-        goto out;
-    }
-
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-    {
-        length = -ENOMEM;
-        goto out;
-    }
-    memset(page, 0, PAGE_SIZE);
-
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
     length = -EINVAL;
-    if ( sscanf(page, "%d", &new_value) != 1 )
+    if ( sscanf(buf, "%d", &new_value) != 1 )
         goto out;
 
     if ( new_value )
@@ -700,40 +615,18 @@ static int flask_security_commit_bools(c
 
 out:
     spin_unlock(&sel_sem);
-    if ( page )
-        xfree(page);
-    return length;
-}
-
-static int flask_security_get_bool(char *buf, int count)
-{
-    char *page = NULL;
+    return length;
+}
+
+static int flask_security_get_bool(char *buf, uint32_t count)
+{
     int length;
     int i, cur_enforcing;
     
     spin_lock(&sel_sem);
     
-    length = -EFAULT;
-
-    if ( count < 0 || count > PAGE_SIZE )
-    {
-        length = -EINVAL;
-        goto out;
-    }
-
-    page = (char *)xmalloc_bytes(PAGE_SIZE);
-    if ( !page )
-    {
-        length = -ENOMEM;
-        goto out;
-    }
-    memset(page, 0, PAGE_SIZE);
-
-    if ( copy_from_user(page, buf, count) )
-        goto out;
-
     length = -EINVAL;
-    if ( sscanf(page, "%d", &i) != 1 )
+    if ( sscanf(buf, "%d", &i) != 1 )
         goto out;
 
     cur_enforcing = security_get_bool_value(i);
@@ -743,18 +636,12 @@ static int flask_security_get_bool(char 
         goto out;
     }
 
-    length = snprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
+    memset(buf, 0, count);
+    length = snprintf(buf, count, "%d %d", cur_enforcing,
                 bool_pending_values[i]);
-    if ( length < 0 )
-        goto out;
-
-    if ( copy_to_user(buf, page, length) )
-        length = -EFAULT;
 
 out:
     spin_unlock(&sel_sem);
-    if ( page )
-        xfree(page);
     return length;
 }
 
@@ -786,7 +673,7 @@ out:
 
 #ifdef FLASK_AVC_STATS
 
-static int flask_security_avc_cachestats(char *buf, int count)
+static int flask_security_avc_cachestats(char *buf, uint32_t count)
 {
     char *page = NULL;
     int len = 0;
@@ -802,9 +689,15 @@ static int flask_security_avc_cachestats
 
     len = snprintf(page, PAGE_SIZE, "lookups hits misses allocations reclaims "
                                                                    "frees\n");
+    if ( len > count ) {
+        length = -EINVAL;
+        goto out;
+    }
+    
     memcpy(buf, page, len);
     buf += len;
     length += len;
+    count -= len;
 
     for ( cpu = idx; cpu < NR_CPUS; ++cpu )
     {
@@ -816,22 +709,27 @@ static int flask_security_avc_cachestats
         len = snprintf(page, PAGE_SIZE, "%u %u %u %u %u %u\n", st->lookups,
                                        st->hits, st->misses, st->allocations,
                                                        st->reclaims, 
st->frees);
+        if ( len > count ) {
+            length = -EINVAL;
+            goto out;
+        }
         memcpy(buf, page, len);
         buf += len;
         length += len;
-    }
-
+        count -= len;
+    }
+
+out:
     xfree(page);    
     return length;
 }
 
 #endif
 
-static int flask_security_load(char *buf, int count)
+static int flask_security_load(char *buf, uint32_t count)
 {
     int ret;
     int length;
-    void *data = NULL;
 
     spin_lock(&sel_sem);
 
@@ -839,18 +737,7 @@ static int flask_security_load(char *buf
     if ( length )
         goto out;
 
-    if ( (count < 0) || (count > 64 * 1024 * 1024) 
-                               || (data = xmalloc_array(char, count)) == NULL )
-    {
-        length = -ENOMEM;
-        goto out;
-    }
-
-    length = -EFAULT;
-    if ( copy_from_user(data, buf, count) != 0 )
-        goto out;
-
-    length = security_load_policy(data, count);
+    length = security_load_policy(buf, count);
     if ( length )
         goto out;
 
@@ -862,7 +749,6 @@ static int flask_security_load(char *buf
 
 out:
     spin_unlock(&sel_sem);
-    xfree(data);
     return length;
 }
 
@@ -871,188 +757,156 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op
     flask_op_t curop, *op = &curop;
     int rc = 0;
     int length = 0;
-    char *page = NULL;
+    char *arg = NULL;
 
     if ( copy_from_guest(op, u_flask_op, 1) )
         return -EFAULT;
 
+    if ( op->cmd > FLASK_LAST)
+        return -EINVAL;
+
+    if ( op->size > MAX_POLICY_SIZE )
+        return -EINVAL;
+
+    if ( (op->buf == NULL && op->size != 0) || 
+                                    (op->buf != NULL && op->size == 0) )
+        return -EINVAL;
+
+    arg = xmalloc_bytes(op->size + 1);
+    if ( !arg )
+        return -ENOMEM;
+
+    memset(arg, 0, op->size + 1);
+
+    if ( (FLASK_COPY_IN&(1UL<<op->cmd)) && op->buf != NULL && 
+           copy_from_guest(arg, guest_handle_from_ptr(op->buf, char), 
op->size) )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
+
     switch ( op->cmd )
     {
 
     case FLASK_LOAD:
     {
-        length = flask_security_load(op->buf, op->size);
+        length = flask_security_load(arg, op->size);
     }
     break;
     
     case FLASK_GETENFORCE:
     {
-        page = (char *)xmalloc_bytes(PAGE_SIZE);
-        if ( !page )
-            return -ENOMEM;
-        memset(page, 0, PAGE_SIZE);
-        
-        length = snprintf(page, PAGE_SIZE, "%d", flask_enforcing);
-        
-        if ( copy_to_user(op->buf, page, length) )
-        {
-            rc = -EFAULT;
-            goto out;
-        }
+        length = snprintf(arg, op->size, "%d", flask_enforcing);
     }
     break;    
 
     case FLASK_SETENFORCE:
     {
-        length = flask_security_setenforce(op->buf, op->size);
+        length = flask_security_setenforce(arg, op->size);
     }
     break;    
 
     case FLASK_CONTEXT_TO_SID:
     {
-        length = flask_security_context(op->buf, op->size);
+        length = flask_security_context(arg, op->size);
     }
     break;    
 
     case FLASK_SID_TO_CONTEXT:
     {
-        length = flask_security_sid(op->buf, op->size);
+        length = flask_security_sid(arg, op->size);
     }
     break; 
 
     case FLASK_ACCESS:
     {
-        length = flask_security_access(op->buf, op->size);
+        length = flask_security_access(arg, op->size);
     }
     break;    
 
     case FLASK_CREATE:
     {
-        length = flask_security_create(op->buf, op->size);
+        length = flask_security_create(arg, op->size);
     }
     break;    
 
     case FLASK_RELABEL:
     {
-        length = flask_security_relabel(op->buf, op->size);
+        length = flask_security_relabel(arg, op->size);
     }
     break;
 
     case FLASK_USER:
     {
-        length = flask_security_user(op->buf, op->size);
+        length = flask_security_user(arg, op->size);
     }
     break;    
 
     case FLASK_POLICYVERS:
     {
-        page = (char *)xmalloc_bytes(PAGE_SIZE);
-        if ( !page )
-            return -ENOMEM;
-        memset(page, 0, PAGE_SIZE);
-
-        length = snprintf(page, PAGE_SIZE, "%d", POLICYDB_VERSION_MAX);
-
-        if ( copy_to_user(op->buf, page, length) )
-        {
-            rc = -EFAULT;
-            goto out;
-        }
+        length = snprintf(arg, op->size, "%d", POLICYDB_VERSION_MAX);
     }
     break;    
 
     case FLASK_GETBOOL:
     {
-        length = flask_security_get_bool(op->buf, op->size);
+        length = flask_security_get_bool(arg, op->size);
     }
     break;
 
     case FLASK_SETBOOL:
     {
-        length = flask_security_set_bool(op->buf, op->size);
+        length = flask_security_set_bool(arg, op->size);
     }
     break;
 
     case FLASK_COMMITBOOLS:
     {
-        length = flask_security_commit_bools(op->buf, op->size);
+        length = flask_security_commit_bools(arg, op->size);
     }
     break;
 
     case FLASK_MLS:
     {
-        page = (char *)xmalloc_bytes(PAGE_SIZE);
-        if ( !page )
-            return -ENOMEM;
-        memset(page, 0, PAGE_SIZE);
-
-        length = snprintf(page, PAGE_SIZE, "%d", flask_mls_enabled);
-
-        if ( copy_to_user(op->buf, page, length) )
-        {
-            rc = -EFAULT;
-            goto out;
-        }
+        length = snprintf(arg, op->size, "%d", flask_mls_enabled);
     }
     break;    
 
     case FLASK_DISABLE:
     {
-        length = flask_security_disable(op->buf, op->size);
+        length = flask_security_disable(arg, op->size);
     }
     break;    
 
     case FLASK_GETAVC_THRESHOLD:
     {
-        page = (char *)xmalloc_bytes(PAGE_SIZE);
-        if ( !page )
-            return -ENOMEM;
-        memset(page, 0, PAGE_SIZE);
-
-        length = snprintf(page, PAGE_SIZE, "%d", avc_cache_threshold);
-
-        if ( copy_to_user(op->buf, page, length) )
-        {
-            rc = -EFAULT;
-            goto out;
-        }
+        length = snprintf(arg, op->size, "%d", avc_cache_threshold);
     }
     break;
 
     case FLASK_SETAVC_THRESHOLD:
     {
-        length = flask_security_setavc_threshold(op->buf, op->size);
+        length = flask_security_setavc_threshold(arg, op->size);
     }
     break;
 
     case FLASK_AVC_HASHSTATS:
     {
-        page = (char *)xmalloc_bytes(PAGE_SIZE);
-        if ( !page )
-            return -ENOMEM;
-        memset(page, 0, PAGE_SIZE);
-
-        length = avc_get_hash_stats(page);
-
-        if ( copy_to_user(op->buf, page, length) )
-        {
-            rc = -EFAULT;
-            goto out;
-        }
+        length = avc_get_hash_stats(arg, op->size);
     }
     break;
 
 #ifdef FLASK_AVC_STATS    
     case FLASK_AVC_CACHESTATS:
     {
-        length = flask_security_avc_cachestats(op->buf, op->size);
+        length = flask_security_avc_cachestats(arg, op->size);
     }
     break;
-#endif    
+#endif
 
     case FLASK_MEMBER:
     {
-        length = flask_security_member(op->buf, op->size);
+        length = flask_security_member(arg, op->size);
     }
     break;    
 
@@ -1067,13 +921,19 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op
         rc = length;
         goto out;
     }
+    
+    if ( (FLASK_COPY_OUT&(1UL<<op->cmd)) && op->buf != NULL && 
+             copy_to_guest(guest_handle_from_ptr(op->buf, char), arg, 
op->size) )
+    {
+        rc = -EFAULT;
+        goto out;
+    }
+
     op->size = length;
     if ( copy_to_guest(u_flask_op, op, 1) )
         rc = -EFAULT;
 
 out:
-    if ( page )
-        xfree(page);
+    xfree(arg);
     return rc;
 }
-
diff -r dbeddb76c2b9 -r fa66b33f975a xen/xsm/flask/include/avc.h
--- a/xen/xsm/flask/include/avc.h       Mon Jul 21 09:40:37 2008 +0100
+++ b/xen/xsm/flask/include/avc.h       Mon Jul 21 09:41:36 2008 +0100
@@ -95,7 +95,7 @@ int avc_add_callback(int (*callback)(u32
                                     u32 ssid, u32 tsid, u16 tclass, u32 perms);
 
 /* Exported to selinuxfs */
-int avc_get_hash_stats(char *page);
+int avc_get_hash_stats(char *buf, uint32_t size);
 extern unsigned int avc_cache_threshold;
 
 #ifdef FLASK_AVC_STATS

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

<Prev in Thread] Current Thread [Next in Thread>
  • [Xen-changelog] [xen-unstable] [XSM][FLASK] Argument handling bugs in XSM:FLASK, Xen patchbot-unstable <=