posix_spawn: parent can get stuck in uninterruptible sleep if child receives SIGTSTP early enough

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Thu Sep 22 19:14:19 GMT 2022



On 22/09/22 14:38, Florian Weimer wrote:
> * Adhemerval Zanella Netto:
> 
>> On 22/09/22 09:18, Florian Weimer wrote:
>>>> Is there anything that prevents to avoid using CLONE_VFORK? The code already
>>>> uses a allocated stack and do synchronizes with waitpid.
>>>
>>> Assuming there is a way to create a thread which gets replaced by execve
>>> only (instead the whole process), this won't work because we have to
>>> block all signals for the new thread (it must not be visible to
>>> application code, and signal handlers must not run on it), and we can't
>>> unblock those signals prior to execve.  With vfork, we can unblock them
>>> after changing the signal handler disposition to SIG_DFL (preventing the
>>> handler execution), but per-thread signal handlers have been removed
>>> from Linux.  So even if we somehow could prevent the termination signal
>>> from beign sent to the whole process (and not just the fake thread), we
>>> still have a gap.
>>
>> But we already block all internal signals with internal_signal_block_all
>> prior clone call and it does not use CLONE_SIGHAND on the clone call. 
>> Also, independently of CLONE_SIGHAND, the calling process and child still 
>> have distinct signal masks.  Recall for posix_spawn we do not use
>> CLONE_THREAD, so per-thread signal handlers does not apply here.
> 
> This only works because we restore SIG_DFL before unblocking signals in
> the new process.  And that depends on a separate set of signal handlers.
> 
>> Doing some tests, the main problem is in fact how to synchronize 
>> the deallocation of the stack, since without CLONE_VFORK there is no way
>> to advertise on a success call when execve has been called.
>>
>> But I agree that even without CLONE_VFORK we still have a small window,
>> between the sigprocmask and execve, that the signal might act upon the
>> child.
> 
> And that window shouldn't exist in the current implementation.

But that's the main issue described in this first message, isn't? The child 
unblocks signals by calling sigprocmask, SIGTSTP is delivered to the child,
but since clone hasn't exited due CLONE_VFORK, it remains stuck in clone
until child receives SIGCONT.

I think to actually fix it we need a execve/execveat where the signal mask
is set atomically, so SIGTSTP is sent to the spawned process instead of
the libc helper one.


More information about the Libc-help mailing list