From f40ae7b7fc76ac11ec049166ff0b59e91a974cd0 Mon Sep 17 00:00:00 2001 From: Siddhesh Poyarekar Date: Thu, 23 Jan 2014 15:49:14 +0530 Subject: [PATCH] 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 deletion(-) create mode 100644 glibc-rh1047979.patch 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 +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 - 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 - 2.18-11 - Allow ldconfig cached objects previously marked as hard or soft ABI to now become unmarked without raising an error. This works