do_signal() can loop & block. The exit condition of the loop in this case
is when dequeue_signal() returns 0. It continues calling it until that
point, it doesn't re-check current->sigpending.
That means on the second iteration, dequeue_signal() can actually be called
with no pending signal.
A that point, dequeue_signal() calls next_signal() which returns 0. The
problem begins when the current task has a "notifier" installed (which
in my case was done by DRM). If current->notifier is non-null, then we
call sigismember() passing it 0 as the "sig" parameter.
sigismember will then do pointer arithmetic with "sig-1", that is
0xffffffff which will crashes when dereferencing.
The patch is simple:
===== kernel/signal.c 1.1 vs edited =====
--- 1.1/kernel/signal.c Sat Jan 6 08:26:12 2001
+++ edited/kernel/signal.c Sun Aug 26 18:50:51 2001
@@ -242,7 +242,7 @@
#endif
sig = next_signal(current, mask);
- if (current->notifier) {
+ if (sig && current->notifier) {
if (sigismember(current->notifier_mask, sig)) {
if (!(current->notifier)(current->notifier_data)) {
current->sigpending = 0;
(You may want to factor with the other if (sig) that is
done just after that code).
Ben.
-
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/