casaroli opened a new pull request, #21530: URL: https://github.com/apache/nuttx/pull/21530
## Summary `fdlist_copy()` gives the child of `fork()` or `vfork()` a copy of each descriptor without its flags, so `FD_CLOEXEC` is lost. POSIX says that the child inherits the descriptors with their flags. When the child then calls `exec()`, `exec()` closes nothing, and the new program has every descriptor that the parent marked close-on-exec. For example, a parent that waits for end of file on a close-on-exec pipe, to see that the child called `exec()`, waits until the new program ends. This PR keeps the close-on-exec flag of each descriptor in the copy for `fork()` and `vfork()`. The copies for `exec()`, `task_create()` and `posix_spawn()` do not change: they leave out the close-on-exec descriptors, as before. ## Impact Common code (`fs/inode/fs_files.c`), so all architectures and all build modes that have `fork()` or `vfork()`. A `fork()` or `vfork()` child now sees `FD_CLOEXEC` in `fcntl(F_GETFD)`, and `exec()` in the child closes these descriptors. A program that used a close-on-exec descriptor in the new program after `fork()` and `exec()` no longer gets it, as on other POSIX systems. No flat-build API change. No Documentation change: `Documentation/` does not describe the flags of a `fork()` child. ## Testing Test program, with a close-on-exec pipe and a plain pipe: `getfd`: in the child, `fcntl(F_GETFD)` has `FD_CLOEXEC` for the close-on-exec descriptor only. `eof`: the child calls `exec()`, and the parent must read end of file on the close-on-exec pipe at once, not after the 2 s that the new program runs. `exec`: the new program must not have the close-on-exec descriptor (`EBADF`), and it reports this through the plain pipe. The kernel builds use `fork()`; the flat and protected builds use `vfork()` and a builtin application. It is not in apps; a regression guard would need an apps PR. | Config | master 43f7f34b995 | this branch | |---|---|---| | `qemu-armv8a:nsh` (flat, `vfork()`), HVF | 3 failed; ostest status 0 | 0 failed; ostest status 0 | | `qemu-armv8a:knsh` (kernel, `fork()`), HVF | 3 failed; ostest status 0 | 0 failed; ostest status 0 | | `mps2-an500:knsh` (protected, `vfork()`), TCG | 3 failed; ostest status 0 | 0 failed; ostest status 0 | | `rv-virt:knsh64` (kernel, `fork()`), TCG | 3 failed; ostest status 0 | 0 failed; ostest status 0 | Master, the same in all: ``` forkcloexec: getfd FAIL (child exit 1) forkcloexec: eof FAIL (read 0 after 2.0 s) forkcloexec: exec FAIL (new program says 1, read 1) ``` Options: `PIPES`, `LIBC_EXECFUNCS`, `SCHED_WAITPID`, `SCHED_HAVE_PARENT`, `SCHED_CHILD_STATUS`. `mps2-an500:knsh` also has `TLS_LOG2_MAXSTACK=15`, for the stack of the test. ostest has `fork()` and `vfork()` cases. Not run: `posix_spawn()` with file actions on a close-on-exec descriptor (the code path does not change), and `CONFIG_FDCLONE_STDIO`. Compilers: aarch64 GCC 14.2, arm-none-eabi GCC 15.3, RISC-V GCC 14.3. `tools/checkpatch.sh -c -u -m -g` passes. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
