5f7b84
commit 108bc4049f8ae82710aec26a92ffdb4b439c83fd
5f7b84
Author: Florian Weimer <fweimer@redhat.com>
5f7b84
Date:   Mon Jan 21 21:26:03 2019 +0100
5f7b84
5f7b84
    CVE-2016-10739: getaddrinfo: Fully parse IPv4 address strings [BZ #20018]
5f7b84
    
5f7b84
    The IPv4 address parser in the getaddrinfo function is changed so that
5f7b84
    it does not ignore trailing whitespace and all characters after it.
5f7b84
    For backwards compatibility, the getaddrinfo function still recognizes
5f7b84
    legacy name syntax, such as 192.000.002.010 interpreted as 192.0.2.8
5f7b84
    (octal).
5f7b84
    
5f7b84
    This commit does not change the behavior of inet_addr and inet_aton.
5f7b84
    gethostbyname already had additional sanity checks (but is switched
5f7b84
    over to the new __inet_aton_exact function for completeness as well).
5f7b84
    
5f7b84
    To avoid sending the problematic query names over DNS, commit
5f7b84
    6ca53a2453598804a2559a548a08424fca96434a ("resolv: Do not send queries
5f7b84
    for non-host-names in nss_dns [BZ #24112]") is needed.
5f7b84
5f7b84
diff --git a/include/arpa/inet.h b/include/arpa/inet.h
5f7b84
index c3f28f2baaa2ed66..19aec74275069a45 100644
5f7b84
--- a/include/arpa/inet.h
5f7b84
+++ b/include/arpa/inet.h
5f7b84
@@ -1,10 +1,10 @@
5f7b84
 #include <inet/arpa/inet.h>
5f7b84
 
5f7b84
 #ifndef _ISOMAC
5f7b84
-extern int __inet_aton (const char *__cp, struct in_addr *__inp);
5f7b84
-libc_hidden_proto (__inet_aton)
5f7b84
+/* Variant of inet_aton which rejects trailing garbage.  */
5f7b84
+extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp);
5f7b84
+libc_hidden_proto (__inet_aton_exact)
5f7b84
 
5f7b84
-libc_hidden_proto (inet_aton)
5f7b84
 libc_hidden_proto (inet_ntop)
5f7b84
 libc_hidden_proto (inet_pton)
5f7b84
 extern __typeof (inet_pton) __inet_pton;
5f7b84
diff --git a/nscd/gai.c b/nscd/gai.c
5f7b84
index 24bdfee1db3791e2..f57f396f574a6e52 100644
5f7b84
--- a/nscd/gai.c
5f7b84
+++ b/nscd/gai.c
5f7b84
@@ -19,7 +19,6 @@
5f7b84
 
5f7b84
 /* This file uses the getaddrinfo code but it compiles it without NSCD
5f7b84
    support.  We just need a few symbol renames.  */
5f7b84
-#define __inet_aton inet_aton
5f7b84
 #define __ioctl ioctl
5f7b84
 #define __getsockname getsockname
5f7b84
 #define __socket socket
5f7b84
diff --git a/nscd/gethstbynm3_r.c b/nscd/gethstbynm3_r.c
5f7b84
index 7beb9dce9f4b350c..f792c4fcd042d13d 100644
5f7b84
--- a/nscd/gethstbynm3_r.c
5f7b84
+++ b/nscd/gethstbynm3_r.c
5f7b84
@@ -38,8 +38,6 @@
5f7b84
 #define HAVE_LOOKUP_BUFFER	1
5f7b84
 #define HAVE_AF			1
5f7b84
 
5f7b84
-#define __inet_aton inet_aton
5f7b84
-
5f7b84
 /* We are nscd, so we don't want to be talking to ourselves.  */
5f7b84
 #undef	USE_NSCD
5f7b84
 
5f7b84
diff --git a/nss/digits_dots.c b/nss/digits_dots.c
5f7b84
index 39bff38865a1ac5b..5441bce16ea8b2e9 100644
5f7b84
--- a/nss/digits_dots.c
5f7b84
+++ b/nss/digits_dots.c
5f7b84
@@ -29,7 +29,6 @@
5f7b84
 #include "nsswitch.h"
5f7b84
 
5f7b84
 #ifdef USE_NSCD
5f7b84
-# define inet_aton __inet_aton
5f7b84
 # include <nscd/nscd_proto.h>
5f7b84
 #endif
5f7b84
 
5f7b84
@@ -160,7 +159,7 @@ __nss_hostname_digits_dots_context (struct resolv_context *ctx,
5f7b84
 		     255.255.255.255?  The test below will succeed
5f7b84
 		     spuriously... ???  */
5f7b84
 		  if (af == AF_INET)
5f7b84
-		    ok = __inet_aton (name, (struct in_addr *) host_addr);
5f7b84
+		    ok = __inet_aton_exact (name, (struct in_addr *) host_addr);
5f7b84
 		  else
5f7b84
 		    {
5f7b84
 		      assert (af == AF_INET6);
5f7b84
diff --git a/resolv/Makefile b/resolv/Makefile
5f7b84
index 56718654eeab85a3..72a0f196506ac489 100644
5f7b84
--- a/resolv/Makefile
5f7b84
+++ b/resolv/Makefile
5f7b84
@@ -34,6 +34,9 @@ routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
5f7b84
 tests = tst-aton tst-leaks tst-inet_ntop
5f7b84
 xtests = tst-leaks2
5f7b84
 
5f7b84
+tests-internal += tst-inet_aton_exact
5f7b84
+
5f7b84
+
5f7b84
 generate := mtrace-tst-leaks.out tst-leaks.mtrace tst-leaks2.mtrace
5f7b84
 
5f7b84
 extra-libs := libresolv libnss_dns
5f7b84
@@ -54,8 +57,10 @@ tests += \
5f7b84
   tst-resolv-binary \
5f7b84
   tst-resolv-edns \
5f7b84
   tst-resolv-network \
5f7b84
+  tst-resolv-nondecimal \
5f7b84
   tst-resolv-res_init-multi \
5f7b84
   tst-resolv-search \
5f7b84
+  tst-resolv-trailing \
5f7b84
 
5f7b84
 # These tests need libdl.
5f7b84
 ifeq (yes,$(build-shared))
5f7b84
@@ -190,9 +195,11 @@ $(objpfx)tst-resolv-res_init-multi: $(objpfx)libresolv.so \
5f7b84
   $(shared-thread-library)
5f7b84
 $(objpfx)tst-resolv-res_init-thread: $(libdl) $(objpfx)libresolv.so \
5f7b84
   $(shared-thread-library)
5f7b84
+$(objpfx)tst-resolv-nondecimal: $(objpfx)libresolv.so $(shared-thread-library)
5f7b84
 $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library)
5f7b84
 $(objpfx)tst-resolv-rotate: $(objpfx)libresolv.so $(shared-thread-library)
5f7b84
 $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library)
5f7b84
+$(objpfx)tst-resolv-trailing: $(objpfx)libresolv.so $(shared-thread-library)
5f7b84
 $(objpfx)tst-resolv-threads: \
5f7b84
   $(libdl) $(objpfx)libresolv.so $(shared-thread-library)
5f7b84
 $(objpfx)tst-resolv-canonname: \
5f7b84
diff --git a/resolv/Versions b/resolv/Versions
5f7b84
index b05778d9654aa0f2..9a82704af75f789b 100644
5f7b84
--- a/resolv/Versions
5f7b84
+++ b/resolv/Versions
5f7b84
@@ -27,6 +27,7 @@ libc {
5f7b84
     __h_errno; __resp;
5f7b84
 
5f7b84
     __res_iclose;
5f7b84
+    __inet_aton_exact;
5f7b84
     __inet_pton_length;
5f7b84
     __resolv_context_get;
5f7b84
     __resolv_context_get_preinit;
5f7b84
diff --git a/resolv/inet_addr.c b/resolv/inet_addr.c
5f7b84
index 32f58b0e13598b32..41b6166a5bd5a44b 100644
5f7b84
--- a/resolv/inet_addr.c
5f7b84
+++ b/resolv/inet_addr.c
5f7b84
@@ -96,26 +96,14 @@
5f7b84
 #include <limits.h>
5f7b84
 #include <errno.h>
5f7b84
 
5f7b84
-/* ASCII IPv4 Internet address interpretation routine.  The value
5f7b84
-   returned is in network order.  */
5f7b84
-in_addr_t
5f7b84
-__inet_addr (const char *cp)
5f7b84
-{
5f7b84
-  struct in_addr val;
5f7b84
-
5f7b84
-  if (__inet_aton (cp, &val))
5f7b84
-    return val.s_addr;
5f7b84
-  return INADDR_NONE;
5f7b84
-}
5f7b84
-weak_alias (__inet_addr, inet_addr)
5f7b84
-
5f7b84
 /* Check whether "cp" is a valid ASCII representation of an IPv4
5f7b84
    Internet address and convert it to a binary address.  Returns 1 if
5f7b84
    the address is valid, 0 if not.  This replaces inet_addr, the
5f7b84
    return value from which cannot distinguish between failure and a
5f7b84
-   local broadcast address.  */
5f7b84
-int
5f7b84
-__inet_aton (const char *cp, struct in_addr *addr)
5f7b84
+   local broadcast address.  Write a pointer to the first
5f7b84
+   non-converted character to *endp.  */
5f7b84
+static int
5f7b84
+inet_aton_end (const char *cp, struct in_addr *addr, const char **endp)
5f7b84
 {
5f7b84
   static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };
5f7b84
   in_addr_t val;
5f7b84
@@ -180,6 +168,7 @@ __inet_aton (const char *cp, struct in_addr *addr)
5f7b84
 
5f7b84
   if (addr != NULL)
5f7b84
     addr->s_addr = res.word | htonl (val);
5f7b84
+  *endp = cp;
5f7b84
 
5f7b84
   __set_errno (saved_errno);
5f7b84
   return 1;
5f7b84
@@ -188,6 +177,41 @@ __inet_aton (const char *cp, struct in_addr *addr)
5f7b84
   __set_errno (saved_errno);
5f7b84
   return 0;
5f7b84
 }
5f7b84
-weak_alias (__inet_aton, inet_aton)
5f7b84
-libc_hidden_def (__inet_aton)
5f7b84
-libc_hidden_weak (inet_aton)
5f7b84
+
5f7b84
+int
5f7b84
+__inet_aton_exact (const char *cp, struct in_addr *addr)
5f7b84
+{
5f7b84
+  struct in_addr val;
5f7b84
+  const char *endp;
5f7b84
+  /* Check that inet_aton_end parsed the entire string.  */
5f7b84
+  if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0)
5f7b84
+    {
5f7b84
+      *addr = val;
5f7b84
+      return 1;
5f7b84
+    }
5f7b84
+  else
5f7b84
+    return 0;
5f7b84
+}
5f7b84
+libc_hidden_def (__inet_aton_exact)
5f7b84
+
5f7b84
+/* inet_aton ignores trailing garbage.  */
5f7b84
+int
5f7b84
+__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr)
5f7b84
+{
5f7b84
+  const char *endp;
5f7b84
+  return  inet_aton_end (cp, addr, &endp);
5f7b84
+}
5f7b84
+weak_alias (__inet_aton_ignore_trailing, inet_aton)
5f7b84
+
5f7b84
+/* ASCII IPv4 Internet address interpretation routine.  The value
5f7b84
+   returned is in network order.  */
5f7b84
+in_addr_t
5f7b84
+__inet_addr (const char *cp)
5f7b84
+{
5f7b84
+  struct in_addr val;
5f7b84
+  const char *endp;
5f7b84
+  if (inet_aton_end (cp, &val, &endp))
5f7b84
+    return val.s_addr;
5f7b84
+  return INADDR_NONE;
5f7b84
+}
5f7b84
+weak_alias (__inet_addr, inet_addr)
5f7b84
diff --git a/resolv/res_init.c b/resolv/res_init.c
5f7b84
index f5e52cbbb9377762..94743a252e39d64a 100644
5f7b84
--- a/resolv/res_init.c
5f7b84
+++ b/resolv/res_init.c
5f7b84
@@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
5f7b84
               cp = parser->buffer + sizeof ("nameserver") - 1;
5f7b84
               while (*cp == ' ' || *cp == '\t')
5f7b84
                 cp++;
5f7b84
+
5f7b84
+              /* Ignore trailing contents on the name server line.  */
5f7b84
+              {
5f7b84
+                char *el;
5f7b84
+                if ((el = strpbrk (cp, " \t\n")) != NULL)
5f7b84
+                  *el = '\0';
5f7b84
+              }
5f7b84
+
5f7b84
               struct sockaddr *sa;
5f7b84
-              if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
5f7b84
+              if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a))
5f7b84
                 {
5f7b84
                   sa = allocate_address_v4 (a, NAMESERVER_PORT);
5f7b84
                   if (sa == NULL)
5f7b84
@@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
5f7b84
                 {
5f7b84
                   struct in6_addr a6;
5f7b84
                   char *el;
5f7b84
-
5f7b84
-                  if ((el = strpbrk (cp, " \t\n")) != NULL)
5f7b84
-                    *el = '\0';
5f7b84
                   if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL)
5f7b84
                     *el = '\0';
5f7b84
                   if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0))
5f7b84
@@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
5f7b84
                   char separator = *cp;
5f7b84
                   *cp = 0;
5f7b84
                   struct resolv_sortlist_entry e;
5f7b84
-                  if (__inet_aton (net, &a))
5f7b84
+                  if (__inet_aton_exact (net, &a))
5f7b84
                     {
5f7b84
                       e.addr = a;
5f7b84
                       if (is_sort_mask (separator))
5f7b84
@@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_conf_parser *parser)
5f7b84
                             cp++;
5f7b84
                           separator = *cp;
5f7b84
                           *cp = 0;
5f7b84
-                          if (__inet_aton (net, &a))
5f7b84
+                          if (__inet_aton_exact (net, &a))
5f7b84
                             e.mask = a.s_addr;
5f7b84
                           else
5f7b84
                             e.mask = net_mask (e.addr);
5f7b84
diff --git a/resolv/tst-aton.c b/resolv/tst-aton.c
5f7b84
index 08110a007af909ff..eb734d7758d6ed87 100644
5f7b84
--- a/resolv/tst-aton.c
5f7b84
+++ b/resolv/tst-aton.c
5f7b84
@@ -1,11 +1,29 @@
5f7b84
+/* Test legacy IPv4 text-to-address function inet_aton.
5f7b84
+   Copyright (C) 1998-2019 Free Software Foundation, Inc.
5f7b84
+   This file is part of the GNU C Library.
5f7b84
+
5f7b84
+   The GNU C Library is free software; you can redistribute it and/or
5f7b84
+   modify it under the terms of the GNU Lesser General Public
5f7b84
+   License as published by the Free Software Foundation; either
5f7b84
+   version 2.1 of the License, or (at your option) any later version.
5f7b84
+
5f7b84
+   The GNU C Library is distributed in the hope that it will be useful,
5f7b84
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
5f7b84
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
5f7b84
+   Lesser General Public License for more details.
5f7b84
+
5f7b84
+   You should have received a copy of the GNU Lesser General Public
5f7b84
+   License along with the GNU C Library; if not, see
5f7b84
+   <http://www.gnu.org/licenses/>.  */
5f7b84
+
5f7b84
+#include <array_length.h>
5f7b84
 #include <stdio.h>
5f7b84
 #include <stdint.h>
5f7b84
 #include <sys/socket.h>
5f7b84
 #include <netinet/in.h>
5f7b84
 #include <arpa/inet.h>
5f7b84
 
5f7b84
-
5f7b84
-static struct tests
5f7b84
+static const struct tests
5f7b84
 {
5f7b84
   const char *input;
5f7b84
   int valid;
5f7b84
@@ -16,6 +34,7 @@ static struct tests
5f7b84
   { "-1", 0, 0 },
5f7b84
   { "256", 1, 0x00000100 },
5f7b84
   { "256.", 0, 0 },
5f7b84
+  { "255a", 0, 0 },
5f7b84
   { "256a", 0, 0 },
5f7b84
   { "0x100", 1, 0x00000100 },
5f7b84
   { "0200.0x123456", 1, 0x80123456 },
5f7b84
@@ -40,7 +59,12 @@ static struct tests
5f7b84
   { "1.2.256.4", 0, 0 },
5f7b84
   { "1.2.3.0x100", 0, 0 },
5f7b84
   { "323543357756889", 0, 0 },
5f7b84
-  { "10.1.2.3.4", 0, 0},
5f7b84
+  { "10.1.2.3.4", 0, 0 },
5f7b84
+  { "192.0.2.1", 1, 0xc0000201 },
5f7b84
+  { "192.0.2.2\nX", 1, 0xc0000202 },
5f7b84
+  { "192.0.2.3 Y", 1, 0xc0000203 },
5f7b84
+  { "192.0.2.3Z", 0, 0 },
5f7b84
+  { "192.000.002.010", 1, 0xc0000208 },
5f7b84
 };
5f7b84
 
5f7b84
 
5f7b84
@@ -50,7 +74,7 @@ do_test (void)
5f7b84
   int result = 0;
5f7b84
   size_t cnt;
5f7b84
 
5f7b84
-  for (cnt = 0; cnt < sizeof (tests) / sizeof (tests[0]); ++cnt)
5f7b84
+  for (cnt = 0; cnt < array_length (tests); ++cnt)
5f7b84
     {
5f7b84
       struct in_addr addr;
5f7b84
 
5f7b84
@@ -73,5 +97,4 @@ do_test (void)
5f7b84
   return result;
5f7b84
 }
5f7b84
 
5f7b84
-#define TEST_FUNCTION do_test ()
5f7b84
-#include "../test-skeleton.c"
5f7b84
+#include <support/test-driver.c>
5f7b84
diff --git a/resolv/tst-inet_aton_exact.c b/resolv/tst-inet_aton_exact.c
5f7b84
new file mode 100644
5f7b84
index 0000000000000000..0fdfa3d6aa9aef91
5f7b84
--- /dev/null
5f7b84
+++ b/resolv/tst-inet_aton_exact.c
5f7b84
@@ -0,0 +1,47 @@
5f7b84
+/* Test internal legacy IPv4 text-to-address function __inet_aton_exact.
5f7b84
+   Copyright (C) 2019 Free Software Foundation, Inc.
5f7b84
+   This file is part of the GNU C Library.
5f7b84
+
5f7b84
+   The GNU C Library is free software; you can redistribute it and/or
5f7b84
+   modify it under the terms of the GNU Lesser General Public
5f7b84
+   License as published by the Free Software Foundation; either
5f7b84
+   version 2.1 of the License, or (at your option) any later version.
5f7b84
+
5f7b84
+   The GNU C Library is distributed in the hope that it will be useful,
5f7b84
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
5f7b84
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
5f7b84
+   Lesser General Public License for more details.
5f7b84
+
5f7b84
+   You should have received a copy of the GNU Lesser General Public
5f7b84
+   License along with the GNU C Library; if not, see
5f7b84
+   <http://www.gnu.org/licenses/>.  */
5f7b84
+
5f7b84
+#include <arpa/inet.h>
5f7b84
+#include <support/check.h>
5f7b84
+
5f7b84
+static int
5f7b84
+do_test (void)
5f7b84
+{
5f7b84
+  struct in_addr addr = { };
5f7b84
+
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.1", &addr), 1);
5f7b84
+  TEST_COMPARE (ntohl (addr.s_addr), 0xC0000201);
5f7b84
+
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.000.002.010", &addr), 1);
5f7b84
+  TEST_COMPARE (ntohl (addr.s_addr), 0xC0000208);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("0xC0000234", &addr), 1);
5f7b84
+  TEST_COMPARE (ntohl (addr.s_addr), 0xC0000234);
5f7b84
+
5f7b84
+  /* Trailing content is not accepted.  */
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.2X", &addr), 0);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.3 Y", &addr), 0);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.4\nZ", &addr), 0);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.5\tT", &addr), 0);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.6 Y", &addr), 0);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.7\n", &addr), 0);
5f7b84
+  TEST_COMPARE (__inet_aton_exact ("192.0.2.8\t", &addr), 0);
5f7b84
+
5f7b84
+  return 0;
5f7b84
+}
5f7b84
+
5f7b84
+#include <support/test-driver.c>
5f7b84
diff --git a/resolv/tst-resolv-nondecimal.c b/resolv/tst-resolv-nondecimal.c
5f7b84
new file mode 100644
5f7b84
index 0000000000000000..a0df6f332ae8faf7
5f7b84
--- /dev/null
5f7b84
+++ b/resolv/tst-resolv-nondecimal.c
5f7b84
@@ -0,0 +1,139 @@
5f7b84
+/* Test name resolution behavior for octal, hexadecimal IPv4 addresses.
5f7b84
+   Copyright (C) 2019 Free Software Foundation, Inc.
5f7b84
+   This file is part of the GNU C Library.
5f7b84
+
5f7b84
+   The GNU C Library is free software; you can redistribute it and/or
5f7b84
+   modify it under the terms of the GNU Lesser General Public
5f7b84
+   License as published by the Free Software Foundation; either
5f7b84
+   version 2.1 of the License, or (at your option) any later version.
5f7b84
+
5f7b84
+   The GNU C Library is distributed in the hope that it will be useful,
5f7b84
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
5f7b84
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
5f7b84
+   Lesser General Public License for more details.
5f7b84
+
5f7b84
+   You should have received a copy of the GNU Lesser General Public
5f7b84
+   License along with the GNU C Library; if not, see
5f7b84
+   <http://www.gnu.org/licenses/>.  */
5f7b84
+
5f7b84
+#include <netdb.h>
5f7b84
+#include <stdlib.h>
5f7b84
+#include <support/check.h>
5f7b84
+#include <support/check_nss.h>
5f7b84
+#include <support/resolv_test.h>
5f7b84
+#include <support/support.h>
5f7b84
+
5f7b84
+static void
5f7b84
+response (const struct resolv_response_context *ctx,
5f7b84
+          struct resolv_response_builder *b,
5f7b84
+          const char *qname, uint16_t qclass, uint16_t qtype)
5f7b84
+{
5f7b84
+  /* The tests are not supposed send any DNS queries.  */
5f7b84
+  FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype);
5f7b84
+}
5f7b84
+
5f7b84
+static void
5f7b84
+run_query_addrinfo (const char *query, const char *address)
5f7b84
+{
5f7b84
+  char *quoted_query = support_quote_string (query);
5f7b84
+
5f7b84
+  struct addrinfo *ai;
5f7b84
+  struct addrinfo hints =
5f7b84
+    {
5f7b84
+     .ai_socktype = SOCK_STREAM,
5f7b84
+     .ai_protocol = IPPROTO_TCP,
5f7b84
+    };
5f7b84
+
5f7b84
+  char *context = xasprintf ("getaddrinfo \"%s\" AF_INET", quoted_query);
5f7b84
+  char *expected = xasprintf ("address: STREAM/TCP %s 80\n", address);
5f7b84
+  hints.ai_family = AF_INET;
5f7b84
+  int ret = getaddrinfo (query, "80", &hints, &ai;;
5f7b84
+  check_addrinfo (context, ai, ret, expected);
5f7b84
+  if (ret == 0)
5f7b84
+    freeaddrinfo (ai);
5f7b84
+  free (context);
5f7b84
+
5f7b84
+  context = xasprintf ("getaddrinfo \"%s\" AF_UNSPEC", quoted_query);
5f7b84
+  hints.ai_family = AF_UNSPEC;
5f7b84
+  ret = getaddrinfo (query, "80", &hints, &ai;;
5f7b84
+  check_addrinfo (context, ai, ret, expected);
5f7b84
+  if (ret == 0)
5f7b84
+    freeaddrinfo (ai);
5f7b84
+  free (expected);
5f7b84
+  free (context);
5f7b84
+
5f7b84
+  context = xasprintf ("getaddrinfo \"%s\" AF_INET6", quoted_query);
5f7b84
+  expected = xasprintf ("flags: AI_V4MAPPED\n"
5f7b84
+                        "address: STREAM/TCP ::ffff:%s 80\n",
5f7b84
+                        address);
5f7b84
+  hints.ai_family = AF_INET6;
5f7b84
+  hints.ai_flags = AI_V4MAPPED;
5f7b84
+  ret = getaddrinfo (query, "80", &hints, &ai;;
5f7b84
+  check_addrinfo (context, ai, ret, expected);
5f7b84
+  if (ret == 0)
5f7b84
+    freeaddrinfo (ai);
5f7b84
+  free (expected);
5f7b84
+  free (context);
5f7b84
+
5f7b84
+  free (quoted_query);
5f7b84
+}
5f7b84
+
5f7b84
+static void
5f7b84
+run_query (const char *query, const char *address)
5f7b84
+{
5f7b84
+  char *quoted_query = support_quote_string (query);
5f7b84
+  char *context = xasprintf ("gethostbyname (\"%s\")", quoted_query);
5f7b84
+  char *expected = xasprintf ("name: %s\n"
5f7b84
+                              "address: %s\n", query, address);
5f7b84
+  check_hostent (context, gethostbyname (query), expected);
5f7b84
+  free (context);
5f7b84
+
5f7b84
+  context = xasprintf ("gethostbyname_r \"%s\"", quoted_query);
5f7b84
+  struct hostent storage;
5f7b84
+  char buf[4096];
5f7b84
+  struct hostent *e = NULL;
5f7b84
+  TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf),
5f7b84
+                                 &e, &h_errno), 0);
5f7b84
+  check_hostent (context, e, expected);
5f7b84
+  free (context);
5f7b84
+
5f7b84
+  context = xasprintf ("gethostbyname2 (\"%s\", AF_INET)", quoted_query);
5f7b84
+  check_hostent (context, gethostbyname2 (query, AF_INET), expected);
5f7b84
+  free (context);
5f7b84
+
5f7b84
+  context = xasprintf ("gethostbyname2_r \"%s\" AF_INET", quoted_query);
5f7b84
+  e = NULL;
5f7b84
+  TEST_COMPARE (gethostbyname2_r (query, AF_INET, &storage, buf, sizeof (buf),
5f7b84
+                                  &e, &h_errno), 0);
5f7b84
+  check_hostent (context, e, expected);
5f7b84
+  free (context);
5f7b84
+  free (expected);
5f7b84
+
5f7b84
+  free (quoted_query);
5f7b84
+
5f7b84
+  /* The gethostbyname tests are always valid for getaddrinfo, but not
5f7b84
+     vice versa.  */
5f7b84
+  run_query_addrinfo (query, address);
5f7b84
+}
5f7b84
+
5f7b84
+static int
5f7b84
+do_test (void)
5f7b84
+{
5f7b84
+  struct resolv_test *aux = resolv_test_start
5f7b84
+    ((struct resolv_redirect_config)
5f7b84
+     {
5f7b84
+       .response_callback = response,
5f7b84
+     });
5f7b84
+
5f7b84
+  run_query ("192.000.002.010", "192.0.2.8");
5f7b84
+
5f7b84
+  /* Hexadecimal numbers are not accepted by gethostbyname.  */
5f7b84
+  run_query_addrinfo ("0xc0000210", "192.0.2.16");
5f7b84
+  run_query_addrinfo ("192.0x234", "192.0.2.52");
5f7b84
+
5f7b84
+  resolv_test_end (aux);
5f7b84
+
5f7b84
+  return 0;
5f7b84
+}
5f7b84
+
5f7b84
+#include <support/test-driver.c>
5f7b84
diff --git a/resolv/tst-resolv-trailing.c b/resolv/tst-resolv-trailing.c
5f7b84
new file mode 100644
5f7b84
index 0000000000000000..7504bdae572ed8d0
5f7b84
--- /dev/null
5f7b84
+++ b/resolv/tst-resolv-trailing.c
5f7b84
@@ -0,0 +1,136 @@
5f7b84
+/* Test name resolution behavior with trailing characters.
5f7b84
+   Copyright (C) 2019 Free Software Foundation, Inc.
5f7b84
+   This file is part of the GNU C Library.
5f7b84
+
5f7b84
+   The GNU C Library is free software; you can redistribute it and/or
5f7b84
+   modify it under the terms of the GNU Lesser General Public
5f7b84
+   License as published by the Free Software Foundation; either
5f7b84
+   version 2.1 of the License, or (at your option) any later version.
5f7b84
+
5f7b84
+   The GNU C Library is distributed in the hope that it will be useful,
5f7b84
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
5f7b84
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
5f7b84
+   Lesser General Public License for more details.
5f7b84
+
5f7b84
+   You should have received a copy of the GNU Lesser General Public
5f7b84
+   License along with the GNU C Library; if not, see
5f7b84
+   <http://www.gnu.org/licenses/>.  */
5f7b84
+
5f7b84
+#include <array_length.h>
5f7b84
+#include <netdb.h>
5f7b84
+#include <support/check.h>
5f7b84
+#include <support/check_nss.h>
5f7b84
+#include <support/resolv_test.h>
5f7b84
+#include <support/support.h>
5f7b84
+
5f7b84
+static void
5f7b84
+response (const struct resolv_response_context *ctx,
5f7b84
+          struct resolv_response_builder *b,
5f7b84
+          const char *qname, uint16_t qclass, uint16_t qtype)
5f7b84
+{
5f7b84
+  /* The tests are not supposed send any DNS queries.  */
5f7b84
+  FAIL_EXIT1 ("unexpected DNS query for %s/%d/%d", qname, qclass, qtype);
5f7b84
+}
5f7b84
+
5f7b84
+static int
5f7b84
+do_test (void)
5f7b84
+{
5f7b84
+  struct resolv_test *aux = resolv_test_start
5f7b84
+    ((struct resolv_redirect_config)
5f7b84
+     {
5f7b84
+       .response_callback = response,
5f7b84
+     });
5f7b84
+
5f7b84
+  static const char *const queries[] =
5f7b84
+    {
5f7b84
+     "192.0.2.1 ",
5f7b84
+     "192.0.2.2\t",
5f7b84
+     "192.0.2.3\n",
5f7b84
+     "192.0.2.4 X",
5f7b84
+     "192.0.2.5\tY",
5f7b84
+     "192.0.2.6\nZ",
5f7b84
+     "192.0.2. ",
5f7b84
+     "192.0.2.\t",
5f7b84
+     "192.0.2.\n",
5f7b84
+     "192.0.2. X",
5f7b84
+     "192.0.2.\tY",
5f7b84
+     "192.0.2.\nZ",
5f7b84
+     "2001:db8::1 ",
5f7b84
+     "2001:db8::2\t",
5f7b84
+     "2001:db8::3\n",
5f7b84
+     "2001:db8::4 X",
5f7b84
+     "2001:db8::5\tY",
5f7b84
+     "2001:db8::6\nZ",
5f7b84
+    };
5f7b84
+  for (size_t query_idx = 0; query_idx < array_length (queries); ++query_idx)
5f7b84
+    {
5f7b84
+      const char *query = queries[query_idx];
5f7b84
+      struct hostent storage;
5f7b84
+      char buf[4096];
5f7b84
+      struct hostent *e;
5f7b84
+
5f7b84
+      h_errno = 0;
5f7b84
+      TEST_VERIFY (gethostbyname (query) == NULL);
5f7b84
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
5f7b84
+
5f7b84
+      h_errno = 0;
5f7b84
+      e = NULL;
5f7b84
+      TEST_COMPARE (gethostbyname_r (query, &storage, buf, sizeof (buf),
5f7b84
+                                     &e, &h_errno), 0);
5f7b84
+      TEST_VERIFY (e == NULL);
5f7b84
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
5f7b84
+
5f7b84
+      h_errno = 0;
5f7b84
+      TEST_VERIFY (gethostbyname2 (query, AF_INET) == NULL);
5f7b84
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
5f7b84
+
5f7b84
+      h_errno = 0;
5f7b84
+      e = NULL;
5f7b84
+      TEST_COMPARE (gethostbyname2_r (query, AF_INET,
5f7b84
+                                      &storage, buf, sizeof (buf),
5f7b84
+                                     &e, &h_errno), 0);
5f7b84
+      TEST_VERIFY (e == NULL);
5f7b84
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
5f7b84
+
5f7b84
+      h_errno = 0;
5f7b84
+      TEST_VERIFY (gethostbyname2 (query, AF_INET6) == NULL);
5f7b84
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
5f7b84
+
5f7b84
+      h_errno = 0;
5f7b84
+      e = NULL;
5f7b84
+      TEST_COMPARE (gethostbyname2_r (query, AF_INET6,
5f7b84
+                                      &storage, buf, sizeof (buf),
5f7b84
+                                     &e, &h_errno), 0);
5f7b84
+      TEST_VERIFY (e == NULL);
5f7b84
+      TEST_COMPARE (h_errno, HOST_NOT_FOUND);
5f7b84
+
5f7b84
+      static const int gai_flags[] =
5f7b84
+        {
5f7b84
+         0,
5f7b84
+         AI_ADDRCONFIG,
5f7b84
+         AI_NUMERICHOST,
5f7b84
+         AI_IDN,
5f7b84
+         AI_IDN | AI_NUMERICHOST,
5f7b84
+         AI_V4MAPPED,
5f7b84
+         AI_V4MAPPED | AI_NUMERICHOST,
5f7b84
+        };
5f7b84
+      for (size_t gai_flags_idx; gai_flags_idx < array_length (gai_flags);
5f7b84
+             ++gai_flags_idx)
5f7b84
+        {
5f7b84
+          struct addrinfo hints = { .ai_flags = gai_flags[gai_flags_idx], };
5f7b84
+          struct addrinfo *ai;
5f7b84
+          hints.ai_family = AF_INET;
5f7b84
+          TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME);
5f7b84
+          hints.ai_family = AF_INET6;
5f7b84
+          TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME);
5f7b84
+          hints.ai_family = AF_UNSPEC;
5f7b84
+          TEST_COMPARE (getaddrinfo (query, "80", &hints, &ai), EAI_NONAME);
5f7b84
+        }
5f7b84
+    };
5f7b84
+
5f7b84
+  resolv_test_end (aux);
5f7b84
+
5f7b84
+  return 0;
5f7b84
+}
5f7b84
+
5f7b84
+#include <support/test-driver.c>
5f7b84
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
5f7b84
index 00e0d94a8f5bb30d..6a5805c9e63a257c 100644
5f7b84
--- a/sysdeps/posix/getaddrinfo.c
5f7b84
+++ b/sysdeps/posix/getaddrinfo.c
5f7b84
@@ -488,7 +488,7 @@ gaih_inet (const char *name, const struct gaih_service *service,
5f7b84
 	  malloc_name = true;
5f7b84
 	}
5f7b84
 
5f7b84
-      if (__inet_aton (name, (struct in_addr *) at->addr) != 0)
5f7b84
+      if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
5f7b84
 	{
5f7b84
 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
5f7b84
 	    at->family = AF_INET;