diff options
Diffstat (limited to 'kernel/sched/core.c')
-rw-r--r-- | kernel/sched/core.c | 78 |
1 files changed, 39 insertions, 39 deletions
diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 010d578118d6..df9f1fe5689b 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c | |||
@@ -5105,37 +5105,40 @@ out_unlock: | |||
5105 | return retval; | 5105 | return retval; |
5106 | } | 5106 | } |
5107 | 5107 | ||
5108 | static int sched_read_attr(struct sched_attr __user *uattr, | 5108 | /* |
5109 | struct sched_attr *attr, | 5109 | * Copy the kernel size attribute structure (which might be larger |
5110 | unsigned int usize) | 5110 | * than what user-space knows about) to user-space. |
5111 | * | ||
5112 | * Note that all cases are valid: user-space buffer can be larger or | ||
5113 | * smaller than the kernel-space buffer. The usual case is that both | ||
5114 | * have the same size. | ||
5115 | */ | ||
5116 | static int | ||
5117 | sched_attr_copy_to_user(struct sched_attr __user *uattr, | ||
5118 | struct sched_attr *kattr, | ||
5119 | unsigned int usize) | ||
5111 | { | 5120 | { |
5112 | int ret; | 5121 | unsigned int ksize = sizeof(*kattr); |
5113 | 5122 | ||
5114 | if (!access_ok(uattr, usize)) | 5123 | if (!access_ok(uattr, usize)) |
5115 | return -EFAULT; | 5124 | return -EFAULT; |
5116 | 5125 | ||
5117 | /* | 5126 | /* |
5118 | * If we're handed a smaller struct than we know of, | 5127 | * sched_getattr() ABI forwards and backwards compatibility: |
5119 | * ensure all the unknown bits are 0 - i.e. old | 5128 | * |
5120 | * user-space does not get uncomplete information. | 5129 | * If usize == ksize then we just copy everything to user-space and all is good. |
5130 | * | ||
5131 | * If usize < ksize then we only copy as much as user-space has space for, | ||
5132 | * this keeps ABI compatibility as well. We skip the rest. | ||
5133 | * | ||
5134 | * If usize > ksize then user-space is using a newer version of the ABI, | ||
5135 | * which part the kernel doesn't know about. Just ignore it - tooling can | ||
5136 | * detect the kernel's knowledge of attributes from the attr->size value | ||
5137 | * which is set to ksize in this case. | ||
5121 | */ | 5138 | */ |
5122 | if (usize < sizeof(*attr)) { | 5139 | kattr->size = min(usize, ksize); |
5123 | unsigned char *addr; | ||
5124 | unsigned char *end; | ||
5125 | 5140 | ||
5126 | addr = (void *)attr + usize; | 5141 | if (copy_to_user(uattr, kattr, kattr->size)) |
5127 | end = (void *)attr + sizeof(*attr); | ||
5128 | |||
5129 | for (; addr < end; addr++) { | ||
5130 | if (*addr) | ||
5131 | return -EFBIG; | ||
5132 | } | ||
5133 | |||
5134 | attr->size = usize; | ||
5135 | } | ||
5136 | |||
5137 | ret = copy_to_user(uattr, attr, attr->size); | ||
5138 | if (ret) | ||
5139 | return -EFAULT; | 5142 | return -EFAULT; |
5140 | 5143 | ||
5141 | return 0; | 5144 | return 0; |
@@ -5145,20 +5148,18 @@ static int sched_read_attr(struct sched_attr __user *uattr, | |||
5145 | * sys_sched_getattr - similar to sched_getparam, but with sched_attr | 5148 | * sys_sched_getattr - similar to sched_getparam, but with sched_attr |
5146 | * @pid: the pid in question. | 5149 | * @pid: the pid in question. |
5147 | * @uattr: structure containing the extended parameters. | 5150 | * @uattr: structure containing the extended parameters. |
5148 | * @size: sizeof(attr) for fwd/bwd comp. | 5151 | * @usize: sizeof(attr) that user-space knows about, for forwards and backwards compatibility. |
5149 | * @flags: for future extension. | 5152 | * @flags: for future extension. |
5150 | */ | 5153 | */ |
5151 | SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, | 5154 | SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, |
5152 | unsigned int, size, unsigned int, flags) | 5155 | unsigned int, usize, unsigned int, flags) |
5153 | { | 5156 | { |
5154 | struct sched_attr attr = { | 5157 | struct sched_attr kattr = { }; |
5155 | .size = sizeof(struct sched_attr), | ||
5156 | }; | ||
5157 | struct task_struct *p; | 5158 | struct task_struct *p; |
5158 | int retval; | 5159 | int retval; |
5159 | 5160 | ||
5160 | if (!uattr || pid < 0 || size > PAGE_SIZE || | 5161 | if (!uattr || pid < 0 || usize > PAGE_SIZE || |
5161 | size < SCHED_ATTR_SIZE_VER0 || flags) | 5162 | usize < SCHED_ATTR_SIZE_VER0 || flags) |
5162 | return -EINVAL; | 5163 | return -EINVAL; |
5163 | 5164 | ||
5164 | rcu_read_lock(); | 5165 | rcu_read_lock(); |
@@ -5171,25 +5172,24 @@ SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, | |||
5171 | if (retval) | 5172 | if (retval) |
5172 | goto out_unlock; | 5173 | goto out_unlock; |
5173 | 5174 | ||
5174 | attr.sched_policy = p->policy; | 5175 | kattr.sched_policy = p->policy; |
5175 | if (p->sched_reset_on_fork) | 5176 | if (p->sched_reset_on_fork) |
5176 | attr.sched_flags |= SCHED_FLAG_RESET_ON_FORK; | 5177 | kattr.sched_flags |= SCHED_FLAG_RESET_ON_FORK; |
5177 | if (task_has_dl_policy(p)) | 5178 | if (task_has_dl_policy(p)) |
5178 | __getparam_dl(p, &attr); | 5179 | __getparam_dl(p, &kattr); |
5179 | else if (task_has_rt_policy(p)) | 5180 | else if (task_has_rt_policy(p)) |
5180 | attr.sched_priority = p->rt_priority; | 5181 | kattr.sched_priority = p->rt_priority; |
5181 | else | 5182 | else |
5182 | attr.sched_nice = task_nice(p); | 5183 | kattr.sched_nice = task_nice(p); |
5183 | 5184 | ||
5184 | #ifdef CONFIG_UCLAMP_TASK | 5185 | #ifdef CONFIG_UCLAMP_TASK |
5185 | attr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value; | 5186 | kattr.sched_util_min = p->uclamp_req[UCLAMP_MIN].value; |
5186 | attr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value; | 5187 | kattr.sched_util_max = p->uclamp_req[UCLAMP_MAX].value; |
5187 | #endif | 5188 | #endif |
5188 | 5189 | ||
5189 | rcu_read_unlock(); | 5190 | rcu_read_unlock(); |
5190 | 5191 | ||
5191 | retval = sched_read_attr(uattr, &attr, size); | 5192 | return sched_attr_copy_to_user(uattr, &kattr, usize); |
5192 | return retval; | ||
5193 | 5193 | ||
5194 | out_unlock: | 5194 | out_unlock: |
5195 | rcu_read_unlock(); | 5195 | rcu_read_unlock(); |