From: Remi Gacogne Date: Tue, 14 May 2024 07:56:15 +0000 (+0200) Subject: dnsdist: Prevent a race when calling `registerWebHandler` at runtime X-Git-Tag: rec-5.1.0-alpha1~1^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a843017673f5b7c1f5c39a3a91592e18ef02d985;p=thirdparty%2Fpdns.git dnsdist: Prevent a race when calling `registerWebHandler` at runtime 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. --- diff --git a/pdns/dnsdistdist/dnsdist-web.cc b/pdns/dnsdistdist/dnsdist-web.cc index 7e0fd1fb44..7fe717b1d3 100644 --- a/pdns/dnsdistdist/dnsdist-web.cc +++ b/pdns/dnsdistdist/dnsdist-web.cc @@ -1716,18 +1716,20 @@ static void handleRings(const YaHTTP::Request& req, YaHTTP::Response& resp) resp.headers["Content-Type"] = "application/json"; } -static std::unordered_map> s_webHandlers; +using WebHandler = std::function; +static SharedLockGuarded> s_webHandlers; -void registerWebHandler(const std::string& endpoint, std::function handler); +void registerWebHandler(const std::string& endpoint, WebHandler handler); -void registerWebHandler(const std::string& endpoint, std::function 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;