From: Andi Kleen This patch fixes the argument length checking in sched_setaffinity. Previously it would error out when the length passed was smaller than sizeof(cpumask_t). And any bits beyond cpumask_s would be silently ignored. First this assumes that the user application knows the size of cpumask_t, which should be kernel internal. When you increase cpumask_t old applications break and there is no good way for the application to find out the cpumask_t size the kernel uses. This patch changes it to do similar checking to the NUMA API calls: - Any length is ok as long as all online CPUs are covered (this could still cause application breakage with more CPUs, but there is no good way around it) - When the user passes more than cpumask_t bytes the excess bytes are checked to be zero. Signed-off-by: Andrew Morton --- 25-akpm/kernel/sched.c | 36 +++++++++++++++++++++++++++++++----- 1 files changed, 31 insertions(+), 5 deletions(-) diff -puN kernel/sched.c~fix-argument-checking-in-sched_setaffinity kernel/sched.c --- 25/kernel/sched.c~fix-argument-checking-in-sched_setaffinity Tue Aug 31 14:35:12 2004 +++ 25-akpm/kernel/sched.c Tue Aug 31 14:35:12 2004 @@ -3369,6 +3369,34 @@ out_unlock: return retval; } +static int get_user_cpu_mask(unsigned long __user *user_mask_ptr, unsigned len, + cpumask_t *new_mask) +{ + if (len < sizeof(cpumask_t)) { + /* Smaller is ok as long as all online CPUs are covered */ + int i, max = 0; + for_each_online_cpu(i) + max = i; + if (len < (max + 7)/8) + return -EINVAL; + memset(new_mask, 0, sizeof(cpumask_t)); + } else if (len > sizeof(cpumask_t)) { + /* Longer is ok as long as all high bits are 0 */ + int i; + if (len > PAGE_SIZE) + return -EINVAL; + for (i = sizeof(cpumask_t); i < len; i++) { + unsigned char val; + if (get_user(val, (unsigned char *)user_mask_ptr + i)) + return -EFAULT; + if (val) + return -EINVAL; + } + len = sizeof(cpumask_t); + } + return copy_from_user(new_mask, user_mask_ptr, len) ? -EFAULT : 0; +} + /** * sys_sched_setaffinity - set the cpu affinity of a process * @pid: pid of the process @@ -3382,11 +3410,9 @@ asmlinkage long sys_sched_setaffinity(pi int retval; task_t *p; - if (len < sizeof(new_mask)) - return -EINVAL; - - if (copy_from_user(&new_mask, user_mask_ptr, sizeof(new_mask))) - return -EFAULT; + retval = get_user_cpu_mask(user_mask_ptr, len, &new_mask); + if (retval) + return retval; lock_cpu_hotplug(); read_lock(&tasklist_lock); _