Skip to content

Automated fix for refs/heads/rwstauner/uaf-fork-pending-events - #50

Open
github-actions[bot] wants to merge 3 commits into
rwstauner/uaf-fork-pending-eventsfrom
create-pull-request/patch-1207d0a
Open

Automated fix for refs/heads/rwstauner/uaf-fork-pending-events#50
github-actions[bot] wants to merge 3 commits into
rwstauner/uaf-fork-pending-eventsfrom
create-pull-request/patch-1207d0a

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown

PanCakes to the rescue!

We noticed that our 'sanity' test was going to fail, but we think we can fix that automatically, so we put together this PR to do just that!

If you'd like to opt-out of these PR's, add yourself to NO_AUTOFIX_USERS in .github/workflows/pr-auto-fix.yaml

rwstauner and others added 3 commits September 3, 2026 12:50
Epoll1Poller::Work() collected pending Epoll1EventHandle* pointers under
the poller mutex, then released the mutex before draining them via
ExecutePendingActions(). Handles are poller-owned memory, recycled via
free_epoll1_handles_list_ and only freed in Close() (called from
~Epoll1Poller), so the unlocked drain was safe when it was introduced
(grpc#30828, 2022): nothing could free a handle mid-drain.

EventEngine fork support (grpc#38441, grpc#38980, grpc#39739, 2025) broke that
invariant. During fork a c-ares DNS socket handle can be orphaned
(~GrpcPolledFdPosix -> OrphanHandle) and the poller torn down
concurrently with a Work() iteration that is still draining
pending_events. The handle is freed by Close() and its slot reused, so
ExecutePendingActions() dereferences recycled memory as a closure pointer.

Fix: hold the poller mutex across the whole collect-and-drain sequence so
a handle in pending_events cannot be freed while it is being
dereferenced. This is deadlock-free: Work() never takes the handle mutex,
and schedule_poll_again() only flips a bool or enqueues a thread-pool
task. The poll-based poller is unaffected because it uses ref-counted
handles.

Adds a regression test (epoll1_poller_handle_lifetime_test) that
interleaves a Work() drain with an OrphanHandle + Close(); without the fix
it fails under ASan with a stack matching the production crash.
@rwstauner
rwstauner force-pushed the rwstauner/uaf-fork-pending-events branch from 1207d0a to 24c9cc9 Compare September 10, 2026 00:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant