From b74d0deb968e1f85942f17080eace015ce3c332c Mon Sep 17 00:00:00 2001 From: Roland McGrath Date: Wed, 6 Jun 2007 03:59:00 -0700 Subject: Restrict clearing TIF_SIGPENDING This patch should get a few birds. It prevents sigaction calls from clearing TIF_SIGPENDING in other threads, which could leak -ERESTART*. And It fixes ptrace_stop not to clear it, which done at the syscall exit stop could leak -ERESTART*. It probably removes the harm from signalfd, at least assuming it never calls dequeue_signal on kernel threads that might have used block_all_signals. Signed-off-by: Roland McGrath Cc: Andrew Morton Cc: Benjamin Herrenschmidt Cc: Paul Mackerras Cc: Satoru Takeuchi Signed-off-by: Linus Torvalds --- kernel/signal.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/signal.c b/kernel/signal.c index acdfc0549c6..fe590e00db8 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -105,7 +105,11 @@ static int recalc_sigpending_tsk(struct task_struct *t) set_tsk_thread_flag(t, TIF_SIGPENDING); return 1; } - clear_tsk_thread_flag(t, TIF_SIGPENDING); + /* + * We must never clear the flag in another thread, or in current + * when it's possible the current syscall is returning -ERESTART*. + * So we don't clear it here, and only callers who know they should do. + */ return 0; } @@ -121,7 +125,9 @@ void recalc_sigpending_and_wake(struct task_struct *t) void recalc_sigpending(void) { - recalc_sigpending_tsk(current); + if (!recalc_sigpending_tsk(current)) + clear_thread_flag(TIF_SIGPENDING); + } /* Given the mask, find the first available signal that should be serviced. */ @@ -385,7 +391,8 @@ int dequeue_signal(struct task_struct *tsk, sigset_t *mask, siginfo_t *info) } } } - recalc_sigpending_tsk(tsk); + if (likely(tsk == current)) + recalc_sigpending(); if (signr && unlikely(sig_kernel_stop(signr))) { /* * Set a marker that we have dequeued a stop signal. Our @@ -1580,8 +1587,9 @@ static void ptrace_stop(int exit_code, int nostop_code, siginfo_t *info) /* * Queued signals ignored us while we were stopped for tracing. * So check for any that we should take before resuming user mode. + * This sets TIF_SIGPENDING, but never clears it. */ - recalc_sigpending(); + recalc_sigpending_tsk(current); } void ptrace_notify(int exit_code) -- cgit v1.2.3