diff --git a/gnu/local.mk b/gnu/local.mk index f2a7b6b984..ef6533bd8d 100644 --- a/gnu/local.mk +++ b/gnu/local.mk @@ -1016,14 +1016,6 @@ dist_patch_DATA = \ %D%/packages/patches/ghostscript-no-header-uuid.patch \ %D%/packages/patches/ghostscript-no-header-creationdate.patch \ %D%/packages/patches/glib-tests-timer.patch \ - %D%/packages/patches/glibc-CVE-2015-5180.patch \ - %D%/packages/patches/glibc-CVE-2015-7547.patch \ - %D%/packages/patches/glibc-CVE-2016-3075.patch \ - %D%/packages/patches/glibc-CVE-2016-3706.patch \ - %D%/packages/patches/glibc-CVE-2016-4429.patch \ - %D%/packages/patches/glibc-CVE-2017-1000366-pt1.patch \ - %D%/packages/patches/glibc-CVE-2017-1000366-pt2.patch \ - %D%/packages/patches/glibc-CVE-2017-1000366-pt3.patch \ %D%/packages/patches/glibc-CVE-2018-11236.patch \ %D%/packages/patches/glibc-CVE-2018-11237.patch \ %D%/packages/patches/glibc-CVE-2019-7309.patch \ @@ -1045,9 +1037,7 @@ dist_patch_DATA = \ %D%/packages/patches/glibc-ldd-x86_64.patch \ %D%/packages/patches/glibc-locales.patch \ %D%/packages/patches/glibc-locales-2.28.patch \ - %D%/packages/patches/glibc-o-largefile.patch \ %D%/packages/patches/glibc-reinstate-prlimit64-fallback.patch \ - %D%/packages/patches/glibc-vectorized-strcspn-guards.patch \ %D%/packages/patches/glibc-versioned-locpath.patch \ %D%/packages/patches/glibc-2.27-git-fixes.patch \ %D%/packages/patches/glibc-2.28-git-fixes.patch \ diff --git a/gnu/packages/base.scm b/gnu/packages/base.scm index 7116708743..6cd7ed749b 100644 --- a/gnu/packages/base.scm +++ b/gnu/packages/base.scm @@ -1014,118 +1014,6 @@ with the Linux kernel.") "glibc-CVE-2018-11237.patch")))) (properties `((lint-hidden-cve . ("CVE-2017-18269")))))) ; glibc-2.27-git-fixes -(define-public glibc-2.26 - (package - (inherit glibc) - ;; This version number corresponds to the output of `git describe` and the - ;; archive can be generated by checking out the commit ID and running: - ;; git archive --prefix=$(git describe)/ HEAD | xz > $(git describe).tar.xz - ;; See for why this was necessary. - (version "2.26.105-g0890d5379c") - (source (origin - (inherit (package-source glibc)) - (uri (string-append "https://alpha.gnu.org/gnu/guix/mirror/" - "glibc-" (version-major+minor version) "-" - (caddr (string-split version #\.)) ".tar.xz")) - (sha256 - (base32 - "1jck0c1i248sn02rvsfjykk77qncma34bjq89dyy2irwm50d7s3g")) - (patches (search-patches "glibc-ldd-x86_64.patch" - "glibc-versioned-locpath.patch" - "glibc-allow-kernel-2.6.32.patch")))))) - -(define-public glibc-2.25 - (package - (inherit glibc) - (version "2.25") - (source (origin - (inherit (package-source glibc)) - (uri (string-append "mirror://gnu/glibc/glibc-" - version ".tar.xz")) - (sha256 - (base32 - "1813dzkgw6v8q8q1m4v96yfis7vjqc9pslqib6j9mrwh6fxxjyq6")) - (patches (search-patches "glibc-ldd-x86_64.patch" - "glibc-versioned-locpath.patch" - "glibc-vectorized-strcspn-guards.patch" - "glibc-CVE-2017-1000366-pt1.patch" - "glibc-CVE-2017-1000366-pt2.patch" - "glibc-CVE-2017-1000366-pt3.patch")))))) - -(define-public glibc-2.24 - (package - (inherit glibc) - (version "2.24") - (source (origin - (inherit (package-source glibc)) - (uri (string-append "mirror://gnu/glibc/glibc-" - version ".tar.xz")) - (sha256 - (base32 - "1lxmprg9gm73gvafxd503x70z32phwjzcy74i0adfi6ixzla7m4r")) - (patches (search-patches "glibc-ldd-x86_64.patch" - "glibc-versioned-locpath.patch" - "glibc-vectorized-strcspn-guards.patch" - "glibc-CVE-2015-5180.patch" - "glibc-CVE-2017-1000366-pt1.patch" - "glibc-CVE-2017-1000366-pt2.patch" - "glibc-CVE-2017-1000366-pt3.patch")))))) - -(define-public glibc-2.23 - (package - (inherit glibc) - (version "2.23") - (source (origin - (inherit (package-source glibc)) - (uri (string-append "mirror://gnu/glibc/glibc-" - version ".tar.xz")) - (sha256 - (base32 - "1s8krs3y2n6pzav7ic59dz41alqalphv7vww4138ag30wh0fpvwl")) - (patches (search-patches "glibc-ldd-x86_64.patch" - "glibc-versioned-locpath.patch" - "glibc-vectorized-strcspn-guards.patch" - "glibc-CVE-2015-5180.patch" - "glibc-CVE-2016-3075.patch" - "glibc-CVE-2016-3706.patch" - "glibc-CVE-2016-4429.patch" - "glibc-CVE-2017-1000366-pt1.patch" - "glibc-CVE-2017-1000366-pt2.patch" - "glibc-CVE-2017-1000366-pt3.patch")))))) - -(define-public glibc-2.22 - (package - (inherit glibc) - (version "2.22") - (source (origin - (inherit (package-source glibc)) - (uri (string-append "mirror://gnu/glibc/glibc-" - version ".tar.xz")) - (sha256 - (base32 - "0j49682pm2nh4qbdw35bas82p1pgfnz4d2l7iwfyzvrvj0318wzb")) - (patches (search-patches "glibc-ldd-x86_64.patch" - "glibc-o-largefile.patch" - "glibc-vectorized-strcspn-guards.patch" - "glibc-CVE-2015-5180.patch" - "glibc-CVE-2015-7547.patch" - "glibc-CVE-2016-3075.patch" - "glibc-CVE-2016-3706.patch" - "glibc-CVE-2016-4429.patch" - "glibc-CVE-2017-1000366-pt1.patch" - "glibc-CVE-2017-1000366-pt2.patch" - "glibc-CVE-2017-1000366-pt3.patch")))) - (arguments - (substitute-keyword-arguments (package-arguments glibc) - ((#:phases phases) - `(modify-phases ,phases - (add-before 'configure 'fix-pwd - (lambda _ - ;; Use `pwd' instead of `/bin/pwd' for glibc-2.22. - (substitute* "configure" - (("/bin/pwd") "pwd")) - #t)))))))) - (define-public (make-gcc-libc base-gcc libc) "Return a GCC that targets LIBC." (package (inherit base-gcc) diff --git a/gnu/packages/patches/glibc-CVE-2015-5180.patch b/gnu/packages/patches/glibc-CVE-2015-5180.patch deleted file mode 100644 index 92e3740fc1..0000000000 --- a/gnu/packages/patches/glibc-CVE-2015-5180.patch +++ /dev/null @@ -1,311 +0,0 @@ -From b3b37f1a5559a7620e31c8053ed1b44f798f2b6d Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Sat, 31 Dec 2016 20:22:09 +0100 -Subject: [PATCH] CVE-2015-5180: resolv: Fix crash with internal QTYPE [BZ - #18784] - -Also rename T_UNSPEC because an upcoming public header file -update will use that name. - -(cherry picked from commit fc82b0a2dfe7dbd35671c10510a8da1043d746a5) ---- - ChangeLog | 14 ++++ - NEWS | 6 ++ - include/arpa/nameser_compat.h | 6 +- - resolv/Makefile | 5 ++ - resolv/nss_dns/dns-host.c | 2 +- - resolv/res_mkquery.c | 4 + - resolv/res_query.c | 6 +- - resolv/tst-resolv-qtypes.c | 185 ++++++++++++++++++++++++++++++++++++++++++ - 8 files changed, 221 insertions(+), 7 deletions(-) - create mode 100644 resolv/tst-resolv-qtypes.c - -diff --git a/include/arpa/nameser_compat.h b/include/arpa/nameser_compat.h -index 2e735ed..7c0deed 100644 ---- a/include/arpa/nameser_compat.h -+++ b/include/arpa/nameser_compat.h -@@ -1,8 +1,8 @@ - #ifndef _ARPA_NAMESER_COMPAT_ - #include - --/* Picksome unused number to represent lookups of IPv4 and IPv6 (i.e., -- T_A and T_AAAA). */ --#define T_UNSPEC 62321 -+/* The number is outside the 16-bit RR type range and is used -+ internally by the implementation. */ -+#define T_QUERY_A_AND_AAAA 439963904 - - #endif -diff --git a/resolv/Makefile b/resolv/Makefile -index 8be41d3..a4c86b9 100644 ---- a/resolv/Makefile -+++ b/resolv/Makefile -@@ -40,6 +40,9 @@ ifeq ($(have-thread-library),yes) - extra-libs += libanl - routines += gai_sigqueue - tests += tst-res_hconf_reorder -+ -+# This test sends millions of packets and is rather slow. -+xtests += tst-resolv-qtypes - endif - extra-libs-others = $(extra-libs) - libresolv-routines := gethnamaddr res_comp res_debug \ -@@ -117,3 +120,5 @@ tst-leaks2-ENV = MALLOC_TRACE=$(objpfx)tst-leaks2.mtrace - $(objpfx)mtrace-tst-leaks2.out: $(objpfx)tst-leaks2.out - $(common-objpfx)malloc/mtrace $(objpfx)tst-leaks2.mtrace > $@; \ - $(evaluate-test) -+ -+$(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) -diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c -index 5f9e357..d16fa4b 100644 ---- a/resolv/nss_dns/dns-host.c -+++ b/resolv/nss_dns/dns-host.c -@@ -323,7 +323,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat, - - int olderr = errno; - enum nss_status status; -- int n = __libc_res_nsearch (&_res, name, C_IN, T_UNSPEC, -+ int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA, - host_buffer.buf->buf, 2048, &host_buffer.ptr, - &ans2p, &nans2p, &resplen2, &ans2p_malloced); - if (n >= 0) -diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c -index 12f9730..d80b531 100644 ---- a/resolv/res_mkquery.c -+++ b/resolv/res_mkquery.c -@@ -103,6 +103,10 @@ res_nmkquery(res_state statp, - int n; - u_char *dnptrs[20], **dpp, **lastdnptr; - -+ if (class < 0 || class > 65535 -+ || type < 0 || type > 65535) -+ return -1; -+ - #ifdef DEBUG - if (statp->options & RES_DEBUG) - printf(";; res_nmkquery(%s, %s, %s, %s)\n", -diff --git a/resolv/res_query.c b/resolv/res_query.c -index 944d1a9..07dc6f6 100644 ---- a/resolv/res_query.c -+++ b/resolv/res_query.c -@@ -122,7 +122,7 @@ __libc_res_nquery(res_state statp, - int n, use_malloc = 0; - u_int oflags = statp->_flags; - -- size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE; -+ size_t bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * QUERYSIZE; - u_char *buf = alloca (bufsize); - u_char *query1 = buf; - int nquery1 = -1; -@@ -137,7 +137,7 @@ __libc_res_nquery(res_state statp, - printf(";; res_query(%s, %d, %d)\n", name, class, type); - #endif - -- if (type == T_UNSPEC) -+ if (type == T_QUERY_A_AND_AAAA) - { - n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL, - query1, bufsize); -@@ -190,7 +190,7 @@ __libc_res_nquery(res_state statp, - if (__builtin_expect (n <= 0, 0) && !use_malloc) { - /* Retry just in case res_nmkquery failed because of too - short buffer. Shouldn't happen. */ -- bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET; -+ bufsize = (type == T_QUERY_A_AND_AAAA ? 2 : 1) * MAXPACKET; - buf = malloc (bufsize); - if (buf != NULL) { - query1 = buf; -diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c -new file mode 100644 -index 0000000..b3e60c6 ---- /dev/null -+++ b/resolv/tst-resolv-qtypes.c -@@ -0,0 +1,185 @@ -+/* Exercise low-level query functions with different QTYPEs. -+ Copyright (C) 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 -+ . */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* If ture, the response function will send the actual response packet -+ over TCP instead of UDP. */ -+static volatile bool force_tcp; -+ -+/* Send back a fake resource record matching the QTYPE. */ -+static void -+response (const struct resolv_response_context *ctx, -+ struct resolv_response_builder *b, -+ const char *qname, uint16_t qclass, uint16_t qtype) -+{ -+ if (force_tcp && ctx->tcp) -+ { -+ resolv_response_init (b, (struct resolv_response_flags) { .tc = 1 }); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ return; -+ } -+ -+ resolv_response_init (b, (struct resolv_response_flags) { }); -+ resolv_response_add_question (b, qname, qclass, qtype); -+ resolv_response_section (b, ns_s_an); -+ resolv_response_open_record (b, qname, qclass, qtype, 0); -+ resolv_response_add_data (b, &qtype, sizeof (qtype)); -+ resolv_response_close_record (b); -+} -+ -+static const const char *domain = "www.example.com"; -+ -+static int -+wrap_res_query (int type, unsigned char *answer, int answer_length) -+{ -+ return res_query (domain, C_IN, type, answer, answer_length); -+} -+ -+static int -+wrap_res_search (int type, unsigned char *answer, int answer_length) -+{ -+ return res_query (domain, C_IN, type, answer, answer_length); -+} -+ -+static int -+wrap_res_querydomain (int type, unsigned char *answer, int answer_length) -+{ -+ return res_querydomain ("www", "example.com", C_IN, type, -+ answer, answer_length); -+} -+ -+static int -+wrap_res_send (int type, unsigned char *answer, int answer_length) -+{ -+ unsigned char buf[512]; -+ int ret = res_mkquery (QUERY, domain, C_IN, type, -+ (const unsigned char *) "", 0, NULL, -+ buf, sizeof (buf)); -+ if (type < 0 || type >= 65536) -+ { -+ /* res_mkquery fails for out-of-range record types. */ -+ TEST_VERIFY_EXIT (ret == -1); -+ return -1; -+ } -+ TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ -+ return res_send (buf, ret, answer, answer_length); -+} -+ -+static int -+wrap_res_nquery (int type, unsigned char *answer, int answer_length) -+{ -+ return res_nquery (&_res, domain, C_IN, type, answer, answer_length); -+} -+ -+static int -+wrap_res_nsearch (int type, unsigned char *answer, int answer_length) -+{ -+ return res_nquery (&_res, domain, C_IN, type, answer, answer_length); -+} -+ -+static int -+wrap_res_nquerydomain (int type, unsigned char *answer, int answer_length) -+{ -+ return res_nquerydomain (&_res, "www", "example.com", C_IN, type, -+ answer, answer_length); -+} -+ -+static int -+wrap_res_nsend (int type, unsigned char *answer, int answer_length) -+{ -+ unsigned char buf[512]; -+ int ret = res_nmkquery (&_res, QUERY, domain, C_IN, type, -+ (const unsigned char *) "", 0, NULL, -+ buf, sizeof (buf)); -+ if (type < 0 || type >= 65536) -+ { -+ /* res_mkquery fails for out-of-range record types. */ -+ TEST_VERIFY_EXIT (ret == -1); -+ return -1; -+ } -+ TEST_VERIFY_EXIT (ret > 12); /* DNS header length. */ -+ return res_nsend (&_res, buf, ret, answer, answer_length); -+} -+ -+static void -+test_function (const char *fname, -+ int (*func) (int type, -+ unsigned char *answer, int answer_length)) -+{ -+ unsigned char buf[512]; -+ for (int tcp = 0; tcp < 2; ++tcp) -+ { -+ force_tcp = tcp; -+ for (unsigned int type = 1; type <= 65535; ++type) -+ { -+ if (test_verbose) -+ printf ("info: sending QTYPE %d with %s (tcp=%d)\n", -+ type, fname, tcp); -+ int ret = func (type, buf, sizeof (buf)); -+ if (ret != 47) -+ FAIL_EXIT1 ("%s tcp=%d qtype=%d return value %d", -+ fname,tcp, type, ret); -+ /* One question, one answer record. */ -+ TEST_VERIFY (memcmp (buf + 4, "\0\1\0\1\0\0\0\0", 8) == 0); -+ /* Question section. */ -+ static const char qname[] = "\3www\7example\3com"; -+ size_t qname_length = sizeof (qname); -+ TEST_VERIFY (memcmp (buf + 12, qname, qname_length) == 0); -+ /* RDATA part of answer. */ -+ uint16_t type16 = type; -+ TEST_VERIFY (memcmp (buf + ret - 2, &type16, sizeof (type16)) == 0); -+ } -+ } -+ -+ TEST_VERIFY (func (-1, buf, sizeof (buf) == -1)); -+ TEST_VERIFY (func (65536, buf, sizeof (buf) == -1)); -+} -+ -+static int -+do_test (void) -+{ -+ struct resolv_redirect_config config = -+ { -+ .response_callback = response, -+ }; -+ struct resolv_test *obj = resolv_test_start (config); -+ -+ test_function ("res_query", &wrap_res_query); -+ test_function ("res_search", &wrap_res_search); -+ test_function ("res_querydomain", &wrap_res_querydomain); -+ test_function ("res_send", &wrap_res_send); -+ -+ test_function ("res_nquery", &wrap_res_nquery); -+ test_function ("res_nsearch", &wrap_res_nsearch); -+ test_function ("res_nquerydomain", &wrap_res_nquerydomain); -+ test_function ("res_nsend", &wrap_res_nsend); -+ -+ resolv_test_end (obj); -+ return 0; -+} -+ -+#define TIMEOUT 300 -+#include --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2015-7547.patch b/gnu/packages/patches/glibc-CVE-2015-7547.patch deleted file mode 100644 index 12abeb76d4..0000000000 --- a/gnu/packages/patches/glibc-CVE-2015-7547.patch +++ /dev/null @@ -1,590 +0,0 @@ -From b995d95a5943785be3ab862b2d3276f3b4a22481 Mon Sep 17 00:00:00 2001 -From: Carlos O'Donell -Date: Tue, 16 Feb 2016 21:26:37 -0500 -Subject: [PATCH] CVE-2015-7547: getaddrinfo() stack-based buffer overflow (Bug - 18665). - -* A stack-based buffer overflow was found in libresolv when invoked from - libnss_dns, allowing specially crafted DNS responses to seize control - of execution flow in the DNS client. The buffer overflow occurs in - the functions send_dg (send datagram) and send_vc (send TCP) for the - NSS module libnss_dns.so.2 when calling getaddrinfo with AF_UNSPEC - family. The use of AF_UNSPEC triggers the low-level resolver code to - send out two parallel queries for A and AAAA. A mismanagement of the - buffers used for those queries could result in the response of a query - writing beyond the alloca allocated buffer created by - _nss_dns_gethostbyname4_r. Buffer management is simplified to remove - the overflow. Thanks to the Google Security Team and Red Hat for - reporting the security impact of this issue, and Robert Holiday of - Ciena for reporting the related bug 18665. (CVE-2015-7547) - -See also: -https://sourceware.org/ml/libc-alpha/2016-02/msg00416.html -https://sourceware.org/ml/libc-alpha/2016-02/msg00418.html - -(cherry picked from commit e9db92d3acfe1822d56d11abcea5bfc4c41cf6ca) ---- - ChangeLog | 15 +++ - NEWS | 14 +++ - resolv/nss_dns/dns-host.c | 111 ++++++++++++++++++- - resolv/res_query.c | 3 + - resolv/res_send.c | 264 ++++++++++++++++++++++++++++++++++------------ - 5 files changed, 338 insertions(+), 69 deletions(-) - -diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c -index 357ac04..a0fe9a8 100644 ---- a/resolv/nss_dns/dns-host.c -+++ b/resolv/nss_dns/dns-host.c -@@ -1031,7 +1031,10 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, - int h_namelen = 0; - - if (ancount == 0) -- return NSS_STATUS_NOTFOUND; -+ { -+ *h_errnop = HOST_NOT_FOUND; -+ return NSS_STATUS_NOTFOUND; -+ } - - while (ancount-- > 0 && cp < end_of_message && had_error == 0) - { -@@ -1208,7 +1211,14 @@ gaih_getanswer_slice (const querybuf *answer, int anslen, const char *qname, - /* Special case here: if the resolver sent a result but it only - contains a CNAME while we are looking for a T_A or T_AAAA record, - we fail with NOTFOUND instead of TRYAGAIN. */ -- return canon == NULL ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND; -+ if (canon != NULL) -+ { -+ *h_errnop = HOST_NOT_FOUND; -+ return NSS_STATUS_NOTFOUND; -+ } -+ -+ *h_errnop = NETDB_INTERNAL; -+ return NSS_STATUS_TRYAGAIN; - } - - -@@ -1222,11 +1232,101 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, - - enum nss_status status = NSS_STATUS_NOTFOUND; - -+ /* Combining the NSS status of two distinct queries requires some -+ compromise and attention to symmetry (A or AAAA queries can be -+ returned in any order). What follows is a breakdown of how this -+ code is expected to work and why. We discuss only SUCCESS, -+ TRYAGAIN, NOTFOUND and UNAVAIL, since they are the only returns -+ that apply (though RETURN and MERGE exist). We make a distinction -+ between TRYAGAIN (recoverable) and TRYAGAIN' (not-recoverable). -+ A recoverable TRYAGAIN is almost always due to buffer size issues -+ and returns ERANGE in errno and the caller is expected to retry -+ with a larger buffer. -+ -+ Lastly, you may be tempted to make significant changes to the -+ conditions in this code to bring about symmetry between responses. -+ Please don't change anything without due consideration for -+ expected application behaviour. Some of the synthesized responses -+ aren't very well thought out and sometimes appear to imply that -+ IPv4 responses are always answer 1, and IPv6 responses are always -+ answer 2, but that's not true (see the implementation of send_dg -+ and send_vc to see response can arrive in any order, particularly -+ for UDP). However, we expect it holds roughly enough of the time -+ that this code works, but certainly needs to be fixed to make this -+ a more robust implementation. -+ -+ ---------------------------------------------- -+ | Answer 1 Status / | Synthesized | Reason | -+ | Answer 2 Status | Status | | -+ |--------------------------------------------| -+ | SUCCESS/SUCCESS | SUCCESS | [1] | -+ | SUCCESS/TRYAGAIN | TRYAGAIN | [5] | -+ | SUCCESS/TRYAGAIN' | SUCCESS | [1] | -+ | SUCCESS/NOTFOUND | SUCCESS | [1] | -+ | SUCCESS/UNAVAIL | SUCCESS | [1] | -+ | TRYAGAIN/SUCCESS | TRYAGAIN | [2] | -+ | TRYAGAIN/TRYAGAIN | TRYAGAIN | [2] | -+ | TRYAGAIN/TRYAGAIN' | TRYAGAIN | [2] | -+ | TRYAGAIN/NOTFOUND | TRYAGAIN | [2] | -+ | TRYAGAIN/UNAVAIL | TRYAGAIN | [2] | -+ | TRYAGAIN'/SUCCESS | SUCCESS | [3] | -+ | TRYAGAIN'/TRYAGAIN | TRYAGAIN | [3] | -+ | TRYAGAIN'/TRYAGAIN' | TRYAGAIN' | [3] | -+ | TRYAGAIN'/NOTFOUND | TRYAGAIN' | [3] | -+ | TRYAGAIN'/UNAVAIL | UNAVAIL | [3] | -+ | NOTFOUND/SUCCESS | SUCCESS | [3] | -+ | NOTFOUND/TRYAGAIN | TRYAGAIN | [3] | -+ | NOTFOUND/TRYAGAIN' | TRYAGAIN' | [3] | -+ | NOTFOUND/NOTFOUND | NOTFOUND | [3] | -+ | NOTFOUND/UNAVAIL | UNAVAIL | [3] | -+ | UNAVAIL/SUCCESS | UNAVAIL | [4] | -+ | UNAVAIL/TRYAGAIN | UNAVAIL | [4] | -+ | UNAVAIL/TRYAGAIN' | UNAVAIL | [4] | -+ | UNAVAIL/NOTFOUND | UNAVAIL | [4] | -+ | UNAVAIL/UNAVAIL | UNAVAIL | [4] | -+ ---------------------------------------------- -+ -+ [1] If the first response is a success we return success. -+ This ignores the state of the second answer and in fact -+ incorrectly sets errno and h_errno to that of the second -+ answer. However because the response is a success we ignore -+ *errnop and *h_errnop (though that means you touched errno on -+ success). We are being conservative here and returning the -+ likely IPv4 response in the first answer as a success. -+ -+ [2] If the first response is a recoverable TRYAGAIN we return -+ that instead of looking at the second response. The -+ expectation here is that we have failed to get an IPv4 response -+ and should retry both queries. -+ -+ [3] If the first response was not a SUCCESS and the second -+ response is not NOTFOUND (had a SUCCESS, need to TRYAGAIN, -+ or failed entirely e.g. TRYAGAIN' and UNAVAIL) then use the -+ result from the second response, otherwise the first responses -+ status is used. Again we have some odd side-effects when the -+ second response is NOTFOUND because we overwrite *errnop and -+ *h_errnop that means that a first answer of NOTFOUND might see -+ its *errnop and *h_errnop values altered. Whether it matters -+ in practice that a first response NOTFOUND has the wrong -+ *errnop and *h_errnop is undecided. -+ -+ [4] If the first response is UNAVAIL we return that instead of -+ looking at the second response. The expectation here is that -+ it will have failed similarly e.g. configuration failure. -+ -+ [5] Testing this code is complicated by the fact that truncated -+ second response buffers might be returned as SUCCESS if the -+ first answer is a SUCCESS. To fix this we add symmetry to -+ TRYAGAIN with the second response. If the second response -+ is a recoverable error we now return TRYAGIN even if the first -+ response was SUCCESS. */ -+ - if (anslen1 > 0) - status = gaih_getanswer_slice(answer1, anslen1, qname, - &pat, &buffer, &buflen, - errnop, h_errnop, ttlp, - &first); -+ - if ((status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND - || (status == NSS_STATUS_TRYAGAIN - /* We want to look at the second answer in case of an -@@ -1242,8 +1342,15 @@ gaih_getanswer (const querybuf *answer1, int anslen1, const querybuf *answer2, - &pat, &buffer, &buflen, - errnop, h_errnop, ttlp, - &first); -+ /* Use the second response status in some cases. */ - if (status != NSS_STATUS_SUCCESS && status2 != NSS_STATUS_NOTFOUND) - status = status2; -+ /* Do not return a truncated second response (unless it was -+ unavoidable e.g. unrecoverable TRYAGAIN). */ -+ if (status == NSS_STATUS_SUCCESS -+ && (status2 == NSS_STATUS_TRYAGAIN -+ && *errnop == ERANGE && *h_errnop != NO_RECOVERY)) -+ status = NSS_STATUS_TRYAGAIN; - } - - return status; -diff --git a/resolv/res_query.c b/resolv/res_query.c -index 4a9b3b3..95470a9 100644 ---- a/resolv/res_query.c -+++ b/resolv/res_query.c -@@ -396,6 +396,7 @@ __libc_res_nsearch(res_state statp, - { - free (*answerp2); - *answerp2 = NULL; -+ *nanswerp2 = 0; - *answerp2_malloced = 0; - } - } -@@ -447,6 +448,7 @@ __libc_res_nsearch(res_state statp, - { - free (*answerp2); - *answerp2 = NULL; -+ *nanswerp2 = 0; - *answerp2_malloced = 0; - } - -@@ -521,6 +523,7 @@ __libc_res_nsearch(res_state statp, - { - free (*answerp2); - *answerp2 = NULL; -+ *nanswerp2 = 0; - *answerp2_malloced = 0; - } - if (saved_herrno != -1) -diff --git a/resolv/res_send.c b/resolv/res_send.c -index 5e53cc2..6511bb1 100644 ---- a/resolv/res_send.c -+++ b/resolv/res_send.c -@@ -1,3 +1,20 @@ -+/* Copyright (C) 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 -+ . */ -+ - /* - * Copyright (c) 1985, 1989, 1993 - * The Regents of the University of California. All rights reserved. -@@ -363,6 +380,8 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen, - #ifdef USE_HOOKS - if (__glibc_unlikely (statp->qhook || statp->rhook)) { - if (anssiz < MAXPACKET && ansp) { -+ /* Always allocate MAXPACKET, callers expect -+ this specific size. */ - u_char *buf = malloc (MAXPACKET); - if (buf == NULL) - return (-1); -@@ -638,6 +657,77 @@ get_nsaddr (res_state statp, int n) - return (struct sockaddr *) (void *) &statp->nsaddr_list[n]; - } - -+/* The send_vc function is responsible for sending a DNS query over TCP -+ to the nameserver numbered NS from the res_state STATP i.e. -+ EXT(statp).nssocks[ns]. The function supports sending both IPv4 and -+ IPv6 queries at the same serially on the same socket. -+ -+ Please note that for TCP there is no way to disable sending both -+ queries, unlike UDP, which honours RES_SNGLKUP and RES_SNGLKUPREOP -+ and sends the queries serially and waits for the result after each -+ sent query. This implemetnation should be corrected to honour these -+ options. -+ -+ Please also note that for TCP we send both queries over the same -+ socket one after another. This technically violates best practice -+ since the server is allowed to read the first query, respond, and -+ then close the socket (to service another client). If the server -+ does this, then the remaining second query in the socket data buffer -+ will cause the server to send the client an RST which will arrive -+ asynchronously and the client's OS will likely tear down the socket -+ receive buffer resulting in a potentially short read and lost -+ response data. This will force the client to retry the query again, -+ and this process may repeat until all servers and connection resets -+ are exhausted and then the query will fail. It's not known if this -+ happens with any frequency in real DNS server implementations. This -+ implementation should be corrected to use two sockets by default for -+ parallel queries. -+ -+ The query stored in BUF of BUFLEN length is sent first followed by -+ the query stored in BUF2 of BUFLEN2 length. Queries are sent -+ serially on the same socket. -+ -+ Answers to the query are stored firstly in *ANSP up to a max of -+ *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP -+ is non-NULL (to indicate that modifying the answer buffer is allowed) -+ then malloc is used to allocate a new response buffer and ANSCP and -+ ANSP will both point to the new buffer. If more than *ANSSIZP bytes -+ are needed but ANSCP is NULL, then as much of the response as -+ possible is read into the buffer, but the results will be truncated. -+ When truncation happens because of a small answer buffer the DNS -+ packets header field TC will bet set to 1, indicating a truncated -+ message and the rest of the socket data will be read and discarded. -+ -+ Answers to the query are stored secondly in *ANSP2 up to a max of -+ *ANSSIZP2 bytes, with the actual response length stored in -+ *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2 -+ is non-NULL (required for a second query) then malloc is used to -+ allocate a new response buffer, *ANSSIZP2 is set to the new buffer -+ size and *ANSP2_MALLOCED is set to 1. -+ -+ The ANSP2_MALLOCED argument will eventually be removed as the -+ change in buffer pointer can be used to detect the buffer has -+ changed and that the caller should use free on the new buffer. -+ -+ Note that the answers may arrive in any order from the server and -+ therefore the first and second answer buffers may not correspond to -+ the first and second queries. -+ -+ It is not supported to call this function with a non-NULL ANSP2 -+ but a NULL ANSCP. Put another way, you can call send_vc with a -+ single unmodifiable buffer or two modifiable buffers, but no other -+ combination is supported. -+ -+ It is the caller's responsibility to free the malloc allocated -+ buffers by detecting that the pointers have changed from their -+ original values i.e. *ANSCP or *ANSP2 has changed. -+ -+ If errors are encountered then *TERRNO is set to an appropriate -+ errno value and a zero result is returned for a recoverable error, -+ and a less-than zero result is returned for a non-recoverable error. -+ -+ If no errors are encountered then *TERRNO is left unmodified and -+ a the length of the first response in bytes is returned. */ - static int - send_vc(res_state statp, - const u_char *buf, int buflen, const u_char *buf2, int buflen2, -@@ -647,11 +737,7 @@ send_vc(res_state statp, - { - const HEADER *hp = (HEADER *) buf; - const HEADER *hp2 = (HEADER *) buf2; -- u_char *ans = *ansp; -- int orig_anssizp = *anssizp; -- // XXX REMOVE -- // int anssiz = *anssizp; -- HEADER *anhp = (HEADER *) ans; -+ HEADER *anhp = (HEADER *) *ansp; - struct sockaddr *nsap = get_nsaddr (statp, ns); - int truncating, connreset, n; - /* On some architectures compiler might emit a warning indicating -@@ -743,6 +829,8 @@ send_vc(res_state statp, - * Receive length & response - */ - int recvresp1 = 0; -+ /* Skip the second response if there is no second query. -+ To do that we mark the second response as received. */ - int recvresp2 = buf2 == NULL; - uint16_t rlen16; - read_len: -@@ -779,40 +867,14 @@ send_vc(res_state statp, - u_char **thisansp; - int *thisresplenp; - if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { -+ /* We have not received any responses -+ yet or we only have one response to -+ receive. */ - thisanssizp = anssizp; - thisansp = anscp ?: ansp; - assert (anscp != NULL || ansp2 == NULL); - thisresplenp = &resplen; - } else { -- if (*anssizp != MAXPACKET) { -- /* No buffer allocated for the first -- reply. We can try to use the rest -- of the user-provided buffer. */ --#if __GNUC_PREREQ (4, 7) -- DIAG_PUSH_NEEDS_COMMENT; -- DIAG_IGNORE_NEEDS_COMMENT (5, "-Wmaybe-uninitialized"); --#endif --#if _STRING_ARCH_unaligned -- *anssizp2 = orig_anssizp - resplen; -- *ansp2 = *ansp + resplen; --#else -- int aligned_resplen -- = ((resplen + __alignof__ (HEADER) - 1) -- & ~(__alignof__ (HEADER) - 1)); -- *anssizp2 = orig_anssizp - aligned_resplen; -- *ansp2 = *ansp + aligned_resplen; --#endif --#if __GNUC_PREREQ (4, 7) -- DIAG_POP_NEEDS_COMMENT; --#endif -- } else { -- /* The first reply did not fit into the -- user-provided buffer. Maybe the second -- answer will. */ -- *anssizp2 = orig_anssizp; -- *ansp2 = *ansp; -- } -- - thisanssizp = anssizp2; - thisansp = ansp2; - thisresplenp = resplen2; -@@ -820,10 +882,14 @@ send_vc(res_state statp, - anhp = (HEADER *) *thisansp; - - *thisresplenp = rlen; -- if (rlen > *thisanssizp) { -- /* Yes, we test ANSCP here. If we have two buffers -- both will be allocatable. */ -- if (__glibc_likely (anscp != NULL)) { -+ /* Is the answer buffer too small? */ -+ if (*thisanssizp < rlen) { -+ /* If the current buffer is not the the static -+ user-supplied buffer then we can reallocate -+ it. */ -+ if (thisansp != NULL && thisansp != ansp) { -+ /* Always allocate MAXPACKET, callers expect -+ this specific size. */ - u_char *newp = malloc (MAXPACKET); - if (newp == NULL) { - *terrno = ENOMEM; -@@ -835,6 +901,9 @@ send_vc(res_state statp, - if (thisansp == ansp2) - *ansp2_malloced = 1; - anhp = (HEADER *) newp; -+ /* A uint16_t can't be larger than MAXPACKET -+ thus it's safe to allocate MAXPACKET but -+ read RLEN bytes instead. */ - len = rlen; - } else { - Dprint(statp->options & RES_DEBUG, -@@ -997,6 +1066,66 @@ reopen (res_state statp, int *terrno, int ns) - return 1; - } - -+/* The send_dg function is responsible for sending a DNS query over UDP -+ to the nameserver numbered NS from the res_state STATP i.e. -+ EXT(statp).nssocks[ns]. The function supports IPv4 and IPv6 queries -+ along with the ability to send the query in parallel for both stacks -+ (default) or serially (RES_SINGLKUP). It also supports serial lookup -+ with a close and reopen of the socket used to talk to the server -+ (RES_SNGLKUPREOP) to work around broken name servers. -+ -+ The query stored in BUF of BUFLEN length is sent first followed by -+ the query stored in BUF2 of BUFLEN2 length. Queries are sent -+ in parallel (default) or serially (RES_SINGLKUP or RES_SNGLKUPREOP). -+ -+ Answers to the query are stored firstly in *ANSP up to a max of -+ *ANSSIZP bytes. If more than *ANSSIZP bytes are needed and ANSCP -+ is non-NULL (to indicate that modifying the answer buffer is allowed) -+ then malloc is used to allocate a new response buffer and ANSCP and -+ ANSP will both point to the new buffer. If more than *ANSSIZP bytes -+ are needed but ANSCP is NULL, then as much of the response as -+ possible is read into the buffer, but the results will be truncated. -+ When truncation happens because of a small answer buffer the DNS -+ packets header field TC will bet set to 1, indicating a truncated -+ message, while the rest of the UDP packet is discarded. -+ -+ Answers to the query are stored secondly in *ANSP2 up to a max of -+ *ANSSIZP2 bytes, with the actual response length stored in -+ *RESPLEN2. If more than *ANSSIZP bytes are needed and ANSP2 -+ is non-NULL (required for a second query) then malloc is used to -+ allocate a new response buffer, *ANSSIZP2 is set to the new buffer -+ size and *ANSP2_MALLOCED is set to 1. -+ -+ The ANSP2_MALLOCED argument will eventually be removed as the -+ change in buffer pointer can be used to detect the buffer has -+ changed and that the caller should use free on the new buffer. -+ -+ Note that the answers may arrive in any order from the server and -+ therefore the first and second answer buffers may not correspond to -+ the first and second queries. -+ -+ It is not supported to call this function with a non-NULL ANSP2 -+ but a NULL ANSCP. Put another way, you can call send_vc with a -+ single unmodifiable buffer or two modifiable buffers, but no other -+ combination is supported. -+ -+ It is the caller's responsibility to free the malloc allocated -+ buffers by detecting that the pointers have changed from their -+ original values i.e. *ANSCP or *ANSP2 has changed. -+ -+ If an answer is truncated because of UDP datagram DNS limits then -+ *V_CIRCUIT is set to 1 and the return value non-zero to indicate to -+ the caller to retry with TCP. The value *GOTSOMEWHERE is set to 1 -+ if any progress was made reading a response from the nameserver and -+ is used by the caller to distinguish between ECONNREFUSED and -+ ETIMEDOUT (the latter if *GOTSOMEWHERE is 1). -+ -+ If errors are encountered then *TERRNO is set to an appropriate -+ errno value and a zero result is returned for a recoverable error, -+ and a less-than zero result is returned for a non-recoverable error. -+ -+ If no errors are encountered then *TERRNO is left unmodified and -+ a the length of the first response in bytes is returned. */ - static int - send_dg(res_state statp, - const u_char *buf, int buflen, const u_char *buf2, int buflen2, -@@ -1006,8 +1135,6 @@ send_dg(res_state statp, - { - const HEADER *hp = (HEADER *) buf; - const HEADER *hp2 = (HEADER *) buf2; -- u_char *ans = *ansp; -- int orig_anssizp = *anssizp; - struct timespec now, timeout, finish; - struct pollfd pfd[1]; - int ptimeout; -@@ -1040,6 +1167,8 @@ send_dg(res_state statp, - int need_recompute = 0; - int nwritten = 0; - int recvresp1 = 0; -+ /* Skip the second response if there is no second query. -+ To do that we mark the second response as received. */ - int recvresp2 = buf2 == NULL; - pfd[0].fd = EXT(statp).nssocks[ns]; - pfd[0].events = POLLOUT; -@@ -1203,55 +1332,56 @@ send_dg(res_state statp, - int *thisresplenp; - - if ((recvresp1 | recvresp2) == 0 || buf2 == NULL) { -+ /* We have not received any responses -+ yet or we only have one response to -+ receive. */ - thisanssizp = anssizp; - thisansp = anscp ?: ansp; - assert (anscp != NULL || ansp2 == NULL); - thisresplenp = &resplen; - } else { -- if (*anssizp != MAXPACKET) { -- /* No buffer allocated for the first -- reply. We can try to use the rest -- of the user-provided buffer. */ --#if _STRING_ARCH_unaligned -- *anssizp2 = orig_anssizp - resplen; -- *ansp2 = *ansp + resplen; --#else -- int aligned_resplen -- = ((resplen + __alignof__ (HEADER) - 1) -- & ~(__alignof__ (HEADER) - 1)); -- *anssizp2 = orig_anssizp - aligned_resplen; -- *ansp2 = *ansp + aligned_resplen; --#endif -- } else { -- /* The first reply did not fit into the -- user-provided buffer. Maybe the second -- answer will. */ -- *anssizp2 = orig_anssizp; -- *ansp2 = *ansp; -- } -- - thisanssizp = anssizp2; - thisansp = ansp2; - thisresplenp = resplen2; - } - - if (*thisanssizp < MAXPACKET -- /* Yes, we test ANSCP here. If we have two buffers -- both will be allocatable. */ -- && anscp -+ /* If the current buffer is not the the static -+ user-supplied buffer then we can reallocate -+ it. */ -+ && (thisansp != NULL && thisansp != ansp) - #ifdef FIONREAD -+ /* Is the size too small? */ - && (ioctl (pfd[0].fd, FIONREAD, thisresplenp) < 0 - || *thisanssizp < *thisresplenp) - #endif - ) { -+ /* Always allocate MAXPACKET, callers expect -+ this specific size. */ - u_char *newp = malloc (MAXPACKET); - if (newp != NULL) { -- *anssizp = MAXPACKET; -- *thisansp = ans = newp; -+ *thisanssizp = MAXPACKET; -+ *thisansp = newp; - if (thisansp == ansp2) - *ansp2_malloced = 1; - } - } -+ /* We could end up with truncation if anscp was NULL -+ (not allowed to change caller's buffer) and the -+ response buffer size is too small. This isn't a -+ reliable way to detect truncation because the ioctl -+ may be an inaccurate report of the UDP message size. -+ Therefore we use this only to issue debug output. -+ To do truncation accurately with UDP we need -+ MSG_TRUNC which is only available on Linux. We -+ can abstract out the Linux-specific feature in the -+ future to detect truncation. */ -+ if (__glibc_unlikely (*thisanssizp < *thisresplenp)) { -+ Dprint(statp->options & RES_DEBUG, -+ (stdout, ";; response may be truncated (UDP)\n") -+ ); -+ } -+ - HEADER *anhp = (HEADER *) *thisansp; - socklen_t fromlen = sizeof(struct sockaddr_in6); - assert (sizeof(from) <= fromlen); --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2016-3075.patch b/gnu/packages/patches/glibc-CVE-2016-3075.patch deleted file mode 100644 index d16722806e..0000000000 --- a/gnu/packages/patches/glibc-CVE-2016-3075.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 146b58d11fddbef15b888906e3be4f33900c416f Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Tue, 29 Mar 2016 12:57:56 +0200 -Subject: [PATCH] CVE-2016-3075: Stack overflow in _nss_dns_getnetbyname_r [BZ - #19879] - -The defensive copy is not needed because the name may not alias the -output buffer. - -(cherry picked from commit 317b199b4aff8cfa27f2302ab404d2bb5032b9a4) -(cherry picked from commit 883dceebc8f11921a9890211a4e202e5be17562f) ---- - ChangeLog | 7 +++++++ - NEWS | 10 ++++++++-- - resolv/nss_dns/dns-network.c | 5 +---- - 3 files changed, 16 insertions(+), 6 deletions(-) - -diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c -index 2eb2f67..8f301a7 100644 ---- a/resolv/nss_dns/dns-network.c -+++ b/resolv/nss_dns/dns-network.c -@@ -118,17 +118,14 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result, - } net_buffer; - querybuf *orig_net_buffer; - int anslen; -- char *qbuf; - enum nss_status status; - - if (__res_maybe_init (&_res, 0) == -1) - return NSS_STATUS_UNAVAIL; - -- qbuf = strdupa (name); -- - net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024); - -- anslen = __libc_res_nsearch (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf, -+ anslen = __libc_res_nsearch (&_res, name, C_IN, T_PTR, net_buffer.buf->buf, - 1024, &net_buffer.ptr, NULL, NULL, NULL, NULL); - if (anslen < 0) - { --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2016-3706.patch b/gnu/packages/patches/glibc-CVE-2016-3706.patch deleted file mode 100644 index 617242df24..0000000000 --- a/gnu/packages/patches/glibc-CVE-2016-3706.patch +++ /dev/null @@ -1,188 +0,0 @@ -From 1a8a7c12950a0026a3c406a7cb1608f96aa1460e Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Fri, 29 Apr 2016 10:35:34 +0200 -Subject: [PATCH] CVE-2016-3706: getaddrinfo: stack overflow in hostent - conversion [BZ #20010] - -When converting a struct hostent response to struct gaih_addrtuple, the -gethosts macro (which is called from gaih_inet) used alloca, without -malloc fallback for large responses. This commit changes this code to -use calloc unconditionally. - -This commit also consolidated a second hostent-to-gaih_addrtuple -conversion loop (in gaih_inet) to use the new conversion function. - -(cherry picked from commit 4ab2ab03d4351914ee53248dc5aef4a8c88ff8b9) ---- - ChangeLog | 10 ++++ - sysdeps/posix/getaddrinfo.c | 130 +++++++++++++++++++++++--------------------- - 2 files changed, 79 insertions(+), 61 deletions(-) - -diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c -index 1ef3f20..fed2d3b 100644 ---- a/sysdeps/posix/getaddrinfo.c -+++ b/sysdeps/posix/getaddrinfo.c -@@ -168,9 +168,58 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, - return 0; - } - -+/* Convert struct hostent to a list of struct gaih_addrtuple objects. -+ h_name is not copied, and the struct hostent object must not be -+ deallocated prematurely. *RESULT must be NULL or a pointer to an -+ object allocated using malloc, which is freed. */ -+static bool -+convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, -+ int family, -+ struct hostent *h, -+ struct gaih_addrtuple **result) -+{ -+ free (*result); -+ *result = NULL; -+ -+ /* Count the number of addresses in h->h_addr_list. */ -+ size_t count = 0; -+ for (char **p = h->h_addr_list; *p != NULL; ++p) -+ ++count; -+ -+ /* Report no data if no addresses are available, or if the incoming -+ address size is larger than what we can store. */ -+ if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) -+ return true; -+ -+ struct gaih_addrtuple *array = calloc (count, sizeof (*array)); -+ if (array == NULL) -+ return false; -+ -+ for (size_t i = 0; i < count; ++i) -+ { -+ if (family == AF_INET && req->ai_family == AF_INET6) -+ { -+ /* Perform address mapping. */ -+ array[i].family = AF_INET6; -+ memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t)); -+ array[i].addr[2] = htonl (0xffff); -+ } -+ else -+ { -+ array[i].family = family; -+ memcpy (array[i].addr, h->h_addr_list[i], h->h_length); -+ } -+ array[i].next = array + i + 1; -+ } -+ array[0].name = h->h_name; -+ array[count - 1].next = NULL; -+ -+ *result = array; -+ return true; -+} -+ - #define gethosts(_family, _type) \ - { \ -- int i; \ - int herrno; \ - struct hostent th; \ - struct hostent *h; \ -@@ -219,36 +268,23 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, - } \ - else if (h != NULL) \ - { \ -- for (i = 0; h->h_addr_list[i]; i++) \ -+ /* Make sure that addrmem can be freed. */ \ -+ if (!malloc_addrmem) \ -+ addrmem = NULL; \ -+ if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem)) \ - { \ -- if (*pat == NULL) \ -- { \ -- *pat = __alloca (sizeof (struct gaih_addrtuple)); \ -- (*pat)->scopeid = 0; \ -- } \ -- uint32_t *addr = (*pat)->addr; \ -- (*pat)->next = NULL; \ -- (*pat)->name = i == 0 ? strdupa (h->h_name) : NULL; \ -- if (_family == AF_INET && req->ai_family == AF_INET6) \ -- { \ -- (*pat)->family = AF_INET6; \ -- addr[3] = *(uint32_t *) h->h_addr_list[i]; \ -- addr[2] = htonl (0xffff); \ -- addr[1] = 0; \ -- addr[0] = 0; \ -- } \ -- else \ -- { \ -- (*pat)->family = _family; \ -- memcpy (addr, h->h_addr_list[i], sizeof(_type)); \ -- } \ -- pat = &((*pat)->next); \ -+ _res.options |= old_res_options & RES_USE_INET6; \ -+ result = -EAI_SYSTEM; \ -+ goto free_and_return; \ - } \ -+ *pat = addrmem; \ -+ /* The conversion uses malloc unconditionally. */ \ -+ malloc_addrmem = true; \ - \ - if (localcanon != NULL && canon == NULL) \ - canon = strdupa (localcanon); \ - \ -- if (_family == AF_INET6 && i > 0) \ -+ if (_family == AF_INET6 && *pat != NULL) \ - got_ipv6 = true; \ - } \ - } -@@ -612,44 +648,16 @@ gaih_inet (const char *name, const struct gaih_service *service, - { - if (h != NULL) - { -- int i; -- /* We found data, count the number of addresses. */ -- for (i = 0; h->h_addr_list[i]; ++i) -- ; -- if (i > 0 && *pat != NULL) -- --i; -- -- if (__libc_use_alloca (alloca_used -- + i * sizeof (struct gaih_addrtuple))) -- addrmem = alloca_account (i * sizeof (struct gaih_addrtuple), -- alloca_used); -- else -- { -- addrmem = malloc (i -- * sizeof (struct gaih_addrtuple)); -- if (addrmem == NULL) -- { -- result = -EAI_MEMORY; -- goto free_and_return; -- } -- malloc_addrmem = true; -- } -- -- /* Now convert it into the list. */ -- struct gaih_addrtuple *addrfree = addrmem; -- for (i = 0; h->h_addr_list[i]; ++i) -+ /* We found data, convert it. */ -+ if (!convert_hostent_to_gaih_addrtuple -+ (req, AF_INET, h, &addrmem)) - { -- if (*pat == NULL) -- { -- *pat = addrfree++; -- (*pat)->scopeid = 0; -- } -- (*pat)->next = NULL; -- (*pat)->family = AF_INET; -- memcpy ((*pat)->addr, h->h_addr_list[i], -- h->h_length); -- pat = &((*pat)->next); -+ result = -EAI_MEMORY; -+ goto free_and_return; - } -+ *pat = addrmem; -+ /* The conversion uses malloc unconditionally. */ -+ malloc_addrmem = true; - } - } - else --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2016-4429.patch b/gnu/packages/patches/glibc-CVE-2016-4429.patch deleted file mode 100644 index 5eebd10543..0000000000 --- a/gnu/packages/patches/glibc-CVE-2016-4429.patch +++ /dev/null @@ -1,58 +0,0 @@ -From bdce95930e1d9a7d013d1ba78740243491262879 Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Mon, 23 May 2016 20:18:34 +0200 -Subject: [PATCH] CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call [BZ - #20112] - -The call is technically in a loop, and under certain circumstances -(which are quite difficult to reproduce in a test case), alloca -can be invoked repeatedly during a single call to clntudp_call. -As a result, the available stack space can be exhausted (even -though individual alloca sizes are bounded implicitly by what -can fit into a UDP packet, as a side effect of the earlier -successful send operation). - -(cherry picked from commit bc779a1a5b3035133024b21e2f339fe4219fb11c) ---- - ChangeLog | 7 +++++++ - NEWS | 4 ++++ - sunrpc/clnt_udp.c | 10 +++++++++- - 3 files changed, 20 insertions(+), 1 deletion(-) - -diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c -index a6cf5f1..4d9acb1 100644 ---- a/sunrpc/clnt_udp.c -+++ b/sunrpc/clnt_udp.c -@@ -388,9 +388,15 @@ send_again: - struct sock_extended_err *e; - struct sockaddr_in err_addr; - struct iovec iov; -- char *cbuf = (char *) alloca (outlen + 256); -+ char *cbuf = malloc (outlen + 256); - int ret; - -+ if (cbuf == NULL) -+ { -+ cu->cu_error.re_errno = errno; -+ return (cu->cu_error.re_status = RPC_CANTRECV); -+ } -+ - iov.iov_base = cbuf + 256; - iov.iov_len = outlen; - msg.msg_name = (void *) &err_addr; -@@ -415,10 +421,12 @@ send_again: - cmsg = CMSG_NXTHDR (&msg, cmsg)) - if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) - { -+ free (cbuf); - e = (struct sock_extended_err *) CMSG_DATA(cmsg); - cu->cu_error.re_errno = e->ee_errno; - return (cu->cu_error.re_status = RPC_CANTRECV); - } -+ free (cbuf); - } - #endif - do --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2017-1000366-pt1.patch b/gnu/packages/patches/glibc-CVE-2017-1000366-pt1.patch deleted file mode 100644 index 71e80968be..0000000000 --- a/gnu/packages/patches/glibc-CVE-2017-1000366-pt1.patch +++ /dev/null @@ -1,36 +0,0 @@ -From f6110a8fee2ca36f8e2d2abecf3cba9fa7b8ea7d Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Mon, 19 Jun 2017 17:09:55 +0200 -Subject: [PATCH] CVE-2017-1000366: Ignore LD_LIBRARY_PATH for AT_SECURE=1 - programs [BZ #21624] - -LD_LIBRARY_PATH can only be used to reorder system search paths, which -is not useful functionality. - -This makes an exploitable unbounded alloca in _dl_init_paths unreachable -for AT_SECURE=1 programs. - -patch from: -https://sourceware.org/git/?p=glibc.git;a=commit;h=f6110a8fee2ca36f8e2d2abecf3cba9fa7b8ea7d ---- - ChangeLog | 7 +++++++ - elf/rtld.c | 3 ++- - 2 files changed, 9 insertions(+), 1 deletion(-) - -diff --git a/elf/rtld.c b/elf/rtld.c -index 2446a87..2269dbe 100644 ---- a/elf/rtld.c -+++ b/elf/rtld.c -@@ -2422,7 +2422,8 @@ process_envvars (enum mode *modep) - - case 12: - /* The library search path. */ -- if (memcmp (envline, "LIBRARY_PATH", 12) == 0) -+ if (!__libc_enable_secure -+ && memcmp (envline, "LIBRARY_PATH", 12) == 0) - { - library_path = &envline[13]; - break; --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2017-1000366-pt2.patch b/gnu/packages/patches/glibc-CVE-2017-1000366-pt2.patch deleted file mode 100644 index 4b859c4bfd..0000000000 --- a/gnu/packages/patches/glibc-CVE-2017-1000366-pt2.patch +++ /dev/null @@ -1,124 +0,0 @@ -From 6d0ba622891bed9d8394eef1935add53003b12e8 Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Mon, 19 Jun 2017 22:31:04 +0200 -Subject: [PATCH] ld.so: Reject overly long LD_PRELOAD path elements - -patch from: -https://sourceware.org/git/?p=glibc.git;a=patch;h=6d0ba622891bed9d8394eef1935add53003b12e8 - ---- - ChangeLog | 7 ++++++ - elf/rtld.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++------------ - 2 files changed, 73 insertions(+), 16 deletions(-) - -diff --git a/elf/rtld.c b/elf/rtld.c -index 2269dbe..86ae20c 100644 ---- a/elf/rtld.c -+++ b/elf/rtld.c -@@ -99,6 +99,35 @@ uintptr_t __pointer_chk_guard_local - strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) - #endif - -+/* Length limits for names and paths, to protect the dynamic linker, -+ particularly when __libc_enable_secure is active. */ -+#ifdef NAME_MAX -+# define SECURE_NAME_LIMIT NAME_MAX -+#else -+# define SECURE_NAME_LIMIT 255 -+#endif -+#ifdef PATH_MAX -+# define SECURE_PATH_LIMIT PATH_MAX -+#else -+# define SECURE_PATH_LIMIT 1024 -+#endif -+ -+/* Check that AT_SECURE=0, or that the passed name does not contain -+ directories and is not overly long. Reject empty names -+ unconditionally. */ -+static bool -+dso_name_valid_for_suid (const char *p) -+{ -+ if (__glibc_unlikely (__libc_enable_secure)) -+ { -+ /* Ignore pathnames with directories for AT_SECURE=1 -+ programs, and also skip overlong names. */ -+ size_t len = strlen (p); -+ if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL) -+ return false; -+ } -+ return *p != '\0'; -+} - - /* List of auditing DSOs. */ - static struct audit_list -@@ -718,6 +747,42 @@ static const char *preloadlist attribute_relro; - /* Nonzero if information about versions has to be printed. */ - static int version_info attribute_relro; - -+/* The LD_PRELOAD environment variable gives list of libraries -+ separated by white space or colons that are loaded before the -+ executable's dependencies and prepended to the global scope list. -+ (If the binary is running setuid all elements containing a '/' are -+ ignored since it is insecure.) Return the number of preloads -+ performed. */ -+unsigned int -+handle_ld_preload (const char *preloadlist, struct link_map *main_map) -+{ -+ unsigned int npreloads = 0; -+ const char *p = preloadlist; -+ char fname[SECURE_PATH_LIMIT]; -+ -+ while (*p != '\0') -+ { -+ /* Split preload list at space/colon. */ -+ size_t len = strcspn (p, " :"); -+ if (len > 0 && len < sizeof (fname)) -+ { -+ memcpy (fname, p, len); -+ fname[len] = '\0'; -+ } -+ else -+ fname[0] = '\0'; -+ -+ /* Skip over the substring and the following delimiter. */ -+ p += len; -+ if (*p != '\0') -+ ++p; -+ -+ if (dso_name_valid_for_suid (fname)) -+ npreloads += do_preload (fname, main_map, "LD_PRELOAD"); -+ } -+ return npreloads; -+} -+ - static void - dl_main (const ElfW(Phdr) *phdr, - ElfW(Word) phnum, -@@ -1464,23 +1529,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", - - if (__glibc_unlikely (preloadlist != NULL)) - { -- /* The LD_PRELOAD environment variable gives list of libraries -- separated by white space or colons that are loaded before the -- executable's dependencies and prepended to the global scope -- list. If the binary is running setuid all elements -- containing a '/' are ignored since it is insecure. */ -- char *list = strdupa (preloadlist); -- char *p; -- - HP_TIMING_NOW (start); -- -- /* Prevent optimizing strsep. Speed is not important here. */ -- while ((p = (strsep) (&list, " :")) != NULL) -- if (p[0] != '\0' -- && (__builtin_expect (! __libc_enable_secure, 1) -- || strchr (p, '/') == NULL)) -- npreloads += do_preload (p, main_map, "LD_PRELOAD"); -- -+ npreloads += handle_ld_preload (preloadlist, main_map); - HP_TIMING_NOW (stop); - HP_TIMING_DIFF (diff, start, stop); - HP_TIMING_ACCUM_NT (load_time, diff); --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-CVE-2017-1000366-pt3.patch b/gnu/packages/patches/glibc-CVE-2017-1000366-pt3.patch deleted file mode 100644 index 3d8f6d2bf8..0000000000 --- a/gnu/packages/patches/glibc-CVE-2017-1000366-pt3.patch +++ /dev/null @@ -1,206 +0,0 @@ -From 81b82fb966ffbd94353f793ad17116c6088dedd9 Mon Sep 17 00:00:00 2001 -From: Florian Weimer -Date: Mon, 19 Jun 2017 22:32:12 +0200 -Subject: [PATCH] ld.so: Reject overly long LD_AUDIT path elements - -Also only process the last LD_AUDIT entry. - -patch from: -https://sourceware.org/git/?p=glibc.git;a=commit;h=81b82fb966ffbd94353f793ad17116c6088dedd9 - ---- - ChangeLog | 11 +++++++ - elf/rtld.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------- - 2 files changed, 106 insertions(+), 15 deletions(-) - -diff --git a/elf/rtld.c b/elf/rtld.c -index 86ae20c..65647fb 100644 ---- a/elf/rtld.c -+++ b/elf/rtld.c -@@ -129,13 +129,91 @@ dso_name_valid_for_suid (const char *p) - return *p != '\0'; - } - --/* List of auditing DSOs. */ -+/* LD_AUDIT variable contents. Must be processed before the -+ audit_list below. */ -+const char *audit_list_string; -+ -+/* Cyclic list of auditing DSOs. audit_list->next is the first -+ element. */ - static struct audit_list - { - const char *name; - struct audit_list *next; - } *audit_list; - -+/* Iterator for audit_list_string followed by audit_list. */ -+struct audit_list_iter -+{ -+ /* Tail of audit_list_string still needing processing, or NULL. */ -+ const char *audit_list_tail; -+ -+ /* The list element returned in the previous iteration. NULL before -+ the first element. */ -+ struct audit_list *previous; -+ -+ /* Scratch buffer for returning a name which is part of -+ audit_list_string. */ -+ char fname[SECURE_NAME_LIMIT]; -+}; -+ -+/* Initialize an audit list iterator. */ -+static void -+audit_list_iter_init (struct audit_list_iter *iter) -+{ -+ iter->audit_list_tail = audit_list_string; -+ iter->previous = NULL; -+} -+ -+/* Iterate through both audit_list_string and audit_list. */ -+static const char * -+audit_list_iter_next (struct audit_list_iter *iter) -+{ -+ if (iter->audit_list_tail != NULL) -+ { -+ /* First iterate over audit_list_string. */ -+ while (*iter->audit_list_tail != '\0') -+ { -+ /* Split audit list at colon. */ -+ size_t len = strcspn (iter->audit_list_tail, ":"); -+ if (len > 0 && len < sizeof (iter->fname)) -+ { -+ memcpy (iter->fname, iter->audit_list_tail, len); -+ iter->fname[len] = '\0'; -+ } -+ else -+ /* Do not return this name to the caller. */ -+ iter->fname[0] = '\0'; -+ -+ /* Skip over the substring and the following delimiter. */ -+ iter->audit_list_tail += len; -+ if (*iter->audit_list_tail == ':') -+ ++iter->audit_list_tail; -+ -+ /* If the name is valid, return it. */ -+ if (dso_name_valid_for_suid (iter->fname)) -+ return iter->fname; -+ /* Otherwise, wrap around and try the next name. */ -+ } -+ /* Fall through to the procesing of audit_list. */ -+ } -+ -+ if (iter->previous == NULL) -+ { -+ if (audit_list == NULL) -+ /* No pre-parsed audit list. */ -+ return NULL; -+ /* Start of audit list. The first list element is at -+ audit_list->next (cyclic list). */ -+ iter->previous = audit_list->next; -+ return iter->previous->name; -+ } -+ if (iter->previous == audit_list) -+ /* Cyclic list wrap-around. */ -+ return NULL; -+ iter->previous = iter->previous->next; -+ return iter->previous->name; -+} -+ - #ifndef HAVE_INLINED_SYSCALLS - /* Set nonzero during loading and initialization of executable and - libraries, cleared before the executable's entry point runs. This -@@ -1305,11 +1383,13 @@ of this helper program; chances are you did not intend to run this program.\n\ - GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); - - /* If we have auditing DSOs to load, do it now. */ -- if (__glibc_unlikely (audit_list != NULL)) -+ bool need_security_init = true; -+ if (__glibc_unlikely (audit_list != NULL) -+ || __glibc_unlikely (audit_list_string != NULL)) - { -- /* Iterate over all entries in the list. The order is important. */ - struct audit_ifaces *last_audit = NULL; -- struct audit_list *al = audit_list->next; -+ struct audit_list_iter al_iter; -+ audit_list_iter_init (&al_iter); - - /* Since we start using the auditing DSOs right away we need to - initialize the data structures now. */ -@@ -1320,9 +1400,14 @@ of this helper program; chances are you did not intend to run this program.\n\ - use different values (especially the pointer guard) and will - fail later on. */ - security_init (); -+ need_security_init = false; - -- do -+ while (true) - { -+ const char *name = audit_list_iter_next (&al_iter); -+ if (name == NULL) -+ break; -+ - int tls_idx = GL(dl_tls_max_dtv_idx); - - /* Now it is time to determine the layout of the static TLS -@@ -1331,7 +1416,7 @@ of this helper program; chances are you did not intend to run this program.\n\ - no DF_STATIC_TLS bit is set. The reason is that we know - glibc will use the static model. */ - struct dlmopen_args dlmargs; -- dlmargs.fname = al->name; -+ dlmargs.fname = name; - dlmargs.map = NULL; - - const char *objname; -@@ -1344,7 +1429,7 @@ of this helper program; chances are you did not intend to run this program.\n\ - not_loaded: - _dl_error_printf ("\ - ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", -- al->name, err_str); -+ name, err_str); - if (malloced) - free ((char *) err_str); - } -@@ -1448,10 +1533,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", - goto not_loaded; - } - } -- -- al = al->next; - } -- while (al != audit_list->next); - - /* If we have any auditing modules, announce that we already - have two objects loaded. */ -@@ -1715,7 +1797,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", - if (tcbp == NULL) - tcbp = init_tls (); - -- if (__glibc_likely (audit_list == NULL)) -+ if (__glibc_likely (need_security_init)) - /* Initialize security features. But only if we have not done it - earlier. */ - security_init (); -@@ -2346,9 +2428,7 @@ process_dl_audit (char *str) - char *p; - - while ((p = (strsep) (&str, ":")) != NULL) -- if (p[0] != '\0' -- && (__builtin_expect (! __libc_enable_secure, 1) -- || strchr (p, '/') == NULL)) -+ if (dso_name_valid_for_suid (p)) - { - /* This is using the local malloc, not the system malloc. The - memory can never be freed. */ -@@ -2412,7 +2492,7 @@ process_envvars (enum mode *modep) - break; - } - if (memcmp (envline, "AUDIT", 5) == 0) -- process_dl_audit (&envline[6]); -+ audit_list_string = &envline[6]; - break; - - case 7: --- -2.9.3 - diff --git a/gnu/packages/patches/glibc-o-largefile.patch b/gnu/packages/patches/glibc-o-largefile.patch deleted file mode 100644 index 2b0ae8c8bb..0000000000 --- a/gnu/packages/patches/glibc-o-largefile.patch +++ /dev/null @@ -1,25 +0,0 @@ -This fixes -whereby, on 32-bit platforms, libc 2.22 would fail to pass O_LARGEFILE -to 'openat'. This was caught by 'tests/sparse03.at' in the tar -test suite. - -commit eb32b0d40308166c4d8f6330cc2958cb1e545075 -Author: Andreas Schwab -Date: Mon Aug 10 14:12:47 2015 +0200 - - Readd O_LARGEFILE flag for openat64 (bug 18781) - ---- a/sysdeps/unix/sysv/linux/openat.c -+++ b/sysdeps/unix/sysv/linux/openat.c -@@ -68,6 +68,11 @@ __OPENAT (int fd, const char *file, int oflag, ...) - va_end (arg); - } - -+ /* We have to add the O_LARGEFILE flag for openat64. */ -+#ifdef MORE_OFLAGS -+ oflag |= MORE_OFLAGS; -+#endif -+ - return SYSCALL_CANCEL (openat, fd, file, oflag, mode); - } - libc_hidden_def (__OPENAT) diff --git a/gnu/packages/patches/glibc-vectorized-strcspn-guards.patch b/gnu/packages/patches/glibc-vectorized-strcspn-guards.patch deleted file mode 100644 index 3d6c7749d4..0000000000 --- a/gnu/packages/patches/glibc-vectorized-strcspn-guards.patch +++ /dev/null @@ -1,23 +0,0 @@ -Copied from Debian. - -2017-06-14 Florian Weimer - - * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. - * sysdeps/i386/i686/multiarch/varshift.c: Likewise. - ---- a/sysdeps/i386/i686/multiarch/strcspn-c.c -+++ b/sysdeps/i386/i686/multiarch/strcspn-c.c -@@ -1,2 +1,4 @@ --#define __strcspn_sse2 __strcspn_ia32 --#include -+#if IS_IN (libc) -+# define __strcspn_sse2 __strcspn_ia32 -+# include -+#endif ---- a/sysdeps/i386/i686/multiarch/varshift.c -+++ b/sysdeps/i386/i686/multiarch/varshift.c -@@ -1 +1,3 @@ --#include -+#if IS_IN (libc) -+# include -+#endif