diff options
author | 2017-03-15 23:54:35 +0000 | |
---|---|---|
committer | 2017-03-15 23:54:35 +0000 | |
commit | 3647e4716bb543b95c6e495c3d959e46085519ec (patch) | |
tree | 403f3fa24810025c8c482c98721844c630ff94a4 | |
parent | add test fix from upstream for building w/newer timezone-data (diff) | |
download | gentoo-3647e4716bb543b95c6e495c3d959e46085519ec.tar.gz gentoo-3647e4716bb543b95c6e495c3d959e46085519ec.tar.bz2 gentoo-3647e4716bb543b95c6e495c3d959e46085519ec.zip |
grab more fixes from upstream
7 files changed, 2042 insertions, 0 deletions
diff --git a/src/patchsets/glibc/2.25/00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch b/src/patchsets/glibc/2.25/00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch new file mode 100644 index 0000000000..7d39b05566 --- /dev/null +++ b/src/patchsets/glibc/2.25/00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch @@ -0,0 +1,84 @@ +From 0232af1ad6cbd8378025e804f535ce9449ad49de Mon Sep 17 00:00:00 2001 +From: Siddhesh Poyarekar <siddhesh@sourceware.org> +Date: Thu, 9 Feb 2017 17:28:54 +0100 +Subject: [PATCH] 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) +(cherry picked from commit 58520986c38e34db60e07260c64c563e3efcf353) +--- + elf/dl-tunable-types.h | 4 ++-- + elf/dl-tunables.c | 2 ++ + malloc/arena.c | 8 ++++---- + 3 files changed, 8 insertions(+), 6 deletions(-) + +diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h +index a986f0b5930d..37a4e8021f8f 100644 +--- a/elf/dl-tunable-types.h ++++ b/elf/dl-tunable-types.h +@@ -21,8 +21,6 @@ + # define _TUNABLE_TYPES_H_ + #include <stddef.h> + +-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 a8d53d6a311d..e42aa6700331 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 b91d7d6b16cd..d49e4a21c840 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.12.0 + diff --git a/src/patchsets/glibc/2.25/00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch b/src/patchsets/glibc/2.25/00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch new file mode 100644 index 0000000000..cd5edb0256 --- /dev/null +++ b/src/patchsets/glibc/2.25/00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch @@ -0,0 +1,131 @@ +From 55df1000167b0143106e063f23159515d0c9c61c Mon Sep 17 00:00:00 2001 +From: Florian Weimer <fweimer@redhat.com> +Date: Tue, 28 Feb 2017 17:05:46 +0100 +Subject: [PATCH] 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) +(cherry picked from commit 045e368799cd253ddbf8bdec42ed92e8ebb3ce67) +--- + sunrpc/Makefile | 3 ++- + sunrpc/clnt_udp.c | 2 +- + sunrpc/tst-udp-error.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 65 insertions(+), 2 deletions(-) + create mode 100644 sunrpc/tst-udp-error.c + +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index 0c1e6124ff4b..daf8a28f1aee 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 4d9acb1e6a6b..1de25cb77116 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 000000000000..1efc02f5c60a +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <netinet/in.h> ++#include <rpc/clnt.h> ++#include <rpc/svc.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/xsocket.h> ++#include <unistd.h> ++ ++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 <support/test-driver.c> +-- +2.12.0 + diff --git a/src/patchsets/glibc/2.25/00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch b/src/patchsets/glibc/2.25/00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch new file mode 100644 index 0000000000..5b0efd0298 --- /dev/null +++ b/src/patchsets/glibc/2.25/00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch @@ -0,0 +1,1566 @@ +From 23b0289cf5f7abf984f5f15f54e8feb21938eece Mon Sep 17 00:00:00 2001 +From: Florian Weimer <fweimer@redhat.com> +Date: Tue, 28 Feb 2017 17:36:00 +0100 +Subject: [PATCH] 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) +(cherry picked from commit 93cf93e06ce123439e41d3d62790601c313134cb) +--- + 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 +++++++++++++++++++++++++++++++++++++++++++ + 9 files changed, 1324 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/inet/Makefile b/inet/Makefile +index 010792af8f3d..6a7d3e066416 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 000000000000..c1fa415a39f7 +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <net-internal.h> ++ ++#include <assert.h> ++#include <limits.h> ++#include <stdio.h> ++#include <stdint.h> ++#include <time.h> ++ ++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 087597ed9923..2b2632c7ba84 100644 +--- a/inet/net-internal.h ++++ b/inet/net-internal.h +@@ -20,11 +20,100 @@ + #define _NET_INTERNAL_H 1 + + #include <arpa/inet.h> ++#include <stdbool.h> + #include <stdint.h> ++#include <sys/time.h> + + 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 000000000000..ed04345c3513 +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <inet/net-internal.h> ++#include <limits.h> ++#include <stdbool.h> ++#include <stdint.h> ++#include <support/check.h> ++ ++/* 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 <support/test-driver.c> +diff --git a/sunrpc/Makefile b/sunrpc/Makefile +index daf8a28f1aee..7e5d2955a0f4 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 1de25cb77116..6ce16eb2988c 100644 +--- a/sunrpc/clnt_udp.c ++++ b/sunrpc/clnt_udp.c +@@ -55,6 +55,7 @@ + #endif + + #include <kernel-features.h> ++#include <inet/net-internal.h> + + 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 000000000000..4abda93f0855 +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <netinet/in.h> ++#include <rpc/clnt.h> ++#include <rpc/svc.h> ++#include <stdbool.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/xsocket.h> ++#include <support/xthread.h> ++#include <sys/socket.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c +new file mode 100644 +index 000000000000..1d6a7f4b56f7 +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <netinet/in.h> ++#include <rpc/clnt.h> ++#include <rpc/svc.h> ++#include <stdbool.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/test-driver.h> ++#include <support/xsocket.h> ++#include <support/xunistd.h> ++#include <sys/socket.h> ++#include <time.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c +new file mode 100644 +index 000000000000..db9943a03e3d +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++#include <netinet/in.h> ++#include <rpc/clnt.h> ++#include <rpc/svc.h> ++#include <stdbool.h> ++#include <string.h> ++#include <support/check.h> ++#include <support/namespace.h> ++#include <support/test-driver.h> ++#include <support/xsocket.h> ++#include <support/xunistd.h> ++#include <sys/socket.h> ++#include <time.h> ++#include <unistd.h> ++ ++/* 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 <support/test-driver.c> +-- +2.12.0 + diff --git a/src/patchsets/glibc/2.25/00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch b/src/patchsets/glibc/2.25/00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch new file mode 100644 index 0000000000..5090c0d335 --- /dev/null +++ b/src/patchsets/glibc/2.25/00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch @@ -0,0 +1,162 @@ +From 32b4c41fb6d814551fa6d6e5e07ecbe2119407a7 Mon Sep 17 00:00:00 2001 +From: Florian Weimer <fweimer@redhat.com> +Date: Thu, 2 Mar 2017 20:11:27 +0100 +Subject: [PATCH] Document and fix --enable-bind-now [BZ #21015] + +(cherry picked from commit 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9) +(cherry picked from commit 69e0a87cc4c570e3b7218392fc3e743b5bddcce2) +--- + INSTALL | 6 ++++++ + Makeconfig | 7 +++++++ + Makerules | 9 +++------ + 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 +- + 8 files changed, 30 insertions(+), 9 deletions(-) + +diff --git a/INSTALL b/INSTALL +index 3b3fd121b232..e77cb2d4e294 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 d944cd5db654..fcd2a5d7b1dd 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 e9194e54cf67..7f0eef8096cc 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/iconvdata/Makefile b/iconvdata/Makefile +index 04157b25c5cc..e4845871f559 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 266add8ba9f4..3398cfab02b5 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 cca17f1e34bd..1f0e3b494e90 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 2c2584956d03..8ea4333846df 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 014a9f455430..a1840cff31cf 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.12.0 + diff --git a/src/patchsets/glibc/2.25/00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch b/src/patchsets/glibc/2.25/00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch new file mode 100644 index 0000000000..92d9e20906 --- /dev/null +++ b/src/patchsets/glibc/2.25/00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch @@ -0,0 +1,53 @@ +From 883dae86d69153092f73a223f226c85fa4fb9a35 Mon Sep 17 00:00:00 2001 +From: John David Anglin <dave.anglin@bell.net> +Date: Mon, 20 Feb 2017 20:31:57 -0500 +Subject: [PATCH] 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) +(cherry picked from commit 8b3caa41b9cb82651e72a0c87aa56719c134000e) +--- + sysdeps/hppa/dl-machine.h | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h +index 339c7bb77129..787b95f5022e 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.12.0 + diff --git a/src/patchsets/glibc/2.25/00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch b/src/patchsets/glibc/2.25/00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch new file mode 100644 index 0000000000..cf36bef90b --- /dev/null +++ b/src/patchsets/glibc/2.25/00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch @@ -0,0 +1,38 @@ +From 92bec3dad990b1dda9a82966913fce04b5c99c02 Mon Sep 17 00:00:00 2001 +From: Mike Frysinger <vapier@gentoo.org> +Date: Sun, 12 Mar 2017 15:12:21 -0700 +Subject: [PATCH] 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 <vapier@gentoo.org> + + * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED + instead of PIC. + +(cherry picked from commit fbe355fbd1973d6e29561084b3eaeb4bfe9d515a) +(cherry picked from commit 0889003c67f9c2f520a37281c4b5c3b8a9861f46) +--- + sysdeps/x86_64/mempcpy_chk.S | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S +index f8a9260e6ea8..f91229157690 100644 +--- a/sysdeps/x86_64/mempcpy_chk.S ++++ b/sysdeps/x86_64/mempcpy_chk.S +@@ -19,7 +19,7 @@ + #include <sysdep.h> + #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.12.0 + diff --git a/src/patchsets/glibc/2.25/README.history b/src/patchsets/glibc/2.25/README.history index 6b3081ab14..521401b6d4 100644 --- a/src/patchsets/glibc/2.25/README.history +++ b/src/patchsets/glibc/2.25/README.history @@ -1,3 +1,11 @@ +2 15 Mar 2017 + + 00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch + + 00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch + + 00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch + + 00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch + + 00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch + + 00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch + 1 09 Feb 2017 + 00_all_0001-disable-ldconfig-during-install.patch + 00_all_0002-reload-etc-resolv.conf-when-it-has-changed.patch |