summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorAdil Alperen Çiftci <[email protected]>2026-11-05 11:37:23 +0300
committerGitHub <[email protected]>2026-11-05 16:37:23 +0800
commitd279c43627dfe9e4de97895b5d52c97013c16ef5 (patch)
tree9b038ece5a312452b58c5801868c81600354c598 /tools
parent40e07d970ecac0a12122c01e15f39dcb2441479b (diff)
dfs/posix: validate bounds and safely detach listener in signalfd_close (#11935)
* dfs/posix: enforce bounds check and clean unregister in signalfd Validate array bounds on signalfd notification registration and remove the unsafe global index counter. Tie the registered process lifetime to the registration: each slot in sfd->lwp[] holds an LWP reference, and the listener node carries a detach hook that the process exit path runs under LWP_LOCK to unlink the node, clear the slot and drop the reference. Final close therefore never walks a freed process, and a child that registered through an inherited descriptor is unregistered when it exits. Move every change of lwp->signalfd_notify_head behind lwp_signal_notify_* helpers in the lwp core, which take LWP_LOCK, the lock lwp_signal_notify() traverses the list under. The lock order is LWP_LOCK -> sfd->lock, the same order the signal path already uses; sfd->lock is never held while taking LWP_LOCK, and a node is only unlinked under LWP_LOCK, so no in-flight notification can be inside it when it is freed. Tear down the vnode, context and mutex before fd_release() when the initial registration fails, and return instead of falling through to freed objects. Propagate registration failures: read returns the error and poll reports POLLERR before anything is added to the poll queue. Fixes: #11933 Signed-off-by: Adil Alperen Ciftci <[email protected]> * dfs/posix: state the signalfd context lifetime and tighten close State the lifetime assumption of the signalfd context explicitly: the descriptor the caller operates on pins the context for the whole read, poll and registration, and a concurrent close of that same descriptor by another thread is not supported, which is what the existing read and poll paths already rely on. The post-registration slot re-check therefore does not add a new requirement. Clear all registration slots in one pass under sfd->lock in close and run the per-process unlink and reference drop outside the lock afterwards, so the "clear first, unlink later" invariant is one block instead of a lock round-trip per slot. Rename SIGNALFD_SHART_MAX to SIGNALFD_SHARE_MAX while the macro block is being touched. Signed-off-by: Adil Alperen Ciftci <[email protected]> * dfs/posix: keep the LWP lock out of signalfd close and make registration atomic dfs_file_close() calls the signalfd close callback under the global DFS file lock, and the process exit path takes that same lock while it already holds LWP_LOCK (__exit_files() under _resr_cleanup()). Unlinking the listeners from close() through lwp_signal_notify_remove_queue() therefore took the two locks in the opposite order to process exit, and a parent closing a shared signalfd while a registered child exits could block each side on the other's lock. Close no longer takes any LWP lock. It marks the context closing, detaches it from the vnode and submits a release work item to the system workqueue. The work takes the slots over under sfd->lock, unlinks the listeners under each process's own LWP_LOCK with no other lock held, drops the references the slots owned, and frees the context. A process that exits before the work runs has already cleared its slot and dropped its reference through the exit hook, so the work only sees slots that are still live. Registration now does the lookup, the slot assignment and the listener insertion in one critical section under LWP_LOCK(self) -> sfd->lock, the same order the exit hook already uses. A slot is never visible without its listener, so a second thread cannot observe a registration whose listener is still missing, and the lookup cannot go stale between the check and the assignment. lwp_signal_notify_add() accordingly expects the caller to hold LWP_LOCK; the single-node unlink helper that the post-registration re-check used is gone with that re-check. A registration that races with close finds the closing flag and fails with EBADF instead of taking a slot the release work will not see. Signed-off-by: Adil Alperen Ciftci <[email protected]> * dfs/posix: do not allocate for an existing signalfd registration signalfd_add_notify() allocated the listener node before looking the calling process up, so read and poll on an already registered descriptor failed with ENOMEM or POLLERR under memory pressure even though no node was needed and a signal may already have been queued. Look the process up first, under LWP_LOCK(self) -> sfd->lock, and return from there when it is registered or the context is closing. Only when a new registration is needed drop the locks, allocate the node, take the locks again and repeat the lookup unconditionally: the closing flag, an existing registration and the free slot are all re-evaluated before the slot is assigned and the listener is linked in the same critical section. A node left over because another thread registered the process meanwhile is freed after the locks are released. Signed-off-by: Adil Alperen Ciftci <[email protected]> * dfs/posix: align signalfd context member comments for clang-format Signed-off-by: Adil Alperen Ciftci <[email protected]> --------- Signed-off-by: Adil Alperen Ciftci <[email protected]> Co-authored-by: Adil Alperen Ciftci <[email protected]>
Diffstat (limited to 'tools')
0 files changed, 0 insertions, 0 deletions