]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Prevent a race when calling `registerWebHandler` at runtime 14167/head
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 14 May 2024 07:56:15 +0000 (09:56 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 14 May 2024 07:56:15 +0000 (09:56 +0200)
The `registerWebHandler()` Lua method can be used to tie a custom Lua
function to an HTTP endpoint. This function was clearly not intended
to be used at runtime but this was never enforced, so let's prevent
a race condition by wrapping the internal web handlers map in a lock.

pdns/dnsdistdist/dnsdist-web.cc

index 7e0fd1fb447a585051f5c67499182df0b287241c..7fe717b1d30ae5c590297904cd81635a1442d58d 100644 (file)
@@ -1716,18 +1716,20 @@ static void handleRings(const YaHTTP::Request& req, YaHTTP::Response& resp)
   resp.headers["Content-Type"] = "application/json";
 }
 
-static std::unordered_map<std::string, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>> s_webHandlers;
+using WebHandler = std::function<void(const YaHTTP::Request&, YaHTTP::Response&)>;
+static SharedLockGuarded<std::unordered_map<std::string, WebHandler>> s_webHandlers;
 
-void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler);
+void registerWebHandler(const std::string& endpoint, WebHandler handler);
 
-void registerWebHandler(const std::string& endpoint, std::function<void(const YaHTTP::Request&, YaHTTP::Response&)> handler)
+void registerWebHandler(const std::string& endpoint, WebHandler handler)
 {
-  s_webHandlers[endpoint] = std::move(handler);
+  auto handlers = s_webHandlers.write_lock();
+  (*handlers)[endpoint] = std::move(handler);
 }
 
 void clearWebHandlers()
 {
-  s_webHandlers.clear();
+  s_webHandlers.write_lock()->clear();
 }
 
 #ifndef DISABLE_BUILTIN_HTML
@@ -1866,9 +1868,17 @@ static void connectionThread(WebClientConnection&& conn)
       resp.status = 405;
     }
     else {
-      const auto webHandlersIt = s_webHandlers.find(req.url.path);
-      if (webHandlersIt != s_webHandlers.end()) {
-        webHandlersIt->second(req, resp);
+      WebHandler handler;
+      {
+        auto handlers = s_webHandlers.read_lock();
+        const auto webHandlersIt = handlers->find(req.url.path);
+        if (webHandlersIt != handlers->end()) {
+          handler = webHandlersIt->second;
+        }
+      }
+
+      if (handler) {
+        handler(req, resp);
       }
       else {
         resp.status = 404;