]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Safe tmp file handling, basic sanity check on size of data. 10238/head
authorOtto <otto.moerbeek@open-xchange.com>
Mon, 29 Mar 2021 13:27:43 +0000 (15:27 +0200)
committerOtto <otto.moerbeek@open-xchange.com>
Mon, 29 Mar 2021 13:51:58 +0000 (15:51 +0200)
pdns/nod.cc
pdns/nod.hh
pdns/recursordist/stable-bloom.hh

index af86697ddc7894f7ae8e7942b41098fc0735e530..cc2e9de73cdcfc0236e7f02d54f5fc3ca92356c6 100644 (file)
@@ -28,8 +28,7 @@
 #include <ctime>
 #include <thread>
 #include "threadname.hh"
-#include <unistd.h>
-#include <boost/filesystem.hpp>
+#include <stdlib.h>
 #include "logger.hh"
 #include "misc.hh"
 
@@ -40,10 +39,9 @@ namespace filesystem = boost::filesystem;
 
 std::mutex PersistentSBF::d_cachedir_mutex;
 
-void PersistentSBF::remove_tmp_files()
+void PersistentSBF::remove_tmp_files(const filesystem::path& p, std::lock_guard<std::mutex>& lock)
 {
-  filesystem::path p(d_cachedir);
-  Regex file_regex(d_prefix + ".*\\." + bf_suffix + "\\.[[:xdigit:]]{8}$");
+  Regex file_regex(d_prefix + ".*\\." + bf_suffix + "\\..{8}$");
   for (filesystem::directory_iterator i(p); i != filesystem::directory_iterator(); ++i) {
     if (filesystem::is_regular_file(i->path()) && file_regex.match(i->path().filename().string())) {
       filesystem::remove(*i);
@@ -65,7 +63,7 @@ bool PersistentSBF::init(bool ignore_pid) {
     filesystem::path p(d_cachedir);
     try {
       if (filesystem::exists(p) && filesystem::is_directory(p)) {
-        remove_tmp_files();
+        remove_tmp_files(p, lock);
         filesystem::path newest_file;
         std::time_t newest_time=time(nullptr);
         Regex file_regex(d_prefix + ".*\\." + bf_suffix + "$");
@@ -138,7 +136,6 @@ bool PersistentSBF::snapshotCurrent(std::thread::id tid)
     std::stringstream ss;
     ss << d_prefix << "_" << tid;
     f /= ss.str() + "_" + std::to_string(getpid()) + "." + bf_suffix;
-    filesystem::path ftmp(filesystem::unique_path(f.string() + ".%%%%%%%%"));
     if (filesystem::exists(p) && filesystem::is_directory(p)) {
       try {
         std::ofstream ofile;
@@ -149,15 +146,22 @@ bool PersistentSBF::snapshotCurrent(std::thread::id tid)
           d_sbf.dump(iss);
         }
         // Now write it out to the file
-        ofile.open(ftmp.string(), std::ios::out | std::ios::binary);
-        ofile << iss.str();
-
-        if (ofile.fail()) {
-          ofile.close();
+        std::string ftmp = f.string() + ".XXXXXXXX";
+        int fd = mkstemp(&ftmp.at(0));
+        if (fd == -1) {
+          throw std::runtime_error("Cannot create temp file: " + stringerror());
+        }
+        std::string str = iss.str();
+        ssize_t len = write(fd,  str.data(), str.length());
+        if (len != static_cast<ssize_t>(str.length())) {
+          close(fd);
+          filesystem::remove(ftmp.c_str());
+          throw std::runtime_error("Failed to write to file:" + ftmp);
+        }
+        if (close(fd) != 0) {
           filesystem::remove(ftmp);
-          throw std::runtime_error("Failed to write to file:" + ftmp.string());
+          throw std::runtime_error("Failed to write to file:" + ftmp);
         }
-        ofile.close();
         try {
           filesystem::rename(ftmp, f);
         }
index a801b1a0e5cdebbed9f8041d52f7405f7af5412e..0def55606b89618f3e0fe8b4609388252bb6978d 100644 (file)
@@ -23,6 +23,7 @@
 #include <atomic>
 #include <mutex>
 #include <thread>
+#include <boost/filesystem.hpp>
 #include "dnsname.hh"
 #include "stable-bloom.hh"
 
@@ -59,7 +60,7 @@ namespace nod {
       return d_sbf.testAndAdd(data); 
     }
   private:
-    void remove_tmp_files();
+    void remove_tmp_files(const boost::filesystem::path&, std::lock_guard<std::mutex>&);
 
     bool d_init{false};
     bf::stableBF d_sbf; // Stable Bloom Filter
index 9fc343f88b34ea72f0872ca9c10a015e3e7fe233..947e92ed0ce2b1803b01b3d667e49aaad4fe4782 100644 (file)
@@ -123,6 +123,9 @@ public:
       throw std::runtime_error("SBF: read failed (file too short?)");
     }
     bitstr_len = ntohl(bitstr_len);
+    if (bitstr_len > 2 * 64 * 1024 * 1024U) { // twice the current size
+      throw std::runtime_error("SBF: read failed (bitstr_len too big)");
+    }
     unique_ptr<char[]> bitcstr = make_unique<char[]>(bitstr_len);
     is.read(bitcstr.get(), bitstr_len);
     if (is.fail()) {