Commit 973705e2 authored by Andi Kleen's avatar Andi Kleen Committed by Linus Torvalds

[PATCH] Fix argument checking in sched_setaffinity

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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 3f9b988c
......@@ -3362,6 +3362,34 @@ asmlinkage long sys_sched_getparam(pid_t pid, struct sched_param __user *param)
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
......@@ -3375,11 +3403,9 @@ asmlinkage long sys_sched_setaffinity(pid_t pid, unsigned int len,
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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment