summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-02-16 19:51:37 -0800
committerLinus Torvalds <torvalds@home.transmeta.com>2003-02-16 19:51:37 -0800
commit2c707d9bf1f45ce6cec9eb99e4a288e5aef87929 (patch)
tree3a3c95eda2f2b4c7f23cba3d7d28ee40369ff850 /kernel
parent00742b03fdb9a1ad038b7fc713df0112a03116f1 (diff)
Fix locking for "send_sig_info()", to avoid possible races with signal
state changes due to execve() and exit(). We need to hold the tasklist lock to guarantee stability of "task->sighand".
Diffstat (limited to 'kernel')
-rw-r--r--kernel/signal.c16
1 files changed, 13 insertions, 3 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index b8fc6a05c031..b7ac6a557ddb 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1109,21 +1109,31 @@ static int kill_something_info(int sig, struct siginfo *info, int pid)
* These are for backward compatibility with the rest of the kernel source.
*/
+/*
+ * XXX should probably nix these interfaces and update the kernel
+ * to specify explicitly whether the signal is a group signal or
+ * specific to a thread.
+ */
int
send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
{
int ret;
- /* XXX should nix these interfaces and update the kernel */
+ /*
+ * We need the tasklist lock even for the specific
+ * thread case (when we don't need to follow the group
+ * lists) in order to avoid races with "p->sighand"
+ * going away or changing from under us.
+ */
+ read_lock(&tasklist_lock);
if (T(sig, SIG_KERNEL_BROADCAST_MASK)) {
- read_lock(&tasklist_lock);
ret = group_send_sig_info(sig, info, p);
- read_unlock(&tasklist_lock);
} else {
spin_lock_irq(&p->sighand->siglock);
ret = specific_send_sig_info(sig, info, p);
spin_unlock_irq(&p->sighand->siglock);
}
+ read_unlock(&tasklist_lock);
return ret;
}