Messages in this thread Patch in this message | | | Date | Wed, 27 Jul 2011 18:34:27 +0200 | From | Oleg Nesterov <> | Subject | [PATCH 8/8] vfork: do not block SIG_DFL/SIG_IGN signals is single-threaded |
| |
vfork() blocks all signals except SIGKILL and SIGSTOP. This means it doesn't react to ^Z or other fatal signals.
We can unblock all signals which doesn't have a handler and solve this. Unfortunately, without the really ugly hacks we can not do this in the multithreaded case, we can not trust sighand->action[] otherwise.
Let's do this in the single-threaded case at least. Anyway, I do not think that vfork() from the multithreaded application is sane. And even in this case other threads can handle the blocked signals unless they exit after clone_vfork_prepare().
Note: "sighand->count == 1" doesn't handle the dead-leader case, this is easy to fix.
Signed-off-by: Oleg Nesterov <oleg@redhat.com> ---
kernel/fork.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-)
--- 3.1/kernel/fork.c~8_more_signals 2011-07-27 17:48:53.000000000 +0200 +++ 3.1/kernel/fork.c 2011-07-27 17:51:54.000000000 +0200 @@ -1506,10 +1506,26 @@ static long clone_vfork_restart(struct r static void clone_vfork_prepare(void) { + struct sighand_struct *sigh = current->sighand; sigset_t vfork_mask; - current->saved_sigmask = current->blocked; siginitsetinv(&vfork_mask, sigmask(SIGKILL) | sigmask(SIGSTOP)); + if (atomic_read(&sigh->count) == 1) { + __sighandler_t h; + int signr; + /* + * Nobody can play with ->action[], we can unblock all + * signals which do not have a handler, they can not + * trigger return-to-user-mode. + */ + for (signr = 1; signr <= _NSIG; ++signr) { + h = sigh->action[signr-1].sa.sa_handler; + if (h == SIG_DFL || h == SIG_IGN) + sigdelset(&vfork_mask, signr); + } + } + + current->saved_sigmask = current->blocked; set_current_blocked(&vfork_mask); }
| |