[glibc] resolv: Test case for accepting mismatching, corrupted packets

Florian Weimer via Glibc-cvs <[email protected]>
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=40ddd85420c11446d5b670a6245e076b11f3173b

commit 40ddd85420c11446d5b670a6245e076b11f3173b
Author: Florian Weimer <[email protected]>
Date:   Sat Aug 15 12:03:35 2026 +0200

    resolv: Test case for accepting mismatching, corrupted packets
    
    The test skeleton was auto-generated.  I think this is fine because
    the harness is so specific to glibc.
    
    Assisted-by: LLM
    Reviewed-by: Adhemerval Zanella <[email protected]>

Diff:
---
 resolv/Makefile                      |   3 +
 resolv/tst-resolv-querymatch-short.c | 109 +++++++++++++++++++++++++++++++++++
 support/resolv_test.c                |   6 ++
 3 files changed, 118 insertions(+)

diff --git a/resolv/Makefile b/resolv/Makefile
index 28f6ba6c3b..e53a2b9bce 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -123,6 +123,7 @@ tests += \
   tst-resolv-noaaaa \
   tst-resolv-noaaaa-vc \
   tst-resolv-nondecimal \
+  tst-resolv-querymatch-short \
   tst-resolv-res_init-failure \
   tst-resolv-res_init-multi \
   tst-resolv-search \
@@ -326,6 +327,8 @@ $(objpfx)tst-resolv-no-search: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-noaaaa: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-noaaaa-vc: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
+$(objpfx)tst-resolv-querymatch-short: $(objpfx)libresolv.so \
+  $(shared-thread-library)
 $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
diff --git a/resolv/tst-resolv-querymatch-short.c b/resolv/tst-resolv-querymatch-short.c
new file mode 100644
index 0000000000..d9f9409622
--- /dev/null
+++ b/resolv/tst-resolv-querymatch-short.c
@@ -0,0 +1,109 @@
+/* Test res_queriesmatch buffer handling (bug 34345, bug 34346).
+   Copyright (C) 2026 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <https://www.gnu.org/licenses/>.  */
+
+#include <netdb.h>
+#include <resolv.h>
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/resolv_test.h>
+
+static void
+response (const struct resolv_response_context *ctx,
+          struct resolv_response_builder *b,
+          const char *qname, uint16_t qclass, uint16_t qtype)
+{
+  switch (ctx->server_index)
+    {
+    case 0:
+      {
+        struct resolv_response_flags flags = { .rcode = 3 }; /* NXDOMAIN.  */
+        resolv_response_init (b, flags);
+        resolv_response_add_question (b, qname, qclass, qtype);
+
+        /* Cause a mismatch in the transaction ID.  */
+        *resolv_response_buffer (b) ^= 1;
+      }
+      break;
+
+    case 1:
+      {
+        struct resolv_response_flags flags = { .rcode = 3 }; /* NXDOMAIN.  */
+        resolv_response_init (b, flags);
+        resolv_response_add_question (b, qname, qclass, qtype);
+
+        /* Truncate the packet.  If bug 34346 is present, this
+           response will be accepted because the final byte (which is
+           overread) has the expected value, carried over from the
+           previous response.  With bug 34345, the response is
+           accepted (as NXDOMAIN) because the packet is corrupt.  */
+        resolv_response_set_buffer (b,
+                                  resolv_response_buffer (b),
+                                  resolv_response_length (b) - 1);
+
+      }
+      break;
+
+    case 2:
+      {
+        /* Finally, provide a valid response.  With either bug
+           present, this is never reached because the stub resolver
+           uses the response from the second server above.  */
+        resolv_response_init (b, (struct resolv_response_flags) {});
+        resolv_response_add_question (b, qname, qclass, qtype);
+        resolv_response_section (b, ns_s_an);
+        resolv_response_open_record (b, qname, qclass, qtype, 0);
+        char ipv4[4] = { 192, 0, 2, 17 };
+        resolv_response_add_data (b, &ipv4, sizeof (ipv4));
+        resolv_response_close_record (b);
+      }
+      break;
+    }
+}
+
+static int
+do_test (void)
+{
+  struct resolv_test *aux = resolv_test_start
+    ((struct resolv_redirect_config)
+     {
+       .response_callback = response,
+     });
+
+  /* Reduce test run time.  The test hits multiple timeouts as it
+     switches between name server.  */
+  _res.retrans = 1;
+  _res.retry = 1;
+
+  struct addrinfo hints =
+    {
+      .ai_family = AF_INET,
+      .ai_socktype = SOCK_STREAM,
+    };
+  struct addrinfo *ai;
+  int ret = getaddrinfo ("www.example", "80", &hints, &ai);
+  check_addrinfo ("www.example", ai, ret,
+                  "address: STREAM/TCP 192.0.2.17 80\n");
+  if (ret == 0)
+    freeaddrinfo (ai);
+
+  resolv_test_end (aux);
+
+  return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/support/resolv_test.c b/support/resolv_test.c
index 4bb642f439..fd97ba1ee4 100644
--- a/support/resolv_test.c
+++ b/support/resolv_test.c
@@ -441,8 +441,14 @@ resolv_response_set_buffer (struct resolv_response_builder *b,
   if (length > max_response_length)
     FAIL_EXIT1 ("resolv_response_set_buffer: length %zu exceeds maximum %d",
                 length, max_response_length);
+  if (b->current_rdata_offset != 0)
+    FAIL_EXIT1 ("resolv_response_set_buffer: called with pending RDATA");
   memmove (b->buffer, data, length);
   b->offset = length;
+
+  /* The cached compression offsets are likely invalid now.  */
+  tdestroy (b->compression_offsets, free);
+  b->compression_offsets = NULL;
 }
 
 struct resolv_response_builder *
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.