fix public clone function to be safe and usable by applications
authorRich Felker <dalias@aerifal.cx>
Wed, 31 May 2023 16:04:06 +0000 (12:04 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 1 Jun 2023 20:15:38 +0000 (16:15 -0400)
commitfa4a8abd06a401822cc8ba4e352a219544c0118d
tree064926e9f147c7d20e3294dd869b3c959567f817
parent0c277ff156749628c678257f878d3a6edb5868de
fix public clone function to be safe and usable by applications

the clone() function has been effectively unusable since it was added,
due to producing a child process with inconsistent state. in
particular, the child process's thread structure still contains the
tid, thread list pointers, thread count, and robust list for the
parent. this will cause malfunction in interfaces that attempt to use
the tid or thread list, some of which are specified to be
async-signal-safe.

this patch attempts to make clone() consistent in a _Fork-like sense.
as in _Fork, when the parent process is multi-threaded, the child
process inherits an async-signal context where it cannot call
AS-unsafe functions, but its context is now intended to be safe for
calling AS-safe functions. making clone fork-like would also be a
future option, if it turns out that this is what makes sense to
applications, but it's not done at this time because the changes would
be more invasive.

in the case where the CLONE_VM flag is used, clone is only vfork-like,
not _Fork-like. in particular, the child will see itself as having the
parent's tid, and cannot safely call any libc functions but one of the
exec family or _exit.

handling of flags and variadic arguments is also changed so that
arguments are only consumed with flags that indicate their presence,
and so that flags which produce an inconsistent state are disallowed
(reported as EINVAL). in particular, all libc functions carry a
contract that they are only callable with ABI requirements met, which
includes having a valid thread pointer to a thread structure that's
unique within the process, and whose contents are opaque and only able
to be setup internally by the implementation. the only way for an
application to use flags that violate these requirements without
executing any libc code is to perform the syscall from
application-provided asm.
src/internal/fork_impl.h
src/linux/clone.c
src/process/_Fork.c