diff options
author | David Howells <dhowells@redhat.com> | 2008-11-13 18:39:19 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-11-13 18:39:19 -0500 |
commit | c69e8d9c01db2adc503464993c358901c9af9de4 (patch) | |
tree | bed94aaa9aeb7a7834d1c880f72b62a11a752c78 /kernel/sched.c | |
parent | 86a264abe542cfececb4df129bc45a0338d8cdb9 (diff) |
CRED: Use RCU to access another task's creds and to release a task's own creds
Use RCU to access another task's creds and to release a task's own creds.
This means that it will be possible for the credentials of a task to be
replaced without another task (a) requiring a full lock to read them, and (b)
seeing deallocated memory.
Signed-off-by: David Howells <dhowells@redhat.com>
Acked-by: James Morris <jmorris@namei.org>
Acked-by: Serge Hallyn <serue@us.ibm.com>
Signed-off-by: James Morris <jmorris@namei.org>
Diffstat (limited to 'kernel/sched.c')
-rw-r--r-- | kernel/sched.c | 31 |
1 files changed, 21 insertions, 10 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 733c59e645a..92992e287b1 100644 --- a/kernel/sched.c +++ b/kernel/sched.c | |||
@@ -345,7 +345,9 @@ static inline struct task_group *task_group(struct task_struct *p) | |||
345 | struct task_group *tg; | 345 | struct task_group *tg; |
346 | 346 | ||
347 | #ifdef CONFIG_USER_SCHED | 347 | #ifdef CONFIG_USER_SCHED |
348 | tg = p->cred->user->tg; | 348 | rcu_read_lock(); |
349 | tg = __task_cred(p)->user->tg; | ||
350 | rcu_read_unlock(); | ||
349 | #elif defined(CONFIG_CGROUP_SCHED) | 351 | #elif defined(CONFIG_CGROUP_SCHED) |
350 | tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id), | 352 | tg = container_of(task_subsys_state(p, cpu_cgroup_subsys_id), |
351 | struct task_group, css); | 353 | struct task_group, css); |
@@ -5121,6 +5123,22 @@ __setscheduler(struct rq *rq, struct task_struct *p, int policy, int prio) | |||
5121 | set_load_weight(p); | 5123 | set_load_weight(p); |
5122 | } | 5124 | } |
5123 | 5125 | ||
5126 | /* | ||
5127 | * check the target process has a UID that matches the current process's | ||
5128 | */ | ||
5129 | static bool check_same_owner(struct task_struct *p) | ||
5130 | { | ||
5131 | const struct cred *cred = current_cred(), *pcred; | ||
5132 | bool match; | ||
5133 | |||
5134 | rcu_read_lock(); | ||
5135 | pcred = __task_cred(p); | ||
5136 | match = (cred->euid == pcred->euid || | ||
5137 | cred->euid == pcred->uid); | ||
5138 | rcu_read_unlock(); | ||
5139 | return match; | ||
5140 | } | ||
5141 | |||
5124 | static int __sched_setscheduler(struct task_struct *p, int policy, | 5142 | static int __sched_setscheduler(struct task_struct *p, int policy, |
5125 | struct sched_param *param, bool user) | 5143 | struct sched_param *param, bool user) |
5126 | { | 5144 | { |
@@ -5128,7 +5146,6 @@ static int __sched_setscheduler(struct task_struct *p, int policy, | |||
5128 | unsigned long flags; | 5146 | unsigned long flags; |
5129 | const struct sched_class *prev_class = p->sched_class; | 5147 | const struct sched_class *prev_class = p->sched_class; |
5130 | struct rq *rq; | 5148 | struct rq *rq; |
5131 | uid_t euid; | ||
5132 | 5149 | ||
5133 | /* may grab non-irq protected spin_locks */ | 5150 | /* may grab non-irq protected spin_locks */ |
5134 | BUG_ON(in_interrupt()); | 5151 | BUG_ON(in_interrupt()); |
@@ -5181,9 +5198,7 @@ recheck: | |||
5181 | return -EPERM; | 5198 | return -EPERM; |
5182 | 5199 | ||
5183 | /* can't change other user's priorities */ | 5200 | /* can't change other user's priorities */ |
5184 | euid = current_euid(); | 5201 | if (!check_same_owner(p)) |
5185 | if (euid != p->cred->euid && | ||
5186 | euid != p->cred->uid) | ||
5187 | return -EPERM; | 5202 | return -EPERM; |
5188 | } | 5203 | } |
5189 | 5204 | ||
@@ -5394,7 +5409,6 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask) | |||
5394 | cpumask_t cpus_allowed; | 5409 | cpumask_t cpus_allowed; |
5395 | cpumask_t new_mask = *in_mask; | 5410 | cpumask_t new_mask = *in_mask; |
5396 | struct task_struct *p; | 5411 | struct task_struct *p; |
5397 | uid_t euid; | ||
5398 | int retval; | 5412 | int retval; |
5399 | 5413 | ||
5400 | get_online_cpus(); | 5414 | get_online_cpus(); |
@@ -5415,11 +5429,8 @@ long sched_setaffinity(pid_t pid, const cpumask_t *in_mask) | |||
5415 | get_task_struct(p); | 5429 | get_task_struct(p); |
5416 | read_unlock(&tasklist_lock); | 5430 | read_unlock(&tasklist_lock); |
5417 | 5431 | ||
5418 | euid = current_euid(); | ||
5419 | retval = -EPERM; | 5432 | retval = -EPERM; |
5420 | if (euid != p->cred->euid && | 5433 | if (!check_same_owner(p) && !capable(CAP_SYS_NICE)) |
5421 | euid != p->cred->uid && | ||
5422 | !capable(CAP_SYS_NICE)) | ||
5423 | goto out_unlock; | 5434 | goto out_unlock; |
5424 | 5435 | ||
5425 | retval = security_task_setscheduler(p, 0, NULL); | 5436 | retval = security_task_setscheduler(p, 0, NULL); |