]> granicus.if.org Git - pdns/commitdiff
Add fuzzing targets
authorRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 22 May 2018 22:26:23 +0000 (00:26 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Tue, 4 Dec 2018 14:42:51 +0000 (15:42 +0100)
configure.ac
m4/pdns_enable_fuzz_targets.m4 [new file with mode: 0644]
pdns/Makefile.am
pdns/dnsdist-cache.hh
pdns/fuzz_dnsdistcache.cc [new file with mode: 0644]
pdns/fuzz_moadnsparser.cc [new file with mode: 0644]
pdns/fuzz_packetcache.cc [new file with mode: 0644]
pdns/fuzz_zoneparsertng.cc [new file with mode: 0644]
pdns/standalone_fuzz_target_runner.cc [new file with mode: 0644]
pdns/tcpiohandler.hh [moved from pdns/dnsdistdist/tcpiohandler.hh with 100% similarity]

index 0bdb48e30c74fe653c47e41c6e85700a87e30439..ce85a2f1600231a21858a81e8b218b32370308b2 100644 (file)
@@ -118,6 +118,7 @@ AS_IF([test "$boost_cv_lib_program_options" = "no"], [
 PDNS_ENABLE_UNIT_TESTS
 PDNS_ENABLE_BACKEND_UNIT_TESTS
 PDNS_ENABLE_REPRODUCIBLE
+PDNS_ENABLE_FUZZ_TARGETS
 
 PDNS_WITH_SQLITE3
 
diff --git a/m4/pdns_enable_fuzz_targets.m4 b/m4/pdns_enable_fuzz_targets.m4
new file mode 100644 (file)
index 0000000..9973fd9
--- /dev/null
@@ -0,0 +1,11 @@
+AC_DEFUN([PDNS_ENABLE_FUZZ_TARGETS], [
+  AC_MSG_CHECKING([whether to enable fuzzing targets])
+  AC_ARG_ENABLE([fuzz_targets],
+    AS_HELP_STRING([--enable-fuzz-targets],
+      [enable fuzz targets @<:@default=no@:>@]),
+    [enable_fuzz_targets=$enableval],
+    [enable_fuzz_targets=no]
+  )
+  AC_MSG_RESULT([$enable_fuzz_targets])
+  AM_CONDITIONAL([FUZZ_TARGETS], [test "x$enable_fuzz_targets" != "xno"])
+])
index 974c70083cb7c243510fa7db4aef554ff8458a76..76d93b5bd27e20886e2e5ebbdaeab3cc3eafde06 100644 (file)
@@ -1370,6 +1370,111 @@ check-local:
        @echo "Run ./configure --enable-unit-tests"
 endif
 
+if FUZZ_TARGETS
+
+LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.o
+
+standalone_fuzz_target_runner.o: standalone_fuzz_target_runner.cc
+
+bin_PROGRAMS += \
+       fuzz_dnsdistcache \
+       fuzz_moadnsparser \
+       fuzz_packetcache \
+       fuzz_zoneparsertng
+
+fuzz_targets_libs = \
+       $(LIBCRYPTO_LIBS) \
+       $(LIB_FUZZING_ENGINE)
+fuzz_targets_ldflags = \
+       $(AM_LDFLAGS) \
+       $(DYNLINKFLAGS) \
+       $(LIBCRYPTO_LDFLAGS) \
+       $(FUZZING_LDFLAGS)
+
+# we need the mockup runner to be built, but not linked if a real fuzzing engine is used
+fuzz_targets_deps = standalone_fuzz_target_runner.o
+
+fuzz_moadnsparser_SOURCES = \
+       fuzz_moadnsparser.cc \
+       base32.cc base32.hh \
+       base64.cc base64.hh \
+       dnslabeltext.cc \
+       dnsname.cc dnsname.hh \
+       dnsparser.cc dnsparser.hh \
+       dnsrecords.cc dnsrecords.hh \
+       dnswriter.cc dnswriter.hh \
+       logger.cc logger.hh \
+       misc.cc misc.hh \
+       nsecrecords.cc  \
+       qtype.cc qtype.hh \
+       rcpgenerator.cc rcpgenerator.hh \
+       sillyrecords.cc \
+       statbag.cc statbag.hh \
+       unix_utility.cc \
+       utility.hh
+
+fuzz_moadnsparser_DEPENDENCIES = $(fuzz_targets_deps)
+fuzz_moadnsparser_LDFLAGS = $(fuzz_targets_ldflags)
+fuzz_moadnsparser_LDADD = $(fuzz_targets_libs)
+
+fuzz_packetcache_SOURCES = \
+       fuzz_packetcache.cc \
+       dnslabeltext.cc \
+       dnsname.cc dnsname.hh \
+       ednsoptions.cc ednsoptions.hh \
+       misc.cc misc.hh \
+       packetcache.hh \
+       statbag.cc statbag.hh
+
+fuzz_packetcache_DEPENDENCIES = $(fuzz_targets_deps)
+fuzz_packetcache_LDFLAGS = $(fuzz_targets_ldflags)
+fuzz_packetcache_LDADD = $(fuzz_targets_libs)
+
+fuzz_dnsdistcache_SOURCES = \
+       fuzz_dnsdistcache.cc \
+       dnsdist-cache.cc dnsdist-cache.hh \
+       dnsdist-ecs.cc dnsdist-ecs.hh \
+       dnslabeltext.cc \
+       dnsname.cc dnsname.hh \
+       dnsparser.cc dnsparser.hh \
+       dnswriter.cc dnswriter.hh \
+       ednsoptions.cc ednsoptions.hh \
+       ednssubnet.cc ednssubnet.hh \
+       iputils.cc iputils.hh \
+       misc.cc misc.hh \
+       packetcache.hh \
+       qtype.cc qtype.hh
+
+fuzz_dnsdistcache_DEPENDENCIES = $(fuzz_targets_deps)
+fuzz_dnsdistcache_LDFLAGS = $(fuzz_targets_ldflags)
+fuzz_dnsdistcache_LDADD = $(fuzz_targets_libs)
+
+fuzz_zoneparsertng_SOURCES = \
+       fuzz_zoneparsertng.cc \
+       base32.cc base32.hh \
+       base64.cc base64.hh \
+       dnslabeltext.cc \
+       dnsname.cc dnsname.hh \
+       dnsparser.cc dnsparser.hh \
+       dnsrecords.cc dnsrecords.hh \
+       dnswriter.cc dnswriter.hh \
+       logger.cc logger.hh \
+       misc.cc misc.hh \
+       nsecrecords.cc  \
+       qtype.cc qtype.hh \
+       rcpgenerator.cc rcpgenerator.hh \
+       sillyrecords.cc \
+       statbag.cc statbag.hh \
+       unix_utility.cc \
+       utility.hh \
+       zoneparser-tng.cc zoneparser-tng.hh
+
+fuzz_zoneparsertng_DEPENDENCIES = $(fuzz_targets_deps)
+fuzz_zoneparsertng_LDFLAGS = $(fuzz_targets_ldflags)
+fuzz_zoneparsertng_LDADD = $(fuzz_targets_libs)
+
+endif
+
 dnslabeltext.cc: dnslabeltext.rl
        $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc
 
index 14902c400c227e5890e02baa56b8114b4f320ce4..8f16f0386816c5a79f4c6b00755ad81b6bafea7d 100644 (file)
@@ -23,6 +23,8 @@
 
 #include <atomic>
 #include <unordered_map>
+
+#include "iputils.hh"
 #include "lock.hh"
 
 struct DNSQuestion;
@@ -54,6 +56,7 @@ public:
 
   static uint32_t getMinTTL(const char* packet, uint16_t length, bool* seenNoDataSOA);
   static uint32_t getKey(const std::string& qname, uint16_t consumed, const unsigned char* packet, uint16_t packetLen, bool tcp);
+  static bool getClientSubnet(const char* packet, unsigned int consumed, uint16_t len, boost::optional<Netmask>& subnet);
 
 private:
 
@@ -95,7 +98,6 @@ private:
     std::atomic<uint64_t> d_entriesCount;
   };
 
-  static bool getClientSubnet(const char* packet, unsigned int consumed, uint16_t len, boost::optional<Netmask>& subnet);
   bool cachedValueMatches(const CacheValue& cachedValue, uint16_t queryFlags, const DNSName& qname, uint16_t qtype, uint16_t qclass, bool tcp, bool dnssecOK, const boost::optional<Netmask>& subnet) const;
   uint32_t getShardIndex(uint32_t key) const;
   void insertLocked(CacheShard& shard, uint32_t key, CacheValue& newValue);
diff --git a/pdns/fuzz_dnsdistcache.cc b/pdns/fuzz_dnsdistcache.cc
new file mode 100644 (file)
index 0000000..d9c8efa
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsdist-cache.hh"
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+
+  /* dnsdist's version */
+  try {
+    uint16_t qtype;
+    uint16_t qclass;
+    unsigned int consumed;
+    DNSName qname(reinterpret_cast<const char*>(data), size, sizeof(dnsheader), false, &qtype, &qclass, &consumed);
+    DNSDistPacketCache::getKey(qname.toString(), consumed, data, size, false);
+    boost::optional<Netmask> subnet;
+    DNSDistPacketCache::getClientSubnet(reinterpret_cast<const char*>(data), consumed, size, subnet);
+  }
+  catch(const std::exception& e) {
+  }
+  catch(const PDNSException& e) {
+  }
+
+  return 0;
+}
diff --git a/pdns/fuzz_moadnsparser.cc b/pdns/fuzz_moadnsparser.cc
new file mode 100644 (file)
index 0000000..cf9660e
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsparser.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+
+StatBag S;
+
+static void init()
+{
+  reportAllTypes();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static bool initialized = false;
+
+  if (!initialized) {
+    init();
+    initialized = true;
+  }
+
+  try {
+    MOADNSParser moaQuery(true, reinterpret_cast<const char*>(data), size);
+  }
+  catch(const std::exception& e) {
+  }
+  catch(const PDNSException& e) {
+  }
+
+  try {
+    MOADNSParser moaAnswer(false, reinterpret_cast<const char*>(data), size);
+  }
+  catch(const std::exception& e) {
+  }
+  catch(const PDNSException& e) {
+  }
+
+  return 0;
+}
diff --git a/pdns/fuzz_packetcache.cc b/pdns/fuzz_packetcache.cc
new file mode 100644 (file)
index 0000000..b8d9f22
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "packetcache.hh"
+#include "statbag.hh"
+
+StatBag S;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+
+  std::string input(reinterpret_cast<const char*>(data), size);
+
+  /* auth's version */
+  try {
+    PacketCache::canHashPacket(input);
+  }
+  catch(const std::exception& e) {
+  }
+  catch(const PDNSException& e) {
+  }
+
+  /* recursor's version */
+  try {
+    uint16_t ecsBegin = 0;
+    uint16_t ecsEnd = 0;
+    PacketCache::canHashPacket(input, &ecsBegin, &ecsEnd);
+  }
+  catch(const std::exception& e) {
+  }
+  catch(const PDNSException& e) {
+  }
+
+  return 0;
+}
diff --git a/pdns/fuzz_zoneparsertng.cc b/pdns/fuzz_zoneparsertng.cc
new file mode 100644 (file)
index 0000000..a6f30d3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "dnsname.hh"
+#include "dnsparser.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include "zoneparser-tng.hh"
+
+StatBag S;
+
+static void init()
+{
+  reportAllTypes();
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  static bool initialized = false;
+
+  if (!initialized) {
+    init();
+    initialized = true;
+  }
+
+  try {
+    std::vector<std::string> lines;
+    std::string tmp(reinterpret_cast<const char*>(data), size);
+    boost::split(lines, tmp, boost::is_any_of("\n"));
+
+    ZoneParserTNG zpt(lines, g_rootdnsname);
+    DNSResourceRecord drr;
+    while (zpt.get(drr)) {
+    }
+  }
+  catch(const std::exception& e) {
+  }
+  catch(const PDNSException& e) {
+  }
+
+  return 0;
+}
diff --git a/pdns/standalone_fuzz_target_runner.cc b/pdns/standalone_fuzz_target_runner.cc
new file mode 100644 (file)
index 0000000..1de874f
--- /dev/null
@@ -0,0 +1,51 @@
+
+#include <fstream>
+#include <iostream>
+#include <sys/stat.h>
+#include <vector>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+extern "C" __attribute__((weak)) int LLVMFuzzerInitialize(int* argc, char*** argv);
+
+int main(int argc, char** argv)
+{
+  std::cerr<<"StandaloneFuzzTargetMain: running "<<(argc-1)<<" inputs"<<std::endl;
+
+  if (LLVMFuzzerInitialize) {
+    LLVMFuzzerInitialize(&argc, &argv);
+  }
+
+  for (int i = 1; i < argc; i++) {
+
+    struct stat st;
+    if (stat(argv[i], &st) || !S_ISREG(st.st_mode)) {
+      std::cerr<<"Skipping non-regular file: "<<std::string(argv[i])<<std::endl;
+      continue;
+    }
+
+    std::cerr<<"Running: "<<std::string(argv[i])<<std::endl;
+
+    std::ifstream file(argv[i], std::ios::binary);
+    file.seekg(0, std::ios::end);
+    size_t fileSize = file.tellg();
+    file.seekg(0, std::ios::beg);
+
+    std::vector<char> buffer;
+    buffer.resize(fileSize);
+
+    file.read(reinterpret_cast<char*>(buffer.data()), fileSize);
+
+    if (file.fail()) {
+      file.close();
+      throw std::runtime_error("Error reading fuzzing input from file '" + std::string(argv[i]) + '"');
+    }
+
+    file.close();
+
+    LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t*>(buffer.data()), fileSize);
+
+    std::cerr<<"Done: '"<<std::string(argv[i])<<"': ("<<fileSize<<" bytes)"<<std::endl;
+  }
+
+  return 0;
+}