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 | |
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')
-rw-r--r-- | kernel/auditsc.c | 33 | ||||
-rw-r--r-- | kernel/cgroup.c | 16 | ||||
-rw-r--r-- | kernel/exit.c | 14 | ||||
-rw-r--r-- | kernel/futex.c | 22 | ||||
-rw-r--r-- | kernel/futex_compat.c | 7 | ||||
-rw-r--r-- | kernel/ptrace.c | 22 | ||||
-rw-r--r-- | kernel/sched.c | 31 | ||||
-rw-r--r-- | kernel/signal.c | 49 | ||||
-rw-r--r-- | kernel/sys.c | 11 | ||||
-rw-r--r-- | kernel/tsacct.c | 6 |
10 files changed, 130 insertions, 81 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index 2febf5165fad..ae8ef88ade3f 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c | |||
@@ -447,7 +447,7 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
447 | struct audit_names *name, | 447 | struct audit_names *name, |
448 | enum audit_state *state) | 448 | enum audit_state *state) |
449 | { | 449 | { |
450 | struct cred *cred = tsk->cred; | 450 | const struct cred *cred = get_task_cred(tsk); |
451 | int i, j, need_sid = 1; | 451 | int i, j, need_sid = 1; |
452 | u32 sid; | 452 | u32 sid; |
453 | 453 | ||
@@ -642,8 +642,10 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
642 | break; | 642 | break; |
643 | } | 643 | } |
644 | 644 | ||
645 | if (!result) | 645 | if (!result) { |
646 | put_cred(cred); | ||
646 | return 0; | 647 | return 0; |
648 | } | ||
647 | } | 649 | } |
648 | if (rule->filterkey && ctx) | 650 | if (rule->filterkey && ctx) |
649 | ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); | 651 | ctx->filterkey = kstrdup(rule->filterkey, GFP_ATOMIC); |
@@ -651,6 +653,7 @@ static int audit_filter_rules(struct task_struct *tsk, | |||
651 | case AUDIT_NEVER: *state = AUDIT_DISABLED; break; | 653 | case AUDIT_NEVER: *state = AUDIT_DISABLED; break; |
652 | case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; | 654 | case AUDIT_ALWAYS: *state = AUDIT_RECORD_CONTEXT; break; |
653 | } | 655 | } |
656 | put_cred(cred); | ||
654 | return 1; | 657 | return 1; |
655 | } | 658 | } |
656 | 659 | ||
@@ -1229,7 +1232,7 @@ static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) | |||
1229 | 1232 | ||
1230 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) | 1233 | static void audit_log_exit(struct audit_context *context, struct task_struct *tsk) |
1231 | { | 1234 | { |
1232 | struct cred *cred = tsk->cred; | 1235 | const struct cred *cred; |
1233 | int i, call_panic = 0; | 1236 | int i, call_panic = 0; |
1234 | struct audit_buffer *ab; | 1237 | struct audit_buffer *ab; |
1235 | struct audit_aux_data *aux; | 1238 | struct audit_aux_data *aux; |
@@ -1239,13 +1242,14 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts | |||
1239 | context->pid = tsk->pid; | 1242 | context->pid = tsk->pid; |
1240 | if (!context->ppid) | 1243 | if (!context->ppid) |
1241 | context->ppid = sys_getppid(); | 1244 | context->ppid = sys_getppid(); |
1242 | context->uid = cred->uid; | 1245 | cred = current_cred(); |
1243 | context->gid = cred->gid; | 1246 | context->uid = cred->uid; |
1244 | context->euid = cred->euid; | 1247 | context->gid = cred->gid; |
1245 | context->suid = cred->suid; | 1248 | context->euid = cred->euid; |
1249 | context->suid = cred->suid; | ||
1246 | context->fsuid = cred->fsuid; | 1250 | context->fsuid = cred->fsuid; |
1247 | context->egid = cred->egid; | 1251 | context->egid = cred->egid; |
1248 | context->sgid = cred->sgid; | 1252 | context->sgid = cred->sgid; |
1249 | context->fsgid = cred->fsgid; | 1253 | context->fsgid = cred->fsgid; |
1250 | context->personality = tsk->personality; | 1254 | context->personality = tsk->personality; |
1251 | 1255 | ||
@@ -2088,7 +2092,7 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid) | |||
2088 | audit_log_format(ab, "login pid=%d uid=%u " | 2092 | audit_log_format(ab, "login pid=%d uid=%u " |
2089 | "old auid=%u new auid=%u" | 2093 | "old auid=%u new auid=%u" |
2090 | " old ses=%u new ses=%u", | 2094 | " old ses=%u new ses=%u", |
2091 | task->pid, task->cred->uid, | 2095 | task->pid, task_uid(task), |
2092 | task->loginuid, loginuid, | 2096 | task->loginuid, loginuid, |
2093 | task->sessionid, sessionid); | 2097 | task->sessionid, sessionid); |
2094 | audit_log_end(ab); | 2098 | audit_log_end(ab); |
@@ -2471,7 +2475,7 @@ void __audit_ptrace(struct task_struct *t) | |||
2471 | 2475 | ||
2472 | context->target_pid = t->pid; | 2476 | context->target_pid = t->pid; |
2473 | context->target_auid = audit_get_loginuid(t); | 2477 | context->target_auid = audit_get_loginuid(t); |
2474 | context->target_uid = t->cred->uid; | 2478 | context->target_uid = task_uid(t); |
2475 | context->target_sessionid = audit_get_sessionid(t); | 2479 | context->target_sessionid = audit_get_sessionid(t); |
2476 | security_task_getsecid(t, &context->target_sid); | 2480 | security_task_getsecid(t, &context->target_sid); |
2477 | memcpy(context->target_comm, t->comm, TASK_COMM_LEN); | 2481 | memcpy(context->target_comm, t->comm, TASK_COMM_LEN); |
@@ -2490,6 +2494,7 @@ int __audit_signal_info(int sig, struct task_struct *t) | |||
2490 | struct audit_aux_data_pids *axp; | 2494 | struct audit_aux_data_pids *axp; |
2491 | struct task_struct *tsk = current; | 2495 | struct task_struct *tsk = current; |
2492 | struct audit_context *ctx = tsk->audit_context; | 2496 | struct audit_context *ctx = tsk->audit_context; |
2497 | uid_t uid = current_uid(), t_uid = task_uid(t); | ||
2493 | 2498 | ||
2494 | if (audit_pid && t->tgid == audit_pid) { | 2499 | if (audit_pid && t->tgid == audit_pid) { |
2495 | if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) { | 2500 | if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) { |
@@ -2497,7 +2502,7 @@ int __audit_signal_info(int sig, struct task_struct *t) | |||
2497 | if (tsk->loginuid != -1) | 2502 | if (tsk->loginuid != -1) |
2498 | audit_sig_uid = tsk->loginuid; | 2503 | audit_sig_uid = tsk->loginuid; |
2499 | else | 2504 | else |
2500 | audit_sig_uid = tsk->cred->uid; | 2505 | audit_sig_uid = uid; |
2501 | security_task_getsecid(tsk, &audit_sig_sid); | 2506 | security_task_getsecid(tsk, &audit_sig_sid); |
2502 | } | 2507 | } |
2503 | if (!audit_signals || audit_dummy_context()) | 2508 | if (!audit_signals || audit_dummy_context()) |
@@ -2509,7 +2514,7 @@ int __audit_signal_info(int sig, struct task_struct *t) | |||
2509 | if (!ctx->target_pid) { | 2514 | if (!ctx->target_pid) { |
2510 | ctx->target_pid = t->tgid; | 2515 | ctx->target_pid = t->tgid; |
2511 | ctx->target_auid = audit_get_loginuid(t); | 2516 | ctx->target_auid = audit_get_loginuid(t); |
2512 | ctx->target_uid = t->cred->uid; | 2517 | ctx->target_uid = t_uid; |
2513 | ctx->target_sessionid = audit_get_sessionid(t); | 2518 | ctx->target_sessionid = audit_get_sessionid(t); |
2514 | security_task_getsecid(t, &ctx->target_sid); | 2519 | security_task_getsecid(t, &ctx->target_sid); |
2515 | memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN); | 2520 | memcpy(ctx->target_comm, t->comm, TASK_COMM_LEN); |
@@ -2530,7 +2535,7 @@ int __audit_signal_info(int sig, struct task_struct *t) | |||
2530 | 2535 | ||
2531 | axp->target_pid[axp->pid_count] = t->tgid; | 2536 | axp->target_pid[axp->pid_count] = t->tgid; |
2532 | axp->target_auid[axp->pid_count] = audit_get_loginuid(t); | 2537 | axp->target_auid[axp->pid_count] = audit_get_loginuid(t); |
2533 | axp->target_uid[axp->pid_count] = t->cred->uid; | 2538 | axp->target_uid[axp->pid_count] = t_uid; |
2534 | axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t); | 2539 | axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t); |
2535 | security_task_getsecid(t, &axp->target_sid[axp->pid_count]); | 2540 | security_task_getsecid(t, &axp->target_sid[axp->pid_count]); |
2536 | memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN); | 2541 | memcpy(axp->target_comm[axp->pid_count], t->comm, TASK_COMM_LEN); |
diff --git a/kernel/cgroup.c b/kernel/cgroup.c index e210526e6401..a512a75a5560 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c | |||
@@ -1279,7 +1279,7 @@ int cgroup_attach_task(struct cgroup *cgrp, struct task_struct *tsk) | |||
1279 | static int attach_task_by_pid(struct cgroup *cgrp, u64 pid) | 1279 | static int attach_task_by_pid(struct cgroup *cgrp, u64 pid) |
1280 | { | 1280 | { |
1281 | struct task_struct *tsk; | 1281 | struct task_struct *tsk; |
1282 | uid_t euid; | 1282 | const struct cred *cred = current_cred(), *tcred; |
1283 | int ret; | 1283 | int ret; |
1284 | 1284 | ||
1285 | if (pid) { | 1285 | if (pid) { |
@@ -1289,16 +1289,16 @@ static int attach_task_by_pid(struct cgroup *cgrp, u64 pid) | |||
1289 | rcu_read_unlock(); | 1289 | rcu_read_unlock(); |
1290 | return -ESRCH; | 1290 | return -ESRCH; |
1291 | } | 1291 | } |
1292 | get_task_struct(tsk); | ||
1293 | rcu_read_unlock(); | ||
1294 | 1292 | ||
1295 | euid = current_euid(); | 1293 | tcred = __task_cred(tsk); |
1296 | if (euid && | 1294 | if (cred->euid && |
1297 | euid != tsk->cred->uid && | 1295 | cred->euid != tcred->uid && |
1298 | euid != tsk->cred->suid) { | 1296 | cred->euid != tcred->suid) { |
1299 | put_task_struct(tsk); | 1297 | rcu_read_unlock(); |
1300 | return -EACCES; | 1298 | return -EACCES; |
1301 | } | 1299 | } |
1300 | get_task_struct(tsk); | ||
1301 | rcu_read_unlock(); | ||
1302 | } else { | 1302 | } else { |
1303 | tsk = current; | 1303 | tsk = current; |
1304 | get_task_struct(tsk); | 1304 | get_task_struct(tsk); |
diff --git a/kernel/exit.c b/kernel/exit.c index e0f6e1892fb9..bbc22530f2c1 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
@@ -160,7 +160,10 @@ void release_task(struct task_struct * p) | |||
160 | int zap_leader; | 160 | int zap_leader; |
161 | repeat: | 161 | repeat: |
162 | tracehook_prepare_release_task(p); | 162 | tracehook_prepare_release_task(p); |
163 | atomic_dec(&p->cred->user->processes); | 163 | /* don't need to get the RCU readlock here - the process is dead and |
164 | * can't be modifying its own credentials */ | ||
165 | atomic_dec(&__task_cred(p)->user->processes); | ||
166 | |||
164 | proc_flush_task(p); | 167 | proc_flush_task(p); |
165 | write_lock_irq(&tasklist_lock); | 168 | write_lock_irq(&tasklist_lock); |
166 | tracehook_finish_release_task(p); | 169 | tracehook_finish_release_task(p); |
@@ -1267,12 +1270,12 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
1267 | unsigned long state; | 1270 | unsigned long state; |
1268 | int retval, status, traced; | 1271 | int retval, status, traced; |
1269 | pid_t pid = task_pid_vnr(p); | 1272 | pid_t pid = task_pid_vnr(p); |
1273 | uid_t uid = __task_cred(p)->uid; | ||
1270 | 1274 | ||
1271 | if (!likely(options & WEXITED)) | 1275 | if (!likely(options & WEXITED)) |
1272 | return 0; | 1276 | return 0; |
1273 | 1277 | ||
1274 | if (unlikely(options & WNOWAIT)) { | 1278 | if (unlikely(options & WNOWAIT)) { |
1275 | uid_t uid = p->cred->uid; | ||
1276 | int exit_code = p->exit_code; | 1279 | int exit_code = p->exit_code; |
1277 | int why, status; | 1280 | int why, status; |
1278 | 1281 | ||
@@ -1393,7 +1396,7 @@ static int wait_task_zombie(struct task_struct *p, int options, | |||
1393 | if (!retval && infop) | 1396 | if (!retval && infop) |
1394 | retval = put_user(pid, &infop->si_pid); | 1397 | retval = put_user(pid, &infop->si_pid); |
1395 | if (!retval && infop) | 1398 | if (!retval && infop) |
1396 | retval = put_user(p->cred->uid, &infop->si_uid); | 1399 | retval = put_user(uid, &infop->si_uid); |
1397 | if (!retval) | 1400 | if (!retval) |
1398 | retval = pid; | 1401 | retval = pid; |
1399 | 1402 | ||
@@ -1458,7 +1461,8 @@ static int wait_task_stopped(int ptrace, struct task_struct *p, | |||
1458 | if (!unlikely(options & WNOWAIT)) | 1461 | if (!unlikely(options & WNOWAIT)) |
1459 | p->exit_code = 0; | 1462 | p->exit_code = 0; |
1460 | 1463 | ||
1461 | uid = p->cred->uid; | 1464 | /* don't need the RCU readlock here as we're holding a spinlock */ |
1465 | uid = __task_cred(p)->uid; | ||
1462 | unlock_sig: | 1466 | unlock_sig: |
1463 | spin_unlock_irq(&p->sighand->siglock); | 1467 | spin_unlock_irq(&p->sighand->siglock); |
1464 | if (!exit_code) | 1468 | if (!exit_code) |
@@ -1532,10 +1536,10 @@ static int wait_task_continued(struct task_struct *p, int options, | |||
1532 | } | 1536 | } |
1533 | if (!unlikely(options & WNOWAIT)) | 1537 | if (!unlikely(options & WNOWAIT)) |
1534 | p->signal->flags &= ~SIGNAL_STOP_CONTINUED; | 1538 | p->signal->flags &= ~SIGNAL_STOP_CONTINUED; |
1539 | uid = __task_cred(p)->uid; | ||
1535 | spin_unlock_irq(&p->sighand->siglock); | 1540 | spin_unlock_irq(&p->sighand->siglock); |
1536 | 1541 | ||
1537 | pid = task_pid_vnr(p); | 1542 | pid = task_pid_vnr(p); |
1538 | uid = p->cred->uid; | ||
1539 | get_task_struct(p); | 1543 | get_task_struct(p); |
1540 | read_unlock(&tasklist_lock); | 1544 | read_unlock(&tasklist_lock); |
1541 | 1545 | ||
diff --git a/kernel/futex.c b/kernel/futex.c index 28421d8210b8..4fe790e89d0f 100644 --- a/kernel/futex.c +++ b/kernel/futex.c | |||
@@ -439,15 +439,20 @@ static void free_pi_state(struct futex_pi_state *pi_state) | |||
439 | static struct task_struct * futex_find_get_task(pid_t pid) | 439 | static struct task_struct * futex_find_get_task(pid_t pid) |
440 | { | 440 | { |
441 | struct task_struct *p; | 441 | struct task_struct *p; |
442 | uid_t euid = current_euid(); | 442 | const struct cred *cred = current_cred(), *pcred; |
443 | 443 | ||
444 | rcu_read_lock(); | 444 | rcu_read_lock(); |
445 | p = find_task_by_vpid(pid); | 445 | p = find_task_by_vpid(pid); |
446 | if (!p || (euid != p->cred->euid && | 446 | if (!p) { |
447 | euid != p->cred->uid)) | ||
448 | p = ERR_PTR(-ESRCH); | 447 | p = ERR_PTR(-ESRCH); |
449 | else | 448 | } else { |
450 | get_task_struct(p); | 449 | pcred = __task_cred(p); |
450 | if (cred->euid != pcred->euid && | ||
451 | cred->euid != pcred->uid) | ||
452 | p = ERR_PTR(-ESRCH); | ||
453 | else | ||
454 | get_task_struct(p); | ||
455 | } | ||
451 | 456 | ||
452 | rcu_read_unlock(); | 457 | rcu_read_unlock(); |
453 | 458 | ||
@@ -1831,7 +1836,7 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr, | |||
1831 | { | 1836 | { |
1832 | struct robust_list_head __user *head; | 1837 | struct robust_list_head __user *head; |
1833 | unsigned long ret; | 1838 | unsigned long ret; |
1834 | uid_t euid = current_euid(); | 1839 | const struct cred *cred = current_cred(), *pcred; |
1835 | 1840 | ||
1836 | if (!futex_cmpxchg_enabled) | 1841 | if (!futex_cmpxchg_enabled) |
1837 | return -ENOSYS; | 1842 | return -ENOSYS; |
@@ -1847,8 +1852,9 @@ sys_get_robust_list(int pid, struct robust_list_head __user * __user *head_ptr, | |||
1847 | if (!p) | 1852 | if (!p) |
1848 | goto err_unlock; | 1853 | goto err_unlock; |
1849 | ret = -EPERM; | 1854 | ret = -EPERM; |
1850 | if (euid != p->cred->euid && | 1855 | pcred = __task_cred(p); |
1851 | euid != p->cred->uid && | 1856 | if (cred->euid != pcred->euid && |
1857 | cred->euid != pcred->uid && | ||
1852 | !capable(CAP_SYS_PTRACE)) | 1858 | !capable(CAP_SYS_PTRACE)) |
1853 | goto err_unlock; | 1859 | goto err_unlock; |
1854 | head = p->robust_list; | 1860 | head = p->robust_list; |
diff --git a/kernel/futex_compat.c b/kernel/futex_compat.c index 2c3fd5ed34f5..d607a5b9ee29 100644 --- a/kernel/futex_compat.c +++ b/kernel/futex_compat.c | |||
@@ -135,7 +135,7 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, | |||
135 | { | 135 | { |
136 | struct compat_robust_list_head __user *head; | 136 | struct compat_robust_list_head __user *head; |
137 | unsigned long ret; | 137 | unsigned long ret; |
138 | uid_t euid = current_euid(); | 138 | const struct cred *cred = current_cred(), *pcred; |
139 | 139 | ||
140 | if (!futex_cmpxchg_enabled) | 140 | if (!futex_cmpxchg_enabled) |
141 | return -ENOSYS; | 141 | return -ENOSYS; |
@@ -151,8 +151,9 @@ compat_sys_get_robust_list(int pid, compat_uptr_t __user *head_ptr, | |||
151 | if (!p) | 151 | if (!p) |
152 | goto err_unlock; | 152 | goto err_unlock; |
153 | ret = -EPERM; | 153 | ret = -EPERM; |
154 | if (euid != p->cred->euid && | 154 | pcred = __task_cred(p); |
155 | euid != p->cred->uid && | 155 | if (cred->euid != pcred->euid && |
156 | cred->euid != pcred->uid && | ||
156 | !capable(CAP_SYS_PTRACE)) | 157 | !capable(CAP_SYS_PTRACE)) |
157 | goto err_unlock; | 158 | goto err_unlock; |
158 | head = p->compat_robust_list; | 159 | head = p->compat_robust_list; |
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 49849d12dd12..b9d5f4e4f6a4 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
@@ -115,7 +115,7 @@ int ptrace_check_attach(struct task_struct *child, int kill) | |||
115 | 115 | ||
116 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) | 116 | int __ptrace_may_access(struct task_struct *task, unsigned int mode) |
117 | { | 117 | { |
118 | struct cred *cred = current->cred, *tcred = task->cred; | 118 | const struct cred *cred = current_cred(), *tcred; |
119 | 119 | ||
120 | /* May we inspect the given task? | 120 | /* May we inspect the given task? |
121 | * This check is used both for attaching with ptrace | 121 | * This check is used both for attaching with ptrace |
@@ -125,19 +125,23 @@ int __ptrace_may_access(struct task_struct *task, unsigned int mode) | |||
125 | * because setting up the necessary parent/child relationship | 125 | * because setting up the necessary parent/child relationship |
126 | * or halting the specified task is impossible. | 126 | * or halting the specified task is impossible. |
127 | */ | 127 | */ |
128 | uid_t uid = cred->uid; | ||
129 | gid_t gid = cred->gid; | ||
130 | int dumpable = 0; | 128 | int dumpable = 0; |
131 | /* Don't let security modules deny introspection */ | 129 | /* Don't let security modules deny introspection */ |
132 | if (task == current) | 130 | if (task == current) |
133 | return 0; | 131 | return 0; |
134 | if ((uid != tcred->euid || | 132 | rcu_read_lock(); |
135 | uid != tcred->suid || | 133 | tcred = __task_cred(task); |
136 | uid != tcred->uid || | 134 | if ((cred->uid != tcred->euid || |
137 | gid != tcred->egid || | 135 | cred->uid != tcred->suid || |
138 | gid != tcred->sgid || | 136 | cred->uid != tcred->uid || |
139 | gid != tcred->gid) && !capable(CAP_SYS_PTRACE)) | 137 | cred->gid != tcred->egid || |
138 | cred->gid != tcred->sgid || | ||
139 | cred->gid != tcred->gid) && | ||
140 | !capable(CAP_SYS_PTRACE)) { | ||
141 | rcu_read_unlock(); | ||
140 | return -EPERM; | 142 | return -EPERM; |
143 | } | ||
144 | rcu_read_unlock(); | ||
141 | smp_rmb(); | 145 | smp_rmb(); |
142 | if (task->mm) | 146 | if (task->mm) |
143 | dumpable = get_dumpable(task->mm); | 147 | dumpable = get_dumpable(task->mm); |
diff --git a/kernel/sched.c b/kernel/sched.c index 733c59e645aa..92992e287b10 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); |
diff --git a/kernel/signal.c b/kernel/signal.c index 80e8a6489f97..84989124bafb 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -177,6 +177,11 @@ int next_signal(struct sigpending *pending, sigset_t *mask) | |||
177 | return sig; | 177 | return sig; |
178 | } | 178 | } |
179 | 179 | ||
180 | /* | ||
181 | * allocate a new signal queue record | ||
182 | * - this may be called without locks if and only if t == current, otherwise an | ||
183 | * appopriate lock must be held to protect t's user_struct | ||
184 | */ | ||
180 | static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, | 185 | static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, |
181 | int override_rlimit) | 186 | int override_rlimit) |
182 | { | 187 | { |
@@ -184,11 +189,12 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, | |||
184 | struct user_struct *user; | 189 | struct user_struct *user; |
185 | 190 | ||
186 | /* | 191 | /* |
187 | * In order to avoid problems with "switch_user()", we want to make | 192 | * We won't get problems with the target's UID changing under us |
188 | * sure that the compiler doesn't re-load "t->user" | 193 | * because changing it requires RCU be used, and if t != current, the |
194 | * caller must be holding the RCU readlock (by way of a spinlock) and | ||
195 | * we use RCU protection here | ||
189 | */ | 196 | */ |
190 | user = t->cred->user; | 197 | user = __task_cred(t)->user; |
191 | barrier(); | ||
192 | atomic_inc(&user->sigpending); | 198 | atomic_inc(&user->sigpending); |
193 | if (override_rlimit || | 199 | if (override_rlimit || |
194 | atomic_read(&user->sigpending) <= | 200 | atomic_read(&user->sigpending) <= |
@@ -562,12 +568,13 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s) | |||
562 | 568 | ||
563 | /* | 569 | /* |
564 | * Bad permissions for sending the signal | 570 | * Bad permissions for sending the signal |
571 | * - the caller must hold at least the RCU read lock | ||
565 | */ | 572 | */ |
566 | static int check_kill_permission(int sig, struct siginfo *info, | 573 | static int check_kill_permission(int sig, struct siginfo *info, |
567 | struct task_struct *t) | 574 | struct task_struct *t) |
568 | { | 575 | { |
576 | const struct cred *cred = current_cred(), *tcred; | ||
569 | struct pid *sid; | 577 | struct pid *sid; |
570 | uid_t uid, euid; | ||
571 | int error; | 578 | int error; |
572 | 579 | ||
573 | if (!valid_signal(sig)) | 580 | if (!valid_signal(sig)) |
@@ -580,10 +587,11 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
580 | if (error) | 587 | if (error) |
581 | return error; | 588 | return error; |
582 | 589 | ||
583 | uid = current_uid(); | 590 | tcred = __task_cred(t); |
584 | euid = current_euid(); | 591 | if ((cred->euid ^ tcred->suid) && |
585 | if ((euid ^ t->cred->suid) && (euid ^ t->cred->uid) && | 592 | (cred->euid ^ tcred->uid) && |
586 | (uid ^ t->cred->suid) && (uid ^ t->cred->uid) && | 593 | (cred->uid ^ tcred->suid) && |
594 | (cred->uid ^ tcred->uid) && | ||
587 | !capable(CAP_KILL)) { | 595 | !capable(CAP_KILL)) { |
588 | switch (sig) { | 596 | switch (sig) { |
589 | case SIGCONT: | 597 | case SIGCONT: |
@@ -1011,6 +1019,10 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long | |||
1011 | return sighand; | 1019 | return sighand; |
1012 | } | 1020 | } |
1013 | 1021 | ||
1022 | /* | ||
1023 | * send signal info to all the members of a group | ||
1024 | * - the caller must hold the RCU read lock at least | ||
1025 | */ | ||
1014 | int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | 1026 | int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) |
1015 | { | 1027 | { |
1016 | unsigned long flags; | 1028 | unsigned long flags; |
@@ -1032,8 +1044,8 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | |||
1032 | /* | 1044 | /* |
1033 | * __kill_pgrp_info() sends a signal to a process group: this is what the tty | 1045 | * __kill_pgrp_info() sends a signal to a process group: this is what the tty |
1034 | * control characters do (^C, ^Z etc) | 1046 | * control characters do (^C, ^Z etc) |
1047 | * - the caller must hold at least a readlock on tasklist_lock | ||
1035 | */ | 1048 | */ |
1036 | |||
1037 | int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) | 1049 | int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) |
1038 | { | 1050 | { |
1039 | struct task_struct *p = NULL; | 1051 | struct task_struct *p = NULL; |
@@ -1089,6 +1101,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1089 | { | 1101 | { |
1090 | int ret = -EINVAL; | 1102 | int ret = -EINVAL; |
1091 | struct task_struct *p; | 1103 | struct task_struct *p; |
1104 | const struct cred *pcred; | ||
1092 | 1105 | ||
1093 | if (!valid_signal(sig)) | 1106 | if (!valid_signal(sig)) |
1094 | return ret; | 1107 | return ret; |
@@ -1099,9 +1112,11 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1099 | ret = -ESRCH; | 1112 | ret = -ESRCH; |
1100 | goto out_unlock; | 1113 | goto out_unlock; |
1101 | } | 1114 | } |
1102 | if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) | 1115 | pcred = __task_cred(p); |
1103 | && (euid != p->cred->suid) && (euid != p->cred->uid) | 1116 | if ((info == SEND_SIG_NOINFO || |
1104 | && (uid != p->cred->suid) && (uid != p->cred->uid)) { | 1117 | (!is_si_special(info) && SI_FROMUSER(info))) && |
1118 | euid != pcred->suid && euid != pcred->uid && | ||
1119 | uid != pcred->suid && uid != pcred->uid) { | ||
1105 | ret = -EPERM; | 1120 | ret = -EPERM; |
1106 | goto out_unlock; | 1121 | goto out_unlock; |
1107 | } | 1122 | } |
@@ -1372,10 +1387,9 @@ int do_notify_parent(struct task_struct *tsk, int sig) | |||
1372 | */ | 1387 | */ |
1373 | rcu_read_lock(); | 1388 | rcu_read_lock(); |
1374 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); | 1389 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); |
1390 | info.si_uid = __task_cred(tsk)->uid; | ||
1375 | rcu_read_unlock(); | 1391 | rcu_read_unlock(); |
1376 | 1392 | ||
1377 | info.si_uid = tsk->cred->uid; | ||
1378 | |||
1379 | thread_group_cputime(tsk, &cputime); | 1393 | thread_group_cputime(tsk, &cputime); |
1380 | info.si_utime = cputime_to_jiffies(cputime.utime); | 1394 | info.si_utime = cputime_to_jiffies(cputime.utime); |
1381 | info.si_stime = cputime_to_jiffies(cputime.stime); | 1395 | info.si_stime = cputime_to_jiffies(cputime.stime); |
@@ -1443,10 +1457,9 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why) | |||
1443 | */ | 1457 | */ |
1444 | rcu_read_lock(); | 1458 | rcu_read_lock(); |
1445 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); | 1459 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); |
1460 | info.si_uid = __task_cred(tsk)->uid; | ||
1446 | rcu_read_unlock(); | 1461 | rcu_read_unlock(); |
1447 | 1462 | ||
1448 | info.si_uid = tsk->cred->uid; | ||
1449 | |||
1450 | info.si_utime = cputime_to_clock_t(tsk->utime); | 1463 | info.si_utime = cputime_to_clock_t(tsk->utime); |
1451 | info.si_stime = cputime_to_clock_t(tsk->stime); | 1464 | info.si_stime = cputime_to_clock_t(tsk->stime); |
1452 | 1465 | ||
@@ -1713,7 +1726,7 @@ static int ptrace_signal(int signr, siginfo_t *info, | |||
1713 | info->si_errno = 0; | 1726 | info->si_errno = 0; |
1714 | info->si_code = SI_USER; | 1727 | info->si_code = SI_USER; |
1715 | info->si_pid = task_pid_vnr(current->parent); | 1728 | info->si_pid = task_pid_vnr(current->parent); |
1716 | info->si_uid = current->parent->cred->uid; | 1729 | info->si_uid = task_uid(current->parent); |
1717 | } | 1730 | } |
1718 | 1731 | ||
1719 | /* If the (new) signal is now blocked, requeue it. */ | 1732 | /* If the (new) signal is now blocked, requeue it. */ |
diff --git a/kernel/sys.c b/kernel/sys.c index c4d6b59553e9..ccc9eb736d35 100644 --- a/kernel/sys.c +++ b/kernel/sys.c | |||
@@ -112,14 +112,17 @@ EXPORT_SYMBOL(cad_pid); | |||
112 | 112 | ||
113 | void (*pm_power_off_prepare)(void); | 113 | void (*pm_power_off_prepare)(void); |
114 | 114 | ||
115 | /* | ||
116 | * set the priority of a task | ||
117 | * - the caller must hold the RCU read lock | ||
118 | */ | ||
115 | static int set_one_prio(struct task_struct *p, int niceval, int error) | 119 | static int set_one_prio(struct task_struct *p, int niceval, int error) |
116 | { | 120 | { |
117 | uid_t euid = current_euid(); | 121 | const struct cred *cred = current_cred(), *pcred = __task_cred(p); |
118 | int no_nice; | 122 | int no_nice; |
119 | 123 | ||
120 | if (p->cred->uid != euid && | 124 | if (pcred->uid != cred->euid && |
121 | p->cred->euid != euid && | 125 | pcred->euid != cred->euid && !capable(CAP_SYS_NICE)) { |
122 | !capable(CAP_SYS_NICE)) { | ||
123 | error = -EPERM; | 126 | error = -EPERM; |
124 | goto out; | 127 | goto out; |
125 | } | 128 | } |
diff --git a/kernel/tsacct.c b/kernel/tsacct.c index 6d1ed07bf312..2dc06ab35716 100644 --- a/kernel/tsacct.c +++ b/kernel/tsacct.c | |||
@@ -27,6 +27,7 @@ | |||
27 | */ | 27 | */ |
28 | void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) | 28 | void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) |
29 | { | 29 | { |
30 | const struct cred *tcred; | ||
30 | struct timespec uptime, ts; | 31 | struct timespec uptime, ts; |
31 | u64 ac_etime; | 32 | u64 ac_etime; |
32 | 33 | ||
@@ -53,10 +54,11 @@ void bacct_add_tsk(struct taskstats *stats, struct task_struct *tsk) | |||
53 | stats->ac_flag |= AXSIG; | 54 | stats->ac_flag |= AXSIG; |
54 | stats->ac_nice = task_nice(tsk); | 55 | stats->ac_nice = task_nice(tsk); |
55 | stats->ac_sched = tsk->policy; | 56 | stats->ac_sched = tsk->policy; |
56 | stats->ac_uid = tsk->cred->uid; | ||
57 | stats->ac_gid = tsk->cred->gid; | ||
58 | stats->ac_pid = tsk->pid; | 57 | stats->ac_pid = tsk->pid; |
59 | rcu_read_lock(); | 58 | rcu_read_lock(); |
59 | tcred = __task_cred(tsk); | ||
60 | stats->ac_uid = tcred->uid; | ||
61 | stats->ac_gid = tcred->gid; | ||
60 | stats->ac_ppid = pid_alive(tsk) ? | 62 | stats->ac_ppid = pid_alive(tsk) ? |
61 | rcu_dereference(tsk->real_parent)->tgid : 0; | 63 | rcu_dereference(tsk->real_parent)->tgid : 0; |
62 | rcu_read_unlock(); | 64 | rcu_read_unlock(); |