This is an automated email from the ASF dual-hosted git repository.

bneradt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git


The following commit(s) were added to refs/heads/master by this push:
     new 6112a78356 NetAcceptAction::cancel() use-after-free fix: part 2 
(#12874)
6112a78356 is described below

commit 6112a78356a86fbf86c466932d554ba8e932d3e4
Author: Brian Neradt <[email protected]>
AuthorDate: Fri Feb 13 17:14:45 2026 -0600

    NetAcceptAction::cancel() use-after-free fix: part 2 (#12874)
    
    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).
---
 src/iocore/net/P_NetAccept.h       | 28 +++++++++++++++++++---------
 src/iocore/net/QUICNetProcessor.cc |  4 +---
 src/iocore/net/UnixNetAccept.cc    |  8 +++++---
 src/iocore/net/UnixNetProcessor.cc |  4 +---
 4 files changed, 26 insertions(+), 18 deletions(-)

diff --git a/src/iocore/net/P_NetAccept.h b/src/iocore/net/P_NetAccept.h
index 163d5578d5..89650e34fa 100644
--- a/src/iocore/net/P_NetAccept.h
+++ b/src/iocore/net/P_NetAccept.h
@@ -43,6 +43,7 @@
 #include "iocore/net/NetAcceptEventIO.h"
 #include "Server.h"
 
+#include <atomic>
 #include <vector>
 
 struct NetAccept;
@@ -60,21 +61,30 @@ AcceptFunction net_accept;
 
 class UnixNetVConnection;
 
-// TODO fix race between cancel accept and call back
 struct NetAcceptAction : public Action, public RefCountObjInHeap {
-  Server *server;
+  std::atomic<Server *> server{nullptr};
 
-  void
-  cancel(Continuation *cont = nullptr) override
+  NetAcceptAction(Continuation *cont, Server *s)
   {
-    Action::cancel(cont);
-    server->close();
+    continuation = cont;
+    if (cont != nullptr) {
+      mutex = cont->mutex;
+    }
+    server.store(s, std::memory_order_release);
   }
 
-  Continuation *
-  operator=(Continuation *acont)
+  void
+  cancel(Continuation *cont = nullptr) override
   {
-    return Action::operator=(acont);
+    // Use atomic exchange so only one thread closes the server, preventing
+    // use-after-free races between cancel() and acceptEvent() cleanup.
+    Server *s = server.exchange(nullptr, std::memory_order_acq_rel);
+    if (s != nullptr) {
+      s->close();
+    }
+    if (!cancelled) {
+      Action::cancel(cont);
+    }
   }
 
   ~NetAcceptAction() override
diff --git a/src/iocore/net/QUICNetProcessor.cc 
b/src/iocore/net/QUICNetProcessor.cc
index 55592ef6f3..d7f7012606 100644
--- a/src/iocore/net/QUICNetProcessor.cc
+++ b/src/iocore/net/QUICNetProcessor.cc
@@ -251,9 +251,7 @@ QUICNetProcessor::main_accept(Continuation *cont, SOCKET 
fd, AcceptOptions const
   na->server.sock = UnixSocket{fd};
   ats_ip_copy(&na->server.accept_addr, &accept_ip);
 
-  na->action_         = new NetAcceptAction();
-  *na->action_        = cont;
-  na->action_->server = &na->server;
+  na->action_ = new NetAcceptAction(cont, &na->server);
   na->init_accept();
 
   return na->action_.get();
diff --git a/src/iocore/net/UnixNetAccept.cc b/src/iocore/net/UnixNetAccept.cc
index cea9df7879..66e73096fa 100644
--- a/src/iocore/net/UnixNetAccept.cc
+++ b/src/iocore/net/UnixNetAccept.cc
@@ -317,9 +317,7 @@ NetAccept::init_accept_per_thread()
 void
 NetAccept::stop_accept()
 {
-  if (!action_->cancelled) {
-    action_->cancel();
-  }
+  action_->cancel();
   server.close();
 }
 
@@ -479,6 +477,7 @@ NetAccept::acceptEvent(int event, void *ep)
   MUTEX_TRY_LOCK(lock, m, e->ethread);
   if (lock.is_locked()) {
     if (action_->cancelled) {
+      // Server was already closed by whoever called cancel().
       e->cancel();
       Metrics::Gauge::decrement(net_rsb.accepts_currently_open);
       delete this;
@@ -487,6 +486,7 @@ NetAccept::acceptEvent(int event, void *ep)
 
     int res;
     if ((res = net_accept(this, e, false)) < 0) {
+      action_->cancel();
       Metrics::Gauge::decrement(net_rsb.accepts_currently_open);
       /* INKqa11179 */
       Warning("Accept on port %d failed with error no %d", 
ats_ip_port_host_order(&server.addr), res);
@@ -637,6 +637,7 @@ Ldone:
   return EVENT_CONT;
 
 Lerror:
+  action_->cancel();
   server.close();
   e->cancel();
   Metrics::Gauge::decrement(net_rsb.accepts_currently_open);
@@ -656,6 +657,7 @@ NetAccept::acceptLoopEvent(int event, Event *e)
   }
 
   // Don't think this ever happens ...
+  action_->cancel();
   Metrics::Gauge::decrement(net_rsb.accepts_currently_open);
   delete this;
   return EVENT_DONE;
diff --git a/src/iocore/net/UnixNetProcessor.cc 
b/src/iocore/net/UnixNetProcessor.cc
index 15630281c5..5c8d5111e1 100644
--- a/src/iocore/net/UnixNetProcessor.cc
+++ b/src/iocore/net/UnixNetProcessor.cc
@@ -133,9 +133,7 @@ UnixNetProcessor::accept_internal(Continuation *cont, int 
fd, AcceptOptions cons
   na->proxyPort     = sa ? sa->proxyPort : nullptr;
   na->snpa          = dynamic_cast<SSLNextProtocolAccept *>(cont);
 
-  na->action_         = new NetAcceptAction();
-  *na->action_        = cont;
-  na->action_->server = &na->server;
+  na->action_ = new NetAcceptAction(cont, &na->server);
 
   if (opt.frequent_accept) { // true
     if (accept_threads > 0 && listen_per_thread == 0) {

Reply via email to