File getaddrinfo-parse-ipv4-address.patch of Package glibc.13450

2019-02-04  Florian Weimer  <fweimer@redhat.com>

	[BZ #20018]
	nscd: Do not rely on new GLIBC_PRIVATE ABI after CVE-2016-10739 fix.
	* nscd/nscd-inet_addr.c: New file.  Build resolv/inet_addr.c for
	nscd, without public symbols.
	* nscd/Makefile (nscd-modules): Add it.
	* nscd/gai.c: Include <arpa/inet.h> and change visibility of
	__inet_aton_exact.

2019-01-21  Florian Weimer  <fweimer@redhat.com>

	[BZ #20018]
	CVE-2016-10739
	resolv: Reject trailing characters in host names
	* include/arpa/inet.h (__inet_aton_exact): Declare.
	(inet_aton): Remove hidden prototype.  No longer used internally.
	* nscd/gai.c (__inet_aton): Do not define.
	* nscd/gethstbynm3_r.c (__inet_aton): Likewise.
	* nss/digits_dots.c (__inet_aton): Likewise.
	(__nss_hostname_digits_dots_context): Call __inet_aton_exact.
	* resolv/Versions (GLIBC_PRIVATE): Export __inet_aton_exact from
	libc.
	* resolv/inet_addr.c (inet_aton_end): Remame from __inet_aton.
	Make static.  Add endp parameter.
	(__inet_aton_exact): New function.
	(__inet_aton_ignore_trailing): New function, aliased to inet_aton.
	(__inet_addr): Call inet_aton_end.
	* resolv/res_init.c (res_vinit_1): Truncate nameserver for IPv4,
	not just IPv6.  Call __inet_aton_exact.
	* sysdeps/posix/getaddrinfo.c (gaih_inet): Call __inet_aton_exact.

2019-01-18  Florian Weimer  <fweimer@redhat.com>

	[BZ #24112]
	resolv: Do not send queries for non-host-names in nss_dns.
	* resolv/nss_dns/dns-host.c (check_name): New function.
	(_nss_dns_gethostbyname2_r): Use it.
	(_nss_dns_gethostbyname_r): Likewise.
	(_nss_dns_gethostbyname4_r): Likewise.

Index: glibc-2.26/include/arpa/inet.h
===================================================================
--- glibc-2.26.orig/include/arpa/inet.h
+++ glibc-2.26/include/arpa/inet.h
@@ -1,10 +1,10 @@
 #include <inet/arpa/inet.h>
 
 #ifndef _ISOMAC
-extern int __inet_aton (const char *__cp, struct in_addr *__inp);
-libc_hidden_proto (__inet_aton)
+/* Variant of inet_aton which rejects trailing garbage.  */
+extern int __inet_aton_exact (const char *__cp, struct in_addr *__inp);
+libc_hidden_proto (__inet_aton_exact)
 
-libc_hidden_proto (inet_aton)
 libc_hidden_proto (inet_ntop)
 libc_hidden_proto (inet_pton)
 extern __typeof (inet_pton) __inet_pton;
Index: glibc-2.26/nscd/Makefile
===================================================================
--- glibc-2.26.orig/nscd/Makefile
+++ glibc-2.26/nscd/Makefile
@@ -36,7 +36,7 @@ nscd-modules := nscd connections pwdcach
 		getsrvbynm_r getsrvbypt_r servicescache \
 		dbg_log nscd_conf nscd_stat cache mem nscd_setup_thread \
 		xmalloc xstrdup aicache initgrcache gai res_hconf \
-		netgroupcache nscd_hash
+		netgroupcache nscd_hash nscd-inet_addr
 
 ifeq ($(build-nscd)$(have-thread-library),yesyes)
 
Index: glibc-2.26/nscd/gai.c
===================================================================
--- glibc-2.26.orig/nscd/gai.c
+++ glibc-2.26/nscd/gai.c
@@ -19,7 +19,6 @@
 
 /* This file uses the getaddrinfo code but it compiles it without NSCD
    support.  We just need a few symbol renames.  */
-#define __inet_aton inet_aton
 #define __ioctl ioctl
 #define __getsockname getsockname
 #define __socket socket
@@ -32,6 +31,12 @@
 /* nscd uses 1MB or 2MB thread stacks.  */
 #define __libc_use_alloca(size) (size <= __MAX_ALLOCA_CUTOFF)
 
+/* We do not want to export __inet_aton_exact.  Get the prototype and
+   change its visibility to hidden.  */
+#include <arpa/inet.h>
+__typeof__ (__inet_aton_exact) __inet_aton_exact
+  __attribute__ ((visibility ("hidden")));
+
 /* We are nscd, so we don't want to be talking to ourselves.  */
 #undef  USE_NSCD
 
Index: glibc-2.26/nscd/gethstbynm3_r.c
===================================================================
--- glibc-2.26.orig/nscd/gethstbynm3_r.c
+++ glibc-2.26/nscd/gethstbynm3_r.c
@@ -38,8 +38,6 @@
 #define HAVE_LOOKUP_BUFFER	1
 #define HAVE_AF			1
 
-#define __inet_aton inet_aton
-
 /* We are nscd, so we don't want to be talking to ourselves.  */
 #undef	USE_NSCD
 
Index: glibc-2.26/nscd/nscd-inet_addr.c
===================================================================
--- /dev/null
+++ glibc-2.26/nscd/nscd-inet_addr.c
@@ -0,0 +1,32 @@
+/* Legacy IPv4 text-to-address functions.  Version for nscd.
+   Copyright (C) 2019 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <arpa/inet.h>
+
+/* We do not want to export __inet_aton_exact.  Get the prototype and
+   change the visibility to hidden.  */
+#include <arpa/inet.h>
+__typeof__ (__inet_aton_exact) __inet_aton_exact
+  __attribute__ ((visibility ("hidden")));
+
+/* Do not provide definitions of the public symbols exported from
+   libc.  */
+#undef weak_alias
+#define weak_alias(from, to)
+
+#include <resolv/inet_addr.c>
Index: glibc-2.26/nss/digits_dots.c
===================================================================
--- glibc-2.26.orig/nss/digits_dots.c
+++ glibc-2.26/nss/digits_dots.c
@@ -29,7 +29,6 @@
 #include "nsswitch.h"
 
 #ifdef USE_NSCD
-# define inet_aton __inet_aton
 # include <nscd/nscd_proto.h>
 #endif
 
@@ -160,7 +159,7 @@ __nss_hostname_digits_dots_context (stru
 		     255.255.255.255?  The test below will succeed
 		     spuriously... ???  */
 		  if (af == AF_INET)
-		    ok = __inet_aton (name, (struct in_addr *) host_addr);
+		    ok = __inet_aton_exact (name, (struct in_addr *) host_addr);
 		  else
 		    {
 		      assert (af == AF_INET6);
Index: glibc-2.26/resolv/Versions
===================================================================
--- glibc-2.26.orig/resolv/Versions
+++ glibc-2.26/resolv/Versions
@@ -27,6 +27,7 @@ libc {
     __h_errno; __resp;
 
     __res_iclose;
+    __inet_aton_exact;
     __inet_pton_length;
     __resolv_context_get;
     __resolv_context_get_preinit;
Index: glibc-2.26/resolv/inet_addr.c
===================================================================
--- glibc-2.26.orig/resolv/inet_addr.c
+++ glibc-2.26/resolv/inet_addr.c
@@ -79,28 +79,15 @@
 #include <errno.h>
 
 /*
- * Ascii internet address interpretation routine.
- * The value returned is in network order.
- */
-in_addr_t
-__inet_addr(const char *cp) {
-	struct in_addr val;
-
-	if (__inet_aton(cp, &val))
-		return (val.s_addr);
-	return (INADDR_NONE);
-}
-weak_alias (__inet_addr, inet_addr)
-
-/*
  * Check whether "cp" is a valid ascii representation
  * of an Internet address and convert to a binary address.
  * Returns 1 if the address is valid, 0 if not.
  * This replaces inet_addr, the return value from which
  * cannot distinguish between failure and a local broadcast address.
+ * Write a pointer to the first non-converted character to *endp.
  */
-int
-__inet_aton(const char *cp, struct in_addr *addr)
+static int
+inet_aton_end(const char *cp, struct in_addr *addr, const char **endp)
 {
 	static const in_addr_t max[4] = { 0xffffffff, 0xffffff, 0xffff, 0xff };
 	in_addr_t val;
@@ -170,6 +157,7 @@ __inet_aton(const char *cp, struct in_ad
 
 	if (addr != NULL)
 		addr->s_addr = res.word | htonl (val);
+	*endp = cp;
 
 	__set_errno (saved_errno);
 	return (1);
@@ -178,6 +166,41 @@ ret_0:
 	__set_errno (saved_errno);
 	return (0);
 }
-weak_alias (__inet_aton, inet_aton)
-libc_hidden_def (__inet_aton)
-libc_hidden_weak (inet_aton)
+
+int
+__inet_aton_exact (const char *cp, struct in_addr *addr)
+{
+  struct in_addr val;
+  const char *endp;
+  /* Check that inet_aton_end parsed the entire string.  */
+  if (inet_aton_end (cp, &val, &endp) != 0 && *endp == 0)
+    {
+      *addr = val;
+      return 1;
+    }
+  else
+    return 0;
+}
+libc_hidden_def (__inet_aton_exact)
+
+/* inet_aton ignores trailing garbage.  */
+int
+__inet_aton_ignore_trailing (const char *cp, struct in_addr *addr)
+{
+  const char *endp;
+  return  inet_aton_end (cp, addr, &endp);
+}
+weak_alias (__inet_aton_ignore_trailing, inet_aton)
+
+/* ASCII IPv4 Internet address interpretation routine.  The value
+   returned is in network order.  */
+in_addr_t
+__inet_addr (const char *cp)
+{
+  struct in_addr val;
+  const char *endp;
+  if (inet_aton_end (cp, &val, &endp))
+    return val.s_addr;
+  return INADDR_NONE;
+}
+weak_alias (__inet_addr, inet_addr)
Index: glibc-2.26/resolv/nss_dns/dns-host.c
===================================================================
--- glibc-2.26.orig/resolv/nss_dns/dns-host.c
+++ glibc-2.26/resolv/nss_dns/dns-host.c
@@ -273,11 +273,26 @@ gethostbyname3_context (struct resolv_co
   return status;
 }
 
+/* Verify that the name looks like a host name.  There is no point in
+   sending a query which will not produce a usable name in the
+   response.  */
+static enum nss_status
+check_name (const char *name, int *h_errnop)
+{
+  if (res_hnok (name))
+    return NSS_STATUS_SUCCESS;
+  *h_errnop = HOST_NOT_FOUND;
+  return NSS_STATUS_NOTFOUND;
+}
+
 enum nss_status
 _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
 			   char *buffer, size_t buflen, int *errnop,
 			   int *h_errnop)
 {
+  enum nss_status status = check_name (name, h_errnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
   return _nss_dns_gethostbyname3_r (name, af, result, buffer, buflen, errnop,
 				    h_errnop, NULL, NULL);
 }
@@ -288,6 +303,9 @@ _nss_dns_gethostbyname_r (const char *na
 			  char *buffer, size_t buflen, int *errnop,
 			  int *h_errnop)
 {
+  enum nss_status status = check_name (name, h_errnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
   struct resolv_context *ctx = __resolv_context_get ();
   if (ctx == NULL)
     {
@@ -295,7 +313,7 @@ _nss_dns_gethostbyname_r (const char *na
       *h_errnop = NETDB_INTERNAL;
       return NSS_STATUS_UNAVAIL;
     }
-  enum nss_status status = NSS_STATUS_NOTFOUND;
+  status = NSS_STATUS_NOTFOUND;
   if (res_use_inet6 ())
     status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
 				     buflen, errnop, h_errnop, NULL, NULL);
@@ -312,6 +330,9 @@ _nss_dns_gethostbyname4_r (const char *n
 			   char *buffer, size_t buflen, int *errnop,
 			   int *herrnop, int32_t *ttlp)
 {
+  enum nss_status status = check_name (name, herrnop);
+  if (status != NSS_STATUS_SUCCESS)
+    return status;
   struct resolv_context *ctx = __resolv_context_get ();
   if (ctx == NULL)
     {
@@ -346,7 +367,6 @@ _nss_dns_gethostbyname4_r (const char *n
   int ans2p_malloced = 0;
 
   int olderr = errno;
-  enum nss_status status;
   int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
 				host_buffer.buf->buf, 2048, &host_buffer.ptr,
 				&ans2p, &nans2p, &resplen2, &ans2p_malloced);
Index: glibc-2.26/resolv/res_init.c
===================================================================
--- glibc-2.26.orig/resolv/res_init.c
+++ glibc-2.26/resolv/res_init.c
@@ -399,8 +399,16 @@ res_vinit_1 (FILE *fp, struct resolv_con
               cp = parser->buffer + sizeof ("nameserver") - 1;
               while (*cp == ' ' || *cp == '\t')
                 cp++;
+
+              /* Ignore trailing contents on the name server line.  */
+              {
+                char *el;
+                if ((el = strpbrk (cp, " \t\n")) != NULL)
+                  *el = '\0';
+              }
+
               struct sockaddr *sa;
-              if ((*cp != '\0') && (*cp != '\n') && __inet_aton (cp, &a))
+              if ((*cp != '\0') && (*cp != '\n') && __inet_aton_exact (cp, &a))
                 {
                   sa = allocate_address_v4 (a, NAMESERVER_PORT);
                   if (sa == NULL)
@@ -410,9 +418,6 @@ res_vinit_1 (FILE *fp, struct resolv_con
                 {
                   struct in6_addr a6;
                   char *el;
-
-                  if ((el = strpbrk (cp, " \t\n")) != NULL)
-                    *el = '\0';
                   if ((el = strchr (cp, SCOPE_DELIMITER)) != NULL)
                     *el = '\0';
                   if ((*cp != '\0') && (__inet_pton (AF_INET6, cp, &a6) > 0))
@@ -472,7 +477,7 @@ res_vinit_1 (FILE *fp, struct resolv_con
                   char separator = *cp;
                   *cp = 0;
                   struct resolv_sortlist_entry e;
-                  if (__inet_aton (net, &a))
+                  if (__inet_aton_exact (net, &a))
                     {
                       e.addr = a;
                       if (is_sort_mask (separator))
@@ -484,7 +489,7 @@ res_vinit_1 (FILE *fp, struct resolv_con
                             cp++;
                           separator = *cp;
                           *cp = 0;
-                          if (__inet_aton (net, &a))
+                          if (__inet_aton_exact (net, &a))
                             e.mask = a.s_addr;
                           else
                             e.mask = net_mask (e.addr);
Index: glibc-2.26/resolv/tst-aton.c
===================================================================
--- glibc-2.26.orig/resolv/tst-aton.c
+++ glibc-2.26/resolv/tst-aton.c
@@ -16,6 +16,7 @@ static struct tests
   { "-1", 0, 0 },
   { "256", 1, 0x00000100 },
   { "256.", 0, 0 },
+  { "255a", 0, 0 },
   { "256a", 0, 0 },
   { "0x100", 1, 0x00000100 },
   { "0200.0x123456", 1, 0x80123456 },
@@ -40,7 +41,12 @@ static struct tests
   { "1.2.256.4", 0, 0 },
   { "1.2.3.0x100", 0, 0 },
   { "323543357756889", 0, 0 },
-  { "10.1.2.3.4", 0, 0},
+  { "10.1.2.3.4", 0, 0 },
+  { "192.0.2.1", 1, 0xc0000201 },
+  { "192.0.2.2\nX", 1, 0xc0000202 },
+  { "192.0.2.3 Y", 1, 0xc0000203 },
+  { "192.0.2.3Z", 0, 0 },
+  { "192.000.002.010", 1, 0xc0000208 },
 };
 
 
Index: glibc-2.26/sysdeps/posix/getaddrinfo.c
===================================================================
--- glibc-2.26.orig/sysdeps/posix/getaddrinfo.c
+++ glibc-2.26/sysdeps/posix/getaddrinfo.c
@@ -508,7 +508,7 @@ gaih_inet (const char *name, const struc
 	}
 #endif
 
-      if (__inet_aton (name, (struct in_addr *) at->addr) != 0)
+      if (__inet_aton_exact (name, (struct in_addr *) at->addr) != 0)
 	{
 	  if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET)
 	    at->family = AF_INET;
openSUSE Build Service is sponsored by