aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/signal.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-06-06 06:59:00 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-06-07 11:52:15 -0400
commitb74d0deb968e1f85942f17080eace015ce3c332c (patch)
tree7db612ba2931ef22ff7166f51dcb0fd1fe1d7ee1 /kernel/signal.c
parent8381e04b90ce9e7669a2d20aa7aaff3be910e447 (diff)
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 <roland@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Paul Mackerras <paulus@samba.org> Cc: Satoru Takeuchi <takeuchi_satoru@jp.fujitsu.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel/signal.c')
-rw-r--r--kernel/signal.c16
1 files changed, 12 insertions, 4 deletions
diff --git a/kernel/signal.c b/kernel/signal.c
index acdfc0549c6f..fe590e00db8d 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -105,7 +105,11 @@ static int recalc_sigpending_tsk(struct task_struct *t)
105 set_tsk_thread_flag(t, TIF_SIGPENDING); 105 set_tsk_thread_flag(t, TIF_SIGPENDING);
106 return 1; 106 return 1;
107 } 107 }
108 clear_tsk_thread_flag(t, TIF_SIGPENDING); 108 /*
109 * We must never clear the flag in another thread, or in current
110 * when it's possible the current syscall is returning -ERESTART*.
111 * So we don't clear it here, and only callers who know they should do.
112 */
109 return 0; 113 return 0;
110} 114}
111 115
@@ -121,7 +125,9 @@ void recalc_sigpending_and_wake(struct task_struct *t)
121 125
122void recalc_sigpending(void) 126void recalc_sigpending(void)
123{ 127{
124 recalc_sigpending_tsk(current); 128 if (!recalc_sigpending_tsk(current))
129 clear_thread_flag(TIF_SIGPENDING);
130
125} 131}
126 132
127/* Given the mask, find the first available signal that should be serviced. */ 133/* 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)
385 } 391 }
386 } 392 }
387 } 393 }
388 recalc_sigpending_tsk(tsk); 394 if (likely(tsk == current))
395 recalc_sigpending();
389 if (signr && unlikely(sig_kernel_stop(signr))) { 396 if (signr && unlikely(sig_kernel_stop(signr))) {
390 /* 397 /*
391 * Set a marker that we have dequeued a stop signal. Our 398 * 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)
1580 /* 1587 /*
1581 * Queued signals ignored us while we were stopped for tracing. 1588 * Queued signals ignored us while we were stopped for tracing.
1582 * So check for any that we should take before resuming user mode. 1589 * So check for any that we should take before resuming user mode.
1590 * This sets TIF_SIGPENDING, but never clears it.
1583 */ 1591 */
1584 recalc_sigpending(); 1592 recalc_sigpending_tsk(current);
1585} 1593}
1586 1594
1587void ptrace_notify(int exit_code) 1595void ptrace_notify(int exit_code)