Scope the signal mutex to just the tg.tty clear in CreateSession, matching how
CreateProcessGroup, JoinProcessGroup, and the exit path already call
handleOrphan without holding a signal mutex.
CreateSession held tg.signalHandlers.mu across the entire process group
manipulation, but it only needs that mutex to clear tg.tty. When setsid(2)
orphans the caller's old process group, decRefWithParent calls handleOrphan,
which locks the signal mutex of every thread group remaining in the group. If
the caller itself, or a sibling thread group that shares the caller's
SignalHandlers (created via clone(CLONE_VM|CLONE_SIGHAND) without CLONE_THREAD),
is still a member, handleOrphan re-locks the already-held, non-reentrant mutex
and the sentry deadlocks while holding TaskSet.mu, freezing the whole sandbox.
Regression test hangs prior to the fix.
- Do not return from ExecSwapPreClone(), which is called from a fork()ed
process.
- Use TEST_*CHECK() rather than ASSERT_*() in some places requiring
async-signal-safety.
- Use ReadFd/WriteFd() rather than bare read/write(), to handle EINTR.
PiperOrigin-RevId: 632019219
The current implementation has a race condition resulting in the skipping of
one element in the queue array. When retrieving objects from the queue, the
stub code can get stuck in an infinite loop due to unexpected unused elements.
Updates #10000
PiperOrigin-RevId: 608679165
This closes the write end of the pipe earlier in the main test
body, and avoids allocations after fork+clone when building up
the `execve` array's flags.
There may be more obvious ways to do this, let me know :)
PiperOrigin-RevId: 453809395
This avoids requiring a lock in `ThreadGroup.ID`, which in turn breaks the
following lock cycle:
`kernel.taskSetRWMutex` -> `kernel.taskMutex` -> `mm.metadataMutex`
-> `mm.mappingRWMutex` -> `kernel.taskSetRWMutex`
(Also, less locking within `createVMALocked` is probably for the better in
general.)
PiperOrigin-RevId: 449588573