diff options
author | James Morris <jmorris@namei.org> | 2008-12-24 19:40:09 -0500 |
---|---|---|
committer | James Morris <jmorris@namei.org> | 2008-12-24 19:40:09 -0500 |
commit | cbacc2c7f066a1e01b33b0e27ae5efbf534bc2db (patch) | |
tree | 90d1093131d2a3543a8b3b1f3364e7c6f4081a93 /kernel/signal.c | |
parent | 4a6908a3a050aacc9c3a2f36b276b46c0629ad91 (diff) | |
parent | 74192246910ff4fb95309ba1a683215644beeb62 (diff) |
Merge branch 'next' into for-linus
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 60 |
1 files changed, 39 insertions, 21 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 4530fc654455..2a64304ed54b 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 stop the target task from exiting | ||
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->user; | 197 | user = get_uid(__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) <= |
@@ -196,12 +202,14 @@ static struct sigqueue *__sigqueue_alloc(struct task_struct *t, gfp_t flags, | |||
196 | q = kmem_cache_alloc(sigqueue_cachep, flags); | 202 | q = kmem_cache_alloc(sigqueue_cachep, flags); |
197 | if (unlikely(q == NULL)) { | 203 | if (unlikely(q == NULL)) { |
198 | atomic_dec(&user->sigpending); | 204 | atomic_dec(&user->sigpending); |
205 | free_uid(user); | ||
199 | } else { | 206 | } else { |
200 | INIT_LIST_HEAD(&q->list); | 207 | INIT_LIST_HEAD(&q->list); |
201 | q->flags = 0; | 208 | q->flags = 0; |
202 | q->user = get_uid(user); | 209 | q->user = user; |
203 | } | 210 | } |
204 | return(q); | 211 | |
212 | return q; | ||
205 | } | 213 | } |
206 | 214 | ||
207 | static void __sigqueue_free(struct sigqueue *q) | 215 | static void __sigqueue_free(struct sigqueue *q) |
@@ -562,10 +570,12 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s) | |||
562 | 570 | ||
563 | /* | 571 | /* |
564 | * Bad permissions for sending the signal | 572 | * Bad permissions for sending the signal |
573 | * - the caller must hold at least the RCU read lock | ||
565 | */ | 574 | */ |
566 | static int check_kill_permission(int sig, struct siginfo *info, | 575 | static int check_kill_permission(int sig, struct siginfo *info, |
567 | struct task_struct *t) | 576 | struct task_struct *t) |
568 | { | 577 | { |
578 | const struct cred *cred = current_cred(), *tcred; | ||
569 | struct pid *sid; | 579 | struct pid *sid; |
570 | int error; | 580 | int error; |
571 | 581 | ||
@@ -579,8 +589,11 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
579 | if (error) | 589 | if (error) |
580 | return error; | 590 | return error; |
581 | 591 | ||
582 | if ((current->euid ^ t->suid) && (current->euid ^ t->uid) && | 592 | tcred = __task_cred(t); |
583 | (current->uid ^ t->suid) && (current->uid ^ t->uid) && | 593 | if ((cred->euid ^ tcred->suid) && |
594 | (cred->euid ^ tcred->uid) && | ||
595 | (cred->uid ^ tcred->suid) && | ||
596 | (cred->uid ^ tcred->uid) && | ||
584 | !capable(CAP_KILL)) { | 597 | !capable(CAP_KILL)) { |
585 | switch (sig) { | 598 | switch (sig) { |
586 | case SIGCONT: | 599 | case SIGCONT: |
@@ -844,7 +857,7 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
844 | q->info.si_errno = 0; | 857 | q->info.si_errno = 0; |
845 | q->info.si_code = SI_USER; | 858 | q->info.si_code = SI_USER; |
846 | q->info.si_pid = task_pid_vnr(current); | 859 | q->info.si_pid = task_pid_vnr(current); |
847 | q->info.si_uid = current->uid; | 860 | q->info.si_uid = current_uid(); |
848 | break; | 861 | break; |
849 | case (unsigned long) SEND_SIG_PRIV: | 862 | case (unsigned long) SEND_SIG_PRIV: |
850 | q->info.si_signo = sig; | 863 | q->info.si_signo = sig; |
@@ -1008,6 +1021,10 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long | |||
1008 | return sighand; | 1021 | return sighand; |
1009 | } | 1022 | } |
1010 | 1023 | ||
1024 | /* | ||
1025 | * send signal info to all the members of a group | ||
1026 | * - the caller must hold the RCU read lock at least | ||
1027 | */ | ||
1011 | int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | 1028 | int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) |
1012 | { | 1029 | { |
1013 | unsigned long flags; | 1030 | unsigned long flags; |
@@ -1029,8 +1046,8 @@ int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | |||
1029 | /* | 1046 | /* |
1030 | * __kill_pgrp_info() sends a signal to a process group: this is what the tty | 1047 | * __kill_pgrp_info() sends a signal to a process group: this is what the tty |
1031 | * control characters do (^C, ^Z etc) | 1048 | * control characters do (^C, ^Z etc) |
1049 | * - the caller must hold at least a readlock on tasklist_lock | ||
1032 | */ | 1050 | */ |
1033 | |||
1034 | int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) | 1051 | int __kill_pgrp_info(int sig, struct siginfo *info, struct pid *pgrp) |
1035 | { | 1052 | { |
1036 | struct task_struct *p = NULL; | 1053 | struct task_struct *p = NULL; |
@@ -1086,6 +1103,7 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1086 | { | 1103 | { |
1087 | int ret = -EINVAL; | 1104 | int ret = -EINVAL; |
1088 | struct task_struct *p; | 1105 | struct task_struct *p; |
1106 | const struct cred *pcred; | ||
1089 | 1107 | ||
1090 | if (!valid_signal(sig)) | 1108 | if (!valid_signal(sig)) |
1091 | return ret; | 1109 | return ret; |
@@ -1096,9 +1114,11 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
1096 | ret = -ESRCH; | 1114 | ret = -ESRCH; |
1097 | goto out_unlock; | 1115 | goto out_unlock; |
1098 | } | 1116 | } |
1099 | if ((info == SEND_SIG_NOINFO || (!is_si_special(info) && SI_FROMUSER(info))) | 1117 | pcred = __task_cred(p); |
1100 | && (euid != p->suid) && (euid != p->uid) | 1118 | if ((info == SEND_SIG_NOINFO || |
1101 | && (uid != p->suid) && (uid != p->uid)) { | 1119 | (!is_si_special(info) && SI_FROMUSER(info))) && |
1120 | euid != pcred->suid && euid != pcred->uid && | ||
1121 | uid != pcred->suid && uid != pcred->uid) { | ||
1102 | ret = -EPERM; | 1122 | ret = -EPERM; |
1103 | goto out_unlock; | 1123 | goto out_unlock; |
1104 | } | 1124 | } |
@@ -1369,10 +1389,9 @@ int do_notify_parent(struct task_struct *tsk, int sig) | |||
1369 | */ | 1389 | */ |
1370 | rcu_read_lock(); | 1390 | rcu_read_lock(); |
1371 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); | 1391 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); |
1392 | info.si_uid = __task_cred(tsk)->uid; | ||
1372 | rcu_read_unlock(); | 1393 | rcu_read_unlock(); |
1373 | 1394 | ||
1374 | info.si_uid = tsk->uid; | ||
1375 | |||
1376 | thread_group_cputime(tsk, &cputime); | 1395 | thread_group_cputime(tsk, &cputime); |
1377 | info.si_utime = cputime_to_jiffies(cputime.utime); | 1396 | info.si_utime = cputime_to_jiffies(cputime.utime); |
1378 | info.si_stime = cputime_to_jiffies(cputime.stime); | 1397 | info.si_stime = cputime_to_jiffies(cputime.stime); |
@@ -1440,10 +1459,9 @@ static void do_notify_parent_cldstop(struct task_struct *tsk, int why) | |||
1440 | */ | 1459 | */ |
1441 | rcu_read_lock(); | 1460 | rcu_read_lock(); |
1442 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); | 1461 | info.si_pid = task_pid_nr_ns(tsk, tsk->parent->nsproxy->pid_ns); |
1462 | info.si_uid = __task_cred(tsk)->uid; | ||
1443 | rcu_read_unlock(); | 1463 | rcu_read_unlock(); |
1444 | 1464 | ||
1445 | info.si_uid = tsk->uid; | ||
1446 | |||
1447 | info.si_utime = cputime_to_clock_t(tsk->utime); | 1465 | info.si_utime = cputime_to_clock_t(tsk->utime); |
1448 | info.si_stime = cputime_to_clock_t(tsk->stime); | 1466 | info.si_stime = cputime_to_clock_t(tsk->stime); |
1449 | 1467 | ||
@@ -1598,7 +1616,7 @@ void ptrace_notify(int exit_code) | |||
1598 | info.si_signo = SIGTRAP; | 1616 | info.si_signo = SIGTRAP; |
1599 | info.si_code = exit_code; | 1617 | info.si_code = exit_code; |
1600 | info.si_pid = task_pid_vnr(current); | 1618 | info.si_pid = task_pid_vnr(current); |
1601 | info.si_uid = current->uid; | 1619 | info.si_uid = current_uid(); |
1602 | 1620 | ||
1603 | /* Let the debugger run. */ | 1621 | /* Let the debugger run. */ |
1604 | spin_lock_irq(¤t->sighand->siglock); | 1622 | spin_lock_irq(¤t->sighand->siglock); |
@@ -1710,7 +1728,7 @@ static int ptrace_signal(int signr, siginfo_t *info, | |||
1710 | info->si_errno = 0; | 1728 | info->si_errno = 0; |
1711 | info->si_code = SI_USER; | 1729 | info->si_code = SI_USER; |
1712 | info->si_pid = task_pid_vnr(current->parent); | 1730 | info->si_pid = task_pid_vnr(current->parent); |
1713 | info->si_uid = current->parent->uid; | 1731 | info->si_uid = task_uid(current->parent); |
1714 | } | 1732 | } |
1715 | 1733 | ||
1716 | /* If the (new) signal is now blocked, requeue it. */ | 1734 | /* If the (new) signal is now blocked, requeue it. */ |
@@ -2211,7 +2229,7 @@ sys_kill(pid_t pid, int sig) | |||
2211 | info.si_errno = 0; | 2229 | info.si_errno = 0; |
2212 | info.si_code = SI_USER; | 2230 | info.si_code = SI_USER; |
2213 | info.si_pid = task_tgid_vnr(current); | 2231 | info.si_pid = task_tgid_vnr(current); |
2214 | info.si_uid = current->uid; | 2232 | info.si_uid = current_uid(); |
2215 | 2233 | ||
2216 | return kill_something_info(sig, &info, pid); | 2234 | return kill_something_info(sig, &info, pid); |
2217 | } | 2235 | } |
@@ -2228,7 +2246,7 @@ static int do_tkill(pid_t tgid, pid_t pid, int sig) | |||
2228 | info.si_errno = 0; | 2246 | info.si_errno = 0; |
2229 | info.si_code = SI_TKILL; | 2247 | info.si_code = SI_TKILL; |
2230 | info.si_pid = task_tgid_vnr(current); | 2248 | info.si_pid = task_tgid_vnr(current); |
2231 | info.si_uid = current->uid; | 2249 | info.si_uid = current_uid(); |
2232 | 2250 | ||
2233 | rcu_read_lock(); | 2251 | rcu_read_lock(); |
2234 | p = find_task_by_vpid(pid); | 2252 | p = find_task_by_vpid(pid); |