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

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



# 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


 


Rackspace

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