From 672ba56d201903900eb8e9cb6934770141d5b6eb Mon Sep 17 00:00:00 2001 From: Leah Neukirchen Date: Sun, 4 Jun 2017 00:04:56 +0200 Subject: [PATCH] glibc: rebuild with 15 upstream patches. Supersedes #5840. --- srcpkgs/glibc/patches/glibc-upstream-01.patch | 121 ++ srcpkgs/glibc/patches/glibc-upstream-02.patch | 161 ++ srcpkgs/glibc/patches/glibc-upstream-03.patch | 1611 +++++++++++++++++ srcpkgs/glibc/patches/glibc-upstream-04.patch | 201 ++ srcpkgs/glibc/patches/glibc-upstream-05.patch | 67 + srcpkgs/glibc/patches/glibc-upstream-06.patch | 52 + srcpkgs/glibc/patches/glibc-upstream-07.patch | 65 + srcpkgs/glibc/patches/glibc-upstream-08.patch | 63 + srcpkgs/glibc/patches/glibc-upstream-09.patch | 51 + srcpkgs/glibc/patches/glibc-upstream-10.patch | 71 + srcpkgs/glibc/patches/glibc-upstream-11.patch | 115 ++ srcpkgs/glibc/patches/glibc-upstream-12.patch | 59 + srcpkgs/glibc/patches/glibc-upstream-13.patch | 136 ++ srcpkgs/glibc/patches/glibc-upstream-14.patch | 236 +++ srcpkgs/glibc/patches/glibc-upstream-15.patch | 89 + .../glibc/patches/revert-memchr-i686.patch | 42 - srcpkgs/glibc/template | 2 +- 17 files changed, 3099 insertions(+), 43 deletions(-) create mode 100644 srcpkgs/glibc/patches/glibc-upstream-01.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-02.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-03.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-04.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-05.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-06.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-07.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-08.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-09.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-10.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-11.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-12.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-13.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-14.patch create mode 100644 srcpkgs/glibc/patches/glibc-upstream-15.patch delete mode 100644 srcpkgs/glibc/patches/revert-memchr-i686.patch diff --git a/srcpkgs/glibc/patches/glibc-upstream-01.patch b/srcpkgs/glibc/patches/glibc-upstream-01.patch new file mode 100644 index 0000000000..d5a0a4d407 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-01.patch @@ -0,0 +1,121 @@ +From 58520986c38e34db60e07260c64c563e3efcf353 Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar +Date: Thu, 9 Feb 2017 17:28:54 +0100 +Subject: [PATCH 01] Fix getting tunable values on big-endian (BZ #21109) + +The code to set value passed a tunable_val_t, which when cast to +int32_t on big-endian gives the wrong value. Instead, use +tunable_val_t.numval instead, which can then be safely cast into +int32_t. + +(cherry picked from commit 8cbc826c37c0221ada65a7a622fe079b4e89a4b0) +--- + ChangeLog | 10 ++++++++++ + NEWS | 6 ++++++ + elf/dl-tunable-types.h | 4 ++-- + elf/dl-tunables.c | 2 ++ + malloc/arena.c | 8 ++++---- + 5 files changed, 24 insertions(+), 6 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index f140ee6..c88238e 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,13 @@ ++2017-02-08 Siddhesh Poyarekar ++ ++ [BZ #21109] ++ * elf/dl-tunable-types.h (tunable_callback_t): Accept ++ tunable_val_t as argument. ++ * elf/dl-tunables.c (__tunable_set_val): Add comment. ++ * malloc/arena.c (set_mallopt_check): Take tunable_val_t as ++ argument. ++ (DL_TUNABLE_CALLBACK_FNDECL): Likewise. ++ + 2017-02-05 Siddhesh Poyarekar + + * version.h (RELEASE): Set to "stable" +diff --git a/NEWS b/NEWS +index ec15dde..325cac7 100644 +--- a/NEWS ++++ b/NEWS +@@ -5,6 +5,12 @@ See the end for copying conditions. + Please send GNU C library bug reports via + using `glibc' in the "product" field. + ++Version 2.25.1 ++ ++The following bugs are resolved with this release: ++ ++ [21109] Tunables broken on big-endian ++ + Version 2.25 + + * The feature test macro __STDC_WANT_LIB_EXT2__, from ISO/IEC TR +diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h +index a986f0b..37a4e80 100644 +--- a/elf/dl-tunable-types.h ++++ b/elf/dl-tunable-types.h +@@ -21,8 +21,6 @@ + # define _TUNABLE_TYPES_H_ + #include + +-typedef void (*tunable_callback_t) (void *); +- + typedef enum + { + TUNABLE_TYPE_INT_32, +@@ -43,6 +41,8 @@ typedef union + const char *strval; + } tunable_val_t; + ++typedef void (*tunable_callback_t) (tunable_val_t *); ++ + /* Security level for tunables. This decides what to do with individual + tunables for AT_SECURE binaries. */ + typedef enum +diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c +index a8d53d6..e42aa67 100644 +--- a/elf/dl-tunables.c ++++ b/elf/dl-tunables.c +@@ -455,6 +455,8 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) + if (cur->strval == NULL) + return; + ++ /* Caller does not need the value, just call the callback with our tunable ++ value. */ + if (valp == NULL) + goto cb; + +diff --git a/malloc/arena.c b/malloc/arena.c +index b91d7d6..d49e4a2 100644 +--- a/malloc/arena.c ++++ b/malloc/arena.c +@@ -212,9 +212,9 @@ __malloc_fork_unlock_child (void) + #if HAVE_TUNABLES + static inline int do_set_mallopt_check (int32_t value); + void +-DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) ++DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp) + { +- int32_t value = *(int32_t *) valp; ++ int32_t value = (int32_t) valp->numval; + do_set_mallopt_check (value); + if (check_action != 0) + __malloc_check_init (); +@@ -223,9 +223,9 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) + # define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \ + static inline int do_ ## __name (__type value); \ + void \ +-DL_TUNABLE_CALLBACK (__name) (void *valp) \ ++DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \ + { \ +- __type value = *(__type *) valp; \ ++ __type value = (__type) (valp)->numval; \ + do_ ## __name (value); \ + } + +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-02.patch b/srcpkgs/glibc/patches/glibc-upstream-02.patch new file mode 100644 index 0000000000..0b07aa3a49 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-02.patch @@ -0,0 +1,161 @@ +From 045e368799cd253ddbf8bdec42ed92e8ebb3ce67 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 28 Feb 2017 17:05:46 +0100 +Subject: [PATCH 02] sunrpc: Avoid use-after-free read access in + clntudp_call [BZ #21115] + +After commit bc779a1a5b3035133024b21e2f339fe4219fb11c +(CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call +[BZ #20112]), ancillary data is stored on the heap, +but it is accessed after it has been freed. + +The test case must be run under a heap debugger such as valgrind +to observe the invalid access. A malloc implementation which +immediately calls munmap on free would catch this bug as well. + +(cherry picked from commit d42eed4a044e5e10dfb885cf9891c2518a72a491) +--- + ChangeLog | 8 +++++++ + NEWS | 1 + + sunrpc/Makefile | 3 ++- + sunrpc/clnt_udp.c | 2 +- + sunrpc/tst-udp-error.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 5 files changed, 74 insertions(+), 2 deletions(-) + create mode 100644 sunrpc/tst-udp-error.c + +diff --git a/ChangeLog b/ChangeLog +index c88238e..3d781a3 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,11 @@ ++2017-02-27 Florian Weimer ++ ++ [BZ #21115] ++ * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later. ++ * sunrpc/Makefile (tests): Add tst-udp-error. ++ (tst-udp-error): Link against libc.so explicitly. ++ * sunrpc/tst-udp-error: New file. ++ + 2017-02-08 Siddhesh Poyarekar + + [BZ #21109] +diff --git a/NEWS b/NEWS +index 325cac7..5ecc565 100644 +--- a/NEWS ++++ b/NEWS +@@ -10,6 +10,7 @@ Version 2.25.1 + The following bugs are resolved with this release: + + [21109] Tunables broken on big-endian ++ [21115] sunrpc: Use-after-free in error path in clntudp_call + + Version 2.25 + +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 0c1e612..daf8a28 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -93,7 +93,7 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ + extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) + others += rpcgen + +-tests = tst-xdrmem tst-xdrmem2 test-rpcent ++tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error + xtests := tst-getmyaddr + + ifeq ($(have-thread-library),yes) +@@ -155,6 +155,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS) + $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so + $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so ++$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so + + $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs)) + +diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c +index 4d9acb1..1de25cb 100644 +--- a/sunrpc/clnt_udp.c ++++ b/sunrpc/clnt_udp.c +@@ -421,9 +421,9 @@ 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; ++ free (cbuf); + return (cu->cu_error.re_status = RPC_CANTRECV); + } + free (cbuf); +diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c +new file mode 100644 +index 0000000..1efc02f +--- /dev/null ++++ b/sunrpc/tst-udp-error.c +@@ -0,0 +1,62 @@ ++/* Check for use-after-free in clntudp_call (bug 21115). ++ Copyright (C) 2017 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 ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ /* Obtain a likely-unused port number. */ ++ struct sockaddr_in sin = ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ }; ++ { ++ int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); ++ xbind (fd, (struct sockaddr *) &sin, sizeof (sin)); ++ socklen_t sinlen = sizeof (sin); ++ xgetsockname (fd, (struct sockaddr *) &sin, &sinlen); ++ /* Close the socket, so that we will receive an error below. */ ++ close (fd); ++ } ++ ++ int sock = RPC_ANYSOCK; ++ CLIENT *clnt = clntudp_create ++ (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock); ++ TEST_VERIFY_EXIT (clnt != NULL); ++ TEST_VERIFY (clnt_call (clnt, 3, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 3, 0 })) ++ == RPC_CANTRECV); ++ clnt_destroy (clnt); ++ ++ return 0; ++} ++ ++#include +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-03.patch b/srcpkgs/glibc/patches/glibc-upstream-03.patch new file mode 100644 index 0000000000..7c9e367be3 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-03.patch @@ -0,0 +1,1611 @@ +From 93cf93e06ce123439e41d3d62790601c313134cb Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Tue, 28 Feb 2017 17:36:00 +0100 +Subject: [PATCH 03] sunrpc: Improvements for UDP client timeout handling + [BZ #20257] + +This commit fixes various aspects in the UDP client timeout handling. +Timeouts are now applied in a more consistent fashion. Discarded UDP +packets no longer prevent the timeout from happening at all. + +(cherry picked from commit cf0bd2f73bd65beab613865bba567d7787836888) +--- + ChangeLog | 23 +++ + NEWS | 1 + + inet/Makefile | 8 +- + inet/deadline.c | 122 +++++++++++++ + inet/net-internal.h | 89 ++++++++++ + inet/tst-deadline.c | 188 ++++++++++++++++++++ + sunrpc/Makefile | 10 +- + sunrpc/clnt_udp.c | 127 ++++++++------ + sunrpc/tst-udp-garbage.c | 104 +++++++++++ + sunrpc/tst-udp-nonblocking.c | 333 +++++++++++++++++++++++++++++++++++ + sunrpc/tst-udp-timeout.c | 402 +++++++++++++++++++++++++++++++++++++++++++ + 11 files changed, 1348 insertions(+), 59 deletions(-) + create mode 100644 inet/deadline.c + create mode 100644 inet/tst-deadline.c + create mode 100644 sunrpc/tst-udp-garbage.c + create mode 100644 sunrpc/tst-udp-nonblocking.c + create mode 100644 sunrpc/tst-udp-timeout.c + +diff --git a/ChangeLog b/ChangeLog +index 3d781a3..510ca42 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,26 @@ ++2017-02-28 Florian Weimer ++ ++ [BZ #20257] ++ * inet/Makefile (routines): Add deadline. ++ (tests-static): Add tst-deadline. ++ * inet/net-internal.h (struct deadline_current_time) ++ (__deadline_current_time, struct deadline, __deadline_is_infinite) ++ (__deadline_elapsed, __deadline_first, __deadline_from_timeval) ++ (__deadline_to_ms, __is_timeval_valid_timeout): Declare. ++ * inet/deadline.c: New file. ++ * inet/tst-deadline.c: Likewise. ++ * sunrpc/Makefile (tests): Add tst-udp-nonblocking, ++ tst-udp-timeout, tst-udp-garbage. ++ (tst-udp-nonblocking, tst-udp-timeout): Link against libc.so ++ explicitly. ++ (tst-udp-garbage): Likewise. Also link against thread library. ++ * sunrpc/clnt_udp.c (struct cu_data): Mention in comment that the ++ struct layout is part of the ABI. ++ (clntudp_call): Rework timeout handling. ++ * sunrpc/tst-udp-garbage.c: New file. ++ * sunrpc/tst-udp-nonblocking.c: Likewise. ++ * sunrpc/tst-udp-timeout.c: Likewise. ++ + 2017-02-27 Florian Weimer + + [BZ #21115] +diff --git a/NEWS b/NEWS +index 5ecc565..e7d6668 100644 +--- a/NEWS ++++ b/NEWS +@@ -11,6 +11,7 @@ The following bugs are resolved with this release: + + [21109] Tunables broken on big-endian + [21115] sunrpc: Use-after-free in error path in clntudp_call ++ [20257] sunrpc: clntudp_call does not enforce timeout when receiving data + + Version 2.25 + +diff --git a/inet/Makefile b/inet/Makefile +index 010792a..6a7d3e0 100644 +--- a/inet/Makefile ++++ b/inet/Makefile +@@ -45,14 +45,18 @@ routines := htonl htons \ + in6_addr getnameinfo if_index ifaddrs inet6_option \ + getipv4sourcefilter setipv4sourcefilter \ + getsourcefilter setsourcefilter inet6_opt inet6_rth \ +- inet6_scopeid_pton ++ inet6_scopeid_pton deadline + + aux := check_pf check_native ifreq + + tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \ + tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \ + tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \ +- tst-sockaddr tst-inet6_scopeid_pton test-hnto-types ++ tst-sockaddr tst-inet6_scopeid_pton test-hnto-types tst-deadline ++ ++# tst-deadline must be linked statically so that we can access ++# internal functions. ++tests-static += tst-deadline + + include ../Rules + +diff --git a/inet/deadline.c b/inet/deadline.c +new file mode 100644 +index 0000000..c1fa415 +--- /dev/null ++++ b/inet/deadline.c +@@ -0,0 +1,122 @@ ++/* Computing deadlines for timeouts. ++ Copyright (C) 2017 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 ++ ++struct deadline_current_time internal_function ++__deadline_current_time (void) ++{ ++ struct deadline_current_time result; ++ if (__clock_gettime (CLOCK_MONOTONIC, &result.current) != 0) ++ { ++ struct timeval current_tv; ++ if (__gettimeofday (¤t_tv, NULL) == 0) ++ __libc_fatal ("Fatal error: gettimeofday system call failed\n"); ++ result.current.tv_sec = current_tv.tv_sec; ++ result.current.tv_nsec = current_tv.tv_usec * 1000; ++ } ++ assert (result.current.tv_sec >= 0); ++ return result; ++} ++ ++/* A special deadline value for which __deadline_is_infinite is ++ true. */ ++static inline struct deadline ++infinite_deadline (void) ++{ ++ return (struct deadline) { { -1, -1 } }; ++} ++ ++struct deadline internal_function ++__deadline_from_timeval (struct deadline_current_time current, ++ struct timeval tv) ++{ ++ assert (__is_timeval_valid_timeout (tv)); ++ ++ /* Compute second-based deadline. Perform the addition in ++ uintmax_t, which is unsigned, to simply overflow detection. */ ++ uintmax_t sec = current.current.tv_sec; ++ sec += tv.tv_sec; ++ if (sec < (uintmax_t) tv.tv_sec) ++ return infinite_deadline (); ++ ++ /* Compute nanosecond deadline. */ ++ int nsec = current.current.tv_nsec + tv.tv_usec * 1000; ++ if (nsec >= 1000 * 1000 * 1000) ++ { ++ /* Carry nanosecond overflow to seconds. */ ++ nsec -= 1000 * 1000 * 1000; ++ if (sec + 1 < sec) ++ return infinite_deadline (); ++ ++sec; ++ } ++ /* This uses a GCC extension, otherwise these casts for detecting ++ overflow would not be defined. */ ++ if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec) ++ return infinite_deadline (); ++ ++ return (struct deadline) { { sec, nsec } }; ++} ++ ++int internal_function ++__deadline_to_ms (struct deadline_current_time current, ++ struct deadline deadline) ++{ ++ if (__deadline_is_infinite (deadline)) ++ return INT_MAX; ++ ++ if (current.current.tv_sec > deadline.absolute.tv_sec ++ || (current.current.tv_sec == deadline.absolute.tv_sec ++ && current.current.tv_nsec >= deadline.absolute.tv_nsec)) ++ return 0; ++ time_t sec = deadline.absolute.tv_sec - current.current.tv_sec; ++ if (sec >= INT_MAX) ++ /* This value will overflow below. */ ++ return INT_MAX; ++ int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec; ++ if (nsec < 0) ++ { ++ /* Borrow from the seconds field. */ ++ assert (sec > 0); ++ --sec; ++ nsec += 1000 * 1000 * 1000; ++ } ++ ++ /* Prepare for rounding up to milliseconds. */ ++ nsec += 999999; ++ if (nsec > 1000 * 1000 * 1000) ++ { ++ assert (sec < INT_MAX); ++ ++sec; ++ nsec -= 1000 * 1000 * 1000; ++ } ++ ++ unsigned int msec = nsec / (1000 * 1000); ++ if (sec > INT_MAX / 1000) ++ return INT_MAX; ++ msec += sec * 1000; ++ if (msec > INT_MAX) ++ return INT_MAX; ++ return msec; ++} +diff --git a/inet/net-internal.h b/inet/net-internal.h +index 087597e..2b2632c 100644 +--- a/inet/net-internal.h ++++ b/inet/net-internal.h +@@ -20,11 +20,100 @@ + #define _NET_INTERNAL_H 1 + + #include ++#include + #include ++#include + + int __inet6_scopeid_pton (const struct in6_addr *address, + const char *scope, uint32_t *result) + internal_function attribute_hidden; + libc_hidden_proto (__inet6_scopeid_pton) + ++ ++/* Deadline handling for enforcing timeouts. ++ ++ Code should call __deadline_current_time to obtain the current time ++ and cache it locally. The cache needs updating after every ++ long-running or potentially blocking operation. Deadlines relative ++ to the current time can be computed using __deadline_from_timeval. ++ The deadlines may have to be recomputed in response to certain ++ events (such as an incoming packet), but they are absolute (not ++ relative to the current time). A timeout suitable for use with the ++ poll function can be computed from such a deadline using ++ __deadline_to_ms. ++ ++ The fields in the structs defined belowed should only be used ++ within the implementation. */ ++ ++/* Cache of the current time. Used to compute deadlines from relative ++ timeouts and vice versa. */ ++struct deadline_current_time ++{ ++ struct timespec current; ++}; ++ ++/* Return the current time. Terminates the process if the current ++ time is not available. */ ++struct deadline_current_time __deadline_current_time (void) ++ internal_function attribute_hidden; ++ ++/* Computed absolute deadline. */ ++struct deadline ++{ ++ struct timespec absolute; ++}; ++ ++ ++/* For internal use only. */ ++static inline bool ++__deadline_is_infinite (struct deadline deadline) ++{ ++ return deadline.absolute.tv_nsec < 0; ++} ++ ++/* Return true if the current time is at the deadline or past it. */ ++static inline bool ++__deadline_elapsed (struct deadline_current_time current, ++ struct deadline deadline) ++{ ++ return !__deadline_is_infinite (deadline) ++ && (current.current.tv_sec > deadline.absolute.tv_sec ++ || (current.current.tv_sec == deadline.absolute.tv_sec ++ && current.current.tv_nsec >= deadline.absolute.tv_nsec)); ++} ++ ++/* Return the deadline which occurs first. */ ++static inline struct deadline ++__deadline_first (struct deadline left, struct deadline right) ++{ ++ if (__deadline_is_infinite (right) ++ || left.absolute.tv_sec < right.absolute.tv_sec ++ || (left.absolute.tv_sec == right.absolute.tv_sec ++ && left.absolute.tv_nsec < right.absolute.tv_nsec)) ++ return left; ++ else ++ return right; ++} ++ ++/* Add TV to the current time and return it. Returns a special ++ infinite absolute deadline on overflow. */ ++struct deadline __deadline_from_timeval (struct deadline_current_time, ++ struct timeval tv) ++ internal_function attribute_hidden; ++ ++/* Compute the number of milliseconds until the specified deadline, ++ from the current time in the argument. The result is mainly for ++ use with poll. If the deadline has already passed, return 0. If ++ the result would overflow an int, return INT_MAX. */ ++int __deadline_to_ms (struct deadline_current_time, struct deadline) ++ internal_function attribute_hidden; ++ ++/* Return true if TV.tv_sec is non-negative and TV.tv_usec is in the ++ interval [0, 999999]. */ ++static inline bool ++__is_timeval_valid_timeout (struct timeval tv) ++{ ++ return tv.tv_sec >= 0 && tv.tv_usec >= 0 && tv.tv_usec < 1000 * 1000; ++} ++ + #endif /* _NET_INTERNAL_H */ +diff --git a/inet/tst-deadline.c b/inet/tst-deadline.c +new file mode 100644 +index 0000000..ed04345 +--- /dev/null ++++ b/inet/tst-deadline.c +@@ -0,0 +1,188 @@ ++/* Tests for computing deadlines for timeouts. ++ Copyright (C) 2017 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 ++ ++/* Find the maximum value which can be represented in a time_t. */ ++static time_t ++time_t_max (void) ++{ ++ _Static_assert (0 > (time_t) -1, "time_t is signed"); ++ uintmax_t current = 1; ++ while (true) ++ { ++ uintmax_t next = current * 2; ++ /* This cannot happen because time_t is signed. */ ++ TEST_VERIFY_EXIT (next > current); ++ ++next; ++ if ((time_t) next < 0 || next != (uintmax_t) (time_t) next) ++ /* Value cannot be represented in time_t. Return the previous ++ value. */ ++ return current; ++ current = next; ++ } ++} ++ ++static int ++do_test (void) ++{ ++ { ++ struct deadline_current_time current_time = __deadline_current_time (); ++ TEST_VERIFY (current_time.current.tv_sec >= 0); ++ current_time = __deadline_current_time (); ++ /* Due to CLOCK_MONOTONIC, either seconds or nanoseconds are ++ greater than zero. This is also true for the gettimeofday ++ fallback. */ ++ TEST_VERIFY (current_time.current.tv_sec >= 0); ++ TEST_VERIFY (current_time.current.tv_sec > 0 ++ || current_time.current.tv_nsec > 0); ++ } ++ ++ /* Check basic computations of deadlines. */ ++ struct deadline_current_time current_time = { { 1, 123456789 } }; ++ struct deadline deadline = __deadline_from_timeval ++ (current_time, (struct timeval) { 0, 1 }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 123457789); ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1); ++ ++ deadline = __deadline_from_timeval ++ (current_time, ((struct timeval) { 0, 2 })); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 123458789); ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1); ++ ++ deadline = __deadline_from_timeval ++ (current_time, ((struct timeval) { 1, 0 })); ++ TEST_VERIFY (deadline.absolute.tv_sec == 2); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 123456789); ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ ++ /* Check if timeouts are correctly rounded up to the next ++ millisecond. */ ++ for (int i = 0; i < 999999; ++i) ++ { ++ ++current_time.current.tv_nsec; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ } ++ ++ /* A full millisecond has elapsed, so the time to the deadline is ++ now less than 1000. */ ++ ++current_time.current.tv_nsec; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999); ++ ++ /* Check __deadline_to_ms carry-over. */ ++ current_time = (struct deadline_current_time) { { 9, 123456789 } }; ++ deadline = (struct deadline) { { 10, 122456789 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999); ++ deadline = (struct deadline) { { 10, 122456790 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ deadline = (struct deadline) { { 10, 123456788 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ deadline = (struct deadline) { { 10, 123456789 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); ++ ++ /* Check __deadline_to_ms overflow. */ ++ deadline = (struct deadline) { { INT_MAX - 1, 1 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == INT_MAX); ++ ++ /* Check __deadline_to_ms for elapsed deadlines. */ ++ current_time = (struct deadline_current_time) { { 9, 123456789 } }; ++ deadline.absolute = current_time.current; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 9, 123456790 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 10, 0 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 10, 123456788 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ current_time = (struct deadline_current_time) { { 10, 123456789 } }; ++ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); ++ ++ /* Check carry-over in __deadline_from_timeval. */ ++ current_time = (struct deadline_current_time) { { 9, 998000001 } }; ++ for (int i = 0; i < 2000; ++i) ++ { ++ deadline = __deadline_from_timeval ++ (current_time, (struct timeval) { 1, i }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 10); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 998000001 + i * 1000); ++ } ++ for (int i = 2000; i < 3000; ++i) ++ { ++ deadline = __deadline_from_timeval ++ (current_time, (struct timeval) { 2, i }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 12); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 1 + (i - 2000) * 1000); ++ } ++ ++ /* Check infinite deadlines. */ ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1000 } }, ++ (struct timeval) { time_t_max (), 1 }); ++ TEST_VERIFY (__deadline_is_infinite (deadline)); ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1001 } }, ++ (struct timeval) { time_t_max (), 1 }); ++ TEST_VERIFY (!__deadline_is_infinite (deadline)); ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) ++ { { time_t_max (), 1000 * 1000 * 1000 - 1000 } }, ++ (struct timeval) { 0, 1 }); ++ TEST_VERIFY (__deadline_is_infinite (deadline)); ++ deadline = __deadline_from_timeval ++ ((struct deadline_current_time) ++ { { time_t_max () / 2 + 1, 0 } }, ++ (struct timeval) { time_t_max () / 2 + 1, 0 }); ++ TEST_VERIFY (__deadline_is_infinite (deadline)); ++ ++ /* Check __deadline_first behavior. */ ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 2 } }, ++ (struct deadline) { { 1, 3 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 3 } }, ++ (struct deadline) { { 1, 2 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 2 } }, ++ (struct deadline) { { 2, 1 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 1, 2 } }, ++ (struct deadline) { { 2, 4 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ deadline = __deadline_first ++ ((struct deadline) { { 2, 4 } }, ++ (struct deadline) { { 1, 2 } }); ++ TEST_VERIFY (deadline.absolute.tv_sec == 1); ++ TEST_VERIFY (deadline.absolute.tv_nsec == 2); ++ ++ return 0; ++} ++ ++#include +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index daf8a28..7e5d295 100644 +--- a/sunrpc/Makefile ++++ b/sunrpc/Makefile +@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ + extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) + others += rpcgen + +-tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error ++tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ ++ tst-udp-nonblocking + xtests := tst-getmyaddr + + ifeq ($(have-thread-library),yes) +-xtests += thrsvc ++xtests += thrsvc tst-udp-garbage + endif + + ifeq ($(run-built-tests),yes) +@@ -235,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen + $(built-program-cmd) -c $< -o $@; \ + $(evaluate-test) + endif ++ ++$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so ++$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so ++$(objpfx)tst-udp-garbage: \ ++ $(common-objpfx)linkobj/libc.so $(shared-thread-library) +diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c +index 1de25cb..6ce16eb 100644 +--- a/sunrpc/clnt_udp.c ++++ b/sunrpc/clnt_udp.c +@@ -55,6 +55,7 @@ + #endif + + #include ++#include + + extern u_long _create_xid (void); + +@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops = + }; + + /* +- * Private data kept per client handle ++ * Private data kept per client handle. This private struct is ++ * unfortunately part of the ABI; ypbind contains a copy of it and ++ * accesses it through CLIENT::cl_private field. + */ + struct cu_data + { +@@ -278,28 +281,38 @@ clntudp_call (/* client handle */ + int inlen; + socklen_t fromlen; + struct pollfd fd; +- int milliseconds = (cu->cu_wait.tv_sec * 1000) + +- (cu->cu_wait.tv_usec / 1000); + struct sockaddr_in from; + struct rpc_msg reply_msg; + XDR reply_xdrs; +- struct timeval time_waited; + bool_t ok; + int nrefreshes = 2; /* number of times to refresh cred */ +- struct timeval timeout; + int anyup; /* any network interface up */ + +- if (cu->cu_total.tv_usec == -1) +- { +- timeout = utimeout; /* use supplied timeout */ +- } +- else ++ struct deadline_current_time current_time = __deadline_current_time (); ++ struct deadline total_deadline; /* Determined once by overall timeout. */ ++ struct deadline response_deadline; /* Determined anew for each query. */ ++ ++ /* Choose the timeout value. For non-sending usage (xargs == NULL), ++ the total deadline does not matter, only cu->cu_wait is used ++ below. */ ++ if (xargs != NULL) + { +- timeout = cu->cu_total; /* use default timeout */ ++ struct timeval tv; ++ if (cu->cu_total.tv_usec == -1) ++ /* Use supplied timeout. */ ++ tv = utimeout; ++ else ++ /* Use default timeout. */ ++ tv = cu->cu_total; ++ if (!__is_timeval_valid_timeout (tv)) ++ return (cu->cu_error.re_status = RPC_TIMEDOUT); ++ total_deadline = __deadline_from_timeval (current_time, tv); + } + +- time_waited.tv_sec = 0; +- time_waited.tv_usec = 0; ++ /* Guard against bad timeout specification. */ ++ if (!__is_timeval_valid_timeout (cu->cu_wait)) ++ return (cu->cu_error.re_status = RPC_TIMEDOUT); ++ + call_again: + xdrs = &(cu->cu_outxdrs); + if (xargs == NULL) +@@ -325,27 +338,46 @@ send_again: + return (cu->cu_error.re_status = RPC_CANTSEND); + } + +- /* +- * Hack to provide rpc-based message passing +- */ +- if (timeout.tv_sec == 0 && timeout.tv_usec == 0) +- { +- return (cu->cu_error.re_status = RPC_TIMEDOUT); +- } ++ /* sendto may have blocked, so recompute the current time. */ ++ current_time = __deadline_current_time (); + get_reply: +- /* +- * sub-optimal code appears here because we have +- * some clock time to spare while the packets are in flight. +- * (We assume that this is actually only executed once.) +- */ ++ response_deadline = __deadline_from_timeval (current_time, cu->cu_wait); ++ + reply_msg.acpted_rply.ar_verf = _null_auth; + reply_msg.acpted_rply.ar_results.where = resultsp; + reply_msg.acpted_rply.ar_results.proc = xresults; + fd.fd = cu->cu_sock; + fd.events = POLLIN; + anyup = 0; ++ ++ /* Per-response retry loop. current_time must be up-to-date at the ++ top of the loop. */ + for (;;) + { ++ int milliseconds; ++ if (xargs != NULL) ++ { ++ if (__deadline_elapsed (current_time, total_deadline)) ++ /* Overall timeout expired. */ ++ return (cu->cu_error.re_status = RPC_TIMEDOUT); ++ milliseconds = __deadline_to_ms ++ (current_time, __deadline_first (total_deadline, ++ response_deadline)); ++ if (milliseconds == 0) ++ /* Per-query timeout expired. */ ++ goto send_again; ++ } ++ else ++ { ++ /* xatgs == NULL. Collect a response without sending a ++ query. In this mode, we need to ignore the total ++ deadline. */ ++ milliseconds = __deadline_to_ms (current_time, response_deadline); ++ if (milliseconds == 0) ++ /* Cannot send again, so bail out. */ ++ return (cu->cu_error.re_status = RPC_CANTSEND); ++ } ++ + switch (__poll (&fd, 1, milliseconds)) + { + +@@ -356,27 +388,10 @@ send_again: + if (!anyup) + return (cu->cu_error.re_status = RPC_CANTRECV); + } +- +- time_waited.tv_sec += cu->cu_wait.tv_sec; +- time_waited.tv_usec += cu->cu_wait.tv_usec; +- while (time_waited.tv_usec >= 1000000) +- { +- time_waited.tv_sec++; +- time_waited.tv_usec -= 1000000; +- } +- if ((time_waited.tv_sec < timeout.tv_sec) || +- ((time_waited.tv_sec == timeout.tv_sec) && +- (time_waited.tv_usec < timeout.tv_usec))) +- goto send_again; +- return (cu->cu_error.re_status = RPC_TIMEDOUT); +- +- /* +- * buggy in other cases because time_waited is not being +- * updated. +- */ ++ goto next_response; + case -1: + if (errno == EINTR) +- continue; ++ goto next_response; + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } +@@ -440,20 +455,22 @@ send_again: + if (inlen < 0) + { + if (errno == EWOULDBLOCK) +- continue; ++ goto next_response; + cu->cu_error.re_errno = errno; + return (cu->cu_error.re_status = RPC_CANTRECV); + } +- if (inlen < 4) +- continue; +- +- /* see if reply transaction id matches sent id. +- Don't do this if we only wait for a replay */ +- if (xargs != NULL +- && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0) +- continue; +- /* we now assume we have the proper reply */ +- break; ++ /* Accept the response if the packet is sufficiently long and ++ the transaction ID matches the query (if available). */ ++ if (inlen >= 4 ++ && (xargs == NULL ++ || memcmp (cu->cu_inbuf, cu->cu_outbuf, ++ sizeof (u_int32_t)) == 0)) ++ break; ++ ++ next_response: ++ /* Update the current time because poll and recvmsg waited for ++ an unknown time. */ ++ current_time = __deadline_current_time (); + } + + /* +diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c +new file mode 100644 +index 0000000..4abda93 +--- /dev/null ++++ b/sunrpc/tst-udp-garbage.c +@@ -0,0 +1,104 @@ ++/* Test that garbage packets do not affect timeout handling. ++ Copyright (C) 2017 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 ++#include ++#include ++ ++/* Descriptor for the server UDP socket. */ ++static int server_fd; ++ ++static void * ++garbage_sender_thread (void *unused) ++{ ++ while (true) ++ { ++ struct sockaddr_storage sa; ++ socklen_t salen = sizeof (sa); ++ char buf[1]; ++ if (recvfrom (server_fd, buf, sizeof (buf), 0, ++ (struct sockaddr *) &sa, &salen) < 0) ++ FAIL_EXIT1 ("recvfrom: %m"); ++ ++ /* Send garbage packets indefinitely. */ ++ buf[0] = 0; ++ while (true) ++ { ++ /* sendto can fail if the client closed the socket. */ ++ if (sendto (server_fd, buf, sizeof (buf), 0, ++ (struct sockaddr *) &sa, salen) < 0) ++ break; ++ ++ /* Wait a bit, to avoid burning too many CPU cycles in a ++ tight loop. The wait period must be much shorter than ++ the client timeouts configured below. */ ++ usleep (50 * 1000); ++ } ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ server_fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); ++ struct sockaddr_in server_address = ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ }; ++ xbind (server_fd, ++ (struct sockaddr *) &server_address, sizeof (server_address)); ++ { ++ socklen_t sinlen = sizeof (server_address); ++ xgetsockname (server_fd, (struct sockaddr *) &server_address, &sinlen); ++ TEST_VERIFY (sizeof (server_address) == sinlen); ++ } ++ ++ /* Garbage packet source. */ ++ xpthread_detach (xpthread_create (NULL, garbage_sender_thread, NULL)); ++ ++ /* Test client. Use an arbitrary timeout of one second, which is ++ much longer than the garbage packet interval, but still ++ reasonably short, so that the test completes quickly. */ ++ int client_fd = RPC_ANYSOCK; ++ CLIENT *clnt = clntudp_create (&server_address, ++ 1, 2, /* Arbitrary RPC endpoint numbers. */ ++ (struct timeval) { 1, 0 }, ++ &client_fd); ++ if (clnt == NULL) ++ FAIL_EXIT1 ("clntudp_create: %m"); ++ ++ TEST_VERIFY (clnt_call (clnt, 3, /* Arbitrary RPC procedure number. */ ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 1, 0 }))); ++ ++ return 0; ++} ++ ++#include +diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c +new file mode 100644 +index 0000000..1d6a7f4 +--- /dev/null ++++ b/sunrpc/tst-udp-nonblocking.c +@@ -0,0 +1,333 @@ ++/* Test non-blocking use of the UDP client. ++ Copyright (C) 2017 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 ++#include ++#include ++#include ++#include ++#include ++ ++/* Test data serialization and deserialization. */ ++ ++struct test_query ++{ ++ uint32_t a; ++ uint32_t b; ++ uint32_t timeout_ms; ++}; ++ ++static bool_t ++xdr_test_query (XDR *xdrs, void *data, ...) ++{ ++ struct test_query *p = data; ++ return xdr_uint32_t (xdrs, &p->a) ++ && xdr_uint32_t (xdrs, &p->b) ++ && xdr_uint32_t (xdrs, &p->timeout_ms); ++} ++ ++struct test_response ++{ ++ uint32_t server_id; ++ uint32_t seq; ++ uint32_t sum; ++}; ++ ++static bool_t ++xdr_test_response (XDR *xdrs, void *data, ...) ++{ ++ struct test_response *p = data; ++ return xdr_uint32_t (xdrs, &p->server_id) ++ && xdr_uint32_t (xdrs, &p->seq) ++ && xdr_uint32_t (xdrs, &p->sum); ++} ++ ++/* Implementation of the test server. */ ++ ++enum ++ { ++ /* Number of test servers to run. */ ++ SERVER_COUNT = 3, ++ ++ /* RPC parameters, chosen at random. */ ++ PROGNUM = 8242, ++ VERSNUM = 19654, ++ ++ /* Main RPC operation. */ ++ PROC_ADD = 1, ++ ++ /* Request process termination. */ ++ PROC_EXIT, ++ ++ /* Special exit status to mark successful processing. */ ++ EXIT_MARKER = 55, ++ }; ++ ++/* Set by the parent process to tell test servers apart. */ ++static int server_id; ++ ++/* Implementation of the test server. */ ++static void ++server_dispatch (struct svc_req *request, SVCXPRT *transport) ++{ ++ /* Query sequence number. */ ++ static uint32_t seq = 0; ++ ++seq; ++ static bool proc_add_seen; ++ ++ if (test_verbose) ++ printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n", ++ server_id, seq, request->rq_proc); ++ ++ switch (request->rq_proc) ++ { ++ case PROC_ADD: ++ { ++ struct test_query query; ++ memset (&query, 0xc0, sizeof (query)); ++ TEST_VERIFY_EXIT ++ (svc_getargs (transport, xdr_test_query, ++ (void *) &query)); ++ ++ if (test_verbose) ++ printf (" a=%u b=%u timeout_ms=%u\n", ++ query.a, query.b, query.timeout_ms); ++ ++ usleep (query.timeout_ms * 1000); ++ ++ struct test_response response = ++ { ++ .server_id = server_id, ++ .seq = seq, ++ .sum = query.a + query.b, ++ }; ++ TEST_VERIFY (svc_sendreply (transport, xdr_test_response, ++ (void *) &response)); ++ if (test_verbose) ++ printf (" server id %d response seq=%u sent\n", server_id, seq); ++ proc_add_seen = true; ++ } ++ break; ++ ++ case PROC_EXIT: ++ TEST_VERIFY (proc_add_seen); ++ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); ++ _exit (EXIT_MARKER); ++ break; ++ ++ default: ++ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); ++ break; ++ } ++} ++ ++/* Return the number seconds since an arbitrary point in time. */ ++static double ++get_ticks (void) ++{ ++ { ++ struct timespec ts; ++ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) ++ return ts.tv_sec + ts.tv_nsec * 1e-9; ++ } ++ { ++ struct timeval tv; ++ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); ++ return tv.tv_sec + tv.tv_usec * 1e-6; ++ } ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ /* Information about the test servers. */ ++ struct ++ { ++ SVCXPRT *transport; ++ struct sockaddr_in address; ++ pid_t pid; ++ uint32_t xid; ++ } servers[SERVER_COUNT]; ++ ++ /* Spawn the test servers. */ ++ for (int i = 0; i < SERVER_COUNT; ++i) ++ { ++ servers[i].transport = svcudp_create (RPC_ANYSOCK); ++ TEST_VERIFY_EXIT (servers[i].transport != NULL); ++ servers[i].address = (struct sockaddr_in) ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ .sin_port = htons (servers[i].transport->xp_port), ++ }; ++ servers[i].xid = 0xabcd0101 + i; ++ if (test_verbose) ++ printf ("info: setting up server %d xid=%x on port %d\n", ++ i, servers[i].xid, servers[i].transport->xp_port); ++ ++ server_id = i; ++ servers[i].pid = xfork (); ++ if (servers[i].pid == 0) ++ { ++ TEST_VERIFY (svc_register (servers[i].transport, ++ PROGNUM, VERSNUM, server_dispatch, 0)); ++ svc_run (); ++ FAIL_EXIT1 ("supposed to be unreachable"); ++ } ++ /* We need to close the socket so that we do not accidentally ++ consume the request. */ ++ TEST_VERIFY (close (servers[i].transport->xp_sock) == 0); ++ } ++ ++ ++ /* The following code mirrors what ypbind does. */ ++ ++ /* Copied from clnt_udp.c (like ypbind). */ ++ struct cu_data ++ { ++ int cu_sock; ++ bool_t cu_closeit; ++ struct sockaddr_in cu_raddr; ++ int cu_rlen; ++ struct timeval cu_wait; ++ struct timeval cu_total; ++ struct rpc_err cu_error; ++ XDR cu_outxdrs; ++ u_int cu_xdrpos; ++ u_int cu_sendsz; ++ char *cu_outbuf; ++ u_int cu_recvsz; ++ char cu_inbuf[1]; ++ }; ++ ++ int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); ++ CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM, ++ /* 5 seconds per-response timeout. */ ++ ((struct timeval) { 5, 0 }), ++ &client_socket); ++ TEST_VERIFY (clnt != NULL); ++ clnt->cl_auth = authunix_create_default (); ++ { ++ struct timeval zero = { 0, 0 }; ++ TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero)); ++ } ++ ++ /* Poke at internal data structures (like ypbind). */ ++ struct cu_data *cu = (struct cu_data *) clnt->cl_private; ++ ++ /* Send a ping to each server. */ ++ double before_pings = get_ticks (); ++ for (int i = 0; i < SERVER_COUNT; ++i) ++ { ++ if (test_verbose) ++ printf ("info: sending server %d ping\n", i); ++ /* Reset the xid because it is changed by each invocation of ++ clnt_call. Subtract one to compensate for the xid update ++ during the call. */ ++ *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1; ++ cu->cu_raddr = servers[i].address; ++ ++ struct test_query query = { .a = 100, .b = i + 1 }; ++ if (i == 1) ++ /* Shorter timeout to prefer this server. These timeouts must ++ be much shorter than the 5-second per-response timeout ++ configured with clntudp_create. */ ++ query.timeout_ms = 700; ++ else ++ query.timeout_ms = 1400; ++ struct test_response response = { 0 }; ++ /* NB: Do not check the return value. The server reply will ++ prove that the call worked. */ ++ double before_one_ping = get_ticks (); ++ clnt_call (clnt, PROC_ADD, ++ xdr_test_query, (void *) &query, ++ xdr_test_response, (void *) &response, ++ ((struct timeval) { 0, 0 })); ++ double after_one_ping = get_ticks (); ++ if (test_verbose) ++ printf ("info: non-blocking send took %f seconds\n", ++ after_one_ping - before_one_ping); ++ /* clnt_call should return immediately. Accept some delay in ++ case the process is descheduled. */ ++ TEST_VERIFY (after_one_ping - before_one_ping < 0.3); ++ } ++ ++ /* Collect the non-blocking response. */ ++ if (test_verbose) ++ printf ("info: collecting response\n"); ++ struct test_response response = { 0 }; ++ TEST_VERIFY ++ (clnt_call (clnt, PROC_ADD, NULL, NULL, ++ xdr_test_response, (void *) &response, ++ ((struct timeval) { 0, 0 })) == RPC_SUCCESS); ++ double after_pings = get_ticks (); ++ if (test_verbose) ++ printf ("info: send/receive took %f seconds\n", ++ after_pings - before_pings); ++ /* Expected timeout is 0.7 seconds. */ ++ TEST_VERIFY (0.7 <= after_pings - before_pings); ++ TEST_VERIFY (after_pings - before_pings < 1.2); ++ ++ uint32_t xid; ++ memcpy (&xid, &cu->cu_inbuf, sizeof (xid)); ++ if (test_verbose) ++ printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n", ++ xid, response.server_id, response.seq, response.sum); ++ /* Check that the reply from the preferred server was used. */ ++ TEST_VERIFY (servers[1].xid == xid); ++ TEST_VERIFY (response.server_id == 1); ++ TEST_VERIFY (response.seq == 1); ++ TEST_VERIFY (response.sum == 102); ++ ++ auth_destroy (clnt->cl_auth); ++ clnt_destroy (clnt); ++ ++ for (int i = 0; i < SERVER_COUNT; ++i) ++ { ++ if (test_verbose) ++ printf ("info: requesting server %d termination\n", i); ++ client_socket = RPC_ANYSOCK; ++ clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM, ++ ((struct timeval) { 5, 0 }), ++ &client_socket); ++ TEST_VERIFY_EXIT (clnt != NULL); ++ TEST_VERIFY (clnt_call (clnt, PROC_EXIT, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 3, 0 })) == RPC_SUCCESS); ++ clnt_destroy (clnt); ++ ++ int status; ++ xwaitpid (servers[i].pid, &status, 0); ++ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); ++ } ++ ++ return 0; ++} ++ ++#include +diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c +new file mode 100644 +index 0000000..db9943a +--- /dev/null ++++ b/sunrpc/tst-udp-timeout.c +@@ -0,0 +1,402 @@ ++/* Test timeout handling in the UDP client. ++ Copyright (C) 2017 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 ++#include ++#include ++#include ++#include ++#include ++ ++/* Test data serialization and deserialization. */ ++ ++struct test_query ++{ ++ uint32_t a; ++ uint32_t b; ++ uint32_t timeout_ms; ++ uint32_t wait_for_seq; ++ uint32_t garbage_packets; ++}; ++ ++static bool_t ++xdr_test_query (XDR *xdrs, void *data, ...) ++{ ++ struct test_query *p = data; ++ return xdr_uint32_t (xdrs, &p->a) ++ && xdr_uint32_t (xdrs, &p->b) ++ && xdr_uint32_t (xdrs, &p->timeout_ms) ++ && xdr_uint32_t (xdrs, &p->wait_for_seq) ++ && xdr_uint32_t (xdrs, &p->garbage_packets); ++} ++ ++struct test_response ++{ ++ uint32_t seq; ++ uint32_t sum; ++}; ++ ++static bool_t ++xdr_test_response (XDR *xdrs, void *data, ...) ++{ ++ struct test_response *p = data; ++ return xdr_uint32_t (xdrs, &p->seq) ++ && xdr_uint32_t (xdrs, &p->sum); ++} ++ ++/* Implementation of the test server. */ ++ ++enum ++ { ++ /* RPC parameters, chosen at random. */ ++ PROGNUM = 15717, ++ VERSNUM = 13689, ++ ++ /* Main RPC operation. */ ++ PROC_ADD = 1, ++ ++ /* Reset the sequence number. */ ++ PROC_RESET_SEQ, ++ ++ /* Request process termination. */ ++ PROC_EXIT, ++ ++ /* Special exit status to mark successful processing. */ ++ EXIT_MARKER = 55, ++ }; ++ ++static void ++server_dispatch (struct svc_req *request, SVCXPRT *transport) ++{ ++ /* Query sequence number. */ ++ static uint32_t seq = 0; ++ ++seq; ++ ++ if (test_verbose) ++ printf ("info: server_dispatch seq=%u rq_proc=%lu\n", ++ seq, request->rq_proc); ++ ++ switch (request->rq_proc) ++ { ++ case PROC_ADD: ++ { ++ struct test_query query; ++ memset (&query, 0xc0, sizeof (query)); ++ TEST_VERIFY_EXIT ++ (svc_getargs (transport, xdr_test_query, ++ (void *) &query)); ++ ++ if (test_verbose) ++ printf (" a=%u b=%u timeout_ms=%u wait_for_seq=%u" ++ " garbage_packets=%u\n", ++ query.a, query.b, query.timeout_ms, query.wait_for_seq, ++ query.garbage_packets); ++ ++ if (seq < query.wait_for_seq) ++ { ++ /* No response at this point. */ ++ if (test_verbose) ++ printf (" skipped response\n"); ++ break; ++ } ++ ++ if (query.garbage_packets > 0) ++ { ++ int per_packet_timeout; ++ if (query.timeout_ms > 0) ++ per_packet_timeout ++ = query.timeout_ms * 1000 / query.garbage_packets; ++ else ++ per_packet_timeout = 0; ++ ++ char buf[20]; ++ memset (&buf, 0xc0, sizeof (buf)); ++ for (int i = 0; i < query.garbage_packets; ++i) ++ { ++ /* 13 is relatively prime to 20 = sizeof (buf) + 1, so ++ the len variable will cover the entire interval ++ [0, 20] if query.garbage_packets is sufficiently ++ large. */ ++ size_t len = (i * 13 + 1) % (sizeof (buf) + 1); ++ TEST_VERIFY (sendto (transport->xp_sock, ++ buf, len, MSG_NOSIGNAL, ++ (struct sockaddr *) &transport->xp_raddr, ++ transport->xp_addrlen) == len); ++ if (per_packet_timeout > 0) ++ usleep (per_packet_timeout); ++ } ++ } ++ else if (query.timeout_ms > 0) ++ usleep (query.timeout_ms * 1000); ++ ++ struct test_response response = ++ { ++ .seq = seq, ++ .sum = query.a + query.b, ++ }; ++ TEST_VERIFY (svc_sendreply (transport, xdr_test_response, ++ (void *) &response)); ++ } ++ break; ++ ++ case PROC_RESET_SEQ: ++ seq = 0; ++ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); ++ break; ++ ++ case PROC_EXIT: ++ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); ++ _exit (EXIT_MARKER); ++ break; ++ ++ default: ++ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); ++ break; ++ } ++} ++ ++/* Implementation of the test client. */ ++ ++static struct test_response ++test_call (CLIENT *clnt, int proc, struct test_query query, ++ struct timeval timeout) ++{ ++ if (test_verbose) ++ printf ("info: test_call proc=%d timeout=%lu.%06lu\n", ++ proc, (unsigned long) timeout.tv_sec, ++ (unsigned long) timeout.tv_usec); ++ struct test_response response; ++ TEST_VERIFY_EXIT (clnt_call (clnt, proc, ++ xdr_test_query, (void *) &query, ++ xdr_test_response, (void *) &response, ++ timeout) ++ == RPC_SUCCESS); ++ return response; ++} ++ ++static void ++test_call_timeout (CLIENT *clnt, int proc, struct test_query query, ++ struct timeval timeout) ++{ ++ struct test_response response; ++ TEST_VERIFY (clnt_call (clnt, proc, ++ xdr_test_query, (void *) &query, ++ xdr_test_response, (void *) &response, ++ timeout) ++ == RPC_TIMEDOUT); ++} ++ ++/* Complete one regular RPC call to drain the server socket ++ buffer. Resets the sequence number. */ ++static void ++test_call_flush (CLIENT *clnt) ++{ ++ /* This needs a longer timeout to flush out all pending requests. ++ The choice of 5 seconds is larger than the per-response timeouts ++ requested via the timeout_ms field. */ ++ if (test_verbose) ++ printf ("info: flushing pending queries\n"); ++ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_RESET_SEQ, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 5, 0 })) ++ == RPC_SUCCESS); ++} ++ ++/* Return the number seconds since an arbitrary point in time. */ ++static double ++get_ticks (void) ++{ ++ { ++ struct timespec ts; ++ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) ++ return ts.tv_sec + ts.tv_nsec * 1e-9; ++ } ++ { ++ struct timeval tv; ++ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); ++ return tv.tv_sec + tv.tv_usec * 1e-6; ++ } ++} ++ ++static void ++test_udp_server (int port) ++{ ++ struct sockaddr_in sin = ++ { ++ .sin_family = AF_INET, ++ .sin_addr.s_addr = htonl (INADDR_LOOPBACK), ++ .sin_port = htons (port) ++ }; ++ int sock = RPC_ANYSOCK; ++ ++ /* The client uses a 1.5 second timeout for retries. The timeouts ++ are arbitrary, but chosen so that there is a substantial gap ++ between them, but the total time spent waiting is not too ++ large. */ ++ CLIENT *clnt = clntudp_create (&sin, PROGNUM, VERSNUM, ++ (struct timeval) { 1, 500 * 1000 }, ++ &sock); ++ TEST_VERIFY_EXIT (clnt != NULL); ++ ++ /* Basic call/response test. */ ++ struct test_response response = test_call ++ (clnt, PROC_ADD, ++ (struct test_query) { .a = 17, .b = 4 }, ++ (struct timeval) { 3, 0 }); ++ TEST_VERIFY (response.sum == 21); ++ TEST_VERIFY (response.seq == 1); ++ ++ /* Check that garbage packets do not interfere with timeout ++ processing. */ ++ double before = get_ticks (); ++ response = test_call ++ (clnt, PROC_ADD, ++ (struct test_query) { ++ .a = 19, .b = 4, .timeout_ms = 500, .garbage_packets = 21, ++ }, ++ (struct timeval) { 3, 0 }); ++ TEST_VERIFY (response.sum == 23); ++ TEST_VERIFY (response.seq == 2); ++ double after = get_ticks (); ++ if (test_verbose) ++ printf ("info: 21 garbage packets took %f seconds\n", after - before); ++ /* Expected timeout is 0.5 seconds. Add some slack in case process ++ scheduling delays processing the query or response, but do not ++ accept a retry (which would happen at 1.5 seconds). */ ++ TEST_VERIFY (0.5 <= after - before); ++ TEST_VERIFY (after - before < 1.2); ++ test_call_flush (clnt); ++ ++ /* Check that missing a response introduces a 1.5 second timeout, as ++ requested when calling clntudp_create. */ ++ before = get_ticks (); ++ response = test_call ++ (clnt, PROC_ADD, ++ (struct test_query) { .a = 170, .b = 40, .wait_for_seq = 2 }, ++ (struct timeval) { 3, 0 }); ++ TEST_VERIFY (response.sum == 210); ++ TEST_VERIFY (response.seq == 2); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: skipping one response took %f seconds\n", ++ after - before); ++ /* Expected timeout is 1.5 seconds. Do not accept a second retry ++ (which would happen at 3 seconds). */ ++ TEST_VERIFY (1.5 <= after - before); ++ TEST_VERIFY (after - before < 2.9); ++ test_call_flush (clnt); ++ ++ /* Check that the overall timeout wins against the per-query ++ timeout. */ ++ before = get_ticks (); ++ test_call_timeout ++ (clnt, PROC_ADD, ++ (struct test_query) { .a = 170, .b = 41, .wait_for_seq = 2 }, ++ (struct timeval) { 0, 750 * 1000 }); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: 0.75 second timeout took %f seconds\n", ++ after - before); ++ TEST_VERIFY (0.75 <= after - before); ++ TEST_VERIFY (after - before < 1.4); ++ test_call_flush (clnt); ++ ++ for (int with_garbage = 0; with_garbage < 2; ++with_garbage) ++ { ++ /* Check that no response at all causes the client to bail out. */ ++ before = get_ticks (); ++ test_call_timeout ++ (clnt, PROC_ADD, ++ (struct test_query) { ++ .a = 170, .b = 40, .timeout_ms = 1200, ++ .garbage_packets = with_garbage * 21 ++ }, ++ (struct timeval) { 0, 750 * 1000 }); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: test_udp_server: 0.75 second timeout took %f seconds" ++ " (garbage %d)\n", ++ after - before, with_garbage); ++ TEST_VERIFY (0.75 <= after - before); ++ TEST_VERIFY (after - before < 1.4); ++ test_call_flush (clnt); ++ ++ /* As above, but check the total timeout. */ ++ before = get_ticks (); ++ test_call_timeout ++ (clnt, PROC_ADD, ++ (struct test_query) { ++ .a = 170, .b = 40, .timeout_ms = 3000, ++ .garbage_packets = with_garbage * 30 ++ }, ++ (struct timeval) { 2, 300 * 1000 }); ++ after = get_ticks (); ++ if (test_verbose) ++ printf ("info: test_udp_server: 2.3 second timeout took %f seconds" ++ " (garbage %d)\n", ++ after - before, with_garbage); ++ TEST_VERIFY (2.3 <= after - before); ++ TEST_VERIFY (after - before < 3.0); ++ test_call_flush (clnt); ++ } ++ ++ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_EXIT, ++ (xdrproc_t) xdr_void, NULL, ++ (xdrproc_t) xdr_void, NULL, ++ ((struct timeval) { 5, 0 })) ++ == RPC_SUCCESS); ++ clnt_destroy (clnt); ++} ++ ++static int ++do_test (void) ++{ ++ support_become_root (); ++ support_enter_network_namespace (); ++ ++ SVCXPRT *transport = svcudp_create (RPC_ANYSOCK); ++ TEST_VERIFY_EXIT (transport != NULL); ++ TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM, server_dispatch, 0)); ++ ++ pid_t pid = xfork (); ++ if (pid == 0) ++ { ++ svc_run (); ++ FAIL_EXIT1 ("supposed to be unreachable"); ++ } ++ test_udp_server (transport->xp_port); ++ ++ int status; ++ xwaitpid (pid, &status, 0); ++ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); ++ ++ SVC_DESTROY (transport); ++ return 0; ++} ++ ++/* The minimum run time is around 17 seconds. */ ++#define TIMEOUT 25 ++#include +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-04.patch b/srcpkgs/glibc/patches/glibc-upstream-04.patch new file mode 100644 index 0000000000..67c135db83 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-04.patch @@ -0,0 +1,201 @@ +From 69e0a87cc4c570e3b7218392fc3e743b5bddcce2 Mon Sep 17 00:00:00 2001 +From: Florian Weimer +Date: Thu, 2 Mar 2017 20:11:27 +0100 +Subject: [PATCH 04] Document and fix --enable-bind-now [BZ #21015] + +(cherry picked from commit 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9) +--- + ChangeLog | 17 +++++++++++++++++ + INSTALL | 6 ++++++ + Makeconfig | 7 +++++++ + Makerules | 9 +++------ + NEWS | 1 + + iconvdata/Makefile | 5 +++++ + manual/install.texi | 6 ++++++ + sysdeps/unix/sysv/linux/alpha/localplt.data | 2 +- + sysdeps/unix/sysv/linux/i386/localplt.data | 2 +- + sysdeps/x86_64/localplt.data | 2 +- + 10 files changed, 48 insertions(+), 9 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index 510ca42..8aaf9f8 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,20 @@ ++2017-03-02 Florian Weimer ++ ++ [BZ #21015] ++ * manual/install.texi (Configuring and compiling): Document ++ --enable-bind-now. ++ * Makeconfig [bind-now] (LDFLAGS-lib.so): Set. ++ (build-shlib-helper): Use $(LDFLAGS-lib.so). ++ (format.lds): Likewise. ++ [bind-now] (LDFLAGS-c.so): Remove. ++ * sysdeps/x86_64/localplt.data (libm.so): matherr relocation can ++ be R_X86_64_GLOB_DAT. ++ * sysdeps/unix/sysv/linux/i386/localplt.data (libm.so): matherr ++ relocation can be R_386_GLOB_DAT. ++ * sysdeps/unix/sysv/linux/alpha/localplt.data (libm.so): matherr ++ relocaiton can be R_ALPHA_GLOB_DAT. ++ * iconvdata/Makefile [bind-now] (LDFLAGS.so): Add -Wl,-z,now. ++ + 2017-02-28 Florian Weimer + + [BZ #20257] +diff --git a/INSTALL b/INSTALL +index 3b3fd12..e77cb2d 100644 +--- a/INSTALL ++++ b/INSTALL +@@ -146,6 +146,12 @@ will be used, and CFLAGS sets optimization options for the compiler. + of routines called directly from assembler are excluded from this + protection. + ++'--enable-bind-now' ++ Disable lazy binding for installed shared objects. This provides ++ additional security hardening because it enables full RELRO and a ++ read-only global offset table (GOT), at the cost of slightly ++ increased program load times. ++ + '--enable-pt_chown' + The file 'pt_chown' is a helper binary for 'grantpt' (*note + Pseudo-Terminals: Allocation.) that is installed setuid root to fix +diff --git a/Makeconfig b/Makeconfig +index 97a15b5..1c81511 100644 +--- a/Makeconfig ++++ b/Makeconfig +@@ -386,6 +386,13 @@ LDFLAGS.so += $(hashstyle-LDFLAGS) + LDFLAGS-rtld += $(hashstyle-LDFLAGS) + endif + ++# If lazy relocations are disabled, add the -z now flag. Use ++# LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to ++# test modules. ++ifeq ($(bind-now),yes) ++LDFLAGS-lib.so += -Wl,-z,now ++endif ++ + # Command to run after every final link (executable or shared object). + # This is invoked with $(call after-link,...), so it should operate on + # the file $1. This can be set to do some sort of post-processing on +diff --git a/Makerules b/Makerules +index e9194e5..7f0eef8 100644 +--- a/Makerules ++++ b/Makerules +@@ -588,7 +588,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \ + $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \ + $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \ + -Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \ +- $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \ ++ $(LDFLAGS.so) $(LDFLAGS-lib.so) $(LDFLAGS-$(@F:lib%.so=%).so) \ + -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) + endef + +@@ -686,10 +686,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles + LDLIBS-c.so += $(libc.so-gnulib) + # Give libc.so an entry point and make it directly runnable itself. + LDFLAGS-c.so += -e __libc_main +-# If lazy relocation is disabled add the -z now flag. +-ifeq ($(bind-now),yes) +-LDFLAGS-c.so += -Wl,-z,now +-endif + # Pre-link the objects of libc_pic.a so that we can locally resolve + # COMMON symbols before we link against ld.so. This is because ld.so + # contains some of libc_pic.a already, which will prevent the COMMONs +@@ -1104,7 +1100,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \ + ifneq (unknown,$(output-format)) + echo > $@.new 'OUTPUT_FORMAT($(output-format))' + else +- $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \ ++ $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \ ++ $(LDFLAGS.so) $(LDFLAGS-lib.so) \ + -x c /dev/null -o $@.so -Wl,--verbose -v 2>&1 \ + | sed -n -f $< > $@.new + test -s $@.new +diff --git a/NEWS b/NEWS +index e7d6668..9bf8c10 100644 +--- a/NEWS ++++ b/NEWS +@@ -12,6 +12,7 @@ The following bugs are resolved with this release: + [21109] Tunables broken on big-endian + [21115] sunrpc: Use-after-free in error path in clntudp_call + [20257] sunrpc: clntudp_call does not enforce timeout when receiving data ++ [21015] Document and fix --enable-bind-now + + Version 2.25 + +diff --git a/iconvdata/Makefile b/iconvdata/Makefile +index 04157b2..e484587 100644 +--- a/iconvdata/Makefile ++++ b/iconvdata/Makefile +@@ -63,6 +63,11 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \ + MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \ + CP770 CP771 CP772 CP773 CP774 + ++# If lazy binding is disabled, use BIND_NOW for the gconv modules. ++ifeq ($(bind-now),yes) ++LDFLAGS.so += -Wl,-z,now ++endif ++ + modules.so := $(addsuffix .so, $(modules)) + + ifeq (yes,$(build-shared)) +diff --git a/manual/install.texi b/manual/install.texi +index 266add8..3398cfa 100644 +--- a/manual/install.texi ++++ b/manual/install.texi +@@ -175,6 +175,12 @@ options to detect stack overruns. Only the dynamic linker and a small + number of routines called directly from assembler are excluded from this + protection. + ++@item --enable-bind-now ++Disable lazy binding for installed shared objects. This provides ++additional security hardening because it enables full RELRO and a ++read-only global offset table (GOT), at the cost of slightly increased ++program load times. ++ + @pindex pt_chown + @findex grantpt + @item --enable-pt_chown +diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data +index cca17f1..1f0e3b4 100644 +--- a/sysdeps/unix/sysv/linux/alpha/localplt.data ++++ b/sysdeps/unix/sysv/linux/alpha/localplt.data +@@ -20,7 +20,7 @@ libc.so: free + RELA R_ALPHA_GLOB_DAT + libc.so: malloc + RELA R_ALPHA_GLOB_DAT + libc.so: memalign + RELA R_ALPHA_GLOB_DAT + libc.so: realloc + RELA R_ALPHA_GLOB_DAT +-libm.so: matherr ++libm.so: matherr + RELA R_ALPHA_GLOB_DAT + # We used to offer inline functions that used this, so it must be exported. + # Ought to reorg things such that carg isn't thus forced to use a plt. + libm.so: __atan2 +diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data +index 2c25849..8ea4333 100644 +--- a/sysdeps/unix/sysv/linux/i386/localplt.data ++++ b/sysdeps/unix/sysv/linux/i386/localplt.data +@@ -6,7 +6,7 @@ libc.so: free + REL R_386_GLOB_DAT + libc.so: malloc + REL R_386_GLOB_DAT + libc.so: memalign + REL R_386_GLOB_DAT + libc.so: realloc + REL R_386_GLOB_DAT +-libm.so: matherr ++libm.so: matherr + REL R_386_GLOB_DAT + # The main malloc is interposed into the dynamic linker, for + # allocations after the initial link (when dlopen is used). + ld.so: malloc + REL R_386_GLOB_DAT +diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data +index 014a9f4..a1840cf 100644 +--- a/sysdeps/x86_64/localplt.data ++++ b/sysdeps/x86_64/localplt.data +@@ -8,7 +8,7 @@ libc.so: free + RELA R_X86_64_GLOB_DAT + libc.so: malloc + RELA R_X86_64_GLOB_DAT + libc.so: memalign + RELA R_X86_64_GLOB_DAT + libc.so: realloc + RELA R_X86_64_GLOB_DAT +-libm.so: matherr ++libm.so: matherr + RELA R_X86_64_GLOB_DAT + # The main malloc is interposed into the dynamic linker, for + # allocations after the initial link (when dlopen is used). + ld.so: malloc + RELA R_X86_64_GLOB_DAT +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-05.patch b/srcpkgs/glibc/patches/glibc-upstream-05.patch new file mode 100644 index 0000000000..60784a4b9a --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-05.patch @@ -0,0 +1,67 @@ +From 8b3caa41b9cb82651e72a0c87aa56719c134000e Mon Sep 17 00:00:00 2001 +From: John David Anglin +Date: Mon, 20 Feb 2017 20:31:57 -0500 +Subject: [PATCH 05] hppa: Fix setting of __libc_stack_end + +The binutils package was recently changed to fix -z relro support on hppa. +See ld/21000 for details: +https://sourceware.org/bugzilla/show_bug.cgi?id=21000 + +This exposed a problem with the _dl_start_user function in the RTLD_START +define. We need to set __libc_stack_end before it is made read only. For +this, we need to define DL_STACK_END. The offset of 0x160 gives the same +stack end as the code in _dl_start_user. + +A build log with the attached patch is here: +https://buildd.debian.org/status/fetch.php?pkg=glibc&arch=hppa&ver=2.24-9&stamp=1487639205&raw=0 + +(cherry picked from commit 5d20a49aaccef5ef7adac93d5ca159f6b7ba0105) +--- + ChangeLog | 5 +++++ + sysdeps/hppa/dl-machine.h | 9 ++++----- + 2 files changed, 9 insertions(+), 5 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index 8aaf9f8..d8ed2e4 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,8 @@ ++2017-03-15 John David Anglin ++ ++ * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. ++ (RTLD_START): Don't record stack end address in _dl_start_user. ++ + 2017-03-02 Florian Weimer + + [BZ #21015] +diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h +index 339c7bb..787b95f 100644 +--- a/sysdeps/hppa/dl-machine.h ++++ b/sysdeps/hppa/dl-machine.h +@@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) + #define ARCH_LA_PLTENTER hppa_gnu_pltenter + #define ARCH_LA_PLTEXIT hppa_gnu_pltexit + ++/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */ ++#define DL_STACK_END(cookie) \ ++ ((void *) (((long) (cookie)) + 0x160)) ++ + /* Initial entry point code for the dynamic linker. + The C function `_dl_start' is the real entry point; + its return value is the user program's entry point. */ +@@ -401,11 +405,6 @@ asm ( \ + /* Save the entry point in %r3. */ \ + " copy %ret0,%r3\n" \ + \ +- /* Remember the lowest stack address. */ \ +-" addil LT'__libc_stack_end,%r19\n" \ +-" ldw RT'__libc_stack_end(%r1),%r20\n" \ +-" stw %sp,0(%r20)\n" \ +- \ + /* See if we were called as a command with the executable file \ + name as an extra leading argument. */ \ + " addil LT'_dl_skip_args,%r19\n" \ +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-06.patch b/srcpkgs/glibc/patches/glibc-upstream-06.patch new file mode 100644 index 0000000000..c1c31aa344 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-06.patch @@ -0,0 +1,52 @@ +From 0889003c67f9c2f520a37281c4b5c3b8a9861f46 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger +Date: Sun, 12 Mar 2017 15:12:21 -0700 +Subject: [PATCH 06] x86_64: fix static build of __mempcpy_chk for compilers + defaulting to PIC/PIE + +When glibc is compiled with gcc 6.2 that has been configured with +to default to PIC/PIE, the static version of __mempcpy_chk is not built, +as the test is done on PIC instead of SHARED. Fix the test to check for +SHARED, like it is done for similar functions like __memcpy_chk. + +2017-03-12 Mike Frysinger + + * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED + instead of PIC. + +(cherry picked from commit fbe355fbd1973d6e29561084b3eaeb4bfe9d515a) +--- + ChangeLog | 5 +++++ + sysdeps/x86_64/mempcpy_chk.S | 2 +- + 2 files changed, 6 insertions(+), 1 deletion(-) + +diff --git a/ChangeLog b/ChangeLog +index d8ed2e4..c29a70a 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,8 @@ ++2017-03-15 Mike Frysinger ++ ++ * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED ++ instead of PIC. ++ + 2017-03-15 John David Anglin + + * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. +diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S +index f8a9260..f912291 100644 +--- a/sysdeps/x86_64/mempcpy_chk.S ++++ b/sysdeps/x86_64/mempcpy_chk.S +@@ -19,7 +19,7 @@ + #include + #include "asm-syntax.h" + +-#ifndef PIC ++#ifndef SHARED + /* For libc.so this is defined in memcpy.S. + For libc.a, this is a separate source to avoid + mempcpy bringing in __chk_fail and all routines +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-07.patch b/srcpkgs/glibc/patches/glibc-upstream-07.patch new file mode 100644 index 0000000000..3319eedbb4 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-07.patch @@ -0,0 +1,65 @@ +From 27ab0d9518746dfb59ed2ba59daefc981dc10e38 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger +Date: Mon, 20 Mar 2017 04:47:56 -0400 +Subject: [PATCH 07] posix_spawn: fix stack setup on ia64 [BZ #21275] + +The ia64-specific clone2 call expects the base of the stack mapping and +the stack size as sep arguments, not an initial stack value as on other +stack-grows-down architectures. Reuse the stack-grows-up macro so we +pass in the right stack base. + +Reported-by: Matt Turner +(cherry picked from commit ddc3fb333469c2997798742dc0509dc1e3201d91) +--- + ChangeLog | 8 ++++++++ + sysdeps/unix/sysv/linux/spawni.c | 11 ++++++----- + 2 files changed, 14 insertions(+), 5 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index c29a70a..ef5388c 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,11 @@ ++2017-03-20 Mike Frysinger ++ ++ [BZ #21275] ++ * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename ++ __stack to __stackbase. ++ (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of ++ checks so we can include defined(__ia64__) first. ++ + 2017-03-15 Mike Frysinger + + * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index 2daf0c5..c96aac8 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -61,17 +61,18 @@ + #define SPAWN_ERROR 127 + + #ifdef __ia64__ +-# define CLONE(__fn, __stack, __stacksize, __flags, __args) \ +- __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0) ++# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \ ++ __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0) + #else + # define CLONE(__fn, __stack, __stacksize, __flags, __args) \ + __clone (__fn, __stack, __flags, __args) + #endif + +-#if _STACK_GROWS_DOWN +-# define STACK(__stack, __stack_size) (__stack + __stack_size) +-#elif _STACK_GROWS_UP ++/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro. */ ++#if _STACK_GROWS_UP || defined (__ia64__) + # define STACK(__stack, __stack_size) (__stack) ++#elif _STACK_GROWS_DOWN ++# define STACK(__stack, __stack_size) (__stack + __stack_size) + #endif + + +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-08.patch b/srcpkgs/glibc/patches/glibc-upstream-08.patch new file mode 100644 index 0000000000..ad522a0690 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-08.patch @@ -0,0 +1,63 @@ +From f035c8d055f25eaf6c93772f308afac10ce31ef2 Mon Sep 17 00:00:00 2001 +From: Slava Barinov +Date: Fri, 31 Mar 2017 08:49:25 +0200 +Subject: [PATCH 08] fts: Fix symbol redirect for fts_set [BZ #21289] + +In a 32-bit environment with _FILE_OFFSET_BITS=64, the __REDIRECT macro +combined with __THROW generates an invalid C++ declaration. + +(cherry picked from commit ce39613205dc47ceaeea76710d49e7a483b503ab) +--- + ChangeLog | 5 +++++ + NEWS | 5 +++-- + io/fts.h | 2 +- + 3 files changed, 9 insertions(+), 3 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index ef5388c..85d6fc6 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,8 @@ ++2017-03-31 Slava Barinov ++ ++ [BZ #21289] ++ * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH. ++ + 2017-03-20 Mike Frysinger + + [BZ #21275] +diff --git a/NEWS b/NEWS +index 9bf8c10..fee1cf8 100644 +--- a/NEWS ++++ b/NEWS +@@ -9,10 +9,11 @@ Version 2.25.1 + + The following bugs are resolved with this release: + +- [21109] Tunables broken on big-endian +- [21115] sunrpc: Use-after-free in error path in clntudp_call + [20257] sunrpc: clntudp_call does not enforce timeout when receiving data + [21015] Document and fix --enable-bind-now ++ [21109] Tunables broken on big-endian ++ [21115] sunrpc: Use-after-free in error path in clntudp_call ++ [21289] Fix symbol redirect for fts_set + + Version 2.25 + +diff --git a/io/fts.h b/io/fts.h +index b9cff53..ab15567 100644 +--- a/io/fts.h ++++ b/io/fts.h +@@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int, + int (*)(const FTSENT **, const FTSENT **)), + fts64_open); + FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read); +-int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW; ++int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set); + # else + # define fts_children fts64_children + # define fts_close fts64_close +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-09.patch b/srcpkgs/glibc/patches/glibc-upstream-09.patch new file mode 100644 index 0000000000..c7ad23ad0b --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-09.patch @@ -0,0 +1,51 @@ +From 74522eeeaa4a39809a28f44171e71d36a69edb58 Mon Sep 17 00:00:00 2001 +From: "Wladimir J. van der Laan" +Date: Sat, 1 Apr 2017 12:39:09 +0530 +Subject: [PATCH 09] Call the right helper function when setting mallopt + M_ARENA_MAX (BZ #21338) + +Fixes a typo introduced in commit +be7991c0705e35b4d70a419d117addcd6c627319. This caused +mallopt(M_ARENA_MAX) as well as the environment variable +MALLOC_ARENA_MAX to not work as intended because it set the +wrong internal parameter. + + [BZ #21338] + * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX + instead of incorrect do_set_arena_test +--- + ChangeLog | 6 ++++++ + malloc/malloc.c | 2 +- + 2 files changed, 7 insertions(+), 1 deletion(-) + +diff --git a/ChangeLog b/ChangeLog +index 85d6fc6..321bf53 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,9 @@ ++2017-04-03 Wladimir van der Laan ++ ++ [BZ# 21338] ++ * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX ++ instead of incorrect do_set_arena_test ++ + 2017-03-31 Slava Barinov + + [BZ #21289] +diff --git a/malloc/malloc.c b/malloc/malloc.c +index 4885793..4e07663 100644 +--- a/malloc/malloc.c ++++ b/malloc/malloc.c +@@ -4902,7 +4902,7 @@ __libc_mallopt (int param_number, int value) + + case M_ARENA_MAX: + if (value > 0) +- do_set_arena_test (value); ++ do_set_arena_max (value); + break; + } + __libc_lock_unlock (av->mutex); +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-10.patch b/srcpkgs/glibc/patches/glibc-upstream-10.patch new file mode 100644 index 0000000000..6bb2645877 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-10.patch @@ -0,0 +1,71 @@ +From df29db0bec24211cfc917db52024bf8deecac2c9 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger +Date: Wed, 15 Mar 2017 23:59:31 -0700 +Subject: [PATCH 10] posix_spawn: use a larger min stack for -fstack-check + [BZ #21253] + +When glibc is built with -fstack-check, trying to use posix_spawn can +lead to segfaults due to gcc internally probing stack memory too far. +The new spawn API will allocate a minimum of 1 page, but the stack +checking logic might probe a couple of pages. When it tries to walk +them, everything falls apart. + +The gcc internal docs [1] state the default interval checking is one +page. Which means we need two pages (the current one, and the next +probed). No target currently defines it larger. + +Further, it mentions that the default minimum stack size needed to +recover from an overflow is 4/8KiB for sjlj or 8/12KiB for others. +But some Linux targets (like mips and ppc) go up to 16KiB (and some +non-Linux targets go up to 24KiB). + +Let's create each child with a minimum of 32KiB slack space to support +them all, and give us future breathing room. + +No test is added as existing ones crash. Even a simple call is +enough to trigger the problem: + char *argv[] = { "/bin/ls", NULL }; + posix_spawn(NULL, "/bin/ls", NULL, NULL, argv, NULL); + +[1] https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gccint/Stack-Checking.html + +(cherry picked from commit 21f042c804835d1f7a4a8e06f2c93ca35a182042) +--- + ChangeLog | 6 ++++++ + sysdeps/unix/sysv/linux/spawni.c | 5 +++++ + 2 files changed, 11 insertions(+) + +diff --git a/ChangeLog b/ChangeLog +index 321bf53..b37a054 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,9 @@ ++2017-04-03 Mike Frysinger ++ ++ [BZ #21253] ++ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size ++ slack space by 32KiB. ++ + 2017-04-03 Wladimir van der Laan + + [BZ# 21338] +diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c +index c96aac8..29d8f25 100644 +--- a/sysdeps/unix/sysv/linux/spawni.c ++++ b/sysdeps/unix/sysv/linux/spawni.c +@@ -319,6 +319,11 @@ __spawnix (pid_t * pid, const char *file, + + /* Add a slack area for child's stack. */ + size_t argv_size = (argc * sizeof (void *)) + 512; ++ /* We need at least a few pages in case the compiler's stack checking is ++ enabled. In some configs, it is known to use at least 24KiB. We use ++ 32KiB to be "safe" from anything the compiler might do. Besides, the ++ extra pages won't actually be allocated unless they get used. */ ++ argv_size += (32 * 1024); + size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); + void *stack = __mmap (NULL, stack_size, prot, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-11.patch b/srcpkgs/glibc/patches/glibc-upstream-11.patch new file mode 100644 index 0000000000..bb120e8227 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-11.patch @@ -0,0 +1,115 @@ +From 903b77defb6f2ee2552c06472339f33091e3c7b4 Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Tue, 21 Mar 2017 10:59:31 -0700 +Subject: [PATCH 11] x86-64: Improve branch predication in + _dl_runtime_resolve_avx512_opt [BZ #21258] + +On Skylake server, _dl_runtime_resolve_avx512_opt is used to preserve +the first 8 vector registers. The code layout is + + if only %xmm0 - %xmm7 registers are used + preserve %xmm0 - %xmm7 registers + if only %ymm0 - %ymm7 registers are used + preserve %ymm0 - %ymm7 registers + preserve %zmm0 - %zmm7 registers + +Branch predication always executes the fallthrough code path to preserve +%zmm0 - %zmm7 registers speculatively, even though only %xmm0 - %xmm7 +registers are used. This leads to lower CPU frequency on Skylake +server. This patch changes the fallthrough code path to preserve +%xmm0 - %xmm7 registers instead: + + if whole %zmm0 - %zmm7 registers are used + preserve %zmm0 - %zmm7 registers + if only %ymm0 - %ymm7 registers are used + preserve %ymm0 - %ymm7 registers + preserve %xmm0 - %xmm7 registers + +Tested on Skylake server. + + [BZ #21258] + * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt): + Define only if _dl_runtime_resolve is defined to + _dl_runtime_resolve_sse_vex. + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt): + Fallthrough to _dl_runtime_resolve_sse_vex. + +(cherry picked from commit c15f8eb50cea7ad1a4ccece6e0982bf426d52c00) +--- + ChangeLog | 9 +++++++++ + sysdeps/x86_64/dl-trampoline.S | 3 +-- + sysdeps/x86_64/dl-trampoline.h | 9 +++++---- + 3 files changed, 15 insertions(+), 6 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index b37a054..8479fba 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,12 @@ ++2017-04-07 H.J. Lu ++ ++ [BZ #21258] ++ * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt): ++ Define only if _dl_runtime_resolve is defined to ++ _dl_runtime_resolve_sse_vex. ++ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt): ++ Fallthrough to _dl_runtime_resolve_sse_vex. ++ + 2017-04-03 Mike Frysinger + + [BZ #21253] +diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S +index 33d7fcf..c14c61a 100644 +--- a/sysdeps/x86_64/dl-trampoline.S ++++ b/sysdeps/x86_64/dl-trampoline.S +@@ -87,11 +87,9 @@ + #endif + #define VEC(i) zmm##i + #define _dl_runtime_resolve _dl_runtime_resolve_avx512 +-#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt + #define _dl_runtime_profile _dl_runtime_profile_avx512 + #include "dl-trampoline.h" + #undef _dl_runtime_resolve +-#undef _dl_runtime_resolve_opt + #undef _dl_runtime_profile + #undef VEC + #undef VMOV +@@ -145,4 +143,5 @@ + # define VMOV vmovdqu + #endif + #define _dl_runtime_resolve _dl_runtime_resolve_sse_vex ++#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt + #include "dl-trampoline.h" +diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h +index b27fa06..8db24c1 100644 +--- a/sysdeps/x86_64/dl-trampoline.h ++++ b/sysdeps/x86_64/dl-trampoline.h +@@ -129,19 +129,20 @@ _dl_runtime_resolve_opt: + # YMM state isn't in use. + PRESERVE_BND_REGS_PREFIX + jz _dl_runtime_resolve_sse_vex +-# elif VEC_SIZE == 64 ++# elif VEC_SIZE == 16 + # For ZMM registers, check if YMM state and ZMM state are in + # use. + andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d + cmpl $bit_YMM_state, %r11d +- # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if +- # neither YMM state nor ZMM state are in use. ++ # Preserve %zmm0 - %zmm7 registers if ZMM state is in use. + PRESERVE_BND_REGS_PREFIX +- jl _dl_runtime_resolve_sse_vex ++ jg _dl_runtime_resolve_avx512 + # Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if + # ZMM state isn't in use. + PRESERVE_BND_REGS_PREFIX + je _dl_runtime_resolve_avx ++ # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if ++ # neither YMM state nor ZMM state are in use. + # else + # error Unsupported VEC_SIZE! + # endif +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-12.patch b/srcpkgs/glibc/patches/glibc-upstream-12.patch new file mode 100644 index 0000000000..b64b0287ce --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-12.patch @@ -0,0 +1,59 @@ +From b30b1c97ccfe72e82b0c95bb55274b5660bc539e Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Tue, 11 Apr 2017 15:08:02 -0300 +Subject: [PATCH 12] posix: Add cleanup on the trap list for globtest.sh + +This patch prevents lingering files for SIGSEGV failures by adding +a cleanup handler on trap handler. Checked on x86_64-linux-gnu. + + * posix/globtest.sh: Add cleanup routine on trap 0. + +Cherry-pick of 4fee33f. +--- + ChangeLog | 4 ++++ + posix/globtest.sh | 9 ++++++--- + 2 files changed, 10 insertions(+), 3 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index 8479fba..4962000 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,7 @@ ++2017-04-11 Adhemerval Zanella ++ ++ * posix/globtest.sh: Add cleanup routine on trap 0. ++ + 2017-04-07 H.J. Lu + + [BZ #21258] +diff --git a/posix/globtest.sh b/posix/globtest.sh +index f9cc80b..73f7ae3 100755 +--- a/posix/globtest.sh ++++ b/posix/globtest.sh +@@ -47,7 +47,12 @@ testout=${common_objpfx}posix/globtest-out + rm -rf $testdir $testout + mkdir $testdir + +-trap 'chmod 777 $testdir/noread; rm -fr $testdir $testout' 1 2 3 15 ++cleanup() { ++ chmod 777 $testdir/noread ++ rm -fr $testdir $testout ++} ++ ++trap cleanup 0 HUP INT QUIT TERM + + echo 1 > $testdir/file1 + echo 2 > $testdir/file2 +@@ -811,8 +816,6 @@ if test $failed -ne 0; then + fi + + if test $result -eq 0; then +- chmod 777 $testdir/noread +- rm -fr $testdir $testout + echo "All OK." > $logfile + fi + +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-13.patch b/srcpkgs/glibc/patches/glibc-upstream-13.patch new file mode 100644 index 0000000000..c6385e1dda --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-13.patch @@ -0,0 +1,136 @@ +From 4c6f97798fe1854a32b1199c42370eac1620eebf Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 28 Apr 2017 10:03:09 -0700 +Subject: [PATCH 13] x86: Set Prefer_No_VZEROUPPER if AVX512ER is available + +AVX512ER won't be implemented in any Xeon processors and will be in +all Xeon Phi processors. Don't check CPU model number when setting +Prefer_No_VZEROUPPER for Xeon Phi. Instead, set Prefer_No_VZEROUPPER +if AVX512ER is available. It works with current and future Xeon Phi +and non-Xeon Phi processors. + + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_VZEROUPPER if AVX512ER is available. + * sysdeps/x86/cpu-features.h + (bit_cpu_AVX512PF): New. + (bit_cpu_AVX512ER): Likewise. + (bit_cpu_AVX512CD): Likewise. + (bit_cpu_AVX512BW): Likewise. + (bit_cpu_AVX512VL): Likewise. + (index_cpu_AVX512PF): Likewise. + (index_cpu_AVX512ER): Likewise. + (index_cpu_AVX512CD): Likewise. + (index_cpu_AVX512BW): Likewise. + (index_cpu_AVX512VL): Likewise. + (reg_AVX512PF): Likewise. + (reg_AVX512ER): Likewise. + (reg_AVX512CD): Likewise. + (reg_AVX512BW): Likewise. + (reg_AVX512VL): Likewise. + +(cherry picked from commit 1c53cb49de6d82d9469ccbd5aa0c55924502bd8b) +--- + ChangeLog | 21 +++++++++++++++++++++ + sysdeps/x86/cpu-features.c | 8 ++++++-- + sysdeps/x86/cpu-features.h | 15 +++++++++++++++ + 3 files changed, 42 insertions(+), 2 deletions(-) + +diff --git a/ChangeLog b/ChangeLog +index 4962000..dc49c78 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,24 @@ ++2017-04-28 H.J. Lu ++ ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ Prefer_No_VZEROUPPER if AVX512ER is available. ++ * sysdeps/x86/cpu-features.h ++ (bit_cpu_AVX512PF): New. ++ (bit_cpu_AVX512ER): Likewise. ++ (bit_cpu_AVX512CD): Likewise. ++ (bit_cpu_AVX512BW): Likewise. ++ (bit_cpu_AVX512VL): Likewise. ++ (index_cpu_AVX512PF): Likewise. ++ (index_cpu_AVX512ER): Likewise. ++ (index_cpu_AVX512CD): Likewise. ++ (index_cpu_AVX512BW): Likewise. ++ (index_cpu_AVX512VL): Likewise. ++ (reg_AVX512PF): Likewise. ++ (reg_AVX512ER): Likewise. ++ (reg_AVX512CD): Likewise. ++ (reg_AVX512BW): Likewise. ++ (reg_AVX512VL): Likewise. ++ + 2017-04-11 Adhemerval Zanella + + * posix/globtest.sh: Add cleanup routine on trap 0. +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 1c714a4..41d0be2 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -139,8 +139,6 @@ init_cpu_features (struct cpu_features *cpu_features) + + case 0x57: + /* Knights Landing. Enable Silvermont optimizations. */ +- cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] +- |= bit_arch_Prefer_No_VZEROUPPER; + + case 0x5c: + case 0x5f: +@@ -226,6 +224,12 @@ init_cpu_features (struct cpu_features *cpu_features) + cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] + |= bit_arch_AVX_Fast_Unaligned_Load; + ++ /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER ++ if AVX512ER is available. */ ++ if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) ++ cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] ++ |= bit_arch_Prefer_No_VZEROUPPER; ++ + /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. + If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ + cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 95f0fcf..2ee8a0a 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -62,6 +62,11 @@ + #define bit_cpu_AVX2 (1 << 5) + #define bit_cpu_AVX512F (1 << 16) + #define bit_cpu_AVX512DQ (1 << 17) ++#define bit_cpu_AVX512PF (1 << 26) ++#define bit_cpu_AVX512ER (1 << 27) ++#define bit_cpu_AVX512CD (1 << 28) ++#define bit_cpu_AVX512BW (1 << 30) ++#define bit_cpu_AVX512VL (1u << 31) + + /* XCR0 Feature flags. */ + #define bit_XMM_state (1 << 1) +@@ -236,6 +241,11 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_cpu_AVX2 COMMON_CPUID_INDEX_7 + # define index_cpu_AVX512F COMMON_CPUID_INDEX_7 + # define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 ++# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 + # define index_cpu_ERMS COMMON_CPUID_INDEX_7 + # define index_cpu_RTM COMMON_CPUID_INDEX_7 + # define index_cpu_FMA COMMON_CPUID_INDEX_1 +@@ -254,6 +264,11 @@ extern const struct cpu_features *__get_cpu_features (void) + # define reg_AVX2 ebx + # define reg_AVX512F ebx + # define reg_AVX512DQ ebx ++# define reg_AVX512PF ebx ++# define reg_AVX512ER ebx ++# define reg_AVX512CD ebx ++# define reg_AVX512BW ebx ++# define reg_AVX512VL ebx + # define reg_ERMS ebx + # define reg_RTM ebx + # define reg_FMA ecx +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-14.patch b/srcpkgs/glibc/patches/glibc-upstream-14.patch new file mode 100644 index 0000000000..99c0367c00 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-14.patch @@ -0,0 +1,236 @@ +From 06d79808f6faf6025c5a7d4e27d949a8216275cc Mon Sep 17 00:00:00 2001 +From: "H.J. Lu" +Date: Fri, 28 Apr 2017 10:04:15 -0700 +Subject: [PATCH 14] x86: Use AVX2 memcpy/memset on Skylake server [BZ + #21396] + +On Skylake server, AVX512 load/store instructions in memcpy/memset may +lead to lower CPU turbo frequency in certain situations. Use of AVX2 +in memcpy/memset has been observed to have improved overall performance +in many workloads due to the higher frequency. + +Since AVX512ER is unique to Xeon Phi, this patch sets Prefer_No_AVX512 +if AVX512ER isn't available so that AVX2 versions of memcpy/memset are +used on Skylake server. + + [BZ #21396] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_AVX512 if AVX512ER isn't available. + * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. + (index_arch_Prefer_No_AVX512): Likewise. + * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use + AVX512 version if Prefer_No_AVX512 is set. + * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): + Likewise. + * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. + * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): + Likewise. + * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. + * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): + Likewise. + * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. + * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): + Likewise. + +(cherry picked from commit 4cb334c4d6249686653137ec273d081371b3672d) +--- + ChangeLog | 21 +++++++++++++++++++++ + sysdeps/x86/cpu-features.c | 6 +++++- + sysdeps/x86/cpu-features.h | 3 +++ + sysdeps/x86_64/multiarch/memcpy.S | 2 ++ + sysdeps/x86_64/multiarch/memcpy_chk.S | 2 ++ + sysdeps/x86_64/multiarch/memmove.S | 2 ++ + sysdeps/x86_64/multiarch/memmove_chk.S | 2 ++ + sysdeps/x86_64/multiarch/mempcpy.S | 2 ++ + sysdeps/x86_64/multiarch/mempcpy_chk.S | 2 ++ + sysdeps/x86_64/multiarch/memset.S | 2 ++ + sysdeps/x86_64/multiarch/memset_chk.S | 2 ++ + 11 files changed, 45 insertions(+), 1 deletion(-) + +diff --git a/ChangeLog b/ChangeLog +index dc49c78..adebc03 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,5 +1,26 @@ + 2017-04-28 H.J. Lu + ++ [BZ #21396] ++ * sysdeps/x86/cpu-features.c (init_cpu_features): Set ++ Prefer_No_AVX512 if AVX512ER isn't available. ++ * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. ++ (index_arch_Prefer_No_AVX512): Likewise. ++ * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use ++ AVX512 version if Prefer_No_AVX512 is set. ++ * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. ++ * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. ++ * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): ++ Likewise. ++ * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. ++ * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): ++ Likewise. ++ ++2017-04-28 H.J. Lu ++ + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_VZEROUPPER if AVX512ER is available. + * sysdeps/x86/cpu-features.h +diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c +index 41d0be2..9afd74c 100644 +--- a/sysdeps/x86/cpu-features.c ++++ b/sysdeps/x86/cpu-features.c +@@ -225,10 +225,14 @@ init_cpu_features (struct cpu_features *cpu_features) + |= bit_arch_AVX_Fast_Unaligned_Load; + + /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER +- if AVX512ER is available. */ ++ if AVX512ER is available. Don't use AVX512 to avoid lower CPU ++ frequency if AVX512ER isn't available. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) + cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] + |= bit_arch_Prefer_No_VZEROUPPER; ++ else ++ cpu_features->feature[index_arch_Prefer_No_AVX512] ++ |= bit_arch_Prefer_No_AVX512; + + /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. + If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ +diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h +index 2ee8a0a..a409db6 100644 +--- a/sysdeps/x86/cpu-features.h ++++ b/sysdeps/x86/cpu-features.h +@@ -39,6 +39,7 @@ + #define bit_arch_Prefer_ERMS (1 << 19) + #define bit_arch_Use_dl_runtime_resolve_opt (1 << 20) + #define bit_arch_Use_dl_runtime_resolve_slow (1 << 21) ++#define bit_arch_Prefer_No_AVX512 (1 << 22) + + /* CPUID Feature flags. */ + +@@ -116,6 +117,7 @@ + # define index_arch_Prefer_ERMS FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE + # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE ++# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1*FEATURE_SIZE + + + # if defined (_LIBC) && !IS_IN (nonlib) +@@ -298,6 +300,7 @@ extern const struct cpu_features *__get_cpu_features (void) + # define index_arch_Prefer_ERMS FEATURE_INDEX_1 + # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1 + # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1 ++# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 + + #endif /* !__ASSEMBLER__ */ + +diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S +index 1f83ee3..af27703 100644 +--- a/sysdeps/x86_64/multiarch/memcpy.S ++++ b/sysdeps/x86_64/multiarch/memcpy.S +@@ -32,6 +32,8 @@ ENTRY(__new_memcpy) + lea __memcpy_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memcpy_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memcpy_chk.S b/sysdeps/x86_64/multiarch/memcpy_chk.S +index 5492342..8737fb9 100644 +--- a/sysdeps/x86_64/multiarch/memcpy_chk.S ++++ b/sysdeps/x86_64/multiarch/memcpy_chk.S +@@ -30,6 +30,8 @@ + ENTRY(__memcpy_chk) + .type __memcpy_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memmove.S b/sysdeps/x86_64/multiarch/memmove.S +index 2021bfc..8c534e8 100644 +--- a/sysdeps/x86_64/multiarch/memmove.S ++++ b/sysdeps/x86_64/multiarch/memmove.S +@@ -30,6 +30,8 @@ ENTRY(__libc_memmove) + lea __memmove_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memmove_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memmove_chk.S b/sysdeps/x86_64/multiarch/memmove_chk.S +index 8a252ad..7870dd0 100644 +--- a/sysdeps/x86_64/multiarch/memmove_chk.S ++++ b/sysdeps/x86_64/multiarch/memmove_chk.S +@@ -29,6 +29,8 @@ + ENTRY(__memmove_chk) + .type __memmove_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __memmove_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/mempcpy.S b/sysdeps/x86_64/multiarch/mempcpy.S +index 79c840d..b8b2b28 100644 +--- a/sysdeps/x86_64/multiarch/mempcpy.S ++++ b/sysdeps/x86_64/multiarch/mempcpy.S +@@ -32,6 +32,8 @@ ENTRY(__mempcpy) + lea __mempcpy_erms(%rip), %RAX_LP + HAS_ARCH_FEATURE (Prefer_ERMS) + jnz 2f ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __mempcpy_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/mempcpy_chk.S b/sysdeps/x86_64/multiarch/mempcpy_chk.S +index 6927962..072b22c 100644 +--- a/sysdeps/x86_64/multiarch/mempcpy_chk.S ++++ b/sysdeps/x86_64/multiarch/mempcpy_chk.S +@@ -30,6 +30,8 @@ + ENTRY(__mempcpy_chk) + .type __mempcpy_chk, @gnu_indirect_function + LOAD_RTLD_GLOBAL_RO_RDX ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 1f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 1f + lea __mempcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S +index c958b2f..9d33118 100644 +--- a/sysdeps/x86_64/multiarch/memset.S ++++ b/sysdeps/x86_64/multiarch/memset.S +@@ -41,6 +41,8 @@ ENTRY(memset) + jnz L(AVX512F) + lea __memset_avx2_unaligned(%rip), %RAX_LP + L(AVX512F): ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 2f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 2f + lea __memset_avx512_no_vzeroupper(%rip), %RAX_LP +diff --git a/sysdeps/x86_64/multiarch/memset_chk.S b/sysdeps/x86_64/multiarch/memset_chk.S +index 79eaa37..7e08311 100644 +--- a/sysdeps/x86_64/multiarch/memset_chk.S ++++ b/sysdeps/x86_64/multiarch/memset_chk.S +@@ -38,6 +38,8 @@ ENTRY(__memset_chk) + jnz L(AVX512F) + lea __memset_chk_avx2_unaligned(%rip), %RAX_LP + L(AVX512F): ++ HAS_ARCH_FEATURE (Prefer_No_AVX512) ++ jnz 2f + HAS_ARCH_FEATURE (AVX512F_Usable) + jz 2f + lea __memset_chk_avx512_no_vzeroupper(%rip), %RAX_LP +-- +2.7.4.GIT + + diff --git a/srcpkgs/glibc/patches/glibc-upstream-15.patch b/srcpkgs/glibc/patches/glibc-upstream-15.patch new file mode 100644 index 0000000000..b1f941ac20 --- /dev/null +++ b/srcpkgs/glibc/patches/glibc-upstream-15.patch @@ -0,0 +1,89 @@ +From ccb4fd7a657b0fbc4890c98f4586d58a135fc583 Mon Sep 17 00:00:00 2001 +From: Adhemerval Zanella +Date: Tue, 14 Mar 2017 14:16:13 -0300 +Subject: [PATCH 15] Fix i686 memchr overflow calculation (BZ#21182) + +This patch fixes the regression added by 23d2770 for final address +overflow calculation. The subtraction of the considered size (16) +at line 120 is at wrong place, for sizes less than 16 subsequent +overflow check will not take in consideration an invalid size (since +the subtraction will be negative). Also, the lea instruction also +does not raise the carry flag (CF) that is used in subsequent jbe +to check for overflow. + +The fix is to follow x86_64 logic from 3daef2c where the overflow +is first check and a sub instruction is issued. In case of resulting +negative size, CF will be set by the sub instruction and a NULL +result will be returned. The patch also add similar tests reported +in bug report. + +Checked on i686-linux-gnu and x86_64-linux-gnu. + + * string/test-memchr.c (do_test): Add BZ#21182 checks for address + near end of a page. + * sysdeps/i386/i686/multiarch/memchr-sse2.S (__memchr): Fix + overflow calculation. + +Cherry-pick of 3abeeec5f46ff036bd9df60bb096e20314ccd078. +--- + ChangeLog | 8 ++++++++ + string/test-memchr.c | 6 ++++++ + sysdeps/i386/i686/multiarch/memchr-sse2.S | 2 +- + 3 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/ChangeLog b/ChangeLog +index adebc03..ac19e98 100644 +--- a/ChangeLog ++++ b/ChangeLog +@@ -1,3 +1,11 @@ ++2017-05-01 Adhemerval Zanella ++ ++ [BZ# 21182] ++ * string/test-memchr.c (do_test): Add BZ#21182 checks for address ++ near end of a page. ++ * sysdeps/i386/i686/multiarch/memchr-sse2.S (__memchr): Fix ++ overflow calculation. ++ + 2017-04-28 H.J. Lu + + [BZ #21396] +diff --git a/string/test-memchr.c b/string/test-memchr.c +index d62889f..6431605 100644 +--- a/string/test-memchr.c ++++ b/string/test-memchr.c +@@ -208,6 +208,12 @@ test_main (void) + do_test (0, i, i + 1, i + 1, 0); + } + ++ /* BZ#21182 - wrong overflow calculation for i686 implementation ++ with address near end of the page. */ ++ for (i = 2; i < 16; ++i) ++ /* page_size is in fact getpagesize() * 2. */ ++ do_test (page_size / 2 - i, i, i, 1, 0x9B); ++ + do_random_tests (); + return ret; + } +diff --git a/sysdeps/i386/i686/multiarch/memchr-sse2.S b/sysdeps/i386/i686/multiarch/memchr-sse2.S +index 910679c..e41f324 100644 +--- a/sysdeps/i386/i686/multiarch/memchr-sse2.S ++++ b/sysdeps/i386/i686/multiarch/memchr-sse2.S +@@ -117,7 +117,6 @@ L(crosscache): + + # ifndef USE_AS_RAWMEMCHR + jnz L(match_case2_prolog1) +- lea -16(%edx), %edx + /* Calculate the last acceptable address and check for possible + addition overflow by using satured math: + edx = ecx + edx +@@ -125,6 +124,7 @@ L(crosscache): + add %ecx, %edx + sbb %eax, %eax + or %eax, %edx ++ sub $16, %edx + jbe L(return_null) + lea 16(%edi), %edi + # else +-- +2.7.4.GIT + diff --git a/srcpkgs/glibc/patches/revert-memchr-i686.patch b/srcpkgs/glibc/patches/revert-memchr-i686.patch deleted file mode 100644 index da5de426a7..0000000000 --- a/srcpkgs/glibc/patches/revert-memchr-i686.patch +++ /dev/null @@ -1,42 +0,0 @@ -diff --git a/sysdeps/i386/i686/multiarch/memchr-sse2-bsf.S b/sysdeps/i386/i686/multiarch/memchr-sse2-bsf.S -index dd316486e6..c035329ece 100644 ---- a/sysdeps/i386/i686/multiarch/memchr-sse2-bsf.S -+++ b/sysdeps/i386/i686/multiarch/memchr-sse2-bsf.S -@@ -149,15 +149,9 @@ L(crosscache): - .p2align 4 - L(unaligned_no_match): - # ifndef USE_AS_RAWMEMCHR -- /* Calculate the last acceptable address and check for possible -- addition overflow by using satured math: -- edx = ecx + edx -- edx |= -(edx < ecx) */ -- add %ecx, %edx -- sbb %eax, %eax -- or %eax, %edx - sub $16, %edx -- jbe L(return_null) -+ add %ecx, %edx -+ jle L(return_null) - add $16, %edi - # else - add $16, %edx -diff --git a/sysdeps/i386/i686/multiarch/memchr-sse2.S b/sysdeps/i386/i686/multiarch/memchr-sse2.S -index 910679cfc0..f1a11b5c67 100644 ---- a/sysdeps/i386/i686/multiarch/memchr-sse2.S -+++ b/sysdeps/i386/i686/multiarch/memchr-sse2.S -@@ -118,14 +118,8 @@ L(crosscache): - # ifndef USE_AS_RAWMEMCHR - jnz L(match_case2_prolog1) - lea -16(%edx), %edx -- /* Calculate the last acceptable address and check for possible -- addition overflow by using satured math: -- edx = ecx + edx -- edx |= -(edx < ecx) */ - add %ecx, %edx -- sbb %eax, %eax -- or %eax, %edx -- jbe L(return_null) -+ jle L(return_null) - lea 16(%edi), %edi - # else - jnz L(match_case1_prolog1) diff --git a/srcpkgs/glibc/template b/srcpkgs/glibc/template index 447a9fedf5..3218295f3e 100644 --- a/srcpkgs/glibc/template +++ b/srcpkgs/glibc/template @@ -1,7 +1,7 @@ # Template file for 'glibc' pkgname=glibc version=2.25 -revision=3 +revision=4 bootstrap=yes short_desc="The GNU C library" maintainer="Juan RP "