]> granicus.if.org Git - pdns/commitdiff
rec: Delay the creation of RPZ threads until we have dropped privileges
authorRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 13 Jul 2018 09:19:04 +0000 (11:19 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Fri, 13 Jul 2018 09:19:04 +0000 (11:19 +0200)
On Linux/glibc, calling `set*id()` from a thread results in the other
threads being sent the `SIGRT_1` signal so they are aware that they
should switch credentials too, because `POSIX` requires that all threads
use the same credentials but Linux actually handles it per thread.
The reception of the signal interrupts the current `syscall` with
`EINTR`, causing the loading of the `RPZ` zone to fail.

pdns/pdns_recursor.cc
pdns/rec-lua-conf.cc
pdns/rec-lua-conf.hh
pdns/rec_channel_rec.cc

index cefafcf4080ad1b0392825339a8bee84a2e4dab8..5a0bc9386a273456dc606b655e7d95131a418db0 100644 (file)
@@ -3189,9 +3189,10 @@ static int serviceMain(int argc, char*argv[])
 
   g_maxCacheEntries = ::arg().asNum("max-cache-entries");
   g_maxPacketCacheEntries = ::arg().asNum("max-packetcache-entries");
-  
+
+  luaConfigDelayedThreads delayedLuaThreads;
   try {
-    loadRecursorLuaConfig(::arg()["lua-config-file"], ::arg().mustDo("daemon"));
+    loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
   }
   catch (PDNSException &e) {
     g_log<<Logger::Error<<"Cannot load Lua configuration: "<<e.reason<<endl;
@@ -3354,7 +3355,6 @@ static int serviceMain(int argc, char*argv[])
     g_log<<Logger::Warning<<"Calling daemonize, going to background"<<endl;
     g_log.toConsole(Logger::Critical);
     daemonize();
-    loadRecursorLuaConfig(::arg()["lua-config-file"], false);
   }
   signal(SIGUSR1,usr1Handler);
   signal(SIGUSR2,usr2Handler);
@@ -3413,6 +3413,8 @@ static int serviceMain(int argc, char*argv[])
 
   Utility::dropUserPrivs(newuid);
 
+  startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
+
   makeThreadPipes();
 
   g_tcpTimeout=::arg().asNum("client-tcp-timeout");
index 6f79ab01bcec4e78b48ed08604dc439df81d5d9d..cac3cc71e3347b595b6cbbeed167697afec18e16 100644 (file)
@@ -81,7 +81,7 @@ static void parseRPZParameters(const std::unordered_map<string,boost::variant<ui
   }
 }
 
-void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
+void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads)
 {
   LuaConfigItems lci;
 
@@ -92,8 +92,6 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
   if(!ifs)
     throw PDNSException("Cannot open file '"+fname+"': "+strerror(errno));
 
-  std::vector<std::tuple<std::vector<ComboAddress>, boost::optional<DNSFilterEngine::Policy>, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t, std::shared_ptr<SOARecordContent>, std::string> > rpzMasterThreads;
-
   auto luaconfsLocal = g_luaconfs.getLocal();
   lci.generation = luaconfsLocal->generation + 1;
 
@@ -139,7 +137,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
       }
     });
 
-  Lua.writeFunction("rpzMaster", [&lci, &rpzMasterThreads](const boost::variant<string, std::vector<std::pair<int, string> > >& masters_, const string& zoneName, const boost::optional<std::unordered_map<string,boost::variant<uint32_t, string>>>& options) {
+  Lua.writeFunction("rpzMaster", [&lci, &delayedThreads](const boost::variant<string, std::vector<std::pair<int, string> > >& masters_, const string& zoneName, const boost::optional<std::unordered_map<string,boost::variant<uint32_t, string>>>& options) {
 
       boost::optional<DNSFilterEngine::Policy> defpol;
       std::shared_ptr<DNSFilterEngine::Zone> zone = std::make_shared<DNSFilterEngine::Zone>();
@@ -249,7 +247,7 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
         exit(1);  // FIXME proper exit code?
       }
 
-      rpzMasterThreads.push_back(std::make_tuple(masters, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, sr, dumpFile));
+      delayedThreads.rpzMasterThreads.push_back(std::make_tuple(masters, defpol, maxTTL, zoneIdx, tt, maxReceivedXFRMBytes, localAddress, axfrTimeout, sr, dumpFile));
     });
 
   typedef vector<pair<int,boost::variant<string, vector<pair<int, string> > > > > argvec_t;
@@ -316,31 +314,29 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
     });
 
 #if HAVE_PROTOBUF
-  Lua.writeFunction("protobufServer", [&lci, checkOnly](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, const boost::optional<uint8_t> maskV4, boost::optional<uint8_t> maskV6, boost::optional<bool> asyncConnect, boost::optional<bool> taggedOnly) {
+  Lua.writeFunction("protobufServer", [&lci](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, const boost::optional<uint8_t> maskV4, boost::optional<uint8_t> maskV6, boost::optional<bool> asyncConnect, boost::optional<bool> taggedOnly) {
       try {
        ComboAddress server(server_);
         if (!lci.protobufExportConfig.enabled) {
 
           lci.protobufExportConfig.enabled = true;
 
-          if (!checkOnly) {
-            lci.protobufExportConfig.server = server;
+          lci.protobufExportConfig.server = server;
 
-            if (timeout) {
-              lci.protobufExportConfig.timeout = *timeout;
-            }
+          if (timeout) {
+            lci.protobufExportConfig.timeout = *timeout;
+          }
 
-            if (maxQueuedEntries) {
-              lci.protobufExportConfig.maxQueuedEntries = *maxQueuedEntries;
-            }
+          if (maxQueuedEntries) {
+            lci.protobufExportConfig.maxQueuedEntries = *maxQueuedEntries;
+          }
 
-            if (reconnectWaitTime) {
-              lci.protobufExportConfig.reconnectWaitTime = *reconnectWaitTime;
-            }
+          if (reconnectWaitTime) {
+            lci.protobufExportConfig.reconnectWaitTime = *reconnectWaitTime;
+          }
 
-            if (asyncConnect) {
-              lci.protobufExportConfig.asyncConnect = *asyncConnect;
-            }
+          if (asyncConnect) {
+            lci.protobufExportConfig.asyncConnect = *asyncConnect;
           }
 
           if (maskV4) {
@@ -365,31 +361,29 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
       }
     });
 
-  Lua.writeFunction("outgoingProtobufServer", [&lci, checkOnly](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, boost::optional<bool> asyncConnect) {
+  Lua.writeFunction("outgoingProtobufServer", [&lci](const string& server_, const boost::optional<uint16_t> timeout, const boost::optional<uint64_t> maxQueuedEntries, const boost::optional<uint8_t> reconnectWaitTime, boost::optional<bool> asyncConnect) {
       try {
        ComboAddress server(server_);
         if (!lci.outgoingProtobufExportConfig.enabled) {
 
           lci.outgoingProtobufExportConfig.enabled = true;
 
-          if (!checkOnly) {
-            lci.outgoingProtobufExportConfig.server = server;
+          lci.outgoingProtobufExportConfig.server = server;
 
-            if (timeout) {
-              lci.outgoingProtobufExportConfig.timeout = *timeout;
-            }
+          if (timeout) {
+            lci.outgoingProtobufExportConfig.timeout = *timeout;
+          }
 
-            if (maxQueuedEntries) {
-              lci.outgoingProtobufExportConfig.maxQueuedEntries = *maxQueuedEntries;
-            }
+          if (maxQueuedEntries) {
+            lci.outgoingProtobufExportConfig.maxQueuedEntries = *maxQueuedEntries;
+          }
 
-            if (reconnectWaitTime) {
-              lci.outgoingProtobufExportConfig.reconnectWaitTime = *reconnectWaitTime;
-            }
+          if (reconnectWaitTime) {
+            lci.outgoingProtobufExportConfig.reconnectWaitTime = *reconnectWaitTime;
+          }
 
-            if (asyncConnect) {
-              lci.outgoingProtobufExportConfig.asyncConnect = *asyncConnect;
-            }
+          if (asyncConnect) {
+            lci.outgoingProtobufExportConfig.asyncConnect = *asyncConnect;
           }
         }
         else {
@@ -408,23 +402,6 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
   try {
     Lua.executeCode(ifs);
     g_luaconfs.setState(lci);
-
-    if (!checkOnly) {
-      for (const auto& rpzMaster : rpzMasterThreads) {
-        try {
-          std::thread t(RPZIXFRTracker, std::get<0>(rpzMaster), std::get<1>(rpzMaster), std::get<2>(rpzMaster), std::get<3>(rpzMaster), std::get<4>(rpzMaster), std::get<5>(rpzMaster) * 1024 * 1024, std::get<6>(rpzMaster), std::get<7>(rpzMaster), std::get<8>(rpzMaster), std::get<9>(rpzMaster), lci.generation);
-          t.detach();
-        }
-        catch(const std::exception& e) {
-          g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.what()<<endl;
-          exit(1);  // FIXME proper exit code?
-        }
-        catch(const PDNSException& e) {
-          g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.reason<<endl;
-          exit(1);  // FIXME proper exit code?
-        }
-      }
-    }
   }
   catch(const LuaContext::ExecutionErrorException& e) {
     g_log<<Logger::Error<<"Unable to load Lua script from '"+fname+"': ";
@@ -448,3 +425,20 @@ void loadRecursorLuaConfig(const std::string& fname, bool checkOnly)
 
 }
 
+void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads, uint64_t generation)
+{
+  for (const auto& rpzMaster : delayedThreads.rpzMasterThreads) {
+    try {
+      std::thread t(RPZIXFRTracker, std::get<0>(rpzMaster), std::get<1>(rpzMaster), std::get<2>(rpzMaster), std::get<3>(rpzMaster), std::get<4>(rpzMaster), std::get<5>(rpzMaster) * 1024 * 1024, std::get<6>(rpzMaster), std::get<7>(rpzMaster), std::get<8>(rpzMaster), std::get<9>(rpzMaster), generation);
+      t.detach();
+    }
+    catch(const std::exception& e) {
+      g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.what()<<endl;
+      exit(1);  // FIXME proper exit code?
+    }
+    catch(const PDNSException& e) {
+      g_log<<Logger::Error<<"Problem starting RPZIXFRTracker thread: "<<e.reason<<endl;
+      exit(1);  // FIXME proper exit code?
+    }
+  }
+}
index a502a209302323a87063e065529eab56643ad3ea..a9ba373e24356e3da2f6a2e67b44863158725d1a 100644 (file)
@@ -55,5 +55,12 @@ public:
 };
 
 extern GlobalStateHolder<LuaConfigItems> g_luaconfs;
-void loadRecursorLuaConfig(const std::string& fname, bool checkOnly);
+
+struct luaConfigDelayedThreads
+{
+  std::vector<std::tuple<std::vector<ComboAddress>, boost::optional<DNSFilterEngine::Policy>, uint32_t, size_t, TSIGTriplet, size_t, ComboAddress, uint16_t, std::shared_ptr<SOARecordContent>, std::string> > rpzMasterThreads;
+};
+
+void loadRecursorLuaConfig(const std::string& fname, luaConfigDelayedThreads& delayedThreads);
+void startLuaConfigDelayedThreads(const luaConfigDelayedThreads& delayedThreads, uint64_t generation);
 
index c46d62da8a433dc94a5b2c7d8a0f771467d5c876..ad3cfdfdf0d99d1242b5c7ea3da5f4b6462a7ac0 100644 (file)
@@ -1332,7 +1332,9 @@ string RecursorControlParser::getAnswer(const string& question, RecursorControlP
       ::arg().set("lua-config-file") = *begin;
 
     try {
-      loadRecursorLuaConfig(::arg()["lua-config-file"], false);
+      luaConfigDelayedThreads delayedLuaThreads;
+      loadRecursorLuaConfig(::arg()["lua-config-file"], delayedLuaThreads);
+      startLuaConfigDelayedThreads(delayedLuaThreads, g_luaconfs.getCopy().generation);
       g_log<<Logger::Warning<<"Reloaded Lua configuration file '"<<::arg()["lua-config-file"]<<"', requested via control channel"<<endl;
       return "Reloaded Lua configuration file '"+::arg()["lua-config-file"]+"'\n";
     }