Messages in this thread Patch in this message | | | From | Kangjie Lu <> | Subject | [PATCH] sched: fix a potential double-fetch bug in sched_copy_attr | Date | Tue, 25 Dec 2018 16:16:47 -0600 |
| |
"uattr->size" is copied in from user space and checked. However, it is copied in again after the security check. A malicious user may race to change it. The fix checks if uattr->size is ever changed after the check.
Signed-off-by: Kangjie Lu <kjlu@umn.edu> --- kernel/sched/core.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 6fedf3a98581..0a55bdce9a42 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -4447,7 +4447,7 @@ do_sched_setscheduler(pid_t pid, int policy, struct sched_param __user *param) */ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *attr) { - u32 size; + u32 size, size_cp; int ret; if (!access_ok(VERIFY_WRITE, uattr, SCHED_ATTR_SIZE_VER0)) @@ -4460,15 +4460,17 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a if (ret) return ret; + size_cp = size; + /* Bail out on silly large: */ if (size > PAGE_SIZE) goto err_size; /* ABI compatibility quirk: */ if (!size) - size = SCHED_ATTR_SIZE_VER0; + size_cp = SCHED_ATTR_SIZE_VER0; - if (size < SCHED_ATTR_SIZE_VER0) + else if (size < SCHED_ATTR_SIZE_VER0) goto err_size; /* @@ -4483,7 +4485,7 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a unsigned char val; addr = (void __user *)uattr + sizeof(*attr); - end = (void __user *)uattr + size; + end = (void __user *)uattr + size_cp; for (; addr < end; addr++) { ret = get_user(val, addr); @@ -4492,13 +4494,17 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a if (val) goto err_size; } - size = sizeof(*attr); + size_cp = sizeof(*attr); } - ret = copy_from_user(attr, uattr, size); + ret = copy_from_user(attr, uattr, size_cp); if (ret) return -EFAULT; + /* Sanity check if size was changed in user space */ + if (attr->size != size) + return -EINVAL; + /* * XXX: Do we want to be lenient like existing syscalls; or do we want * to be strict and return an error on out-of-bounds values? -- 2.17.2 (Apple Git-113)
| |