diff options
| author | Adil Alperen Çiftci <[email protected]> | 2026-11-05 11:37:23 +0300 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-11-05 16:37:23 +0800 |
| commit | d279c43627dfe9e4de97895b5d52c97013c16ef5 (patch) | |
| tree | 9b038ece5a312452b58c5801868c81600354c598 /tools/ci/git_diff_show.py | |
| parent | 40e07d970ecac0a12122c01e15f39dcb2441479b (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/ci/git_diff_show.py')
0 files changed, 0 insertions, 0 deletions
