summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes2017-04-06 19:56:44 -0400
committerTavian Barnes2017-04-06 20:08:30 -0400
commit60468697b22774100e54a5f3b821ca19dc1d9c88 (patch)
tree07fd8eeb11ff90089888f171b4f652f5490ef7d8
parent09d0d47d7dafcc2667ef4f1e3a09f2c30549fadf (diff)
downloadaur-60468697b22774100e54a5f3b821ca19dc1d9c88.tar.gz
Bump to 2.25-1
-rw-r--r--.SRCINFO18
-rw-r--r--PKGBUILD44
-rw-r--r--glibc-69e0a87cc4c570e3b7218392fc3e743b5bddcce2.patch1911
3 files changed, 1946 insertions, 27 deletions
diff --git a/.SRCINFO b/.SRCINFO
index f9e0b280414..cce7a03f990 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,22 +1,24 @@
# Generated by mksrcinfo v8
-# Fri Feb 3 00:39:42 UTC 2017
+# Fri Apr 7 00:08:24 UTC 2017
pkgbase = arm-linux-gnueabihf-glibc-headers
pkgdesc = GNU C Library headers (arm-linux-gnueabihf)
- pkgver = 2.24
- pkgrel = 2
+ pkgver = 2.25
+ pkgrel = 1
url = http://www.gnu.org/software/libc/
arch = any
license = GPL
license = LGPL
- makedepends = arm-linux-gnueabihf-gcc-stage1>=6.3.1
- depends = arm-linux-gnueabihf-linux-api-headers>=4.7
+ makedepends = arm-linux-gnueabihf-gcc-stage1>=6.3.1-2
+ depends = arm-linux-gnueabihf-linux-api-headers>=4.10.1-1
options = !buildflags
options = !strip
options = staticlibs
- source = http://ftp.gnu.org/gnu/libc/glibc-2.24.tar.xz
- source = http://ftp.gnu.org/gnu/libc/glibc-2.24.tar.xz.sig
- md5sums = 97dc5517f92016f3d70d83e3162ad318
+ source = http://ftp.gnu.org/gnu/libc/glibc-2.25.tar.xz
+ source = http://ftp.gnu.org/gnu/libc/glibc-2.25.tar.xz.sig
+ source = glibc-69e0a87cc4c570e3b7218392fc3e743b5bddcce2.patch
+ md5sums = 1496c3bf41adf9db0ebd0af01f202eed
md5sums = SKIP
+ md5sums = ead76a671d598295114b07c11bee79ba
pkgname = arm-linux-gnueabihf-glibc-headers
diff --git a/PKGBUILD b/PKGBUILD
index 6b062837343..154cb246fb3 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -6,25 +6,27 @@
_target="arm-linux-gnueabihf"
pkgname=${_target}-glibc-headers
-pkgver=2.24
-pkgrel=2
-_commit=fdfc9260
+pkgver=2.25
+pkgrel=1
+_commit=69e0a87cc4c570e3b7218392fc3e743b5bddcce2
pkgdesc="GNU C Library headers (${_target})"
arch=('any')
url="http://www.gnu.org/software/libc/"
license=('GPL' 'LGPL')
-depends=("${_target}-linux-api-headers>=4.7")
-makedepends=("${_target}-gcc-stage1>=6.3.1")
+depends=("${_target}-linux-api-headers>=4.10.1-1")
+makedepends=("${_target}-gcc-stage1>=6.3.1-2")
options=('!buildflags' '!strip' 'staticlibs')
-source=(http://ftp.gnu.org/gnu/libc/glibc-${pkgver}.tar.xz{,.sig})
-md5sums=('97dc5517f92016f3d70d83e3162ad318'
- 'SKIP')
-validpgpkeys=('7273542B39962DF7B299931416792B4EA25340F8') # Carlos O'Donell
+source=(http://ftp.gnu.org/gnu/libc/glibc-${pkgver}.tar.xz{,.sig}
+ glibc-${_commit}.patch)
+md5sums=('1496c3bf41adf9db0ebd0af01f202eed'
+ 'SKIP'
+ 'ead76a671d598295114b07c11bee79ba')
+validpgpkeys=('BC7C7372637EC10C57D7AA6579C43DFBF1CF2187') # Siddhesh Poyarekar
prepare() {
cd glibc-${pkgver}
- #patch -p1 -i ${srcdir}/glibc-${_commit}.patch
+ patch -p1 -i ${srcdir}/glibc-${_commit}.patch
mkdir ${srcdir}/glibc-build
}
@@ -37,10 +39,8 @@ build() {
echo "sbindir=/bin" >> configparms
echo "rootsbindir=/bin" >> configparms
- # remove hardening options for building libraries
- export CFLAGS="-U_FORTIFY_SOURCE -mlittle-endian -O2"
- export CPPFLAGS="-U_FORTIFY_SOURCE -O2"
- unset LD_LIBRARY_PATH
+ # remove fortify for building libraries
+ CPPFLAGS=${CPPFLAGS/-D_FORTIFY_SOURCE=2/}
export BUILD_CC=gcc
export CC=${_target}-gcc
@@ -48,18 +48,24 @@ build() {
export AR=${_target}-ar
export RANLIB=${_target}-ranlib
- ../glibc-${pkgver}/configure --prefix=/ \
- --target=${_target} --host=${_target} --build=${CHOST} \
- --libdir=/lib --libexecdir=/lib \
+ ../glibc-${pkgver}/configure \
+ --prefix=/ \
+ --libdir=/lib \
+ --libexecdir=/lib \
--with-headers=/usr/${_target}/include \
--enable-add-ons \
--enable-obsolete-rpc \
--enable-kernel=2.6.32 \
- --enable-bind-now --disable-profile \
+ --enable-bind-now \
+ --disable-profile \
--enable-stackguard-randomization \
+ --enable-stack-protector=strong \
--enable-lock-elision \
--disable-multi-arch \
- --disable-werror
+ --disable-werror \
+ --target=${_target} \
+ --host=${_target} \
+ --build=${CHOST}
# make some libs and stubs
make csu/subdir_lib
diff --git a/glibc-69e0a87cc4c570e3b7218392fc3e743b5bddcce2.patch b/glibc-69e0a87cc4c570e3b7218392fc3e743b5bddcce2.patch
new file mode 100644
index 00000000000..68e86f47b1f
--- /dev/null
+++ b/glibc-69e0a87cc4c570e3b7218392fc3e743b5bddcce2.patch
@@ -0,0 +1,1911 @@
+diff --git a/ChangeLog b/ChangeLog
+index f140ee67de..8aaf9f825d 100644
+--- a/ChangeLog
++++ b/ChangeLog
+@@ -1,3 +1,61 @@
++2017-03-02 Florian Weimer <fweimer@redhat.com>
++
++ [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 <fweimer@redhat.com>
++
++ [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 <fweimer@redhat.com>
++
++ [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 <siddhesh@sourceware.org>
++
++ [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 <siddhesh@sourceware.org>
+
+ * version.h (RELEASE): Set to "stable"
+diff --git a/INSTALL b/INSTALL
+index 3b3fd121b2..e77cb2d4e2 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 97a15b569e..1c815113b9 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 e9194e54cf..7f0eef8096 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 ec15dde761..9bf8c10926 100644
+--- a/NEWS
++++ b/NEWS
+@@ -5,6 +5,15 @@ See the end for copying conditions.
+ Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
+ using `glibc' in the "product" field.
+
++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
++
+ 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 a986f0b593..37a4e8021f 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 a8d53d6a31..e42aa67003 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/iconvdata/Makefile b/iconvdata/Makefile
+index 04157b25c5..e4845871f5 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/inet/Makefile b/inet/Makefile
+index 010792af8f..6a7d3e0664 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 0000000000..c1fa415a39
+--- /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 (&current_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 087597ed99..2b2632c7ba 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 0000000000..ed04345c35
+--- /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/malloc/arena.c b/malloc/arena.c
+index b91d7d6b16..d49e4a21c8 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); \
+ }
+
+diff --git a/manual/install.texi b/manual/install.texi
+index 266add8ba9..3398cfab02 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/sunrpc/Makefile b/sunrpc/Makefile
+index 0c1e6124ff..7e5d2955a0 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
++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)
+@@ -155,6 +156,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))
+
+@@ -234,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 4d9acb1e6a..6ce16eb298 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);
+ }
+@@ -421,9 +436,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);
+@@ -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-error.c b/sunrpc/tst-udp-error.c
+new file mode 100644
+index 0000000000..1efc02f5c6
+--- /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>
+diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c
+new file mode 100644
+index 0000000000..4abda93f08
+--- /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 0000000000..1d6a7f4b56
+--- /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 0000000000..db9943a03e
+--- /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>
+diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
+index cca17f1e34..1f0e3b494e 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 2c2584956d..8ea4333846 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 014a9f4554..a1840cff31 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