# 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
|