ia64/xen-unstable

changeset 18116:fa66b33f975a

[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>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jul 21 09:41:36 2008 +0100 (2008-07-21)
parents dbeddb76c2b9
children 217c8b6ebfab
files 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
line diff
     1.1 --- a/tools/flask/libflask/flask_op.c	Mon Jul 21 09:40:37 2008 +0100
     1.2 +++ b/tools/flask/libflask/flask_op.c	Mon Jul 21 09:41:36 2008 +0100
     1.3 @@ -22,7 +22,7 @@
     1.4  #include <flask.h>
     1.5  #include <xenctrl.h>
     1.6  
     1.7 -int flask_load(int xc_handle, char *buf, int size)
     1.8 +int flask_load(int xc_handle, char *buf, uint32_t size)
     1.9  {
    1.10      int err;
    1.11      flask_op_t op;
    1.12 @@ -37,7 +37,7 @@ int flask_load(int xc_handle, char *buf,
    1.13      return 0;
    1.14  }
    1.15  
    1.16 -int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid)
    1.17 +int flask_context_to_sid(int xc_handle, char *buf, uint32_t size, uint32_t *sid)
    1.18  {
    1.19      int err;
    1.20      flask_op_t op;
    1.21 @@ -54,7 +54,7 @@ int flask_context_to_sid(int xc_handle, 
    1.22      return 0;
    1.23  }
    1.24  
    1.25 -int flask_sid_to_context(int xc_handle, int sid, char *buf, int size)
    1.26 +int flask_sid_to_context(int xc_handle, int sid, char *buf, uint32_t size)
    1.27  {
    1.28      int err;
    1.29      flask_op_t op;
     2.1 --- a/tools/flask/libflask/include/flask.h	Mon Jul 21 09:40:37 2008 +0100
     2.2 +++ b/tools/flask/libflask/include/flask.h	Mon Jul 21 09:41:36 2008 +0100
     2.3 @@ -15,8 +15,8 @@
     2.4  #include <xen/xen.h>
     2.5  #include <xen/xsm/flask_op.h>
     2.6  
     2.7 -int flask_load(int xc_handle, char *buf, int size);
     2.8 -int flask_context_to_sid(int xc_handle, char *buf, int size, uint32_t *sid);
     2.9 -int flask_sid_to_context(int xc_handle, int sid, char *buf, int size);
    2.10 +int flask_load(int xc_handle, char *buf, uint32_t size);
    2.11 +int flask_context_to_sid(int xc_handle, char *buf, uint32_t size, uint32_t *sid);
    2.12 +int flask_sid_to_context(int xc_handle, int sid, char *buf, uint32_t size);
    2.13  
    2.14  #endif /* __FLASK_H__ */
     3.1 --- a/xen/arch/x86/time.c	Mon Jul 21 09:40:37 2008 +0100
     3.2 +++ b/xen/arch/x86/time.c	Mon Jul 21 09:41:36 2008 +0100
     3.3 @@ -481,6 +481,46 @@ static int init_pmtimer(struct platform_
     3.4  }
     3.5  
     3.6  /************************************************************
     3.7 + * PLATFORM TIMER 5: TSC
     3.8 + */
     3.9 +
    3.10 +#define platform_timer_is_tsc() (!strcmp(plt_src.name, "TSC"))
    3.11 +static u64 tsc_freq;
    3.12 +
    3.13 +static u64 read_tsc_count(void)
    3.14 +{
    3.15 +    u64 tsc;
    3.16 +    rdtscll(tsc);
    3.17 +    return tsc;
    3.18 +}
    3.19 +
    3.20 +static int init_tsctimer(struct platform_timesource *pts)
    3.21 +{
    3.22 +    unsigned int cpu;
    3.23 +
    3.24 +    /*
    3.25 +     * TODO: evaluate stability of TSC here, return 0 if not stable.
    3.26 +     * For now we assume all TSCs are synchronised and hence can all share
    3.27 +     * CPU 0's calibration values.
    3.28 +     */
    3.29 +    for_each_cpu ( cpu )
    3.30 +    {
    3.31 +        if ( cpu == 0 )
    3.32 +            continue;
    3.33 +        memcpy(&per_cpu(cpu_time, cpu),
    3.34 +               &per_cpu(cpu_time, 0),
    3.35 +               sizeof(struct cpu_time));
    3.36 +    }
    3.37 +
    3.38 +    pts->name = "TSC";
    3.39 +    pts->frequency = tsc_freq;
    3.40 +    pts->read_counter = read_tsc_count;
    3.41 +    pts->counter_bits = 64;
    3.42 +
    3.43 +    return 1;
    3.44 +}
    3.45 +
    3.46 +/************************************************************
    3.47   * GENERIC PLATFORM TIMER INFRASTRUCTURE
    3.48   */
    3.49  
    3.50 @@ -565,6 +605,8 @@ static void init_platform_timer(void)
    3.51              rc = init_cyclone(pts);
    3.52          else if ( !strcmp(opt_clocksource, "acpi") )
    3.53              rc = init_pmtimer(pts);
    3.54 +        else if ( !strcmp(opt_clocksource, "tsc") )
    3.55 +            rc = init_tsctimer(pts);
    3.56  
    3.57          if ( rc <= 0 )
    3.58              printk("WARNING: %s clocksource '%s'.\n",
    3.59 @@ -780,6 +822,10 @@ int cpu_frequency_change(u64 freq)
    3.60      struct cpu_time *t = &this_cpu(cpu_time);
    3.61      u64 curr_tsc;
    3.62  
    3.63 +    /* Nothing to do if TSC is platform timer. Assume it is constant-rate. */
    3.64 +    if ( platform_timer_is_tsc() )
    3.65 +        return 0;
    3.66 +
    3.67      /* Sanity check: CPU frequency allegedly dropping below 1MHz? */
    3.68      if ( freq < 1000000u )
    3.69      {
    3.70 @@ -978,6 +1024,9 @@ void init_percpu_time(void)
    3.71      unsigned long flags;
    3.72      s_time_t now;
    3.73  
    3.74 +    if ( platform_timer_is_tsc() )
    3.75 +        return;
    3.76 +
    3.77      local_irq_save(flags);
    3.78      rdtscll(t->local_tsc_stamp);
    3.79      now = !plt_src.read_counter ? 0 : read_platform_stime();
    3.80 @@ -998,11 +1047,11 @@ int __init init_xen_time(void)
    3.81  
    3.82      local_irq_disable();
    3.83  
    3.84 -    init_percpu_time();
    3.85 -
    3.86      stime_platform_stamp = 0;
    3.87      init_platform_timer();
    3.88  
    3.89 +    init_percpu_time();
    3.90 +
    3.91      /* check if TSC is invariant during deep C state
    3.92         this is a new feature introduced by Nehalem*/
    3.93      if ( cpuid_edx(0x80000007) & (1U<<8) )
    3.94 @@ -1019,6 +1068,7 @@ void __init early_time_init(void)
    3.95  {
    3.96      u64 tmp = init_pit_and_calibrate_tsc();
    3.97  
    3.98 +    tsc_freq = tmp;
    3.99      set_time_scale(&this_cpu(cpu_time).tsc_scale, tmp);
   3.100  
   3.101      do_div(tmp, 1000);
     4.1 --- a/xen/include/public/xsm/flask_op.h	Mon Jul 21 09:40:37 2008 +0100
     4.2 +++ b/xen/include/public/xsm/flask_op.h	Mon Jul 21 09:41:36 2008 +0100
     4.3 @@ -32,10 +32,12 @@
     4.4  #define FLASK_AVC_CACHESTATS    19
     4.5  #define FLASK_MEMBER            20
     4.6  
     4.7 +#define FLASK_LAST              FLASK_MEMBER
     4.8 +
     4.9  typedef struct flask_op {
    4.10 -    int   cmd;
    4.11 -    int   size;
    4.12 -    char *buf;
    4.13 +    uint32_t  cmd;
    4.14 +    uint32_t  size;
    4.15 +    char      *buf;
    4.16  } flask_op_t;
    4.17  
    4.18  DEFINE_XEN_GUEST_HANDLE(flask_op_t);
     5.1 --- a/xen/xsm/flask/avc.c	Mon Jul 21 09:40:37 2008 +0100
     5.2 +++ b/xen/xsm/flask/avc.c	Mon Jul 21 09:41:36 2008 +0100
     5.3 @@ -250,7 +250,7 @@ void __init avc_init(void)
     5.4      printk("AVC INITIALIZED\n");
     5.5  }
     5.6  
     5.7 -int avc_get_hash_stats(char *page)
     5.8 +int avc_get_hash_stats(char *buf, uint32_t size)
     5.9  {
    5.10      int i, chain_len, max_chain_len, slots_used;
    5.11      struct avc_node *node;
    5.12 @@ -274,7 +274,7 @@ int avc_get_hash_stats(char *page)
    5.13  
    5.14      rcu_read_unlock();
    5.15      
    5.16 -    return snprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
    5.17 +    return snprintf(buf, size, "entries: %d\nbuckets used: %d/%d\n"
    5.18                                  "longest chain: %d\n",
    5.19                                  atomic_read(&avc_cache.active_nodes),
    5.20                                  slots_used, AVC_CACHE_SLOTS, max_chain_len);
     6.1 --- a/xen/xsm/flask/flask_op.c	Mon Jul 21 09:40:37 2008 +0100
     6.2 +++ b/xen/xsm/flask/flask_op.c	Mon Jul 21 09:41:36 2008 +0100
     6.3 @@ -29,6 +29,43 @@ int flask_enabled = 1;
     6.4  integer_param("flask_enabled", flask_enabled);
     6.5  #endif
     6.6  
     6.7 +#define MAX_POLICY_SIZE 0x4000000
     6.8 +#define FLASK_COPY_IN \
     6.9 +    ( \
    6.10 +        1UL<<FLASK_LOAD | \
    6.11 +        1UL<<FLASK_SETENFORCE | \
    6.12 +        1UL<<FLASK_CONTEXT_TO_SID | \
    6.13 +        1UL<<FLASK_SID_TO_CONTEXT | \
    6.14 +        1UL<<FLASK_ACCESS | \
    6.15 +        1UL<<FLASK_CREATE | \
    6.16 +        1UL<<FLASK_RELABEL | \
    6.17 +        1UL<<FLASK_USER | \
    6.18 +        1UL<<FLASK_GETBOOL | \
    6.19 +        1UL<<FLASK_SETBOOL | \
    6.20 +        1UL<<FLASK_COMMITBOOLS | \
    6.21 +        1UL<<FLASK_DISABLE | \
    6.22 +        1UL<<FLASK_SETAVC_THRESHOLD | \
    6.23 +        1UL<<FLASK_MEMBER \
    6.24 +    )
    6.25 +
    6.26 +#define FLASK_COPY_OUT \
    6.27 +    ( \
    6.28 +        1UL<<FLASK_GETENFORCE | \
    6.29 +        1UL<<FLASK_CONTEXT_TO_SID | \
    6.30 +        1UL<<FLASK_SID_TO_CONTEXT | \
    6.31 +        1UL<<FLASK_ACCESS | \
    6.32 +        1UL<<FLASK_CREATE | \
    6.33 +        1UL<<FLASK_RELABEL | \
    6.34 +        1UL<<FLASK_USER | \
    6.35 +        1UL<<FLASK_POLICYVERS | \
    6.36 +        1UL<<FLASK_GETBOOL | \
    6.37 +        1UL<<FLASK_MLS | \
    6.38 +        1UL<<FLASK_GETAVC_THRESHOLD | \
    6.39 +        1UL<<FLASK_AVC_HASHSTATS | \
    6.40 +        1UL<<FLASK_AVC_CACHESTATS | \
    6.41 +        1UL<<FLASK_MEMBER \
    6.42 +    )
    6.43 +
    6.44  static DEFINE_SPINLOCK(sel_sem);
    6.45  
    6.46  /* global data for booleans */
    6.47 @@ -51,7 +88,7 @@ static int domain_has_security(struct do
    6.48                                                                  perms, NULL);
    6.49  }
    6.50  
    6.51 -static int flask_security_user(char *buf, int size)
    6.52 +static int flask_security_user(char *buf, uint32_t size)
    6.53  {
    6.54      char *page = NULL;
    6.55      char *con, *user, *ptr;
    6.56 @@ -82,12 +119,8 @@ static int flask_security_user(char *buf
    6.57          goto out2;
    6.58      memset(page, 0, PAGE_SIZE);
    6.59  
    6.60 -    length = -EFAULT;
    6.61 -    if ( copy_from_user(page, buf, size) )
    6.62 -        goto out2;
    6.63 -        
    6.64      length = -EINVAL;
    6.65 -    if ( sscanf(page, "%s %s", con, user) != 2 )
    6.66 +    if ( sscanf(buf, "%s %s", con, user) != 2 )
    6.67          goto out2;
    6.68  
    6.69      length = security_context_to_sid(con, strlen(con)+1, &sid);
    6.70 @@ -98,7 +131,6 @@ static int flask_security_user(char *buf
    6.71      if ( length < 0 )
    6.72          goto out2;
    6.73      
    6.74 -    memset(page, 0, PAGE_SIZE);
    6.75      length = snprintf(page, PAGE_SIZE, "%u", nsids) + 1;
    6.76      ptr = page + length;
    6.77      for ( i = 0; i < nsids; i++ )
    6.78 @@ -121,8 +153,16 @@ static int flask_security_user(char *buf
    6.79          length += len;
    6.80      }
    6.81      
    6.82 -    if ( copy_to_user(buf, page, length) )
    6.83 -        length = -EFAULT;
    6.84 +    if ( length > size )
    6.85 +    {
    6.86 +        printk( "%s:  context size (%u) exceeds payload "
    6.87 +                "max\n", __FUNCTION__, length);
    6.88 +        length = -ERANGE;
    6.89 +        goto out3;
    6.90 +    }
    6.91 +
    6.92 +    memset(buf, 0, size);
    6.93 +    memcpy(buf, page, length);
    6.94          
    6.95  out3:
    6.96      xfree(sids);
    6.97 @@ -135,7 +175,7 @@ out:
    6.98      return length;
    6.99  }
   6.100  
   6.101 -static int flask_security_relabel(char *buf, int size)
   6.102 +static int flask_security_relabel(char *buf, uint32_t size)
   6.103  {
   6.104      char *scon, *tcon;
   6.105      u32 ssid, tsid, newsid;
   6.106 @@ -178,17 +218,18 @@ static int flask_security_relabel(char *
   6.107      if ( length < 0 )
   6.108          goto out2;
   6.109              
   6.110 -    if ( len > PAGE_SIZE )
   6.111 +    if ( len > size )
   6.112      {
   6.113 +        printk( "%s:  context size (%u) exceeds payload "
   6.114 +                "max\n", __FUNCTION__, len);
   6.115          length = -ERANGE;
   6.116          goto out3;
   6.117      }
   6.118 -        
   6.119 -    if ( copy_to_user(buf, newcon, len) )
   6.120 -        len = -EFAULT;
   6.121  
   6.122 +    memset(buf, 0, size);
   6.123 +    memcpy(buf, newcon, len);
   6.124      length = len;
   6.125 -        
   6.126 +
   6.127  out3:
   6.128      xfree(newcon);
   6.129  out2:
   6.130 @@ -198,7 +239,7 @@ out:
   6.131      return length;
   6.132  }
   6.133  
   6.134 -static int flask_security_create(char *buf, int size)
   6.135 +static int flask_security_create(char *buf, uint32_t size)
   6.136  {
   6.137      char *scon, *tcon;
   6.138      u32 ssid, tsid, newsid;
   6.139 @@ -242,7 +283,7 @@ static int flask_security_create(char *b
   6.140      if ( length < 0 )    
   6.141          goto out2;
   6.142  
   6.143 -    if ( len > PAGE_SIZE )
   6.144 +    if ( len > size )
   6.145      {
   6.146          printk( "%s:  context size (%u) exceeds payload "
   6.147                  "max\n", __FUNCTION__, len);
   6.148 @@ -250,9 +291,8 @@ static int flask_security_create(char *b
   6.149          goto out3;
   6.150      }
   6.151  
   6.152 -    if ( copy_to_user(buf, newcon, len) )
   6.153 -        len = -EFAULT;
   6.154 -
   6.155 +    memset(buf, 0, size);
   6.156 +    memcpy(buf, newcon, len);
   6.157      length = len;
   6.158          
   6.159  out3:
   6.160 @@ -264,9 +304,8 @@ out:
   6.161      return length;
   6.162  }
   6.163  
   6.164 -static int flask_security_access(char *buf, int size)
   6.165 +static int flask_security_access(char *buf, uint32_t size)
   6.166  {
   6.167 -    char *page = NULL;
   6.168      char *scon, *tcon;
   6.169      u32 ssid, tsid;
   6.170      u16 tclass;
   6.171 @@ -305,23 +344,12 @@ static int flask_security_access(char *b
   6.172      if ( length < 0 )
   6.173          goto out2;
   6.174  
   6.175 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.176 -    if ( !page )
   6.177 -    {
   6.178 -        length = -ENOMEM;
   6.179 -        goto out2;
   6.180 -    }
   6.181 -
   6.182 -    memset(page, 0, PAGE_SIZE);
   6.183 -
   6.184 -    length = snprintf(page, PAGE_SIZE, "%x %x %x %x %u", 
   6.185 +    memset(buf, 0, size);
   6.186 +    length = snprintf(buf, size, "%x %x %x %x %u", 
   6.187                                          avd.allowed, avd.decided,
   6.188                                          avd.auditallow, avd.auditdeny, 
   6.189                                          avd.seqno);
   6.190                  
   6.191 -    if ( copy_to_user(buf, page, length) )
   6.192 -        length = -EFAULT;
   6.193 -        
   6.194  out2:
   6.195      xfree(tcon);
   6.196  out:
   6.197 @@ -329,7 +357,7 @@ out:
   6.198      return length;
   6.199  }
   6.200  
   6.201 -static int flask_security_member(char *buf, int size)
   6.202 +static int flask_security_member(char *buf, uint32_t size)
   6.203  {
   6.204      char *scon, *tcon;
   6.205      u32 ssid, tsid, newsid;
   6.206 @@ -373,7 +401,7 @@ static int flask_security_member(char *b
   6.207      if ( length < 0 )
   6.208          goto out2;
   6.209  
   6.210 -    if ( len > PAGE_SIZE )
   6.211 +    if ( len > size )
   6.212      {
   6.213          printk("%s:  context size (%u) exceeds payload "
   6.214                  "max\n", __FUNCTION__, len);
   6.215 @@ -381,9 +409,8 @@ static int flask_security_member(char *b
   6.216          goto out3;
   6.217      }
   6.218  
   6.219 -    if ( copy_to_user(buf, newcon, len) )
   6.220 -        len = -EFAULT;
   6.221 -
   6.222 +    memset(buf, 0, size);
   6.223 +    memcpy(buf, newcon, len);
   6.224      length = len;
   6.225  
   6.226  out3:
   6.227 @@ -395,26 +422,13 @@ out:
   6.228      return length;
   6.229  }
   6.230  
   6.231 -static int flask_security_setenforce(char *buf, int count)
   6.232 +static int flask_security_setenforce(char *buf, uint32_t count)
   6.233  {
   6.234 -    char *page = NULL;
   6.235      int length;
   6.236      int new_value;
   6.237  
   6.238 -    if ( count < 0 || count >= PAGE_SIZE )
   6.239 -        return -ENOMEM;
   6.240 -
   6.241 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.242 -    if ( !page )
   6.243 -        return -ENOMEM;
   6.244 -    memset(page, 0, PAGE_SIZE);
   6.245 -    length = -EFAULT;
   6.246 -    if ( copy_from_user(page, buf, count) )
   6.247 -        goto out;
   6.248 -
   6.249 -    length = -EINVAL;
   6.250 -    if ( sscanf(page, "%d", &new_value) != 1 )
   6.251 -        goto out;
   6.252 +    if ( sscanf(buf, "%d", &new_value) != 1 )
   6.253 +        return -EINVAL;
   6.254  
   6.255      if ( new_value != flask_enforcing )
   6.256      {
   6.257 @@ -428,13 +442,11 @@ static int flask_security_setenforce(cha
   6.258      length = count;
   6.259  
   6.260  out:
   6.261 -    xfree(page);
   6.262      return length;
   6.263  }
   6.264  
   6.265 -static int flask_security_context(char *buf, int count)
   6.266 +static int flask_security_context(char *buf, uint32_t count)
   6.267  {
   6.268 -    char *page = NULL;
   6.269      u32 sid;
   6.270      int length;
   6.271  
   6.272 @@ -442,35 +454,19 @@ static int flask_security_context(char *
   6.273      if ( length )
   6.274          goto out;
   6.275  
   6.276 -    if ( count < 0 || count >= PAGE_SIZE )
   6.277 -        return -ENOMEM;
   6.278 -
   6.279 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.280 -    if ( !page )
   6.281 -        return -ENOMEM;
   6.282 -    memset(page, 0, PAGE_SIZE);
   6.283 -    length = -EFAULT;
   6.284 -    if ( copy_from_user(page, buf, count) )
   6.285 -        goto out;
   6.286 -
   6.287 -    length = security_context_to_sid(page, count, &sid);
   6.288 +    length = security_context_to_sid(buf, count, &sid);
   6.289      if ( length < 0 )
   6.290          goto out;
   6.291  
   6.292 -    memset(page, 0, PAGE_SIZE);
   6.293 -    length = snprintf(page, PAGE_SIZE, "%u", sid);
   6.294 -
   6.295 -    if ( copy_to_user(buf, page, count) )
   6.296 -        length = -EFAULT;
   6.297 +    memset(buf, 0, count);
   6.298 +    length = snprintf(buf, count, "%u", sid);
   6.299  
   6.300  out:
   6.301 -    xfree(page);
   6.302      return length;
   6.303  }
   6.304  
   6.305 -static int flask_security_sid(char *buf, int count)
   6.306 +static int flask_security_sid(char *buf, uint32_t count)
   6.307  {
   6.308 -    char *page = NULL;
   6.309      char *context;
   6.310      u32 sid;
   6.311      u32 len;
   6.312 @@ -480,31 +476,20 @@ static int flask_security_sid(char *buf,
   6.313      if ( length )
   6.314          goto out;
   6.315  
   6.316 -    if ( count < 0 || count >= PAGE_SIZE )
   6.317 -        return -ENOMEM;
   6.318 -
   6.319 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.320 -    if ( !page )
   6.321 -        return -ENOMEM;
   6.322 -    memset(page, 0, PAGE_SIZE);
   6.323 -    length = -EFAULT;
   6.324 -    if ( copy_from_user(page, buf, count) )
   6.325 -        goto out;
   6.326 -
   6.327 -    if ( sscanf(page, "%u", &sid) != 1 )
   6.328 +    if ( sscanf(buf, "%u", &sid) != 1 )
   6.329          goto out;
   6.330  
   6.331      length = security_sid_to_context(sid, &context, &len);
   6.332      if ( length < 0 )
   6.333          goto out;
   6.334  
   6.335 -    if ( copy_to_user(buf, context, len) )
   6.336 -        length = -EFAULT;
   6.337 -    
   6.338 +    memset(buf, 0, count);
   6.339 +    memcpy(buf, context, len);
   6.340 +    length = len;
   6.341 +
   6.342      xfree(context);
   6.343  
   6.344  out:
   6.345 -    xfree(page);
   6.346      return length;
   6.347  }
   6.348  
   6.349 @@ -534,24 +519,13 @@ int flask_disable(void)
   6.350      return 0;
   6.351  }
   6.352  
   6.353 -static int flask_security_disable(char *buf, int count)
   6.354 +static int flask_security_disable(char *buf, uint32_t count)
   6.355  {
   6.356 -    char *page = NULL;
   6.357      int length;
   6.358      int new_value;
   6.359  
   6.360 -    if ( count < 0 || count >= PAGE_SIZE )
   6.361 -        return -ENOMEM;
   6.362 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.363 -    if ( !page )
   6.364 -        return -ENOMEM;
   6.365 -    memset(page, 0, PAGE_SIZE);
   6.366 -    length = -EFAULT;
   6.367 -    if ( copy_from_user(page, buf, count) )
   6.368 -        goto out;
   6.369 -
   6.370      length = -EINVAL;
   6.371 -    if ( sscanf(page, "%d", &new_value) != 1 )
   6.372 +    if ( sscanf(buf, "%d", &new_value) != 1 )
   6.373          goto out;
   6.374  
   6.375      if ( new_value )
   6.376 @@ -564,57 +538,35 @@ static int flask_security_disable(char *
   6.377      length = count;
   6.378  
   6.379  out:
   6.380 -    xfree(page);
   6.381      return length;
   6.382  }
   6.383  
   6.384 -static int flask_security_setavc_threshold(char *buf, int count)
   6.385 +static int flask_security_setavc_threshold(char *buf, uint32_t count)
   6.386  {
   6.387 -    char *page = NULL;
   6.388      int ret;
   6.389      int new_value;
   6.390  
   6.391 -    if ( count < 0 || count >= PAGE_SIZE )
   6.392 -    {
   6.393 -        ret = -ENOMEM;
   6.394 -        goto out;
   6.395 -    }
   6.396 -
   6.397 -    page = (char*)xmalloc_bytes(PAGE_SIZE);
   6.398 -    if (!page)
   6.399 -        return -ENOMEM;
   6.400 -    memset(page, 0, PAGE_SIZE);
   6.401 -
   6.402 -    if ( copy_from_user(page, buf, count) )
   6.403 -    {
   6.404 -        ret = -EFAULT;
   6.405 -        goto out_free;
   6.406 -    }
   6.407 -
   6.408 -    if ( sscanf(page, "%u", &new_value) != 1 )
   6.409 +    if ( sscanf(buf, "%u", &new_value) != 1 )
   6.410      {
   6.411          ret = -EINVAL;
   6.412 -        goto out_free;
   6.413 +        goto out;
   6.414      }
   6.415  
   6.416      if ( new_value != avc_cache_threshold )
   6.417      {
   6.418          ret = domain_has_security(current->domain, SECURITY__SETSECPARAM);
   6.419          if ( ret )
   6.420 -            goto out_free;
   6.421 +            goto out;
   6.422          avc_cache_threshold = new_value;
   6.423      }
   6.424      ret = count;
   6.425  
   6.426 -out_free:
   6.427 -    xfree(page);
   6.428  out:
   6.429      return ret;
   6.430  }
   6.431  
   6.432 -static int flask_security_set_bool(char *buf, int count)
   6.433 +static int flask_security_set_bool(char *buf, uint32_t count)
   6.434  {
   6.435 -    char *page = NULL;
   6.436      int length = -EFAULT;
   6.437      int i, new_value;
   6.438  
   6.439 @@ -624,25 +576,8 @@ static int flask_security_set_bool(char 
   6.440      if ( length )
   6.441          goto out;
   6.442  
   6.443 -    if ( count < 0 || count >= PAGE_SIZE )
   6.444 -    {
   6.445 -        length = -ENOMEM;
   6.446 -        goto out;
   6.447 -    }
   6.448 -
   6.449 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.450 -    if ( !page )
   6.451 -    {
   6.452 -        length = -ENOMEM;
   6.453 -        goto out;
   6.454 -    }
   6.455 -    memset(page, 0, PAGE_SIZE);
   6.456 -
   6.457 -    if ( copy_from_user(page, buf, count) )
   6.458 -        goto out;
   6.459 -
   6.460      length = -EINVAL;
   6.461 -    if ( sscanf(page, "%d %d", &i, &new_value) != 2 )
   6.462 +    if ( sscanf(buf, "%d %d", &i, &new_value) != 2 )
   6.463          goto out;
   6.464  
   6.465      if ( new_value )
   6.466 @@ -655,14 +590,11 @@ static int flask_security_set_bool(char 
   6.467  
   6.468  out:
   6.469      spin_unlock(&sel_sem);
   6.470 -    if ( page )
   6.471 -        xfree(page);
   6.472      return length;
   6.473  }
   6.474  
   6.475 -static int flask_security_commit_bools(char *buf, int count)
   6.476 +static int flask_security_commit_bools(char *buf, uint32_t count)
   6.477  {
   6.478 -    char *page = NULL;
   6.479      int length = -EFAULT;
   6.480      int new_value;
   6.481  
   6.482 @@ -672,25 +604,8 @@ static int flask_security_commit_bools(c
   6.483      if ( length )
   6.484          goto out;
   6.485  
   6.486 -    if ( count < 0 || count >= PAGE_SIZE )
   6.487 -    {
   6.488 -        length = -ENOMEM;
   6.489 -        goto out;
   6.490 -    }
   6.491 -
   6.492 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.493 -    if ( !page )
   6.494 -    {
   6.495 -        length = -ENOMEM;
   6.496 -        goto out;
   6.497 -    }
   6.498 -    memset(page, 0, PAGE_SIZE);
   6.499 -
   6.500 -    if ( copy_from_user(page, buf, count) )
   6.501 -        goto out;
   6.502 -
   6.503      length = -EINVAL;
   6.504 -    if ( sscanf(page, "%d", &new_value) != 1 )
   6.505 +    if ( sscanf(buf, "%d", &new_value) != 1 )
   6.506          goto out;
   6.507  
   6.508      if ( new_value )
   6.509 @@ -700,40 +615,18 @@ static int flask_security_commit_bools(c
   6.510  
   6.511  out:
   6.512      spin_unlock(&sel_sem);
   6.513 -    if ( page )
   6.514 -        xfree(page);
   6.515      return length;
   6.516  }
   6.517  
   6.518 -static int flask_security_get_bool(char *buf, int count)
   6.519 +static int flask_security_get_bool(char *buf, uint32_t count)
   6.520  {
   6.521 -    char *page = NULL;
   6.522      int length;
   6.523      int i, cur_enforcing;
   6.524      
   6.525      spin_lock(&sel_sem);
   6.526      
   6.527 -    length = -EFAULT;
   6.528 -
   6.529 -    if ( count < 0 || count > PAGE_SIZE )
   6.530 -    {
   6.531 -        length = -EINVAL;
   6.532 -        goto out;
   6.533 -    }
   6.534 -
   6.535 -    page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.536 -    if ( !page )
   6.537 -    {
   6.538 -        length = -ENOMEM;
   6.539 -        goto out;
   6.540 -    }
   6.541 -    memset(page, 0, PAGE_SIZE);
   6.542 -
   6.543 -    if ( copy_from_user(page, buf, count) )
   6.544 -        goto out;
   6.545 -
   6.546      length = -EINVAL;
   6.547 -    if ( sscanf(page, "%d", &i) != 1 )
   6.548 +    if ( sscanf(buf, "%d", &i) != 1 )
   6.549          goto out;
   6.550  
   6.551      cur_enforcing = security_get_bool_value(i);
   6.552 @@ -743,18 +636,12 @@ static int flask_security_get_bool(char 
   6.553          goto out;
   6.554      }
   6.555  
   6.556 -    length = snprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
   6.557 +    memset(buf, 0, count);
   6.558 +    length = snprintf(buf, count, "%d %d", cur_enforcing,
   6.559                  bool_pending_values[i]);
   6.560 -    if ( length < 0 )
   6.561 -        goto out;
   6.562 -
   6.563 -    if ( copy_to_user(buf, page, length) )
   6.564 -        length = -EFAULT;
   6.565  
   6.566  out:
   6.567      spin_unlock(&sel_sem);
   6.568 -    if ( page )
   6.569 -        xfree(page);
   6.570      return length;
   6.571  }
   6.572  
   6.573 @@ -786,7 +673,7 @@ out:
   6.574  
   6.575  #ifdef FLASK_AVC_STATS
   6.576  
   6.577 -static int flask_security_avc_cachestats(char *buf, int count)
   6.578 +static int flask_security_avc_cachestats(char *buf, uint32_t count)
   6.579  {
   6.580      char *page = NULL;
   6.581      int len = 0;
   6.582 @@ -802,9 +689,15 @@ static int flask_security_avc_cachestats
   6.583  
   6.584      len = snprintf(page, PAGE_SIZE, "lookups hits misses allocations reclaims "
   6.585                                                                     "frees\n");
   6.586 +    if ( len > count ) {
   6.587 +        length = -EINVAL;
   6.588 +        goto out;
   6.589 +    }
   6.590 +    
   6.591      memcpy(buf, page, len);
   6.592      buf += len;
   6.593      length += len;
   6.594 +    count -= len;
   6.595  
   6.596      for ( cpu = idx; cpu < NR_CPUS; ++cpu )
   6.597      {
   6.598 @@ -816,22 +709,27 @@ static int flask_security_avc_cachestats
   6.599          len = snprintf(page, PAGE_SIZE, "%u %u %u %u %u %u\n", st->lookups,
   6.600                                         st->hits, st->misses, st->allocations,
   6.601                                                         st->reclaims, st->frees);
   6.602 +        if ( len > count ) {
   6.603 +            length = -EINVAL;
   6.604 +            goto out;
   6.605 +        }
   6.606          memcpy(buf, page, len);
   6.607          buf += len;
   6.608          length += len;
   6.609 +        count -= len;
   6.610      }
   6.611  
   6.612 +out:
   6.613      xfree(page);    
   6.614      return length;
   6.615  }
   6.616  
   6.617  #endif
   6.618  
   6.619 -static int flask_security_load(char *buf, int count)
   6.620 +static int flask_security_load(char *buf, uint32_t count)
   6.621  {
   6.622      int ret;
   6.623      int length;
   6.624 -    void *data = NULL;
   6.625  
   6.626      spin_lock(&sel_sem);
   6.627  
   6.628 @@ -839,18 +737,7 @@ static int flask_security_load(char *buf
   6.629      if ( length )
   6.630          goto out;
   6.631  
   6.632 -    if ( (count < 0) || (count > 64 * 1024 * 1024) 
   6.633 -                               || (data = xmalloc_array(char, count)) == NULL )
   6.634 -    {
   6.635 -        length = -ENOMEM;
   6.636 -        goto out;
   6.637 -    }
   6.638 -
   6.639 -    length = -EFAULT;
   6.640 -    if ( copy_from_user(data, buf, count) != 0 )
   6.641 -        goto out;
   6.642 -
   6.643 -    length = security_load_policy(data, count);
   6.644 +    length = security_load_policy(buf, count);
   6.645      if ( length )
   6.646          goto out;
   6.647  
   6.648 @@ -862,7 +749,6 @@ static int flask_security_load(char *buf
   6.649  
   6.650  out:
   6.651      spin_unlock(&sel_sem);
   6.652 -    xfree(data);
   6.653      return length;
   6.654  }
   6.655  
   6.656 @@ -871,188 +757,156 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op
   6.657      flask_op_t curop, *op = &curop;
   6.658      int rc = 0;
   6.659      int length = 0;
   6.660 -    char *page = NULL;
   6.661 +    char *arg = NULL;
   6.662  
   6.663      if ( copy_from_guest(op, u_flask_op, 1) )
   6.664          return -EFAULT;
   6.665  
   6.666 +    if ( op->cmd > FLASK_LAST)
   6.667 +        return -EINVAL;
   6.668 +
   6.669 +    if ( op->size > MAX_POLICY_SIZE )
   6.670 +        return -EINVAL;
   6.671 +
   6.672 +    if ( (op->buf == NULL && op->size != 0) || 
   6.673 +                                    (op->buf != NULL && op->size == 0) )
   6.674 +        return -EINVAL;
   6.675 +
   6.676 +    arg = xmalloc_bytes(op->size + 1);
   6.677 +    if ( !arg )
   6.678 +        return -ENOMEM;
   6.679 +
   6.680 +    memset(arg, 0, op->size + 1);
   6.681 +
   6.682 +    if ( (FLASK_COPY_IN&(1UL<<op->cmd)) && op->buf != NULL && 
   6.683 +           copy_from_guest(arg, guest_handle_from_ptr(op->buf, char), op->size) )
   6.684 +    {
   6.685 +        rc = -EFAULT;
   6.686 +        goto out;
   6.687 +    }
   6.688 +
   6.689      switch ( op->cmd )
   6.690      {
   6.691  
   6.692      case FLASK_LOAD:
   6.693      {
   6.694 -        length = flask_security_load(op->buf, op->size);
   6.695 +        length = flask_security_load(arg, op->size);
   6.696      }
   6.697      break;
   6.698      
   6.699      case FLASK_GETENFORCE:
   6.700      {
   6.701 -        page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.702 -        if ( !page )
   6.703 -            return -ENOMEM;
   6.704 -        memset(page, 0, PAGE_SIZE);
   6.705 -        
   6.706 -        length = snprintf(page, PAGE_SIZE, "%d", flask_enforcing);
   6.707 -        
   6.708 -        if ( copy_to_user(op->buf, page, length) )
   6.709 -        {
   6.710 -            rc = -EFAULT;
   6.711 -            goto out;
   6.712 -        }
   6.713 +        length = snprintf(arg, op->size, "%d", flask_enforcing);
   6.714      }
   6.715      break;    
   6.716  
   6.717      case FLASK_SETENFORCE:
   6.718      {
   6.719 -        length = flask_security_setenforce(op->buf, op->size);
   6.720 +        length = flask_security_setenforce(arg, op->size);
   6.721      }
   6.722      break;    
   6.723  
   6.724      case FLASK_CONTEXT_TO_SID:
   6.725      {
   6.726 -        length = flask_security_context(op->buf, op->size);
   6.727 +        length = flask_security_context(arg, op->size);
   6.728      }
   6.729      break;    
   6.730  
   6.731      case FLASK_SID_TO_CONTEXT:
   6.732      {
   6.733 -        length = flask_security_sid(op->buf, op->size);
   6.734 +        length = flask_security_sid(arg, op->size);
   6.735      }
   6.736      break; 
   6.737  
   6.738      case FLASK_ACCESS:
   6.739      {
   6.740 -        length = flask_security_access(op->buf, op->size);
   6.741 +        length = flask_security_access(arg, op->size);
   6.742      }
   6.743      break;    
   6.744  
   6.745      case FLASK_CREATE:
   6.746      {
   6.747 -        length = flask_security_create(op->buf, op->size);
   6.748 +        length = flask_security_create(arg, op->size);
   6.749      }
   6.750      break;    
   6.751  
   6.752      case FLASK_RELABEL:
   6.753      {
   6.754 -        length = flask_security_relabel(op->buf, op->size);
   6.755 +        length = flask_security_relabel(arg, op->size);
   6.756      }
   6.757      break;
   6.758  
   6.759      case FLASK_USER:
   6.760      {
   6.761 -        length = flask_security_user(op->buf, op->size);
   6.762 +        length = flask_security_user(arg, op->size);
   6.763      }
   6.764      break;    
   6.765  
   6.766      case FLASK_POLICYVERS:
   6.767      {
   6.768 -        page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.769 -        if ( !page )
   6.770 -            return -ENOMEM;
   6.771 -        memset(page, 0, PAGE_SIZE);
   6.772 -
   6.773 -        length = snprintf(page, PAGE_SIZE, "%d", POLICYDB_VERSION_MAX);
   6.774 -
   6.775 -        if ( copy_to_user(op->buf, page, length) )
   6.776 -        {
   6.777 -            rc = -EFAULT;
   6.778 -            goto out;
   6.779 -        }
   6.780 +        length = snprintf(arg, op->size, "%d", POLICYDB_VERSION_MAX);
   6.781      }
   6.782      break;    
   6.783  
   6.784      case FLASK_GETBOOL:
   6.785      {
   6.786 -        length = flask_security_get_bool(op->buf, op->size);
   6.787 +        length = flask_security_get_bool(arg, op->size);
   6.788      }
   6.789      break;
   6.790  
   6.791      case FLASK_SETBOOL:
   6.792      {
   6.793 -        length = flask_security_set_bool(op->buf, op->size);
   6.794 +        length = flask_security_set_bool(arg, op->size);
   6.795      }
   6.796      break;
   6.797  
   6.798      case FLASK_COMMITBOOLS:
   6.799      {
   6.800 -        length = flask_security_commit_bools(op->buf, op->size);
   6.801 +        length = flask_security_commit_bools(arg, op->size);
   6.802      }
   6.803      break;
   6.804  
   6.805      case FLASK_MLS:
   6.806      {
   6.807 -        page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.808 -        if ( !page )
   6.809 -            return -ENOMEM;
   6.810 -        memset(page, 0, PAGE_SIZE);
   6.811 -
   6.812 -        length = snprintf(page, PAGE_SIZE, "%d", flask_mls_enabled);
   6.813 -
   6.814 -        if ( copy_to_user(op->buf, page, length) )
   6.815 -        {
   6.816 -            rc = -EFAULT;
   6.817 -            goto out;
   6.818 -        }
   6.819 +        length = snprintf(arg, op->size, "%d", flask_mls_enabled);
   6.820      }
   6.821      break;    
   6.822  
   6.823      case FLASK_DISABLE:
   6.824      {
   6.825 -        length = flask_security_disable(op->buf, op->size);
   6.826 +        length = flask_security_disable(arg, op->size);
   6.827      }
   6.828      break;    
   6.829  
   6.830      case FLASK_GETAVC_THRESHOLD:
   6.831      {
   6.832 -        page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.833 -        if ( !page )
   6.834 -            return -ENOMEM;
   6.835 -        memset(page, 0, PAGE_SIZE);
   6.836 -
   6.837 -        length = snprintf(page, PAGE_SIZE, "%d", avc_cache_threshold);
   6.838 -
   6.839 -        if ( copy_to_user(op->buf, page, length) )
   6.840 -        {
   6.841 -            rc = -EFAULT;
   6.842 -            goto out;
   6.843 -        }
   6.844 +        length = snprintf(arg, op->size, "%d", avc_cache_threshold);
   6.845      }
   6.846      break;
   6.847  
   6.848      case FLASK_SETAVC_THRESHOLD:
   6.849      {
   6.850 -        length = flask_security_setavc_threshold(op->buf, op->size);
   6.851 +        length = flask_security_setavc_threshold(arg, op->size);
   6.852      }
   6.853      break;
   6.854  
   6.855      case FLASK_AVC_HASHSTATS:
   6.856      {
   6.857 -        page = (char *)xmalloc_bytes(PAGE_SIZE);
   6.858 -        if ( !page )
   6.859 -            return -ENOMEM;
   6.860 -        memset(page, 0, PAGE_SIZE);
   6.861 -
   6.862 -        length = avc_get_hash_stats(page);
   6.863 -
   6.864 -        if ( copy_to_user(op->buf, page, length) )
   6.865 -        {
   6.866 -            rc = -EFAULT;
   6.867 -            goto out;
   6.868 -        }
   6.869 +        length = avc_get_hash_stats(arg, op->size);
   6.870      }
   6.871      break;
   6.872  
   6.873  #ifdef FLASK_AVC_STATS    
   6.874      case FLASK_AVC_CACHESTATS:
   6.875      {
   6.876 -        length = flask_security_avc_cachestats(op->buf, op->size);
   6.877 +        length = flask_security_avc_cachestats(arg, op->size);
   6.878      }
   6.879      break;
   6.880 -#endif    
   6.881 +#endif
   6.882  
   6.883      case FLASK_MEMBER:
   6.884      {
   6.885 -        length = flask_security_member(op->buf, op->size);
   6.886 +        length = flask_security_member(arg, op->size);
   6.887      }
   6.888      break;    
   6.889  
   6.890 @@ -1067,13 +921,19 @@ long do_flask_op(XEN_GUEST_HANDLE(xsm_op
   6.891          rc = length;
   6.892          goto out;
   6.893      }
   6.894 +    
   6.895 +    if ( (FLASK_COPY_OUT&(1UL<<op->cmd)) && op->buf != NULL && 
   6.896 +             copy_to_guest(guest_handle_from_ptr(op->buf, char), arg, op->size) )
   6.897 +    {
   6.898 +        rc = -EFAULT;
   6.899 +        goto out;
   6.900 +    }
   6.901 +
   6.902      op->size = length;
   6.903      if ( copy_to_guest(u_flask_op, op, 1) )
   6.904          rc = -EFAULT;
   6.905  
   6.906  out:
   6.907 -    if ( page )
   6.908 -        xfree(page);
   6.909 +    xfree(arg);
   6.910      return rc;
   6.911  }
   6.912 -
     7.1 --- a/xen/xsm/flask/include/avc.h	Mon Jul 21 09:40:37 2008 +0100
     7.2 +++ b/xen/xsm/flask/include/avc.h	Mon Jul 21 09:41:36 2008 +0100
     7.3 @@ -95,7 +95,7 @@ int avc_add_callback(int (*callback)(u32
     7.4                                      u32 ssid, u32 tsid, u16 tclass, u32 perms);
     7.5  
     7.6  /* Exported to selinuxfs */
     7.7 -int avc_get_hash_stats(char *page);
     7.8 +int avc_get_hash_stats(char *buf, uint32_t size);
     7.9  extern unsigned int avc_cache_threshold;
    7.10  
    7.11  #ifdef FLASK_AVC_STATS