[XSM][FLASK] Argument handling bugs in XSM:FLASK
authorKeir Fraser <keir.fraser@citrix.com>
Mon, 21 Jul 2008 08:41:36 +0000 (09:41 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Mon, 21 Jul 2008 08:41:36 +0000 (09:41 +0100)
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@alpha.ncsc.mil>
tools/flask/libflask/flask_op.c
tools/flask/libflask/include/flask.h
xen/arch/x86/time.c
xen/include/public/xsm/flask_op.h
xen/xsm/flask/avc.c
xen/xsm/flask/flask_op.c
xen/xsm/flask/include/avc.h

index c0ca22d0dddbdd9f10cfe72ec60859041db988a2..396c0814a88043c403ec696e0d10b554ee8bd075 100644 (file)
@@ -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, int size)
     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, char *buf, int size, uint32_t *sid)
     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;
index 5973933ac8a6f5fa04ac07f0fcb60a163adf3872..5241f7a2a0086db17b85bbcbefaa64aa5677bf63 100644 (file)
@@ -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__ */
index aac0dde782f889e62132005eb70ea461bb4c3614..24df5bcbe4dfbf953af1d067803f349026bb3603 100644 (file)
@@ -480,6 +480,46 @@ static int init_pmtimer(struct platform_timesource *pts)
     return 1;
 }
 
+/************************************************************
+ * 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,11 +1047,11 @@ 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*/
     if ( cpuid_edx(0x80000007) & (1U<<8) )
@@ -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);
index af2090994cda25aecf9a69a2c9778b36fd4a8bd4..7882d73cea9b94499e3d5e127de71e554889533d 100644 (file)
 #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);
index cbbb7e5d7aedfd5f8ffa7a77ef2edce02ae958bf..218b20d4c404d9a2c647b109d9c40a4672f08910 100644 (file)
@@ -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);
index 3cd58f8d75d32b1beddb05484621dce9319565fc..3b583d122cf30737e33b741f4c53234cf57b7b61 100644 (file)
@@ -29,6 +29,43 @@ int flask_enabled = 1;
 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 domain *d, u32 perms)
                                                                 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, int size)
         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, int size)
     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, int size)
         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,17 +218,18 @@ static int flask_security_relabel(char *buf, int size)
     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:
@@ -198,7 +239,7 @@ out:
     return length;
 }
 
-static int flask_security_create(char *buf, int size)
+static int flask_security_create(char *buf, uint32_t size)
 {
     char *scon, *tcon;
     u32 ssid, tsid, newsid;
@@ -242,7 +283,7 @@ static int flask_security_create(char *buf, int size)
     if ( length < 0 )    
         goto out2;
 
-    if ( len > PAGE_SIZE )
+    if ( len > size )
     {
         printk( "%s:  context size (%u) exceeds payload "
                 "max\n", __FUNCTION__, len);
@@ -250,9 +291,8 @@ static int flask_security_create(char *buf, int size)
         goto out3;
     }
 
-    if ( copy_to_user(buf, newcon, len) )
-        len = -EFAULT;
-
+    memset(buf, 0, size);
+    memcpy(buf, newcon, len);
     length = len;
         
 out3:
@@ -264,9 +304,8 @@ out:
     return length;
 }
 
-static int flask_security_access(char *buf, int size)
+static int flask_security_access(char *buf, uint32_t size)
 {
-    char *page = NULL;
     char *scon, *tcon;
     u32 ssid, tsid;
     u16 tclass;
@@ -305,23 +344,12 @@ static int flask_security_access(char *buf, int size)
     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 *buf, int size)
     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 *buf, int size)
         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)
+static int flask_security_setenforce(char *buf, uint32_t count)
 {
-    char *page = NULL;
     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(char *buf, int count)
     length = count;
 
 out:
-    xfree(page);
     return length;
 }
 
-static int flask_security_context(char *buf, int count)
+static int flask_security_context(char *buf, uint32_t count)
 {
-    char *page = NULL;
     u32 sid;
     int length;
 
@@ -442,35 +454,19 @@ static int flask_security_context(char *buf, int count)
     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);
+    length = security_context_to_sid(buf, 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;
+    memset(buf, 0, count);
+    length = snprintf(buf, count, "%u", sid);
 
 out:
-    xfree(page);
     return length;
 }
 
-static int flask_security_sid(char *buf, int count)
+static int flask_security_sid(char *buf, uint32_t count)
 {
-    char *page = NULL;
     char *context;
     u32 sid;
     u32 len;
@@ -480,31 +476,20 @@ static int flask_security_sid(char *buf, int count)
     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)
+static int flask_security_disable(char *buf, uint32_t count)
 {
-    char *page = NULL;
     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 *buf, int count)
     length = count;
 
 out:
-    xfree(page);
     return length;
 }
 
-static int flask_security_setavc_threshold(char *buf, int count)
+static int flask_security_setavc_threshold(char *buf, uint32_t count)
 {
-    char *page = NULL;
     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)
+static int flask_security_set_bool(char *buf, uint32_t count)
 {
-    char *page = NULL;
     int length = -EFAULT;
     int i, new_value;
 
@@ -624,25 +576,8 @@ static int flask_security_set_bool(char *buf, int count)
     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 *buf, int count)
 
 out:
     spin_unlock(&sel_sem);
-    if ( page )
-        xfree(page);
     return length;
 }
 
-static int flask_security_commit_bools(char *buf, int count)
+static int flask_security_commit_bools(char *buf, uint32_t count)
 {
-    char *page = NULL;
     int length = -EFAULT;
     int new_value;
 
@@ -672,25 +604,8 @@ static int flask_security_commit_bools(char *buf, int count)
     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(char *buf, int count)
 
 out:
     spin_unlock(&sel_sem);
-    if ( page )
-        xfree(page);
     return length;
 }
 
-static int flask_security_get_bool(char *buf, int count)
+static int flask_security_get_bool(char *buf, uint32_t count)
 {
-    char *page = NULL;
     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 *buf, int count)
         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(char *buf, int count)
 
     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(char *buf, int count)
         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, int count)
     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, int count)
 
 out:
     spin_unlock(&sel_sem);
-    xfree(data);
     return length;
 }
 
@@ -871,188 +757,156 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op_t) u_flask_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_t) u_flask_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;
 }
-
index f1e1c03b27b1031f9213540a6de7060d7420a49d..d11ecff990f7b98649fda63c2fcbad8a20b99c23 100644 (file)
@@ -95,7 +95,7 @@ int avc_add_callback(int (*callback)(u32 event, u32 ssid, u32 tsid,
                                     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