* Signal restarting happing multiple time in do_signal
@ 2006-08-08 11:04 Ralf Baechle
2006-08-08 22:25 ` David Miller
2006-08-11 8:12 ` Heiko Carstens
0 siblings, 2 replies; 4+ messages in thread
From: Ralf Baechle @ 2006-08-08 11:04 UTC (permalink / raw)
To: linux-arch
In the MIPS entry.S the symbol resume_userspace to the call to
do_notify_resume form a loop through which the kernel will iterate as
long as work is pending. If we iterate through this loop more than once
with no signal pending for at least one but the last iteration we will
perform the syscall restarting multiple times resulting in a syscall
return prior to the the syscall instruction in userspace because the
return program counter will be adjusted several times by:
regs->regs[7] = regs->regs[26];
regs->cp0_epc -= 8;
resulting in return to userspace at a too low address. On MIPS this often
happens to be a stackpointer adjustment but in many cases this may also
just be a harmless instruction such as reloading the syscall number so
may go unnoticed.
We were able to trigger this when debugging a multithreaded programs.
At least i386 uses virtually identical algorithms so I think is likely
to have the same issue.
The fix in case of MIPS is trivial:
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 73f8aad..8676055 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -465,6 +464,7 @@ void do_signal(struct pt_regs *regs)
regs->regs[7] = regs->regs[26];
regs->cp0_epc -= 4;
}
+ regs->regs[0] = 0; /* Don't deal with this again. */
}
/*
Ralf
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: Signal restarting happing multiple time in do_signal
2006-08-08 11:04 Signal restarting happing multiple time in do_signal Ralf Baechle
@ 2006-08-08 22:25 ` David Miller
2006-08-09 2:26 ` Andi Kleen
2006-08-11 8:12 ` Heiko Carstens
1 sibling, 1 reply; 4+ messages in thread
From: David Miller @ 2006-08-08 22:25 UTC (permalink / raw)
To: ralf; +Cc: linux-arch
From: Ralf Baechle <ralf@linux-mips.org>
Date: Tue, 8 Aug 2006 12:04:37 +0100
> We were able to trigger this when debugging a multithreaded programs.
> At least i386 uses virtually identical algorithms so I think is likely
> to have the same issue.
Other platforms, including x86, clear the state out in one way or
another before the next iteration.
Actually on x86 it occurs as a side effect of setting
regs->eax, it is reset to the system call number requested
at syscall trap time, so it will not match any of the
error return values in this switch statement:
/* Are we from a system call? */
if (regs->orig_eax >= 0) {
/* If so, check system call restarting.. */
switch (regs->eax) {
case -ERESTART_RESTARTBLOCK:
case -ERESTARTNOHAND:
regs->eax = -EINTR;
break;
case -ERESTARTSYS:
if (!(ka->sa.sa_flags & SA_RESTART)) {
regs->eax = -EINTR;
break;
}
/* fallthrough */
case -ERESTARTNOINTR:
regs->eax = regs->orig_eax;
regs->eip -= 2;
}
}
So after the first iteration, the next time through here we
won't be "from a system call".
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Signal restarting happing multiple time in do_signal
2006-08-08 22:25 ` David Miller
@ 2006-08-09 2:26 ` Andi Kleen
0 siblings, 0 replies; 4+ messages in thread
From: Andi Kleen @ 2006-08-09 2:26 UTC (permalink / raw)
To: David Miller; +Cc: ralf, linux-arch
>
> So after the first iteration, the next time through here we
> won't be "from a system call".
Thanks for the analysis David. I agree it shouldn't be a problem for x86.
-Andi
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: Signal restarting happing multiple time in do_signal
2006-08-08 11:04 Signal restarting happing multiple time in do_signal Ralf Baechle
2006-08-08 22:25 ` David Miller
@ 2006-08-11 8:12 ` Heiko Carstens
1 sibling, 0 replies; 4+ messages in thread
From: Heiko Carstens @ 2006-08-11 8:12 UTC (permalink / raw)
To: Ralf Baechle; +Cc: linux-arch
> In the MIPS entry.S the symbol resume_userspace to the call to
> do_notify_resume form a loop through which the kernel will iterate as
> long as work is pending. If we iterate through this loop more than once
> with no signal pending for at least one but the last iteration we will
> perform the syscall restarting multiple times resulting in a syscall
> return prior to the the syscall instruction in userspace because the
> return program counter will be adjusted several times by:
>
> regs->regs[7] = regs->regs[26];
> regs->cp0_epc -= 8;
>
> resulting in return to userspace at a too low address. On MIPS this often
> happens to be a stackpointer adjustment but in many cases this may also
> just be a harmless instruction such as reloading the syscall number so
> may go unnoticed.
>
> We were able to trigger this when debugging a multithreaded programs.
> At least i386 uses virtually identical algorithms so I think is likely
> to have the same issue.
s390 has the same problem. Thanks for pointing this out.
btw. is there a reason why mips doesn't have a 'return' within do_signal()
(see patch below)? That would save you some cycles.
Also I think that powerpc's do_signal() could be converted to be a void
function and that their EXPORT_SYMBOL(do_signal) could be removed. Would
also save some cycles/memory.
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c
index 6b4d9be..43c37d9 100644
--- a/arch/mips/kernel/signal.c
+++ b/arch/mips/kernel/signal.c
@@ -446,6 +446,7 @@ void do_signal(struct pt_regs *regs)
if (test_thread_flag(TIF_RESTORE_SIGMASK))
clear_thread_flag(TIF_RESTORE_SIGMASK);
}
+ return;
}
no_signal:
^ permalink raw reply related [flat|nested] 4+ messages in thread
end of thread, other threads:[~2006-08-11 8:12 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-08-08 11:04 Signal restarting happing multiple time in do_signal Ralf Baechle
2006-08-08 22:25 ` David Miller
2006-08-09 2:26 ` Andi Kleen
2006-08-11 8:12 ` Heiko Carstens
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox