This is an automated email from the ASF dual-hosted git repository.
acassis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git
The following commit(s) were added to refs/heads/master by this push:
new 4cf4913de12 fs/inode: Keep the close-on-exec flag of descriptors in a
fork() child
4cf4913de12 is described below
commit 4cf4913de12b1dcfa4129d1ffc65d194c2201edd
Author: Marco Casaroli <[email protected]>
AuthorDate: Mon Nov 2 19:48:41 2026 +0100
fs/inode: Keep the close-on-exec flag of descriptors in a fork() child
fdlist_copy() gives the child of fork() or vfork() a copy of each
descriptor without its flags, so FD_CLOEXEC is lost. POSIX: the child
inherits the descriptors with their flags. When the child then calls
exec(), exec() closes nothing: the new program has every descriptor that
the caller 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.
The copy for fork() now keeps the close-on-exec flag of each descriptor.
The copies for exec() and posix_spawn() do not change. The parameter
cloexec of fdlist_copy() and group_setuptaskfiles() is now exec: it
tells that the copy is for a new program, not the flag of a descriptor.
Assisted-by: Claude Code:claude-opus-5-5
Signed-off-by: Marco Casaroli <[email protected]>
---
fs/inode/fs_files.c | 20 ++++++++++++++++----
include/nuttx/fs/fs.h | 2 +-
sched/group/group.h | 2 +-
sched/group/group_setuptaskfiles.c | 7 ++++---
4 files changed, 22 insertions(+), 9 deletions(-)
diff --git a/fs/inode/fs_files.c b/fs/inode/fs_files.c
index be522834f71..479ceb368eb 100644
--- a/fs/inode/fs_files.c
+++ b/fs/inode/fs_files.c
@@ -720,6 +720,14 @@ int file_allocate_from_inode(FAR struct inode *inode, int
oflags, off_t pos,
* Description:
* Copy parent task's file descriptors to child task.
*
+ * Input Parameters:
+ * plist - The descriptor list of the parent
+ * clist - The descriptor list of the child
+ * actions - The spawn file actions, or NULL
+ * exec - True when the child is a new program (exec(), posix_spawn(),
+ * task_create()): leave out the close-on-exec descriptors.
+ * False for fork() and vfork(): keep them, with their flag.
+ *
* Returned Value:
* Zero (OK) is returned on success; a negated errno value is returned on
* any failure.
@@ -728,7 +736,7 @@ int file_allocate_from_inode(FAR struct inode *inode, int
oflags, off_t pos,
int fdlist_copy(FAR struct fdlist *plist, FAR struct fdlist *clist,
FAR const posix_spawn_file_actions_t *actions,
- bool cloexec)
+ bool exec)
{
bool fcloexec;
int ret;
@@ -765,7 +773,7 @@ int fdlist_copy(FAR struct fdlist *plist, FAR struct fdlist
*clist,
continue;
}
- fcloexec = cloexec && fdp->f_cloexec;
+ fcloexec = exec && fdp->f_cloexec;
/* Skip file dup if file action is unnecessary to duplicate */
@@ -797,9 +805,13 @@ int fdlist_copy(FAR struct fdlist *plist, FAR struct
fdlist *clist,
return ret;
}
- /* Assign filep to the child's descriptor list. Omit the flags */
+ /* Assign filep to the child's descriptor list. A fork() child
+ * keeps the close-on-exec flag of each descriptor (POSIX); the
+ * descriptors that a new program keeps have none.
+ */
- fdlist_install(clist, fd, filep, fdp, 0, true);
+ fdlist_install(clist, fd, filep, fdp,
+ !exec && fdp->f_cloexec ? O_CLOEXEC : 0, true);
file_put(filep);
}
}
diff --git a/include/nuttx/fs/fs.h b/include/nuttx/fs/fs.h
index bcd438ece95..8f74c119988 100644
--- a/include/nuttx/fs/fs.h
+++ b/include/nuttx/fs/fs.h
@@ -959,7 +959,7 @@ int fdlist_count(FAR struct fdlist *list);
int fdlist_copy(FAR struct fdlist *plist, FAR struct fdlist *clist,
FAR const posix_spawn_file_actions_t *actions,
- bool cloexec);
+ bool exec);
/****************************************************************************
* Name: fdlist_get2
diff --git a/sched/group/group.h b/sched/group/group.h
index 4a639edc59f..7465f028a30 100644
--- a/sched/group/group.h
+++ b/sched/group/group.h
@@ -118,6 +118,6 @@ bool group_has_child(FAR struct task_group_s *group, pid_t
pid);
int group_setupidlefiles(void);
int group_setuptaskfiles(FAR struct tcb_s *tcb,
FAR const posix_spawn_file_actions_t *actions,
- bool cloexec);
+ bool exec);
#endif /* __SCHED_GROUP_GROUP_H */
diff --git a/sched/group/group_setuptaskfiles.c
b/sched/group/group_setuptaskfiles.c
index 18f69f49365..148200246e3 100644
--- a/sched/group/group_setuptaskfiles.c
+++ b/sched/group/group_setuptaskfiles.c
@@ -49,7 +49,8 @@
* Input Parameters:
* tcb - tcb of the new task.
* actions - The spawn file actions
- * cloexec - Perform O_CLOEXEC on setup task files
+ * exec - True when the task is a new program: leave out the
+ * close-on-exec descriptors (see fdlist_copy())
*
* Returned Value:
* Zero (OK) is returned on success; A negated errno value is returned on
@@ -61,7 +62,7 @@
int group_setuptaskfiles(FAR struct tcb_s *tcb,
FAR const posix_spawn_file_actions_t *actions,
- bool cloexec)
+ bool exec)
{
FAR struct task_group_s *group = tcb->group;
int ret = OK;
@@ -87,7 +88,7 @@ int group_setuptaskfiles(FAR struct tcb_s *tcb,
(tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
{
ret = fdlist_copy(&rtcb->group->tg_fdlist,
- &group->tg_fdlist, actions, cloexec);
+ &group->tg_fdlist, actions, exec);
}
if (ret >= 0 && actions != NULL &&