diff options
author | Roland McGrath <roland@redhat.com> | 2007-06-06 06:59:00 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-06-07 11:52:15 -0400 |
commit | b74d0deb968e1f85942f17080eace015ce3c332c (patch) | |
tree | 7db612ba2931ef22ff7166f51dcb0fd1fe1d7ee1 /kernel/signal.c | |
parent | 8381e04b90ce9e7669a2d20aa7aaff3be910e447 (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.c | 16 |
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 | ||
122 | void recalc_sigpending(void) | 126 | void 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 | ||
1587 | void ptrace_notify(int exit_code) | 1595 | void ptrace_notify(int exit_code) |