Messages in this thread Patch in this message | | | From | Roland McGrath <> | Subject | Re: [BUG] ptraced process waiting on syscall may return kernel internal errnos | Date | Wed, 6 Jun 2007 03:59:00 -0700 (PDT) |
| |
Oleg and I were just discussing this issue in relation to other problems. We established that it is never safe to clear TIF_SIGPENDING on another thread. But I hadn't really thought through that it's sometimes not safe to clear your own TIF_SIGPENDING either. That is, any time you are not positive you cannot be in a syscall that will return a -ERESTART* code. (I had the ptrace_stop case lurking in the back of my mind but hadn't considered how it would really come up.)
I have a general recollection of thinking that dequeue_signal could only be called on current and that it mattered somehow. But aside from avoiding recalc_sigpending, and kernel threads with notifier_mask set, I can't see off hand what it is. I won't testify that I think signalfd is necessarily on safe ground, though.
Thanks, Roland
---
[PATCH] 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*. 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> --- kernel/signal.c | 40 ++++++++++++++++++++++++---------------- 1 files changed, 24 insertions(+), 16 deletions(-)
diff --git a/kernel/signal.c b/kernel/signal.c index acdfc05..dc5797c 100644 --- a/kernel/signal.c +++ b/kernel/signal.c @@ -105,7 +105,11 @@ static int recalc_sigpending_tsk(struct 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 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 *t } } } - 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, i /* * 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) - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |