[glibc/f20] Resolves: #1047979
Siddhesh Poyarekar
siddhesh at fedoraproject.org
Thu Jan 23 10:23:17 UTC 2014
commit f40ae7b7fc76ac11ec049166ff0b59e91a974cd0
Author: Siddhesh Poyarekar <siddhesh at redhat.com>
Date: Thu Jan 23 15:49:14 2014 +0530
Resolves: #1047979
Use first name entry for address in /etc/hosts as the canonical name
in getaddrinfo.
glibc-rh1047979.patch | 555 +++++++++++++++++++++++++++++++++++++++++++++++++
glibc.spec | 8 +-
2 files changed, 562 insertions(+), 1 deletions(-)
---
diff --git a/glibc-rh1047979.patch b/glibc-rh1047979.patch
new file mode 100644
index 0000000..695da21
--- /dev/null
+++ b/glibc-rh1047979.patch
@@ -0,0 +1,555 @@
+commit 5a4c6d53f50b264d60cf6453576ca2810c7890b7
+Author: Siddhesh Poyarekar <siddhesh at redhat.com>
+Date: Thu Nov 28 17:18:12 2013 +0530
+
+ Get canonical name in getaddrinfo from hosts file for AF_INET (fixes 16077)
+
+ AF_INET lookup in hosts file uses _nss_files_gethostbyname2_r, which
+ is not capable of returning a canonical name if it has found one.
+ This change adds _nss_files_gethostbyname3_r, which wraps around
+ _nss_files_gethostbyname2_r and then returns result.h_name as the
+ canonical name.
+
+diff --git a/nss/Versions b/nss/Versions
+index d13d570..f8ababc 100644
+--- a/nss/Versions
++++ b/nss/Versions
+@@ -40,6 +40,7 @@ libnss_files {
+ _nss_files_endhostent;
+ _nss_files_gethostbyaddr_r;
+ _nss_files_gethostbyname2_r;
++ _nss_files_gethostbyname3_r;
+ _nss_files_gethostbyname4_r;
+ _nss_files_gethostbyname_r;
+ _nss_files_gethostent_r;
+diff --git a/nss/nss_files/files-hosts.c b/nss/nss_files/files-hosts.c
+index 6db2535..957c9aa 100644
+--- a/nss/nss_files/files-hosts.c
++++ b/nss/nss_files/files-hosts.c
+@@ -97,262 +97,12 @@ LINE_PARSER
+ STRING_FIELD (result->h_name, isspace, 1);
+ })
+
+-
+-
+-#define HOST_DB_LOOKUP(name, keysize, keypattern, break_if_match, proto...) \
+-enum nss_status \
+-_nss_files_get##name##_r (proto, \
+- struct STRUCTURE *result, char *buffer, \
+- size_t buflen, int *errnop H_ERRNO_PROTO) \
+-{ \
+- uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data); \
+- buffer += pad; \
+- buflen = buflen > pad ? buflen - pad : 0; \
+- \
+- __libc_lock_lock (lock); \
+- \
+- /* Reset file pointer to beginning or open file. */ \
+- enum nss_status status = internal_setent (keep_stream); \
+- \
+- if (status == NSS_STATUS_SUCCESS) \
+- { \
+- /* Tell getent function that we have repositioned the file pointer. */ \
+- last_use = getby; \
+- \
+- while ((status = internal_getent (result, buffer, buflen, errnop \
+- H_ERRNO_ARG EXTRA_ARGS_VALUE)) \
+- == NSS_STATUS_SUCCESS) \
+- { break_if_match } \
+- \
+- if (status == NSS_STATUS_SUCCESS \
+- && _res_hconf.flags & HCONF_FLAG_MULTI) \
+- { \
+- /* We have to get all host entries from the file. */ \
+- size_t tmp_buflen = MIN (buflen, 4096); \
+- char tmp_buffer_stack[tmp_buflen] \
+- __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));\
+- char *tmp_buffer = tmp_buffer_stack; \
+- struct hostent tmp_result_buf; \
+- int naddrs = 1; \
+- int naliases = 0; \
+- char *bufferend; \
+- bool tmp_buffer_malloced = false; \
+- \
+- while (result->h_aliases[naliases] != NULL) \
+- ++naliases; \
+- \
+- bufferend = (char *) &result->h_aliases[naliases + 1]; \
+- \
+- again: \
+- while ((status = internal_getent (&tmp_result_buf, tmp_buffer, \
+- tmp_buflen, errnop H_ERRNO_ARG \
+- EXTRA_ARGS_VALUE)) \
+- == NSS_STATUS_SUCCESS) \
+- { \
+- int matches = 1; \
+- struct hostent *old_result = result; \
+- result = &tmp_result_buf; \
+- /* The following piece is a bit clumsy but we want to use the \
+- `break_if_match' value. The optimizer should do its \
+- job. */ \
+- do \
+- { \
+- break_if_match \
+- result = old_result; \
+- } \
+- while ((matches = 0)); \
+- \
+- if (matches) \
+- { \
+- /* We could be very clever and try to recycle a few bytes \
+- in the buffer instead of generating new arrays. But \
+- we are not doing this here since it's more work than \
+- it's worth. Simply let the user provide a bit bigger \
+- buffer. */ \
+- char **new_h_addr_list; \
+- char **new_h_aliases; \
+- int newaliases = 0; \
+- size_t newstrlen = 0; \
+- int cnt; \
+- \
+- /* Count the new aliases and the length of the strings. */ \
+- while (tmp_result_buf.h_aliases[newaliases] != NULL) \
+- { \
+- char *cp = tmp_result_buf.h_aliases[newaliases]; \
+- ++newaliases; \
+- newstrlen += strlen (cp) + 1; \
+- } \
+- /* If the real name is different add it also to the \
+- aliases. This means that there is a duplication \
+- in the alias list but this is really the user's \
+- problem. */ \
+- if (strcmp (old_result->h_name, \
+- tmp_result_buf.h_name) != 0) \
+- { \
+- ++newaliases; \
+- newstrlen += strlen (tmp_result_buf.h_name) + 1; \
+- } \
+- \
+- /* Make sure bufferend is aligned. */ \
+- assert ((bufferend - (char *) 0) % sizeof (char *) == 0); \
+- \
+- /* Now we can check whether the buffer is large enough. \
+- 16 is the maximal size of the IP address. */ \
+- if (bufferend + 16 + (naddrs + 2) * sizeof (char *) \
+- + roundup (newstrlen, sizeof (char *)) \
+- + (naliases + newaliases + 1) * sizeof (char *) \
+- >= buffer + buflen) \
+- { \
+- *errnop = ERANGE; \
+- *herrnop = NETDB_INTERNAL; \
+- status = NSS_STATUS_TRYAGAIN; \
+- goto out; \
+- } \
+- \
+- new_h_addr_list = \
+- (char **) (bufferend \
+- + roundup (newstrlen, sizeof (char *)) \
+- + 16); \
+- new_h_aliases = \
+- (char **) ((char *) new_h_addr_list \
+- + (naddrs + 2) * sizeof (char *)); \
+- \
+- /* Copy the old data in the new arrays. */ \
+- for (cnt = 0; cnt < naddrs; ++cnt) \
+- new_h_addr_list[cnt] = old_result->h_addr_list[cnt]; \
+- \
+- for (cnt = 0; cnt < naliases; ++cnt) \
+- new_h_aliases[cnt] = old_result->h_aliases[cnt]; \
+- \
+- /* Store the new strings. */ \
+- cnt = 0; \
+- while (tmp_result_buf.h_aliases[cnt] != NULL) \
+- { \
+- new_h_aliases[naliases++] = bufferend; \
+- bufferend = (__stpcpy (bufferend, \
+- tmp_result_buf.h_aliases[cnt]) \
+- + 1); \
+- ++cnt; \
+- } \
+- \
+- if (cnt < newaliases) \
+- { \
+- new_h_aliases[naliases++] = bufferend; \
+- bufferend = __stpcpy (bufferend, \
+- tmp_result_buf.h_name) + 1; \
+- } \
+- \
+- /* Final NULL pointer. */ \
+- new_h_aliases[naliases] = NULL; \
+- \
+- /* Round up the buffer end address. */ \
+- bufferend += (sizeof (char *) \
+- - ((bufferend - (char *) 0) \
+- % sizeof (char *))) % sizeof (char *); \
+- \
+- /* Now the new address. */ \
+- new_h_addr_list[naddrs++] = \
+- memcpy (bufferend, tmp_result_buf.h_addr, \
+- tmp_result_buf.h_length); \
+- \
+- /* Also here a final NULL pointer. */ \
+- new_h_addr_list[naddrs] = NULL; \
+- \
+- /* Store the new array pointers. */ \
+- old_result->h_aliases = new_h_aliases; \
+- old_result->h_addr_list = new_h_addr_list; \
+- \
+- /* Compute the new buffer end. */ \
+- bufferend = (char *) &new_h_aliases[naliases + 1]; \
+- assert (bufferend <= buffer + buflen); \
+- \
+- result = old_result; \
+- } \
+- } \
+- \
+- if (status == NSS_STATUS_TRYAGAIN) \
+- { \
+- size_t newsize = 2 * tmp_buflen; \
+- if (tmp_buffer_malloced) \
+- { \
+- char *newp = realloc (tmp_buffer, newsize); \
+- if (newp != NULL) \
+- { \
+- assert ((((uintptr_t) newp) \
+- & (__alignof__ (struct hostent_data) - 1)) \
+- == 0); \
+- tmp_buffer = newp; \
+- tmp_buflen = newsize; \
+- goto again; \
+- } \
+- } \
+- else if (!__libc_use_alloca (buflen + newsize)) \
+- { \
+- tmp_buffer = malloc (newsize); \
+- if (tmp_buffer != NULL) \
+- { \
+- assert ((((uintptr_t) tmp_buffer) \
+- & (__alignof__ (struct hostent_data) - 1)) \
+- == 0); \
+- tmp_buffer_malloced = true; \
+- tmp_buflen = newsize; \
+- goto again; \
+- } \
+- } \
+- else \
+- { \
+- tmp_buffer \
+- = extend_alloca (tmp_buffer, tmp_buflen, \
+- newsize \
+- + __alignof__ (struct hostent_data)); \
+- tmp_buffer = (char *) (((uintptr_t) tmp_buffer \
+- + __alignof__ (struct hostent_data) \
+- - 1) \
+- & ~(__alignof__ (struct hostent_data)\
+- - 1)); \
+- goto again; \
+- } \
+- } \
+- else \
+- status = NSS_STATUS_SUCCESS; \
+- out: \
+- if (tmp_buffer_malloced) \
+- free (tmp_buffer); \
+- } \
+- \
+- \
+- if (! keep_stream) \
+- internal_endent (); \
+- } \
+- \
+- __libc_lock_unlock (lock); \
+- \
+- return status; \
+-}
+-
+-
+ #define EXTRA_ARGS_VALUE \
+ , ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET), \
+ ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
+ #include "files-XXX.c"
+-HOST_DB_LOOKUP (hostbyname, ,,
+- {
+- LOOKUP_NAME_CASE (h_name, h_aliases)
+- }, const char *name)
+ #undef EXTRA_ARGS_VALUE
+
+-
+-/* XXX Is using _res to determine whether we want to convert IPv4 addresses
+- to IPv6 addresses really the right thing to do? */
+-#define EXTRA_ARGS_VALUE \
+- , af, ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0)
+-HOST_DB_LOOKUP (hostbyname2, ,,
+- {
+- LOOKUP_NAME_CASE (h_name, h_aliases)
+- }, const char *name, int af)
+-#undef EXTRA_ARGS_VALUE
+-
+-
+ /* We only need to consider IPv4 mapped addresses if the input to the
+ gethostbyaddr() function is an IPv6 address. */
+ #define EXTRA_ARGS_VALUE \
+@@ -365,6 +115,263 @@ DB_LOOKUP (hostbyaddr, ,,,
+ }, const void *addr, socklen_t len, int af)
+ #undef EXTRA_ARGS_VALUE
+
++enum nss_status
++_nss_files_gethostbyname3_r (const char *name, int af, struct hostent *result,
++ char *buffer, size_t buflen, int *errnop,
++ int *herrnop, int32_t *ttlp, char **canonp)
++{
++ uintptr_t pad = -(uintptr_t) buffer % __alignof__ (struct hostent_data);
++ buffer += pad;
++ buflen = buflen > pad ? buflen - pad : 0;
++
++ __libc_lock_lock (lock);
++
++ /* Reset file pointer to beginning or open file. */
++ enum nss_status status = internal_setent (keep_stream);
++
++ if (status == NSS_STATUS_SUCCESS)
++ {
++ /* XXX Is using _res to determine whether we want to convert IPv4
++ addresses to IPv6 addresses really the right thing to do? */
++ int flags = ((_res.options & RES_USE_INET6) ? AI_V4MAPPED : 0);
++
++ /* Tell getent function that we have repositioned the file pointer. */
++ last_use = getby;
++
++ while ((status = internal_getent (result, buffer, buflen, errnop,
++ herrnop, af, flags))
++ == NSS_STATUS_SUCCESS)
++ {
++ LOOKUP_NAME_CASE (h_name, h_aliases)
++ }
++
++ if (status == NSS_STATUS_SUCCESS
++ && _res_hconf.flags & HCONF_FLAG_MULTI)
++ {
++ /* We have to get all host entries from the file. */
++ size_t tmp_buflen = MIN (buflen, 4096);
++ char tmp_buffer_stack[tmp_buflen]
++ __attribute__ ((__aligned__ (__alignof__ (struct hostent_data))));
++ char *tmp_buffer = tmp_buffer_stack;
++ struct hostent tmp_result_buf;
++ int naddrs = 1;
++ int naliases = 0;
++ char *bufferend;
++ bool tmp_buffer_malloced = false;
++
++ while (result->h_aliases[naliases] != NULL)
++ ++naliases;
++
++ bufferend = (char *) &result->h_aliases[naliases + 1];
++
++ again:
++ while ((status = internal_getent (&tmp_result_buf, tmp_buffer,
++ tmp_buflen, errnop, herrnop, af,
++ flags))
++ == NSS_STATUS_SUCCESS)
++ {
++ int matches = 1;
++ struct hostent *old_result = result;
++ result = &tmp_result_buf;
++ /* The following piece is a bit clumsy but we want to use the
++ `LOOKUP_NAME_CASE' value. The optimizer should do its
++ job. */
++ do
++ {
++ LOOKUP_NAME_CASE (h_name, h_aliases)
++ result = old_result;
++ }
++ while ((matches = 0));
++
++ if (matches)
++ {
++ /* We could be very clever and try to recycle a few bytes
++ in the buffer instead of generating new arrays. But
++ we are not doing this here since it's more work than
++ it's worth. Simply let the user provide a bit bigger
++ buffer. */
++ char **new_h_addr_list;
++ char **new_h_aliases;
++ int newaliases = 0;
++ size_t newstrlen = 0;
++ int cnt;
++
++ /* Count the new aliases and the length of the strings. */
++ while (tmp_result_buf.h_aliases[newaliases] != NULL)
++ {
++ char *cp = tmp_result_buf.h_aliases[newaliases];
++ ++newaliases;
++ newstrlen += strlen (cp) + 1;
++ }
++ /* If the real name is different add it also to the
++ aliases. This means that there is a duplication
++ in the alias list but this is really the user's
++ problem. */
++ if (strcmp (old_result->h_name,
++ tmp_result_buf.h_name) != 0)
++ {
++ ++newaliases;
++ newstrlen += strlen (tmp_result_buf.h_name) + 1;
++ }
++
++ /* Make sure bufferend is aligned. */
++ assert ((bufferend - (char *) 0) % sizeof (char *) == 0);
++
++ /* Now we can check whether the buffer is large enough.
++ 16 is the maximal size of the IP address. */
++ if (bufferend + 16 + (naddrs + 2) * sizeof (char *)
++ + roundup (newstrlen, sizeof (char *))
++ + (naliases + newaliases + 1) * sizeof (char *)
++ >= buffer + buflen)
++ {
++ *errnop = ERANGE;
++ *herrnop = NETDB_INTERNAL;
++ status = NSS_STATUS_TRYAGAIN;
++ goto out;
++ }
++
++ new_h_addr_list =
++ (char **) (bufferend
++ + roundup (newstrlen, sizeof (char *))
++ + 16);
++ new_h_aliases =
++ (char **) ((char *) new_h_addr_list
++ + (naddrs + 2) * sizeof (char *));
++
++ /* Copy the old data in the new arrays. */
++ for (cnt = 0; cnt < naddrs; ++cnt)
++ new_h_addr_list[cnt] = old_result->h_addr_list[cnt];
++
++ for (cnt = 0; cnt < naliases; ++cnt)
++ new_h_aliases[cnt] = old_result->h_aliases[cnt];
++
++ /* Store the new strings. */
++ cnt = 0;
++ while (tmp_result_buf.h_aliases[cnt] != NULL)
++ {
++ new_h_aliases[naliases++] = bufferend;
++ bufferend = (__stpcpy (bufferend,
++ tmp_result_buf.h_aliases[cnt])
++ + 1);
++ ++cnt;
++ }
++
++ if (cnt < newaliases)
++ {
++ new_h_aliases[naliases++] = bufferend;
++ bufferend = __stpcpy (bufferend,
++ tmp_result_buf.h_name) + 1;
++ }
++
++ /* Final NULL pointer. */
++ new_h_aliases[naliases] = NULL;
++
++ /* Round up the buffer end address. */
++ bufferend += (sizeof (char *)
++ - ((bufferend - (char *) 0)
++ % sizeof (char *))) % sizeof (char *);
++
++ /* Now the new address. */
++ new_h_addr_list[naddrs++] =
++ memcpy (bufferend, tmp_result_buf.h_addr,
++ tmp_result_buf.h_length);
++
++ /* Also here a final NULL pointer. */
++ new_h_addr_list[naddrs] = NULL;
++
++ /* Store the new array pointers. */
++ old_result->h_aliases = new_h_aliases;
++ old_result->h_addr_list = new_h_addr_list;
++
++ /* Compute the new buffer end. */
++ bufferend = (char *) &new_h_aliases[naliases + 1];
++ assert (bufferend <= buffer + buflen);
++
++ result = old_result;
++ }
++ }
++
++ if (status == NSS_STATUS_TRYAGAIN)
++ {
++ size_t newsize = 2 * tmp_buflen;
++ if (tmp_buffer_malloced)
++ {
++ char *newp = realloc (tmp_buffer, newsize);
++ if (newp != NULL)
++ {
++ assert ((((uintptr_t) newp)
++ & (__alignof__ (struct hostent_data) - 1))
++ == 0);
++ tmp_buffer = newp;
++ tmp_buflen = newsize;
++ goto again;
++ }
++ }
++ else if (!__libc_use_alloca (buflen + newsize))
++ {
++ tmp_buffer = malloc (newsize);
++ if (tmp_buffer != NULL)
++ {
++ assert ((((uintptr_t) tmp_buffer)
++ & (__alignof__ (struct hostent_data) - 1))
++ == 0);
++ tmp_buffer_malloced = true;
++ tmp_buflen = newsize;
++ goto again;
++ }
++ }
++ else
++ {
++ tmp_buffer
++ = extend_alloca (tmp_buffer, tmp_buflen,
++ newsize
++ + __alignof__ (struct hostent_data));
++ tmp_buffer = (char *) (((uintptr_t) tmp_buffer
++ + __alignof__ (struct hostent_data)
++ - 1)
++ & ~(__alignof__ (struct hostent_data)
++ - 1));
++ goto again;
++ }
++ }
++ else
++ status = NSS_STATUS_SUCCESS;
++ out:
++ if (tmp_buffer_malloced)
++ free (tmp_buffer);
++ }
++
++ if (! keep_stream)
++ internal_endent ();
++ }
++
++ if (canonp && status == NSS_STATUS_SUCCESS)
++ *canonp = result->h_name;
++
++ __libc_lock_unlock (lock);
++
++ return status;
++}
++
++enum nss_status
++_nss_files_gethostbyname_r (const char *name, struct hostent *result,
++ char *buffer, size_t buflen, int *errnop,
++ int *herrnop)
++{
++ int af = ((_res.options & RES_USE_INET6) ? AF_INET6 : AF_INET);
++
++ return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
++ errnop, herrnop, NULL, NULL);
++}
++
++enum nss_status
++_nss_files_gethostbyname2_r (const char *name, int af, struct hostent *result,
++ char *buffer, size_t buflen, int *errnop,
++ int *herrnop)
++{
++ return _nss_files_gethostbyname3_r (name, af, result, buffer, buflen,
++ errnop, herrnop, NULL, NULL);
++}
+
+ enum nss_status
+ _nss_files_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
diff --git a/glibc.spec b/glibc.spec
index 3e36ec2..c1d2e0c 100644
--- a/glibc.spec
+++ b/glibc.spec
@@ -1,6 +1,6 @@
%define glibcsrcdir glibc-2.18
%define glibcversion 2.18
-%define glibcrelease 11%{?dist}
+%define glibcrelease 12%{?dist}
# Pre-release tarballs are pulled in from git using a command that is
# effectively:
#
@@ -189,6 +189,7 @@ Patch0043: %{name}-rh1009145.patch
#
Patch1001: %{name}-rh995841.patch
Patch1002: %{name}-rh1008299.patch
+Patch1003: %{name}-rh1047979.patch
#
# Patches submitted, but not yet approved upstream.
@@ -564,6 +565,7 @@ package or when debugging this package.
%patch2031 -p1
%patch2032 -p1
%patch0043 -p1
+%patch1003 -p1
##############################################################################
# %%prep - Additional prep required...
@@ -1649,6 +1651,10 @@ rm -f *.filelist*
%endif
%changelog
+* Thu Jan 23 2014 Siddhesh Poyarekar <siddhesh at redhat.com> - 2.18-12
+- Use first name entry for address in /etc/hosts as the canonical name
+ in getaddrinfo (#1047979).
+
* Wed Oct 2 2013 Carlos O'Donell <carlos at redhat.com> - 2.18-11
- Allow ldconfig cached objects previously marked as hard or soft
ABI to now become unmarked without raising an error. This works
More information about the scm-commits
mailing list