diff options
author | Florian Weimer <fweimer@redhat.com> | 2017-04-13 11:56:28 +0200 |
---|---|---|
committer | Florian Weimer <fweimer@redhat.com> | 2017-04-13 11:56:28 +0200 |
commit | c803cb9b24c6cea15698768e4301e963b98e742c (patch) | |
tree | 8b1dfb346ea50ccd7f1da044c65b60bb4b9aee27 /resolv/tst-ns_name.c | |
parent | a7ff1da8239a5f0e1927db9d5310f53cfea97fc2 (diff) | |
download | glibc-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.c | 139 |
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); } |