diff options
Diffstat (limited to 'kernel/signal.c')
-rw-r--r-- | kernel/signal.c | 56 |
1 files changed, 27 insertions, 29 deletions
diff --git a/kernel/signal.c b/kernel/signal.c index 5d3b3f8f219b..c6d7a24a86a1 100644 --- a/kernel/signal.c +++ b/kernel/signal.c | |||
@@ -971,6 +971,20 @@ specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t) | |||
971 | return send_signal(sig, info, t, 0); | 971 | return send_signal(sig, info, t, 0); |
972 | } | 972 | } |
973 | 973 | ||
974 | int do_send_sig_info(int sig, struct siginfo *info, struct task_struct *p, | ||
975 | bool group) | ||
976 | { | ||
977 | unsigned long flags; | ||
978 | int ret = -ESRCH; | ||
979 | |||
980 | if (lock_task_sighand(p, &flags)) { | ||
981 | ret = send_signal(sig, info, p, group); | ||
982 | unlock_task_sighand(p, &flags); | ||
983 | } | ||
984 | |||
985 | return ret; | ||
986 | } | ||
987 | |||
974 | /* | 988 | /* |
975 | * Force a signal that the process can't ignore: if necessary | 989 | * Force a signal that the process can't ignore: if necessary |
976 | * we unblock the signal and change any SIG_IGN to SIG_DFL. | 990 | * we unblock the signal and change any SIG_IGN to SIG_DFL. |
@@ -1068,18 +1082,10 @@ struct sighand_struct *lock_task_sighand(struct task_struct *tsk, unsigned long | |||
1068 | */ | 1082 | */ |
1069 | int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | 1083 | int group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) |
1070 | { | 1084 | { |
1071 | unsigned long flags; | 1085 | int ret = check_kill_permission(sig, info, p); |
1072 | int ret; | ||
1073 | |||
1074 | ret = check_kill_permission(sig, info, p); | ||
1075 | 1086 | ||
1076 | if (!ret && sig) { | 1087 | if (!ret && sig) |
1077 | ret = -ESRCH; | 1088 | ret = do_send_sig_info(sig, info, p, true); |
1078 | if (lock_task_sighand(p, &flags)) { | ||
1079 | ret = __group_send_sig_info(sig, info, p); | ||
1080 | unlock_task_sighand(p, &flags); | ||
1081 | } | ||
1082 | } | ||
1083 | 1089 | ||
1084 | return ret; | 1090 | return ret; |
1085 | } | 1091 | } |
@@ -1224,15 +1230,9 @@ static int kill_something_info(int sig, struct siginfo *info, pid_t pid) | |||
1224 | * These are for backward compatibility with the rest of the kernel source. | 1230 | * These are for backward compatibility with the rest of the kernel source. |
1225 | */ | 1231 | */ |
1226 | 1232 | ||
1227 | /* | ||
1228 | * The caller must ensure the task can't exit. | ||
1229 | */ | ||
1230 | int | 1233 | int |
1231 | send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | 1234 | send_sig_info(int sig, struct siginfo *info, struct task_struct *p) |
1232 | { | 1235 | { |
1233 | int ret; | ||
1234 | unsigned long flags; | ||
1235 | |||
1236 | /* | 1236 | /* |
1237 | * Make sure legacy kernel users don't send in bad values | 1237 | * Make sure legacy kernel users don't send in bad values |
1238 | * (normal paths check this in check_kill_permission). | 1238 | * (normal paths check this in check_kill_permission). |
@@ -1240,10 +1240,7 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p) | |||
1240 | if (!valid_signal(sig)) | 1240 | if (!valid_signal(sig)) |
1241 | return -EINVAL; | 1241 | return -EINVAL; |
1242 | 1242 | ||
1243 | spin_lock_irqsave(&p->sighand->siglock, flags); | 1243 | return do_send_sig_info(sig, info, p, false); |
1244 | ret = specific_send_sig_info(sig, info, p); | ||
1245 | spin_unlock_irqrestore(&p->sighand->siglock, flags); | ||
1246 | return ret; | ||
1247 | } | 1244 | } |
1248 | 1245 | ||
1249 | #define __si_special(priv) \ | 1246 | #define __si_special(priv) \ |
@@ -2278,7 +2275,6 @@ static int | |||
2278 | do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) | 2275 | do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) |
2279 | { | 2276 | { |
2280 | struct task_struct *p; | 2277 | struct task_struct *p; |
2281 | unsigned long flags; | ||
2282 | int error = -ESRCH; | 2278 | int error = -ESRCH; |
2283 | 2279 | ||
2284 | rcu_read_lock(); | 2280 | rcu_read_lock(); |
@@ -2288,14 +2284,16 @@ do_send_specific(pid_t tgid, pid_t pid, int sig, struct siginfo *info) | |||
2288 | /* | 2284 | /* |
2289 | * The null signal is a permissions and process existence | 2285 | * The null signal is a permissions and process existence |
2290 | * probe. No signal is actually delivered. | 2286 | * probe. No signal is actually delivered. |
2291 | * | ||
2292 | * If lock_task_sighand() fails we pretend the task dies | ||
2293 | * after receiving the signal. The window is tiny, and the | ||
2294 | * signal is private anyway. | ||
2295 | */ | 2287 | */ |
2296 | if (!error && sig && lock_task_sighand(p, &flags)) { | 2288 | if (!error && sig) { |
2297 | error = specific_send_sig_info(sig, info, p); | 2289 | error = do_send_sig_info(sig, info, p, false); |
2298 | unlock_task_sighand(p, &flags); | 2290 | /* |
2291 | * If lock_task_sighand() failed we pretend the task | ||
2292 | * dies after receiving the signal. The window is tiny, | ||
2293 | * and the signal is private anyway. | ||
2294 | */ | ||
2295 | if (unlikely(error == -ESRCH)) | ||
2296 | error = 0; | ||
2299 | } | 2297 | } |
2300 | } | 2298 | } |
2301 | rcu_read_unlock(); | 2299 | rcu_read_unlock(); |