aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/sched/core.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched/core.c')
-rw-r--r--kernel/sched/core.c78
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
5108static 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 */
5116static int
5117sched_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 */
5151SYSCALL_DEFINE4(sched_getattr, pid_t, pid, struct sched_attr __user *, uattr, 5154SYSCALL_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
5194out_unlock: 5194out_unlock:
5195 rcu_read_unlock(); 5195 rcu_read_unlock();