diff --git a/glibc-rh1333901-1.patch b/glibc-rh1333901-1.patch new file mode 100644 index 0000000..135c7d3 --- /dev/null +++ b/glibc-rh1333901-1.patch @@ -0,0 +1,54 @@ +commit 2b54cbce2c363ab6ae89d10657d7465858116d7a +Author: Florian Weimer +Date: Thu Apr 28 17:41:49 2016 +0200 + + getnameinfo: Do not preserve errno + + POSIX does not require it, the companion getaddrinfo implementation + does not do it, and this behavior is not documented in the manual + page, either. + +diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c +index 40f67f0..9b1847b 100644 +--- a/inet/getnameinfo.c ++++ b/inet/getnameinfo.c +@@ -175,7 +175,6 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + socklen_t hostlen, char *serv, socklen_t servlen, + int flags) + { +- int serrno = errno; + int herrno; + struct hostent th; + int ok = 0; +@@ -326,10 +325,7 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + if (!ok) + { + if (flags & NI_NAMEREQD) +- { +- __set_errno (serrno); +- return EAI_NONAME; +- } ++ return EAI_NONAME; + else + { + const char *c; +@@ -406,10 +402,7 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + }; + + if (flags & NI_NAMEREQD) +- { +- __set_errno (serrno); +- return EAI_NONAME; +- } ++ return EAI_NONAME; + + strncpy (host, "localhost", hostlen); + break; +@@ -463,7 +456,6 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + host[hostlen-1] = 0; + if (serv && (servlen > 0)) + serv[servlen-1] = 0; +- errno = serrno; + return 0; + } + libc_hidden_def (getnameinfo) diff --git a/glibc-rh1333901-2.patch b/glibc-rh1333901-2.patch new file mode 100644 index 0000000..c8b3548 --- /dev/null +++ b/glibc-rh1333901-2.patch @@ -0,0 +1,634 @@ +commit 2dce81a319601e1ee110f7316f705b48c5686e72 +Author: Florian Weimer +Date: Fri Apr 29 17:08:06 2016 +0200 + + getnameinfo: Refactor and fix memory leak [BZ #19642] + + Split getnameinfo into separate functions for host and service + lookups, and for different address families. + +diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c +index 9b1847b..ce05dda 100644 +--- a/inet/getnameinfo.c ++++ b/inet/getnameinfo.c +@@ -1,3 +1,21 @@ ++/* Convert socket address to string using Name Service Switch modules. ++ Copyright (C) 1997-2016 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 ++ . */ ++ + /* The Inner Net License, Version 2.00 + + The author(s) grant permission for redistribution and use in source and +@@ -169,19 +187,323 @@ nrl_domainname (void) + return domain; + }; + ++/* Convert host name, AF_INET/AF_INET6 case, name only. */ ++static int ++gni_host_inet_name (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *host, socklen_t hostlen, int flags) ++{ ++ int herrno; ++ struct hostent th; ++ struct hostent *h = NULL; ++ if (sa->sa_family == AF_INET6) ++ { ++ while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr), ++ sizeof(struct in6_addr), ++ AF_INET6, &th, ++ tmpbuf->data, tmpbuf->length, ++ &h, &herrno)) ++ if (herrno == NETDB_INTERNAL && errno == ERANGE) ++ { ++ if (!scratch_buffer_grow (tmpbuf)) ++ { ++ __set_h_errno (herrno); ++ return EAI_MEMORY; ++ } ++ } ++ else ++ break; ++ } ++ else ++ { ++ while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr), ++ sizeof(struct in_addr), ++ AF_INET, &th, ++ tmpbuf->data, tmpbuf->length, ++ &h, &herrno)) ++ if (herrno == NETDB_INTERNAL && errno == ERANGE) ++ { ++ if (!scratch_buffer_grow (tmpbuf)) ++ { ++ __set_h_errno (herrno); ++ return EAI_MEMORY; ++ } ++ } ++ else ++ break; ++ } ++ ++ if (h == NULL) ++ { ++ if (herrno == NETDB_INTERNAL) ++ { ++ __set_h_errno (herrno); ++ return EAI_SYSTEM; ++ } ++ if (herrno == TRY_AGAIN) ++ { ++ __set_h_errno (herrno); ++ return EAI_AGAIN; ++ } ++ } ++ ++ if (h) ++ { ++ char *c; ++ if ((flags & NI_NOFQDN) ++ && (c = nrl_domainname ()) ++ && (c = strstr (h->h_name, c)) ++ && (c != h->h_name) && (*(--c) == '.')) ++ /* Terminate the string after the prefix. */ ++ *c = '\0'; ++ ++#ifdef HAVE_LIBIDN ++ /* If requested, convert from the IDN format. */ ++ if (flags & NI_IDN) ++ { ++ int idn_flags = 0; ++ if (flags & NI_IDN_ALLOW_UNASSIGNED) ++ idn_flags |= IDNA_ALLOW_UNASSIGNED; ++ if (flags & NI_IDN_USE_STD3_ASCII_RULES) ++ idn_flags |= IDNA_USE_STD3_ASCII_RULES; ++ ++ char *out; ++ int rc = __idna_to_unicode_lzlz (h->h_name, &out, ++ idn_flags); ++ if (rc != IDNA_SUCCESS) ++ { ++ if (rc == IDNA_MALLOC_ERROR) ++ return EAI_MEMORY; ++ if (rc == IDNA_DLOPEN_ERROR) ++ return EAI_SYSTEM; ++ return EAI_IDN_ENCODE; ++ } ++ ++ if (out != h->h_name) ++ { ++ h->h_name = strdupa (out); ++ free (out); ++ } ++ } ++#endif ++ ++ size_t len = strlen (h->h_name) + 1; ++ if (len > hostlen) ++ return EAI_OVERFLOW; ++ ++ memcpy (host, h->h_name, len); ++ ++ return 0; ++ } ++ ++ return EAI_NONAME; ++} ++ ++/* Convert host name, AF_INET/AF_INET6 case, numeric conversion. */ ++static int ++gni_host_inet_numeric (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *host, socklen_t hostlen, int flags) ++{ ++ const char *c; ++ if (sa->sa_family == AF_INET6) ++ { ++ const struct sockaddr_in6 *sin6p; ++ uint32_t scopeid; ++ ++ sin6p = (const struct sockaddr_in6 *) sa; ++ ++ c = inet_ntop (AF_INET6, ++ (const void *) &sin6p->sin6_addr, host, hostlen); ++ scopeid = sin6p->sin6_scope_id; ++ if (scopeid != 0) ++ { ++ /* Buffer is >= IFNAMSIZ+1. */ ++ char scopebuf[IFNAMSIZ + 1]; ++ char *scopeptr; ++ int ni_numericscope = 0; ++ size_t real_hostlen = __strnlen (host, hostlen); ++ size_t scopelen = 0; ++ ++ scopebuf[0] = SCOPE_DELIMITER; ++ scopebuf[1] = '\0'; ++ scopeptr = &scopebuf[1]; ++ ++ if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr) ++ || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) ++ { ++ if (if_indextoname (scopeid, scopeptr) == NULL) ++ ++ni_numericscope; ++ else ++ scopelen = strlen (scopebuf); ++ } ++ else ++ ++ni_numericscope; ++ ++ if (ni_numericscope) ++ scopelen = 1 + __snprintf (scopeptr, ++ (scopebuf ++ + sizeof scopebuf ++ - scopeptr), ++ "%u", scopeid); ++ ++ if (real_hostlen + scopelen + 1 > hostlen) ++ /* Signal the buffer is too small. This is ++ what inet_ntop does. */ ++ c = NULL; ++ else ++ memcpy (host + real_hostlen, scopebuf, scopelen + 1); ++ } ++ } ++ else ++ c = inet_ntop (AF_INET, ++ (const void *) &(((const struct sockaddr_in *) sa)->sin_addr), ++ host, hostlen); ++ if (c == NULL) ++ return EAI_OVERFLOW; ++ return 0; ++} ++ ++static int ++gni_host_inet (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *host, socklen_t hostlen, int flags) ++{ ++ if (!(flags & NI_NUMERICHOST)) ++ { ++ int result = gni_host_inet_name ++ (tmpbuf, sa, addrlen, host, hostlen, flags); ++ if (result != EAI_NONAME) ++ return result; ++ } ++ ++ if (flags & NI_NAMEREQD) ++ return EAI_NONAME; ++ else ++ return gni_host_inet_numeric ++ (tmpbuf, sa, addrlen, host, hostlen, flags); ++} ++ ++static int ++gni_host_local (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *host, socklen_t hostlen, int flags) ++{ ++ ++ if (!(flags & NI_NUMERICHOST)) ++ { ++ struct utsname utsname; ++ ++ if (!uname (&utsname)) ++ { ++ strncpy (host, utsname.nodename, hostlen); ++ return 0; ++ } ++ } ++ ++ if (flags & NI_NAMEREQD) ++ return EAI_NONAME; ++ ++ strncpy (host, "localhost", hostlen); ++ return 0; ++} ++ ++static int ++gni_host (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *host, socklen_t hostlen, int flags) ++{ ++ switch (sa->sa_family) ++ { ++ case AF_INET: ++ case AF_INET6: ++ return gni_host_inet (tmpbuf, sa, addrlen, host, hostlen, flags); ++ ++ case AF_LOCAL: ++ return gni_host_local (tmpbuf, sa, addrlen, host, hostlen, flags); ++ ++ default: ++ return EAI_FAMILY; ++ } ++} ++ ++/* Convert service to string, AF_INET and AF_INET6 variant. */ ++static int ++gni_serv_inet (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *serv, socklen_t servlen, int flags) ++{ ++ _Static_assert ++ (offsetof (struct sockaddr_in, sin_port) ++ == offsetof (struct sockaddr_in6, sin6_port) ++ && sizeof (((struct sockaddr_in) {}).sin_port) == sizeof (in_port_t) ++ && sizeof (((struct sockaddr_in6) {}).sin6_port) == sizeof (in_port_t), ++ "AF_INET and AF_INET6 port consistency"); ++ if (!(flags & NI_NUMERICSERV)) ++ { ++ struct servent *s, ts; ++ int e; ++ while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port, ++ ((flags & NI_DGRAM) ++ ? "udp" : "tcp"), &ts, ++ tmpbuf->data, tmpbuf->length, &s))) ++ { ++ if (e == ERANGE) ++ { ++ if (!scratch_buffer_grow (tmpbuf)) ++ return EAI_MEMORY; ++ } ++ else ++ break; ++ } ++ if (s) ++ { ++ strncpy (serv, s->s_name, servlen); ++ return 0; ++ } ++ /* Fall through to numeric conversion. */ ++ } ++ if (__snprintf (serv, servlen, "%d", ++ ntohs (((const struct sockaddr_in *) sa)->sin_port)) ++ + 1 > servlen) ++ return EAI_OVERFLOW; ++ return 0; ++} ++ ++/* Convert service to string, AF_LOCAL variant. */ ++static int ++gni_serv_local (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *serv, socklen_t servlen, int flags) ++{ ++ strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen); ++ return 0; ++} ++ ++/* Convert service to string, dispatching to the implementations ++ above. */ ++static int ++gni_serv (struct scratch_buffer *tmpbuf, ++ const struct sockaddr *sa, socklen_t addrlen, ++ char *serv, socklen_t servlen, int flags) ++{ ++ switch (sa->sa_family) ++ { ++ case AF_INET: ++ case AF_INET6: ++ return gni_serv_inet (tmpbuf, sa, addrlen, serv, servlen, flags); ++ case AF_LOCAL: ++ return gni_serv_local (tmpbuf, sa, addrlen, serv, servlen, flags); ++ default: ++ return EAI_FAMILY; ++ } ++} + + int + getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + socklen_t hostlen, char *serv, socklen_t servlen, + int flags) + { +- int herrno; +- struct hostent th; +- int ok = 0; +- struct scratch_buffer tmpbuf; +- +- scratch_buffer_init (&tmpbuf); +- + if (flags & ~(NI_NUMERICHOST|NI_NUMERICSERV|NI_NOFQDN|NI_NAMEREQD|NI_DGRAM + #ifdef HAVE_LIBIDN + |NI_IDN|NI_IDN_ALLOW_UNASSIGNED|NI_IDN_USE_STD3_ASCII_RULES +@@ -213,249 +535,34 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + return EAI_FAMILY; + } + +- if (host != NULL && hostlen > 0) +- switch (sa->sa_family) +- { +- case AF_INET: +- case AF_INET6: +- if (!(flags & NI_NUMERICHOST)) +- { +- struct hostent *h = NULL; +- if (sa->sa_family == AF_INET6) +- { +- while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr), +- sizeof(struct in6_addr), +- AF_INET6, &th, +- tmpbuf.data, tmpbuf.length, +- &h, &herrno)) +- if (herrno == NETDB_INTERNAL && errno == ERANGE) +- { +- if (!scratch_buffer_grow (&tmpbuf)) +- { +- __set_h_errno (herrno); +- return EAI_MEMORY; +- } +- } +- else +- break; +- } +- else +- { +- while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr), +- sizeof(struct in_addr), +- AF_INET, &th, +- tmpbuf.data, tmpbuf.length, +- &h, &herrno)) +- if (herrno == NETDB_INTERNAL && errno == ERANGE) +- { +- if (!scratch_buffer_grow (&tmpbuf)) +- { +- __set_h_errno (herrno); +- return EAI_MEMORY; +- } +- } +- else +- break; +- } +- +- if (h == NULL) +- { +- if (herrno == NETDB_INTERNAL) +- { +- __set_h_errno (herrno); +- return EAI_SYSTEM; +- } +- if (herrno == TRY_AGAIN) +- { +- __set_h_errno (herrno); +- return EAI_AGAIN; +- } +- } +- +- if (h) +- { +- char *c; +- if ((flags & NI_NOFQDN) +- && (c = nrl_domainname ()) +- && (c = strstr (h->h_name, c)) +- && (c != h->h_name) && (*(--c) == '.')) +- /* Terminate the string after the prefix. */ +- *c = '\0'; +- +-#ifdef HAVE_LIBIDN +- /* If requested, convert from the IDN format. */ +- if (flags & NI_IDN) +- { +- int idn_flags = 0; +- if (flags & NI_IDN_ALLOW_UNASSIGNED) +- idn_flags |= IDNA_ALLOW_UNASSIGNED; +- if (flags & NI_IDN_USE_STD3_ASCII_RULES) +- idn_flags |= IDNA_USE_STD3_ASCII_RULES; +- +- char *out; +- int rc = __idna_to_unicode_lzlz (h->h_name, &out, +- idn_flags); +- if (rc != IDNA_SUCCESS) +- { +- if (rc == IDNA_MALLOC_ERROR) +- return EAI_MEMORY; +- if (rc == IDNA_DLOPEN_ERROR) +- return EAI_SYSTEM; +- return EAI_IDN_ENCODE; +- } +- +- if (out != h->h_name) +- { +- h->h_name = strdupa (out); +- free (out); +- } +- } +-#endif +- +- size_t len = strlen (h->h_name) + 1; +- if (len > hostlen) +- return EAI_OVERFLOW; +- +- memcpy (host, h->h_name, len); +- +- ok = 1; +- } +- } +- +- if (!ok) +- { +- if (flags & NI_NAMEREQD) +- return EAI_NONAME; +- else +- { +- const char *c; +- if (sa->sa_family == AF_INET6) +- { +- const struct sockaddr_in6 *sin6p; +- uint32_t scopeid; +- +- sin6p = (const struct sockaddr_in6 *) sa; +- +- c = inet_ntop (AF_INET6, +- (const void *) &sin6p->sin6_addr, host, hostlen); +- scopeid = sin6p->sin6_scope_id; +- if (scopeid != 0) +- { +- /* Buffer is >= IFNAMSIZ+1. */ +- char scopebuf[IFNAMSIZ + 1]; +- char *scopeptr; +- int ni_numericscope = 0; +- size_t real_hostlen = __strnlen (host, hostlen); +- size_t scopelen = 0; +- +- scopebuf[0] = SCOPE_DELIMITER; +- scopebuf[1] = '\0'; +- scopeptr = &scopebuf[1]; +- +- if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr) +- || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) +- { +- if (if_indextoname (scopeid, scopeptr) == NULL) +- ++ni_numericscope; +- else +- scopelen = strlen (scopebuf); +- } +- else +- ++ni_numericscope; +- +- if (ni_numericscope) +- scopelen = 1 + __snprintf (scopeptr, +- (scopebuf +- + sizeof scopebuf +- - scopeptr), +- "%u", scopeid); +- +- if (real_hostlen + scopelen + 1 > hostlen) +- /* Signal the buffer is too small. This is +- what inet_ntop does. */ +- c = NULL; +- else +- memcpy (host + real_hostlen, scopebuf, scopelen + 1); +- } +- } +- else +- c = inet_ntop (AF_INET, +- (const void *) &(((const struct sockaddr_in *) sa)->sin_addr), +- host, hostlen); +- if (c == NULL) +- return EAI_OVERFLOW; +- } +- ok = 1; +- } +- break; +- +- case AF_LOCAL: +- if (!(flags & NI_NUMERICHOST)) +- { +- struct utsname utsname; +- +- if (!uname (&utsname)) +- { +- strncpy (host, utsname.nodename, hostlen); +- break; +- }; +- }; +- +- if (flags & NI_NAMEREQD) +- return EAI_NONAME; +- +- strncpy (host, "localhost", hostlen); +- break; ++ struct scratch_buffer tmpbuf; ++ scratch_buffer_init (&tmpbuf); + +- default: +- return EAI_FAMILY; ++ if (host != NULL && hostlen > 0) ++ { ++ int result = gni_host (&tmpbuf, sa, addrlen, host, hostlen, flags); ++ if (result != 0) ++ { ++ scratch_buffer_free (&tmpbuf); ++ return result; ++ } + } + + if (serv && (servlen > 0)) +- switch (sa->sa_family) +- { +- case AF_INET: +- case AF_INET6: +- if (!(flags & NI_NUMERICSERV)) +- { +- struct servent *s, ts; +- int e; +- while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port, +- ((flags & NI_DGRAM) +- ? "udp" : "tcp"), &ts, +- tmpbuf.data, tmpbuf.length, &s))) +- { +- if (e == ERANGE) +- { +- if (!scratch_buffer_grow (&tmpbuf)) +- return EAI_MEMORY; +- } +- else +- break; +- } +- if (s) +- { +- strncpy (serv, s->s_name, servlen); +- break; +- } +- } +- +- if (__snprintf (serv, servlen, "%d", +- ntohs (((const struct sockaddr_in *) sa)->sin_port)) +- + 1 > servlen) +- return EAI_OVERFLOW; +- +- break; +- +- case AF_LOCAL: +- strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen); +- break; ++ { ++ int result = gni_serv (&tmpbuf, sa, addrlen, serv, servlen, flags); ++ if (result != 0) ++ { ++ scratch_buffer_free (&tmpbuf); ++ return result; ++ } + } + + if (host && (hostlen > 0)) + host[hostlen-1] = 0; + if (serv && (servlen > 0)) + serv[servlen-1] = 0; ++ scratch_buffer_free (&tmpbuf); + return 0; + } + libc_hidden_def (getnameinfo) diff --git a/glibc-rh1333901-3.patch b/glibc-rh1333901-3.patch new file mode 100644 index 0000000..d1c67f8 --- /dev/null +++ b/glibc-rh1333901-3.patch @@ -0,0 +1,116 @@ +commit c9b0e6a432e827b61f12eb52c2aaeadc77b64461 +Author: Florian Weimer +Date: Wed May 4 14:35:12 2016 +0200 + + getnameinfo: Reduce line length and add missing comments + +diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c +index ce05dda..c649c49 100644 +--- a/inet/getnameinfo.c ++++ b/inet/getnameinfo.c +@@ -198,10 +198,9 @@ gni_host_inet_name (struct scratch_buffer *tmpbuf, + struct hostent *h = NULL; + if (sa->sa_family == AF_INET6) + { +- while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in6 *) sa)->sin6_addr), +- sizeof(struct in6_addr), +- AF_INET6, &th, +- tmpbuf->data, tmpbuf->length, ++ const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa; ++ while (__gethostbyaddr_r (&sin6p->sin6_addr, sizeof(struct in6_addr), ++ AF_INET6, &th, tmpbuf->data, tmpbuf->length, + &h, &herrno)) + if (herrno == NETDB_INTERNAL && errno == ERANGE) + { +@@ -216,10 +215,9 @@ gni_host_inet_name (struct scratch_buffer *tmpbuf, + } + else + { +- while (__gethostbyaddr_r ((const void *) &(((const struct sockaddr_in *)sa)->sin_addr), +- sizeof(struct in_addr), +- AF_INET, &th, +- tmpbuf->data, tmpbuf->length, ++ const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa; ++ while (__gethostbyaddr_r (&sinp->sin_addr, sizeof(struct in_addr), ++ AF_INET, &th, tmpbuf->data, tmpbuf->length, + &h, &herrno)) + if (herrno == NETDB_INTERNAL && errno == ERANGE) + { +@@ -308,14 +306,10 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf, + const char *c; + if (sa->sa_family == AF_INET6) + { +- const struct sockaddr_in6 *sin6p; +- uint32_t scopeid; +- +- sin6p = (const struct sockaddr_in6 *) sa; +- ++ const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa; + c = inet_ntop (AF_INET6, + (const void *) &sin6p->sin6_addr, host, hostlen); +- scopeid = sin6p->sin6_scope_id; ++ uint32_t scopeid = sin6p->sin6_scope_id; + if (scopeid != 0) + { + /* Buffer is >= IFNAMSIZ+1. */ +@@ -356,14 +350,16 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf, + } + } + else +- c = inet_ntop (AF_INET, +- (const void *) &(((const struct sockaddr_in *) sa)->sin_addr), +- host, hostlen); ++ { ++ const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa; ++ c = inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen); ++ } + if (c == NULL) + return EAI_OVERFLOW; + return 0; + } + ++/* Convert AF_INET or AF_INET6 socket address, host part. */ + static int + gni_host_inet (struct scratch_buffer *tmpbuf, + const struct sockaddr *sa, socklen_t addrlen, +@@ -384,6 +380,7 @@ gni_host_inet (struct scratch_buffer *tmpbuf, + (tmpbuf, sa, addrlen, host, hostlen, flags); + } + ++/* Convert AF_LOCAL socket address, host part. */ + static int + gni_host_local (struct scratch_buffer *tmpbuf, + const struct sockaddr *sa, socklen_t addrlen, +@@ -408,6 +405,7 @@ gni_host_local (struct scratch_buffer *tmpbuf, + return 0; + } + ++/* Convert the host part of an AF_LOCAK socket address. */ + static int + gni_host (struct scratch_buffer *tmpbuf, + const struct sockaddr *sa, socklen_t addrlen, +@@ -439,11 +437,12 @@ gni_serv_inet (struct scratch_buffer *tmpbuf, + && sizeof (((struct sockaddr_in) {}).sin_port) == sizeof (in_port_t) + && sizeof (((struct sockaddr_in6) {}).sin6_port) == sizeof (in_port_t), + "AF_INET and AF_INET6 port consistency"); ++ const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa; + if (!(flags & NI_NUMERICSERV)) + { + struct servent *s, ts; + int e; +- while ((e = __getservbyport_r (((const struct sockaddr_in *) sa)->sin_port, ++ while ((e = __getservbyport_r (sinp->sin_port, + ((flags & NI_DGRAM) + ? "udp" : "tcp"), &ts, + tmpbuf->data, tmpbuf->length, &s))) +@@ -463,9 +462,7 @@ gni_serv_inet (struct scratch_buffer *tmpbuf, + } + /* Fall through to numeric conversion. */ + } +- if (__snprintf (serv, servlen, "%d", +- ntohs (((const struct sockaddr_in *) sa)->sin_port)) +- + 1 > servlen) ++ if (__snprintf (serv, servlen, "%d", ntohs (sinp->sin_port)) + 1 > servlen) + return EAI_OVERFLOW; + return 0; + } diff --git a/glibc-rh1333901-4.patch b/glibc-rh1333901-4.patch new file mode 100644 index 0000000..c89d522 --- /dev/null +++ b/glibc-rh1333901-4.patch @@ -0,0 +1,52 @@ +commit 1c3490d4b29fc5b3f30dd6b13082046aee94443d +Author: Florian Weimer +Date: Wed May 4 14:35:23 2016 +0200 + + getnameinfo: Avoid calling strnlen on uninitialized buffer + + In the numeric AF_INET/AF_INET6 case, if inet_ntop fails + as the result of a short host buffer, we used to call strnlen + on the uninitialized host buffer. + +diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c +index c649c49..c8de163 100644 +--- a/inet/getnameinfo.c ++++ b/inet/getnameinfo.c +@@ -303,12 +303,12 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf, + const struct sockaddr *sa, socklen_t addrlen, + char *host, socklen_t hostlen, int flags) + { +- const char *c; + if (sa->sa_family == AF_INET6) + { + const struct sockaddr_in6 *sin6p = (const struct sockaddr_in6 *) sa; +- c = inet_ntop (AF_INET6, +- (const void *) &sin6p->sin6_addr, host, hostlen); ++ if (inet_ntop (AF_INET6, &sin6p->sin6_addr, host, hostlen) == NULL) ++ return EAI_OVERFLOW; ++ + uint32_t scopeid = sin6p->sin6_scope_id; + if (scopeid != 0) + { +@@ -344,7 +344,7 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf, + if (real_hostlen + scopelen + 1 > hostlen) + /* Signal the buffer is too small. This is + what inet_ntop does. */ +- c = NULL; ++ return EAI_OVERFLOW; + else + memcpy (host + real_hostlen, scopebuf, scopelen + 1); + } +@@ -352,10 +352,9 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf, + else + { + const struct sockaddr_in *sinp = (const struct sockaddr_in *) sa; +- c = inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen); ++ if (inet_ntop (AF_INET, &sinp->sin_addr, host, hostlen) == NULL) ++ return EAI_OVERFLOW; + } +- if (c == NULL) +- return EAI_OVERFLOW; + return 0; + } + diff --git a/glibc-rh1333901-5.patch b/glibc-rh1333901-5.patch new file mode 100644 index 0000000..5b5d0d1 --- /dev/null +++ b/glibc-rh1333901-5.patch @@ -0,0 +1,175 @@ +commit 066746783d6c6c0f61b39c741177e24a9b398a20 +Author: Florian Weimer +Date: Wed May 4 14:45:17 2016 +0200 + + getnameinfo: Return EAI_OVERFLOW in more cases [BZ #19787] + + The AF_LOCAL and AF_INET/AF_INET6 non-numerci service conversion + did not return EAI_OVERFLOW if the supplied buffer was too small, + silently returning truncated data. In the AF_INET/AF_INET6 + numeric cases, the snprintf return value checking was incorrect. + +diff --git a/inet/getnameinfo.c b/inet/getnameinfo.c +index c8de163..283da55 100644 +--- a/inet/getnameinfo.c ++++ b/inet/getnameinfo.c +@@ -187,6 +187,39 @@ nrl_domainname (void) + return domain; + }; + ++/* Copy a string to a destination buffer with length checking. Return ++ EAI_OVERFLOW if the buffer is not large enough, and 0 on ++ success. */ ++static int ++checked_copy (char *dest, size_t destlen, const char *source) ++{ ++ size_t source_length = strlen (source); ++ if (source_length + 1 > destlen) ++ return EAI_OVERFLOW; ++ memcpy (dest, source, source_length + 1); ++ return 0; ++} ++ ++/* Helper function for CHECKED_SNPRINTF below. */ ++static int ++check_sprintf_result (int result, size_t destlen) ++{ ++ if (result < 0) ++ return EAI_SYSTEM; ++ if ((size_t) result >= destlen) ++ /* If ret == destlen, there was no room for the terminating NUL ++ character. */ ++ return EAI_OVERFLOW; ++ return 0; ++} ++ ++/* Format a string in the destination buffer. Return 0 on success, ++ EAI_OVERFLOW in case the buffer is too small, or EAI_SYSTEM on any ++ other error. */ ++#define CHECKED_SNPRINTF(dest, destlen, format, ...) \ ++ check_sprintf_result \ ++ (__snprintf (dest, destlen, format, __VA_ARGS__), destlen) ++ + /* Convert host name, AF_INET/AF_INET6 case, name only. */ + static int + gni_host_inet_name (struct scratch_buffer *tmpbuf, +@@ -312,41 +345,22 @@ gni_host_inet_numeric (struct scratch_buffer *tmpbuf, + uint32_t scopeid = sin6p->sin6_scope_id; + if (scopeid != 0) + { +- /* Buffer is >= IFNAMSIZ+1. */ +- char scopebuf[IFNAMSIZ + 1]; +- char *scopeptr; +- int ni_numericscope = 0; +- size_t real_hostlen = __strnlen (host, hostlen); +- size_t scopelen = 0; +- +- scopebuf[0] = SCOPE_DELIMITER; +- scopebuf[1] = '\0'; +- scopeptr = &scopebuf[1]; ++ size_t used_hostlen = __strnlen (host, hostlen); ++ /* Location of the scope string in the host buffer. */ ++ char *scope_start = host + used_hostlen; ++ size_t scope_length = hostlen - used_hostlen; + + if (IN6_IS_ADDR_LINKLOCAL (&sin6p->sin6_addr) + || IN6_IS_ADDR_MC_LINKLOCAL (&sin6p->sin6_addr)) + { +- if (if_indextoname (scopeid, scopeptr) == NULL) +- ++ni_numericscope; +- else +- scopelen = strlen (scopebuf); ++ char scopebuf[IFNAMSIZ]; ++ if (if_indextoname (scopeid, scopebuf) != NULL) ++ return CHECKED_SNPRINTF ++ (scope_start, scope_length, ++ "%c%s", SCOPE_DELIMITER, scopebuf); + } +- else +- ++ni_numericscope; +- +- if (ni_numericscope) +- scopelen = 1 + __snprintf (scopeptr, +- (scopebuf +- + sizeof scopebuf +- - scopeptr), +- "%u", scopeid); +- +- if (real_hostlen + scopelen + 1 > hostlen) +- /* Signal the buffer is too small. This is +- what inet_ntop does. */ +- return EAI_OVERFLOW; +- else +- memcpy (host + real_hostlen, scopebuf, scopelen + 1); ++ return CHECKED_SNPRINTF ++ (scope_start, scope_length, "%c%u", SCOPE_DELIMITER, scopeid); + } + } + else +@@ -385,23 +399,17 @@ gni_host_local (struct scratch_buffer *tmpbuf, + const struct sockaddr *sa, socklen_t addrlen, + char *host, socklen_t hostlen, int flags) + { +- + if (!(flags & NI_NUMERICHOST)) + { + struct utsname utsname; +- +- if (!uname (&utsname)) +- { +- strncpy (host, utsname.nodename, hostlen); +- return 0; +- } ++ if (uname (&utsname) == 0) ++ return checked_copy (host, hostlen, utsname.nodename); + } + + if (flags & NI_NAMEREQD) + return EAI_NONAME; + +- strncpy (host, "localhost", hostlen); +- return 0; ++ return checked_copy (host, hostlen, "localhost"); + } + + /* Convert the host part of an AF_LOCAK socket address. */ +@@ -455,15 +463,10 @@ gni_serv_inet (struct scratch_buffer *tmpbuf, + break; + } + if (s) +- { +- strncpy (serv, s->s_name, servlen); +- return 0; +- } ++ return checked_copy (serv, servlen, s->s_name); + /* Fall through to numeric conversion. */ + } +- if (__snprintf (serv, servlen, "%d", ntohs (sinp->sin_port)) + 1 > servlen) +- return EAI_OVERFLOW; +- return 0; ++ return CHECKED_SNPRINTF (serv, servlen, "%d", ntohs (sinp->sin_port)); + } + + /* Convert service to string, AF_LOCAL variant. */ +@@ -472,8 +475,8 @@ gni_serv_local (struct scratch_buffer *tmpbuf, + const struct sockaddr *sa, socklen_t addrlen, + char *serv, socklen_t servlen, int flags) + { +- strncpy (serv, ((const struct sockaddr_un *) sa)->sun_path, servlen); +- return 0; ++ return checked_copy ++ (serv, servlen, ((const struct sockaddr_un *) sa)->sun_path); + } + + /* Convert service to string, dispatching to the implementations +@@ -554,10 +557,6 @@ getnameinfo (const struct sockaddr *sa, socklen_t addrlen, char *host, + } + } + +- if (host && (hostlen > 0)) +- host[hostlen-1] = 0; +- if (serv && (servlen > 0)) +- serv[servlen-1] = 0; + scratch_buffer_free (&tmpbuf); + return 0; + } diff --git a/glibc.spec b/glibc.spec index 520e18d..bb9a6a5 100644 --- a/glibc.spec +++ b/glibc.spec @@ -1,6 +1,6 @@ %define glibcsrcdir glibc-2.22 %define glibcversion 2.22 -%define glibcrelease 13%{?dist} +%define glibcrelease 14%{?dist} # Pre-release tarballs are pulled in from git using a command that is # effectively: # @@ -238,6 +238,11 @@ Patch1015: glibc-rh1321861.patch Patch1016: glibc-rh1316972.patch Patch1017: glibc-rh1316972-2.patch Patch1018: glibc-rh1333940.patch +Patch1019: glibc-rh1333901-1.patch +Patch1020: glibc-rh1333901-2.patch +Patch1021: glibc-rh1333901-3.patch +Patch1022: glibc-rh1333901-4.patch +Patch1023: glibc-rh1333901-5.patch ############################################################################## # @@ -675,6 +680,11 @@ microbenchmark tests on the system. %patch1016 -p1 %patch1017 -p1 %patch1018 -p1 +%patch1019 -p1 +%patch1020 -p1 +%patch1021 -p1 +%patch1022 -p1 +%patch1023 -p1 %patch0059 -p1 ############################################################################## @@ -1895,6 +1905,9 @@ rm -f *.filelist* %endif %changelog +* Fri May 6 2016 Florian Weimer - 2.22-14 +- Fix getnameinfo memory leak and incorrect truncation (#1333901) + * Fri May 6 2016 Florian Weimer - 2.22-13 - Avoid build failure in TZ tests (#1333940)