]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsname: Properly reject 256-bytes wire-encoded DNS names
authorRemi Gacogne <remi.gacogne@powerdns.com>
Thu, 16 Jul 2026 10:31:21 +0000 (12:31 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 27 Jul 2026 08:44:25 +0000 (10:44 +0200)
The length check was off by one for uncompressed names.

Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
(cherry picked from commit 740f5ce2cee645926197115f1b97a8aa08300107)

pdns/dnsname.cc
pdns/test-dnsname_cc.cc

index f97b1837a714d528203e75d46d939f9002a224bf..d357bbc175f0ccf97c2b8a4670c9f8abf735c5a3 100644 (file)
@@ -144,6 +144,7 @@ static void checkLabelLength(uint8_t length)
 size_t DNSName::parsePacketUncompressed(const pdns::views::UnsignedCharView& view, size_t pos, bool uncompress)
 {
   const size_t initialPos = pos;
+  const size_t neededSizeForFinalLabel = /* final empty label length */ (d_storage.empty() ? 1U : 0U);
   size_t totalLength = 0;
   unsigned char labellen = 0;
 
@@ -168,8 +169,8 @@ size_t DNSName::parsePacketUncompressed(const pdns::views::UnsignedCharView& vie
       throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)");
     }
     checkLabelLength(labellen);
-    // reserve one byte for the label length
-    if (totalLength + labellen > s_maxDNSNameLength - 1) {
+    // reserve one byte for the label length, plus one byte for the final empty label if we were empty before
+    if (totalLength + labellen > s_maxDNSNameLength - (neededSizeForFinalLabel + 1)) {
       throw std::range_error("name too long to append");
     }
     if (pos + labellen >= view.size()) {
index e197ec54883d46874c598ae0ce0a849128751cf0..5d0180085693e102f1611effff83a92206186da4 100644 (file)
@@ -860,6 +860,12 @@ BOOST_AUTO_TEST_CASE(test_invalid_label_length) { // Invalid label length in qna
   BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error);
 }
 
+BOOST_AUTO_TEST_CASE(test_name_length_too_long_from_wire) {
+
+  string name("\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x03""www""\x05""stats""\x05""stats""\x02""fr""\x00", 256);
+  BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error);
+}
+
 BOOST_AUTO_TEST_CASE(test_compression) { // Compression test
 
   string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05", 21);