diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2008-07-21 09:41:36 +0100 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2008-07-21 09:41:36 +0100 |
commit | 2325e6972157eaaad9af69892fd0fd70154c04ae (patch) | |
tree | 027f355dc5467bf6989981e7527c86618bdc76aa | |
parent | 39f22f5e08c8d7ff61d44eb04befb1c122ca763c (diff) | |
download | xen-2325e6972157eaaad9af69892fd0fd70154c04ae.tar.gz xen-2325e6972157eaaad9af69892fd0fd70154c04ae.tar.bz2 xen-2325e6972157eaaad9af69892fd0fd70154c04ae.zip |
[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@alpha.ncsc.mil>
-rw-r--r-- | tools/flask/libflask/flask_op.c | 6 | ||||
-rw-r--r-- | tools/flask/libflask/include/flask.h | 6 | ||||
-rw-r--r-- | xen/arch/x86/time.c | 54 | ||||
-rw-r--r-- | xen/include/public/xsm/flask_op.h | 8 | ||||
-rw-r--r-- | xen/xsm/flask/avc.c | 4 | ||||
-rw-r--r-- | xen/xsm/flask/flask_op.c | 466 | ||||
-rw-r--r-- | xen/xsm/flask/include/avc.h | 2 |
7 files changed, 229 insertions, 317 deletions
diff --git a/tools/flask/libflask/flask_op.c b/tools/flask/libflask/flask_op.c index c0ca22d0dd..396c0814a8 100644 --- a/tools/flask/libflask/flask_op.c +++ b/tools/flask/libflask/flask_op.c @@ -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; diff --git a/tools/flask/libflask/include/flask.h b/tools/flask/libflask/include/flask.h index 5973933ac8..5241f7a2a0 100644 --- a/tools/flask/libflask/include/flask.h +++ b/tools/flask/libflask/include/flask.h @@ -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 --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index aac0dde782..24df5bcbe4 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -481,6 +481,46 @@ static int init_pmtimer(struct platform_timesource *pts) } /************************************************************ + * 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); diff --git a/xen/include/public/xsm/flask_op.h b/xen/include/public/xsm/flask_op.h index af2090994c..7882d73cea 100644 --- a/xen/include/public/xsm/flask_op.h +++ b/xen/include/public/xsm/flask_op.h @@ -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 --git a/xen/xsm/flask/avc.c b/xen/xsm/flask/avc.c index cbbb7e5d7a..218b20d4c4 100644 --- a/xen/xsm/flask/avc.c +++ b/xen/xsm/flask/avc.c @@ -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 --git a/xen/xsm/flask/flask_op.c b/xen/xsm/flask/flask_op.c index 3cd58f8d75..3b583d122c 100644 --- a/xen/xsm/flask/flask_op.c +++ b/xen/xsm/flask/flask_op.c @@ -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; } - diff --git a/xen/xsm/flask/include/avc.h b/xen/xsm/flask/include/avc.h index f1e1c03b27..d11ecff990 100644 --- a/xen/xsm/flask/include/avc.h +++ b/xen/xsm/flask/include/avc.h @@ -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 |