File getaddrinfo-parse-ipv4-address.patch of Package glibc.15121
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;