lkml.org 
[lkml]   [2003]   [Nov]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
/
Date
From
SubjectRe: [PATCH] PPC32: cancel syscall restart on signal delivery
Linus Torvalds writes:

> On Sat, 15 Nov 2003, Paul Mackerras wrote:
> >
> > BTW, do we have a test program that triggers the bug that this fixes?
>
> No. In fact, it's an _incredibly_ tiny race, because the old code that
> only handled it at the return path of the system call that got interrupted
> would catch the thing in all cases _except_ if the system
>
> (a) decided to restart the system call
> (b) got an interrupt _after_ the return to user mode but _before_ the
> system call instruction itself actually did the restart
> (c) this interrupt caused a new signal with a handler (different from the
> one that caused the restart, since that one by definition had no
> handler) to the same program.

I just had another look at the x86 syscall exit code. It looks to me
as though you have interrupts disabled all the way from before you
check current_thread_info()->flags, through the call to do_signal,
until you return to userspace. Also, you deliver one signal and then
return to userspace even if there are more signals pending. I could
be wrong about either or both assertions, of course, my x86 assembler
isn't particularly strong.

(Having interrupts disabled during do_signal is interesting, given
that its subroutines call __put_user and friends. :)

On PPC, I disable interrupts before checking the thread_info flags,
but then reenable them before calling do_signal. Then after do_signal
returns, I check the thread_info flags again (having first disabled
interrupts), so if there is another signal pending, it will get
delivered before we return to userspace.

Thus I think the race was possibly a little wider on PPC than on x86:
we didn't have to get back to userspace, the interrupt could happen
during do_signal.

However, I think the race window was actually wider on x86 than you
seem to imply, since the external interrupt could become pending any
time from when you disable interrupts before checking the thread_info
flags until you return to userspace, and still cause the problem.
Still, either way it's a pretty narrow race.

> To make it even worse, even if the above incredibly unlikely thing
> actually _happens_, most of the time it wouldn't really matter. The worst
> case schenario is that the signal handler itself does a system call that
> needs restarting, in which case on signal handler return we now restart
> the _wrong_ system call once we return.

Now you have me scared, because I can't see where the restart_syscall
system call resets current_thread_info()->restart_block.fn to
do_no_restart_syscall. Now, when we get an ignored signal during a
restartable system call, the signal code sets up userspace to do a
restart_syscall system call. If we get the race and then deliver a
signal to the process, we don't undo the changes to userspace, we just
arrange that when it does the restart_syscall call, it will give the
same effect as if the original system call had returned -EINTR.

Now if the signal handler does a restartable system call, which ends
needing to be restarted, that will undo the change that we made on
signal delivery where we set restart_block.fn = do_no_restart_syscall.
In other words, we will return from the signal handler with
restart_block.fn set to something else, and promptly proceed to
restart the wrong syscall.

Am I missing something? Perhaps we should reset restart_block.fn in
sys_{,rt_}sigreturn, or possibly in sys_restart_syscall.

Paul.
-
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/

\
 
 \ /
  Last update: 2005-03-22 13:58    [W:0.332 / U:0.104 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site