about summary refs log tree commit diff
path: root/resolv/tst-ns_name.c
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2017-04-13 11:56:28 +0200
committerFlorian Weimer <fweimer@redhat.com>2017-04-13 11:56:28 +0200
commitc803cb9b24c6cea15698768e4301e963b98e742c (patch)
tree8b1dfb346ea50ccd7f1da044c65b60bb4b9aee27 /resolv/tst-ns_name.c
parenta7ff1da8239a5f0e1927db9d5310f53cfea97fc2 (diff)
downloadglibc-c803cb9b24c6cea15698768e4301e963b98e742c.tar.gz
glibc-c803cb9b24c6cea15698768e4301e963b98e742c.tar.xz
glibc-c803cb9b24c6cea15698768e4301e963b98e742c.zip
resolv: Support an exactly sized buffer in ns_name_pack [BZ #21359]
This bug did not affect name resolution because those functions
indirectly call ns_name_pack with a buffer which is always larger
than the generated query packet, even in the case of the
longest-possible domain name.
Diffstat (limited to 'resolv/tst-ns_name.c')
-rw-r--r--resolv/tst-ns_name.c139
1 files changed, 137 insertions, 2 deletions
diff --git a/resolv/tst-ns_name.c b/resolv/tst-ns_name.c
index 66d9a6666b..65eea4c827 100644
--- a/resolv/tst-ns_name.c
+++ b/resolv/tst-ns_name.c
@@ -195,6 +195,7 @@ print_hex (const char *label, struct buffer buffer)
 static void
 run_test_case (struct test_case *t)
 {
+  /* Test ns_name_unpack.  */
   unsigned char *unpacked = xmalloc (NS_MAXCDNAME);
   int consumed = ns_name_unpack
     (t->input.data, t->input.data + t->input.length,
@@ -211,16 +212,19 @@ run_test_case (struct test_case *t)
     }
   if (consumed != -1)
     {
-      if (memcmp (unpacked, t->unpack_output.data, consumed) != 0)
+      if (memcmp (unpacked, t->unpack_output.data,
+                  t->unpack_output.length) != 0)
         {
           support_record_failure ();
           printf ("%s:%zu: error: wrong data from ns_name_unpack\n",
                   t->path, t->lineno);
           print_hex ("expected:", t->unpack_output);
-          print_hex ("actual:  ", (struct buffer) { unpacked, consumed });
+          print_hex ("actual:  ",
+                     (struct buffer) { unpacked, t->unpack_output.length });
           return;
         }
 
+      /* Test ns_name_ntop.  */
       char *text = xmalloc (NS_MAXDNAME);
       int ret = ns_name_ntop (unpacked, text, NS_MAXDNAME);
       if (ret != t->ntop_result)
@@ -243,6 +247,137 @@ run_test_case (struct test_case *t)
               printf ("  actual:   \"%s\"\n", text);
               return;
             }
+
+          /* Test ns_name_pton.  Unpacking does not check the
+             NS_MAXCDNAME limit, but packing does, so we need to
+             adjust the expected result.  */
+          int expected;
+          if (t->unpack_output.length > NS_MAXCDNAME)
+            expected = -1;
+          else if (strcmp (text, ".") == 0)
+            /* The root domain is fully qualified.  */
+            expected = 1;
+          else
+            /* The domain name is never fully qualified.  */
+            expected = 0;
+          unsigned char *repacked = xmalloc (NS_MAXCDNAME);
+          ret = ns_name_pton (text, repacked, NS_MAXCDNAME);
+          if (ret != expected)
+            {
+              support_record_failure ();
+              printf ("%s:%zu: error: wrong result from ns_name_pton\n"
+                      "  expected: %d\n"
+                      "  actual:   %d\n",
+                      t->path, t->lineno, expected, ret);
+              return;
+            }
+          if (ret >= 0
+              && memcmp (repacked, unpacked, t->unpack_output.length) != 0)
+            {
+              support_record_failure ();
+              printf ("%s:%zu: error: wrong data from ns_name_pton\n",
+                      t->path, t->lineno);
+              print_hex ("expected:", t->unpack_output);
+              print_hex ("actual:  ",
+                         (struct buffer) { repacked, t->unpack_output.length });
+              return;
+            }
+
+          /* Test ns_name_compress, no compression case.  */
+          if (t->unpack_output.length > NS_MAXCDNAME)
+            expected = -1;
+          else
+            expected = t->unpack_output.length;
+          memset (repacked, '$', NS_MAXCDNAME);
+          {
+            enum { ptr_count = 5 };
+            const unsigned char *dnptrs[ptr_count] = { repacked, };
+            ret = ns_name_compress (text, repacked, NS_MAXCDNAME,
+                                    dnptrs, dnptrs + ptr_count);
+            if (ret != expected)
+              {
+                support_record_failure ();
+                printf ("%s:%zu: error: wrong result from ns_name_compress\n"
+                        "  expected: %d\n"
+                        "  actual:   %d\n",
+                        t->path, t->lineno, expected, ret);
+                return;
+              }
+            if (ret < 0)
+              {
+                TEST_VERIFY (dnptrs[0] == repacked);
+                TEST_VERIFY (dnptrs[1] == NULL);
+              }
+            else
+              {
+                if (memcmp (repacked, unpacked, t->unpack_output.length) != 0)
+                  {
+                    support_record_failure ();
+                    printf ("%s:%zu: error: wrong data from ns_name_compress\n",
+                            t->path, t->lineno);
+                    print_hex ("expected:", t->unpack_output);
+                    print_hex ("actual:  ", (struct buffer) { repacked, ret });
+                    return;
+                  }
+                TEST_VERIFY (dnptrs[0] == repacked);
+                if (unpacked[0] == '\0')
+                  /* The root domain is not a compression target.  */
+                  TEST_VERIFY (dnptrs[1] == NULL);
+                else
+                  {
+                    TEST_VERIFY (dnptrs[1] == repacked);
+                    TEST_VERIFY (dnptrs[2] == NULL);
+                  }
+              }
+          }
+
+          /* Test ns_name_compress, full compression case.  Skip this
+             test for invalid names and the root domain.  */
+          if (expected >= 0 && unpacked[0] != '\0')
+            {
+              /* The destination buffer needs additional room for the
+                 offset, the initial name, and the compression
+                 reference.  */
+              enum { name_offset = 259 };
+              size_t target_offset = name_offset + t->unpack_output.length;
+              size_t repacked_size = target_offset + 2;
+              repacked = xrealloc (repacked, repacked_size);
+              memset (repacked, '@', repacked_size);
+              memcpy (repacked + name_offset,
+                      t->unpack_output.data, t->unpack_output.length);
+              enum { ptr_count = 5 };
+              const unsigned char *dnptrs[ptr_count]
+                = { repacked, repacked + name_offset, };
+              ret = ns_name_compress
+                (text, repacked + target_offset, NS_MAXCDNAME,
+                 dnptrs, dnptrs + ptr_count);
+              if (ret != 2)
+                {
+                  support_record_failure ();
+                  printf ("%s:%zu: error: wrong result from ns_name_compress"
+                          " (2)\n"
+                          "  expected: 2\n"
+                          "  actual:   %d\n",
+                          t->path, t->lineno, ret);
+                  return;
+                }
+              if (memcmp (repacked + target_offset, "\xc1\x03", 2) != 0)
+                {
+                  support_record_failure ();
+                  printf ("%s:%zu: error: wrong data from ns_name_compress"
+                          " (2)\n"
+                          "  expected: C103\n",
+                          t->path, t->lineno);
+                  print_hex ("actual:  ",
+                             (struct buffer) { repacked + target_offset, ret });
+                  return;
+                }
+              TEST_VERIFY (dnptrs[0] == repacked);
+              TEST_VERIFY (dnptrs[1] == repacked + name_offset);
+              TEST_VERIFY (dnptrs[2] == NULL);
+            }
+
+          free (repacked);
         }
       free (text);
     }