File bsc1243378.patch of Package dnsdist.38874

based on

commit bb9aaec283b97c1ef2081cc66a2cf33e6edc40ea
Author: Remi Gacogne <remi.gacogne@powerdns.com>
Date:   Tue May 13 15:50:21 2025 +0200

    dnsdist: Fix a crash when TCP queries and responses keep coming
    
    It happens when we keep finding queries waiting for us on the incoming
    TCP socket from the client, and responses waiting for us on the TCP
    socket to the backend after forwarding a new query. This is quite
    unlikely but not impossible to happen, as reported by Renaud Allard
    (many thanks for taking the time to investigate the issue!).


Index: dnsdist-1.8.0/dnsdist-tcp-upstream.hh
===================================================================
--- dnsdist-1.8.0.orig/dnsdist-tcp-upstream.hh
+++ dnsdist-1.8.0/dnsdist-tcp-upstream.hh
@@ -176,4 +176,5 @@ static void handleTimeout(std::shared_pt
   bool d_proxyProtocolPayloadHasTLV{false};
   bool d_lastIOBlocked{false};
   bool d_hadErrors{false};
+  bool d_handlingIO{false};
 };
Index: dnsdist-1.8.0/dnsdist-tcp.cc
===================================================================
--- dnsdist-1.8.0.orig/dnsdist-tcp.cc
+++ dnsdist-1.8.0/dnsdist-tcp.cc
@@ -827,8 +827,39 @@ void IncomingTCPConnectionState::handleI
   handleIO(conn, now);
 }
 
+class HandlingIOGuard
+{
+public:
+  HandlingIOGuard(bool& handlingIO) :
+    d_handlingIO(handlingIO)
+  {
+  }
+  HandlingIOGuard(const HandlingIOGuard&) = delete;
+  HandlingIOGuard(HandlingIOGuard&&) = delete;
+  HandlingIOGuard& operator=(const HandlingIOGuard& rhs) = delete;
+  HandlingIOGuard& operator=(HandlingIOGuard&&) = delete;
+  ~HandlingIOGuard()
+  {
+    d_handlingIO = false;
+  }
+
+private:
+  bool& d_handlingIO;
+};
+
 void IncomingTCPConnectionState::handleIO(std::shared_ptr<IncomingTCPConnectionState>& state, const struct timeval& now)
 {
+  // let's make sure we are not already in handleIO() below in the stack:
+  // this might happen when we have a response available on the backend socket
+  // right after forwarding the query, and then a query waiting for us on the
+  // client socket right after forwarding the response, and then a response available
+  // on the backend socket right after forwarding the query.. you get the idea.
+  if (state->d_handlingIO) {
+    return;
+  }
+  state->d_handlingIO = true;
+  HandlingIOGuard reentryGuard(state->d_handlingIO);
+
   // why do we loop? Because the TLS layer does buffering, and thus can have data ready to read
   // even though the underlying socket is not ready, so we need to actually ask for the data first
   IOState iostate = IOState::Done;
openSUSE Build Service is sponsored by