aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2008-11-13 18:39:19 -0500
committerJames Morris <jmorris@namei.org>2008-11-13 18:39:19 -0500
commitc69e8d9c01db2adc503464993c358901c9af9de4 (patch)
treebed94aaa9aeb7a7834d1c880f72b62a11a752c78 /kernel/signal.c
parent86a264abe542cfececb4df129bc45a0338d8cdb9 (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/signal.c')
-rw-r--r--kernel/signal.c49
1 files changed, 31 insertions, 18 deletions
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 */
180static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, 185static 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 */
566static int check_kill_permission(int sig, struct siginfo *info, 573static 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 */
1014int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) 1026int 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
1037int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) 1049int __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. */