[Backport][main to 0.9] | fix(iouring): plug UAF on _async_io early returns (#1569) - #1619
Merged
lihuiba merged 3 commits intoAug 21, 2026
Conversation
The stack-allocated ioCtx/timer_ctx could go out of scope while their CQEs were still in flight, on three early-return paths: timer/cancel SQE allocation failure and the cancel branch itself. Introduce an ioCtx::done flag set by reap_events on the final CQE; neutralize the queued first SQE with a NOP, and wait on the done flags before returning. A generation counter unblocks the waiters once reset() (fork) drops the old ring, whose CQEs never arrive. Add regression test test-iouring-uaf. Fixes #1270.
This engine still has the pre-refactoring shape of main, so the fix had to be re-expressed rather than applied. - io/iouring-wrapper.cpp: set ctx->done in the CQE loop of wait_and_fire_events(), which here is separate from wait_for_events() and has no is_event handling, so main's unified reap_events() block is not imported. The flag is set right after ctx->res, guarded by !IORING_CQE_F_MORE, instead of at the end of the loop body: the -ECANCELED branches of this branch come first and `continue`, and both io_ctx and timer_ctx report -ECANCELED once a cancellation takes effect, so the end of the body is unreachable for exactly the contexts the new wait loops in _async_io block on. Verified by experiment: with the flag at the end, iouring_uaf.interrupt_storm hangs. - io/iouring-wrapper.cpp: drop the try_submit() call the cherry-pick brought into the cancel path. That helper does not exist here and cannot be ported, as it is gated on m_args.eager_submit, which this branch has no equivalent of; submission stays lazy, driven by wait_and_fire_events(), as it was before. Note that git reported no conflict for this hunk, so it would have been a build break. - io/test/CMakeLists.txt: keep the signalfdboom target of this branch and register test-iouring-uaf with add_executable/target_link_libraries/ add_test under the existing `if (NOT APPLE)`, since photon_add_test() and `if (LINUX)` come from main's test-helper refactoring. - io/test/test-iouring-uaf.cpp: restore the regression test, which the backport tooling dropped as a new file while still referencing it from CMakeLists.txt. It needs no adaptation. Validated: test-iouring-uaf passes all 4 cases, including the interrupt storms that drive the cancel path over ~1200 rounds; test-iouring (10) and test-fork (5) pass, the latter covering ForkTest.Iouring, i.e. the reset()/generation path that releases the waiters.
Coldwings
marked this pull request as ready for review
August 20, 2026 04:23
lihuiba
approved these changes
Aug 21, 2026
photonlibos
deleted the
backport-pr-8e97a7737773dc6e632e61d6fe45e5b998ff33ec-0.9
branch
August 21, 2026 01:58
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The stack-allocated ioCtx/timer_ctx could go out of scope while
their CQEs were still in flight, on three early-return paths:
timer/cancel SQE allocation failure and the cancel branch itself.
Introduce an ioCtx::done flag set by reap_events on the final CQE;
neutralize the queued first SQE with a NOP, and wait on the done
flags before returning. A generation counter unblocks the waiters
once reset() (fork) drops the old ring, whose CQEs never arrive.
Add regression test test-iouring-uaf. Fixes #1270.
Generated by Backport Auto PR, by cherry-pick related commits.
Please review and decide whether to merge or close this backport PR.
Conflicts
Cherry-pick produced conflicts. Conflict markers are committed as-is; please resolve them manually before merging.
Dropped new files
The following new files introduced by cherry-pick were dropped because they don't exist in
release/0.9: