summaryrefslogtreecommitdiffstats
path: root/kernel/sched
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-10-04 13:36:31 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2019-10-04 13:36:31 -0400
commite524d16e7e324039f2a9f82e302f0a39ac7d5812 (patch)
tree8ebd39c05da4165b74a1380d6baa5a6b5064fbaf /kernel/sched
parentaf0622f6ae416f9ac340d6d632be9879805c294a (diff)
parent341115822f8832f0c2d8af2f7e151c4c9a77bcd1 (diff)
Merge tag 'copy-struct-from-user-v5.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux
Pull copy_struct_from_user() helper from Christian Brauner: "This contains the copy_struct_from_user() helper which got split out from the openat2() patchset. It is a generic interface designed to copy a struct from userspace. The helper will be especially useful for structs versioned by size of which we have quite a few. This allows for backwards compatibility, i.e. an extended struct can be passed to an older kernel, or a legacy struct can be passed to a newer kernel. For the first case (extended struct, older kernel) the new fields in an extended struct can be set to zero and the struct safely passed to an older kernel. The most obvious benefit is that this helper lets us get rid of duplicate code present in at least sched_setattr(), perf_event_open(), and clone3(). More importantly it will also help to ensure that users implementing versioning-by-size end up with the same core semantics. This point is especially crucial since we have at least one case where versioning-by-size is used but with slighly different semantics: sched_setattr(), perf_event_open(), and clone3() all do do similar checks to copy_struct_from_user() while rt_sigprocmask(2) always rejects differently-sized struct arguments. With this pull request we also switch over sched_setattr(), perf_event_open(), and clone3() to use the new helper" * tag 'copy-struct-from-user-v5.4-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux: usercopy: Add parentheses around assignment in test_copy_struct_from_user perf_event_open: switch to copy_struct_from_user() sched_setattr: switch to copy_struct_from_user() clone3: switch to copy_struct_from_user() lib: introduce copy_struct_from_user() helper
Diffstat (limited to 'kernel/sched')
-rw-r--r--kernel/sched/core.c43
1 files changed, 7 insertions, 36 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 7880f4f64d0e..dd05a378631a 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -5106,9 +5106,6 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a
5106 u32 size; 5106 u32 size;
5107 int ret; 5107 int ret;
5108 5108
5109 if (!access_ok(uattr, SCHED_ATTR_SIZE_VER0))
5110 return -EFAULT;
5111
5112 /* Zero the full structure, so that a short copy will be nice: */ 5109 /* Zero the full structure, so that a short copy will be nice: */
5113 memset(attr, 0, sizeof(*attr)); 5110 memset(attr, 0, sizeof(*attr));
5114 5111
@@ -5116,45 +5113,19 @@ static int sched_copy_attr(struct sched_attr __user *uattr, struct sched_attr *a
5116 if (ret) 5113 if (ret)
5117 return ret; 5114 return ret;
5118 5115
5119 /* Bail out on silly large: */
5120 if (size > PAGE_SIZE)
5121 goto err_size;
5122
5123 /* ABI compatibility quirk: */ 5116 /* ABI compatibility quirk: */
5124 if (!size) 5117 if (!size)
5125 size = SCHED_ATTR_SIZE_VER0; 5118 size = SCHED_ATTR_SIZE_VER0;
5126 5119 if (size < SCHED_ATTR_SIZE_VER0 || size > PAGE_SIZE)
5127 if (size < SCHED_ATTR_SIZE_VER0)
5128 goto err_size; 5120 goto err_size;
5129 5121
5130 /* 5122 ret = copy_struct_from_user(attr, sizeof(*attr), uattr, size);
5131 * If we're handed a bigger struct than we know of, 5123 if (ret) {
5132 * ensure all the unknown bits are 0 - i.e. new 5124 if (ret == -E2BIG)
5133 * user-space does not rely on any kernel feature 5125 goto err_size;
5134 * extensions we dont know about yet. 5126 return ret;
5135 */
5136 if (size > sizeof(*attr)) {
5137 unsigned char __user *addr;
5138 unsigned char __user *end;
5139 unsigned char val;
5140
5141 addr = (void __user *)uattr + sizeof(*attr);
5142 end = (void __user *)uattr + size;
5143
5144 for (; addr < end; addr++) {
5145 ret = get_user(val, addr);
5146 if (ret)
5147 return ret;
5148 if (val)
5149 goto err_size;
5150 }
5151 size = sizeof(*attr);
5152 } 5127 }
5153 5128
5154 ret = copy_from_user(attr, uattr, size);
5155 if (ret)
5156 return -EFAULT;
5157
5158 if ((attr->sched_flags & SCHED_FLAG_UTIL_CLAMP) && 5129 if ((attr->sched_flags & SCHED_FLAG_UTIL_CLAMP) &&
5159 size < SCHED_ATTR_SIZE_VER1) 5130 size < SCHED_ATTR_SIZE_VER1)
5160 return -EINVAL; 5131 return -EINVAL;
@@ -5354,7 +5325,7 @@ sched_attr_copy_to_user(struct sched_attr __user *uattr,
5354 * sys_sched_getattr - similar to sched_getparam, but with sched_attr 5325 * sys_sched_getattr - similar to sched_getparam, but with sched_attr
5355 * @pid: the pid in question. 5326 * @pid: the pid in question.
5356 * @uattr: structure containing the extended parameters. 5327 * @uattr: structure containing the extended parameters.
5357 * @usize: sizeof(attr) that user-space knows about, for forwards and backwards compatibility. 5328 * @usize: sizeof(attr) for fwd/bwd comp.
5358 * @flags: for future extension. 5329 * @flags: for future extension.
5359 */ 5330 */
5360SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, 5331SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr,