[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |