diff options
Diffstat (limited to 'kernel/signal.c')
| -rw-r--r-- | kernel/signal.c | 66 | 
1 files changed, 36 insertions, 30 deletions
| diff --git a/kernel/signal.c b/kernel/signal.c index 6b982f2cf524..934ae5e687b9 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
| @@ -218,13 +218,13 @@ __sigqueue_alloc(int sig, struct task_struct *t, gfp_t flags, int override_rlimi | |||
| 218 | struct user_struct *user; | 218 | struct user_struct *user; | 
| 219 | 219 | ||
| 220 | /* | 220 | /* | 
| 221 | * We won't get problems with the target's UID changing under us | 221 | * Protect access to @t credentials. This can go away when all | 
| 222 | * because changing it requires RCU be used, and if t != current, the | 222 | * callers hold rcu read lock. | 
| 223 | * caller must be holding the RCU readlock (by way of a spinlock) and | ||
| 224 | * we use RCU protection here | ||
| 225 | */ | 223 | */ | 
| 224 | rcu_read_lock(); | ||
| 226 | user = get_uid(__task_cred(t)->user); | 225 | user = get_uid(__task_cred(t)->user); | 
| 227 | atomic_inc(&user->sigpending); | 226 | atomic_inc(&user->sigpending); | 
| 227 | rcu_read_unlock(); | ||
| 228 | 228 | ||
| 229 | if (override_rlimit || | 229 | if (override_rlimit || | 
| 230 | atomic_read(&user->sigpending) <= | 230 | atomic_read(&user->sigpending) <= | 
| @@ -423,7 +423,7 @@ still_pending: | |||
| 423 | */ | 423 | */ | 
| 424 | info->si_signo = sig; | 424 | info->si_signo = sig; | 
| 425 | info->si_errno = 0; | 425 | info->si_errno = 0; | 
| 426 | info->si_code = 0; | 426 | info->si_code = SI_USER; | 
| 427 | info->si_pid = 0; | 427 | info->si_pid = 0; | 
| 428 | info->si_uid = 0; | 428 | info->si_uid = 0; | 
| 429 | } | 429 | } | 
| @@ -607,6 +607,17 @@ static int rm_from_queue(unsigned long mask, struct sigpending *s) | |||
| 607 | return 1; | 607 | return 1; | 
| 608 | } | 608 | } | 
| 609 | 609 | ||
| 610 | static inline int is_si_special(const struct siginfo *info) | ||
| 611 | { | ||
| 612 | return info <= SEND_SIG_FORCED; | ||
| 613 | } | ||
| 614 | |||
| 615 | static inline bool si_fromuser(const struct siginfo *info) | ||
| 616 | { | ||
| 617 | return info == SEND_SIG_NOINFO || | ||
| 618 | (!is_si_special(info) && SI_FROMUSER(info)); | ||
| 619 | } | ||
| 620 | |||
| 610 | /* | 621 | /* | 
| 611 | * Bad permissions for sending the signal | 622 | * Bad permissions for sending the signal | 
| 612 | * - the caller must hold at least the RCU read lock | 623 | * - the caller must hold at least the RCU read lock | 
| @@ -621,7 +632,7 @@ static int check_kill_permission(int sig, struct siginfo *info, | |||
| 621 | if (!valid_signal(sig)) | 632 | if (!valid_signal(sig)) | 
| 622 | return -EINVAL; | 633 | return -EINVAL; | 
| 623 | 634 | ||
| 624 | if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) | 635 | if (!si_fromuser(info)) | 
| 625 | return 0; | 636 | return 0; | 
| 626 | 637 | ||
| 627 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ | 638 | error = audit_signal_info(sig, t); /* Let audit system see the signal */ | 
| @@ -949,9 +960,8 @@ static int send_signal(int sig, struct siginfo *info, struct task_struct *t, | |||
| 949 | int from_ancestor_ns = 0; | 960 | int from_ancestor_ns = 0; | 
| 950 | 961 | ||
| 951 | #ifdef CONFIG_PID_NS | 962 | #ifdef CONFIG_PID_NS | 
| 952 | if (!is_si_special(info) && SI_FROMUSER(info) && | 963 | from_ancestor_ns = si_fromuser(info) && | 
| 953 | task_pid_nr_ns(current, task_active_pid_ns(t)) <= 0) | 964 | !task_pid_nr_ns(current, task_active_pid_ns(t)); | 
| 954 | from_ancestor_ns = 1; | ||
| 955 | #endif | 965 | #endif | 
| 956 | 966 | ||
| 957 | return __send_signal(sig, info, t, group, from_ancestor_ns); | 967 | return __send_signal(sig, info, t, group, from_ancestor_ns); | 
| @@ -969,7 +979,8 @@ static void print_fatal_signal(struct pt_regs *regs, int signr) | |||
| 969 | for (i = 0; i < 16; i++) { | 979 | for (i = 0; i < 16; i++) { | 
| 970 | unsigned char insn; | 980 | unsigned char insn; | 
| 971 | 981 | ||
| 972 | __get_user(insn, (unsigned char *)(regs->ip + i)); | 982 | if (get_user(insn, (unsigned char *)(regs->ip + i))) | 
| 983 | break; | ||
| 973 | printk("%02x ", insn); | 984 | printk("%02x ", insn); | 
| 974 | } | 985 | } | 
| 975 | } | 986 | } | 
| @@ -1052,12 +1063,6 @@ force_sig_info(int sig, struct siginfo *info, struct task_struct *t) | |||
| 1052 | return ret; | 1063 | return ret; | 
| 1053 | } | 1064 | } | 
| 1054 | 1065 | ||
| 1055 | void | ||
| 1056 | force_sig_specific(int sig, struct task_struct *t) | ||
| 1057 | { | ||
| 1058 | force_sig_info(sig, SEND_SIG_FORCED, t); | ||
| 1059 | } | ||
| 1060 | |||
| 1061 | /* | 1066 | /* | 
| 1062 | * Nuke all other threads in the group. | 1067 | * Nuke all other threads in the group. | 
| 1063 | */ | 1068 | */ | 
| @@ -1175,19 +1180,19 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
| 1175 | int ret = -EINVAL; | 1180 | int ret = -EINVAL; | 
| 1176 | struct task_struct *p; | 1181 | struct task_struct *p; | 
| 1177 | const struct cred *pcred; | 1182 | const struct cred *pcred; | 
| 1183 | unsigned long flags; | ||
| 1178 | 1184 | ||
| 1179 | if (!valid_signal(sig)) | 1185 | if (!valid_signal(sig)) | 
| 1180 | return ret; | 1186 | return ret; | 
| 1181 | 1187 | ||
| 1182 | read_lock(&tasklist_lock); | 1188 | rcu_read_lock(); | 
| 1183 | p = pid_task(pid, PIDTYPE_PID); | 1189 | p = pid_task(pid, PIDTYPE_PID); | 
| 1184 | if (!p) { | 1190 | if (!p) { | 
| 1185 | ret = -ESRCH; | 1191 | ret = -ESRCH; | 
| 1186 | goto out_unlock; | 1192 | goto out_unlock; | 
| 1187 | } | 1193 | } | 
| 1188 | pcred = __task_cred(p); | 1194 | pcred = __task_cred(p); | 
| 1189 | if ((info == SEND_SIG_NOINFO || | 1195 | if (si_fromuser(info) && | 
| 1190 | (!is_si_special(info) && SI_FROMUSER(info))) && | ||
| 1191 | euid != pcred->suid && euid != pcred->uid && | 1196 | euid != pcred->suid && euid != pcred->uid && | 
| 1192 | uid != pcred->suid && uid != pcred->uid) { | 1197 | uid != pcred->suid && uid != pcred->uid) { | 
| 1193 | ret = -EPERM; | 1198 | ret = -EPERM; | 
| @@ -1196,14 +1201,16 @@ int kill_pid_info_as_uid(int sig, struct siginfo *info, struct pid *pid, | |||
| 1196 | ret = security_task_kill(p, info, sig, secid); | 1201 | ret = security_task_kill(p, info, sig, secid); | 
| 1197 | if (ret) | 1202 | if (ret) | 
| 1198 | goto out_unlock; | 1203 | goto out_unlock; | 
| 1199 | if (sig && p->sighand) { | 1204 | |
| 1200 | unsigned long flags; | 1205 | if (sig) { | 
| 1201 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1206 | if (lock_task_sighand(p, &flags)) { | 
| 1202 | ret = __send_signal(sig, info, p, 1, 0); | 1207 | ret = __send_signal(sig, info, p, 1, 0); | 
| 1203 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | 1208 | unlock_task_sighand(p, &flags); | 
| 1209 | } else | ||
| 1210 | ret = -ESRCH; | ||
| 1204 | } | 1211 | } | 
| 1205 | out_unlock: | 1212 | out_unlock: | 
| 1206 | read_unlock(&tasklist_lock); | 1213 | rcu_read_unlock(); | 
| 1207 | return ret; | 1214 | return ret; | 
| 1208 | } | 1215 | } | 
| 1209 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); | 1216 | EXPORT_SYMBOL_GPL(kill_pid_info_as_uid); | 
| @@ -1837,11 +1844,6 @@ relock: | |||
| 1837 | 1844 | ||
| 1838 | for (;;) { | 1845 | for (;;) { | 
| 1839 | struct k_sigaction *ka; | 1846 | struct k_sigaction *ka; | 
| 1840 | |||
| 1841 | if (unlikely(signal->group_stop_count > 0) && | ||
| 1842 | do_signal_stop(0)) | ||
| 1843 | goto relock; | ||
| 1844 | |||
| 1845 | /* | 1847 | /* | 
| 1846 | * Tracing can induce an artifical signal and choose sigaction. | 1848 | * Tracing can induce an artifical signal and choose sigaction. | 
| 1847 | * The return value in @signr determines the default action, | 1849 | * The return value in @signr determines the default action, | 
| @@ -1853,6 +1855,10 @@ relock: | |||
| 1853 | if (unlikely(signr != 0)) | 1855 | if (unlikely(signr != 0)) | 
| 1854 | ka = return_ka; | 1856 | ka = return_ka; | 
| 1855 | else { | 1857 | else { | 
| 1858 | if (unlikely(signal->group_stop_count > 0) && | ||
| 1859 | do_signal_stop(0)) | ||
| 1860 | goto relock; | ||
| 1861 | |||
| 1856 | signr = dequeue_signal(current, ¤t->blocked, | 1862 | signr = dequeue_signal(current, ¤t->blocked, | 
| 1857 | info); | 1863 | info); | 
| 1858 | 1864 | ||
