Skip to content

Revert "Fix NetAcceptAction::cancel() use-after-free race condition"#12841

Merged
bneradt merged 1 commit intomasterfrom
revert-12803-fix_unix_socket_use_after_free
Jan 29, 2026
Merged

Revert "Fix NetAcceptAction::cancel() use-after-free race condition"#12841
bneradt merged 1 commit intomasterfrom
revert-12803-fix_unix_socket_use_after_free

Conversation

@bneradt
Copy link
Contributor

@bneradt bneradt commented Jan 29, 2026

Reverts #12803

I suspect this is introducing different crashes in NetAccept::cancel.

@bneradt bneradt added this to the 10.2.0 milestone Jan 29, 2026
@bneradt bneradt self-assigned this Jan 29, 2026
@bneradt bneradt merged commit 074671f into master Jan 29, 2026
15 checks passed
@maskit
Copy link
Member

maskit commented Jan 30, 2026

Should we remove Milestone from both this and #12803 ? I don't think these two need to be on 10.2 release note since nothing changed effectively.

@bneradt
Copy link
Contributor Author

bneradt commented Jan 30, 2026

Should we remove Milestone from both this and #12803 ? I don't think these two need to be on 10.2 release note since nothing changed effectively.

Thanks. That's a good idea.

@bneradt bneradt deleted the revert-12803-fix_unix_socket_use_after_free branch January 30, 2026 03:05
@zwoop
Copy link
Contributor

zwoop commented Jan 30, 2026

Yeah, definitely clear both the Milestones, unless the first one has been in a release.

bneradt added a commit to bneradt/trafficserver that referenced this pull request Feb 10, 2026
There is a race between NetAcceptAction::cancel() and
NetAccept::acceptEvent() where the server pointer could be dereferenced
after the NetAccept object was deleted. Thread A calls cancel(), which
sets cancelled=true via Action::cancel(). Thread B running acceptEvent()
sees cancelled==true and deletes the NetAccept (including the embedded
Server). Thread A then calls server->close() on freed memory.

This is fixed by making the server pointer in NetAcceptAction atomic and
using exchange(nullptr) so only one thread can obtain and close the
server. Additionally, cancel() is made idempotent by checking !cancelled
before calling Action::cancel(), which prevents ink_assert(!cancelled)
assertion failures when cancel is called from both external callers
(TSActionCancel) and internal error paths (acceptEvent, acceptFastEvent,
acceptLoopEvent).

This is a revised version of PR apache#12803 which was reverted in PR apache#12841
because it lacked the idempotent cancel guard.
bneradt added a commit to bneradt/trafficserver that referenced this pull request Feb 10, 2026
This is a revised version of PR apache#12803 which was reverted in PR apache#12841
because it lacked the idempotent cancel guard, causing its own set of
crashes.

There is a race between NetAcceptAction::cancel() and
NetAccept::acceptEvent() where the server pointer could be dereferenced
after the NetAccept object was deleted. Thread A calls cancel(), which
sets cancelled=true via Action::cancel(). Thread B running acceptEvent()
sees cancelled==true and deletes the NetAccept (including the embedded
Server). Thread A then calls server->close() on freed memory.

This is fixed by making the server pointer in NetAcceptAction atomic and
using exchange(nullptr) so only one thread can obtain and close the
server. Additionally, cancel() is made idempotent by checking !cancelled
before calling Action::cancel(), which prevents ink_assert(!cancelled)
assertion failures when cancel is called from both external callers
(TSActionCancel) and internal error paths (acceptEvent, acceptFastEvent,
acceptLoopEvent).
bneradt added a commit that referenced this pull request Feb 13, 2026
This is a revised version of PR #12803 which was reverted in PR #12841
because it lacked the idempotent cancel guard, causing its own set of
crashes.

There is a race between NetAcceptAction::cancel() and
NetAccept::acceptEvent() where the server pointer could be dereferenced
after the NetAccept object was deleted. Thread A calls cancel(), which
sets cancelled=true via Action::cancel(). Thread B running acceptEvent()
sees cancelled==true and deletes the NetAccept (including the embedded
Server). Thread A then calls server->close() on freed memory.

This is fixed by making the server pointer in NetAcceptAction atomic and
using exchange(nullptr) so only one thread can obtain and close the
server. Additionally, cancel() is made idempotent by checking !cancelled
before calling Action::cancel(), which prevents ink_assert(!cancelled)
assertion failures when cancel is called from both external callers
(TSActionCancel) and internal error paths (acceptEvent, acceptFastEvent,
acceptLoopEvent).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants