posix_spawn: parent can get stuck in uninterruptible sleep if child receives SIGTSTP early enough
Florian Weimer
fweimer@redhat.com
Mon Oct 10 13:45:26 GMT 2022
* Adhemerval Zanella Netto:
> 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.
Yes, we do it this way to avoid a different bug, and trade it for
another.
> 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.
Right, I don't see a way around that.
I don't think switching back to fork by default is really an option.
The impact on latency is much worse than with vfork.
Thanks,
Florian
More information about the Libc-help
mailing list