commit 58520986c38e34db60e07260c64c563e3efcf353
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Thu Feb 9 17:28:54 2017 +0100

    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)

diff --git a/ChangeLog b/ChangeLog
index f140ee67de..c88238e0fa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+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/NEWS b/NEWS
index ec15dde761..325cac78e4 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,12 @@ 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
+
 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/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);						      \
 }
 

commit 045e368799cd253ddbf8bdec42ed92e8ebb3ce67
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Feb 28 17:05:46 2017 +0100

    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)

diff --git a/ChangeLog b/ChangeLog
index c88238e0fa..3d781a354a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+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]
diff --git a/NEWS b/NEWS
index 325cac78e4..5ecc565371 100644
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Version 2.25.1
 The following bugs are resolved with this release:
 
   [21109] Tunables broken on big-endian
+  [21115] sunrpc: Use-after-free in error path in clntudp_call
 
 Version 2.25
 
diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index 0c1e6124ff..daf8a28f1a 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 4d9acb1e6a..1de25cb771 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 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>

commit 93cf93e06ce123439e41d3d62790601c313134cb
Author: Florian Weimer <fweimer@redhat.com>
Date:   Tue Feb 28 17:36:00 2017 +0100

    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)

diff --git a/ChangeLog b/ChangeLog
index 3d781a354a..510ca42c2b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,26 @@
+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]
diff --git a/NEWS b/NEWS
index 5ecc565371..e7d6668664 100644
--- a/NEWS
+++ b/NEWS
@@ -11,6 +11,7 @@ The following bugs are resolved with this release:
 
   [21109] Tunables broken on big-endian
   [21115] sunrpc: Use-after-free in error path in clntudp_call
+  [20257] sunrpc: clntudp_call does not enforce timeout when receiving data
 
 Version 2.25
 
diff --git a/inet/Makefile b/inet/Makefile
index 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/sunrpc/Makefile b/sunrpc/Makefile
index daf8a28f1a..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 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 1de25cb771..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);
 	}
@@ -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 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>

commit 69e0a87cc4c570e3b7218392fc3e743b5bddcce2
Author: Florian Weimer <fweimer@redhat.com>
Date:   Thu Mar 2 20:11:27 2017 +0100

    Document and fix --enable-bind-now [BZ #21015]
    
    (cherry picked from commit 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9)

diff --git a/ChangeLog b/ChangeLog
index 510ca42c2b..8aaf9f825d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+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]
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 e7d6668664..9bf8c10926 100644
--- a/NEWS
+++ b/NEWS
@@ -12,6 +12,7 @@ The following bugs are resolved with this release:
   [21109] Tunables broken on big-endian
   [21115] sunrpc: Use-after-free in error path in clntudp_call
   [20257] sunrpc: clntudp_call does not enforce timeout when receiving data
+  [21015] Document and fix --enable-bind-now
 
 Version 2.25
 
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 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/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/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

commit 8b3caa41b9cb82651e72a0c87aa56719c134000e
Author: John David Anglin <dave.anglin@bell.net>
Date:   Mon Feb 20 20:31:57 2017 -0500

    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)

diff --git a/ChangeLog b/ChangeLog
index 8aaf9f825d..d8ed2e4d90 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-03-15  John David Anglin  <danglin@gcc.gnu.org>
+
+	* sysdeps/hppa/dl-machine.h (DL_STACK_END): Define.
+	(RTLD_START): Don't record stack end address in _dl_start_user.
+
 2017-03-02  Florian Weimer  <fweimer@redhat.com>
 
 	[BZ #21015]
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
index 339c7bb771..787b95f502 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"				\

commit 0889003c67f9c2f520a37281c4b5c3b8a9861f46
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Sun Mar 12 15:12:21 2017 -0700

    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)

diff --git a/ChangeLog b/ChangeLog
index d8ed2e4d90..c29a70aa72 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-03-15  Mike Frysinger  <vapier@gentoo.org>
+
+	* sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED
+	instead of PIC.
+
 2017-03-15  John David Anglin  <danglin@gcc.gnu.org>
 
 	* sysdeps/hppa/dl-machine.h (DL_STACK_END): Define.
diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S
index f8a9260e6e..f912291576 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

commit 27ab0d9518746dfb59ed2ba59daefc981dc10e38
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Mon Mar 20 04:47:56 2017 -0400

    posix_spawn: fix stack setup on ia64 [BZ #21275]
    
    The ia64-specific clone2 call expects the base of the stack mapping and
    the stack size as sep arguments, not an initial stack value as on other
    stack-grows-down architectures.  Reuse the stack-grows-up macro so we
    pass in the right stack base.
    
    Reported-by: Matt Turner <mattst88@gentoo.org>
    (cherry picked from commit ddc3fb333469c2997798742dc0509dc1e3201d91)

diff --git a/ChangeLog b/ChangeLog
index c29a70aa72..ef5388c2c3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2017-03-20  Mike Frysinger  <vapier@gentoo.org>
+
+	[BZ #21275]
+	* sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename
+	__stack to __stackbase.
+	(STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of
+	checks so we can include defined(__ia64__) first.
+
 2017-03-15  Mike Frysinger  <vapier@gentoo.org>
 
 	* sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index 2daf0c5ef0..c96aac889d 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -61,17 +61,18 @@
 #define SPAWN_ERROR	127
 
 #ifdef __ia64__
-# define CLONE(__fn, __stack, __stacksize, __flags, __args) \
-  __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0)
+# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \
+  __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0)
 #else
 # define CLONE(__fn, __stack, __stacksize, __flags, __args) \
   __clone (__fn, __stack, __flags, __args)
 #endif
 
-#if _STACK_GROWS_DOWN
-# define STACK(__stack, __stack_size) (__stack + __stack_size)
-#elif _STACK_GROWS_UP
+/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro.  */
+#if _STACK_GROWS_UP || defined (__ia64__)
 # define STACK(__stack, __stack_size) (__stack)
+#elif _STACK_GROWS_DOWN
+# define STACK(__stack, __stack_size) (__stack + __stack_size)
 #endif
 
 

commit f035c8d055f25eaf6c93772f308afac10ce31ef2
Author: Slava Barinov <v.barinov@samsung.com>
Date:   Fri Mar 31 08:49:25 2017 +0200

    fts: Fix symbol redirect for fts_set [BZ #21289]
    
    In a 32-bit environment with _FILE_OFFSET_BITS=64, the __REDIRECT macro
    combined with __THROW generates an invalid C++ declaration.
    
    (cherry picked from commit ce39613205dc47ceaeea76710d49e7a483b503ab)

diff --git a/ChangeLog b/ChangeLog
index ef5388c2c3..85d6fc6192 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-03-31  Slava Barinov  <v.barinov@samsung.com>
+
+	[BZ #21289]
+	* io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH.
+
 2017-03-20  Mike Frysinger  <vapier@gentoo.org>
 
 	[BZ #21275]
diff --git a/NEWS b/NEWS
index 9bf8c10926..fee1cf8ca8 100644
--- a/NEWS
+++ b/NEWS
@@ -9,10 +9,11 @@ Version 2.25.1
 
 The following bugs are resolved with this release:
 
-  [21109] Tunables broken on big-endian
-  [21115] sunrpc: Use-after-free in error path in clntudp_call
   [20257] sunrpc: clntudp_call does not enforce timeout when receiving data
   [21015] Document and fix --enable-bind-now
+  [21109] Tunables broken on big-endian
+  [21115] sunrpc: Use-after-free in error path in clntudp_call
+  [21289] Fix symbol redirect for fts_set
 
 Version 2.25
 
diff --git a/io/fts.h b/io/fts.h
index b9cff534e9..ab15567001 100644
--- a/io/fts.h
+++ b/io/fts.h
@@ -193,7 +193,7 @@ FTS	*__REDIRECT (fts_open, (char * const *, int,
 				int (*)(const FTSENT **, const FTSENT **)),
 		     fts64_open);
 FTSENT	*__REDIRECT (fts_read, (FTS *), fts64_read);
-int	 __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW;
+int	 __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set);
 # else
 #  define fts_children fts64_children
 #  define fts_close fts64_close

commit 74522eeeaa4a39809a28f44171e71d36a69edb58
Author: Wladimir J. van der Laan <laanwj@gmail.com>
Date:   Sat Apr 1 12:39:09 2017 +0530

    Call the right helper function when setting mallopt M_ARENA_MAX (BZ #21338)
    
    Fixes a typo introduced in commit
    be7991c0705e35b4d70a419d117addcd6c627319. This caused
    mallopt(M_ARENA_MAX) as well as the environment variable
    MALLOC_ARENA_MAX to not work as intended because it set the
    wrong internal parameter.
    
            [BZ #21338]
            * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX
            instead of incorrect do_set_arena_test

diff --git a/ChangeLog b/ChangeLog
index 85d6fc6192..321bf53191 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2017-04-03  Wladimir van der Laan  <laanwj@gmail.com>
+
+	[BZ# 21338]
+	* malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX
+	instead of incorrect do_set_arena_test
+
 2017-03-31  Slava Barinov  <v.barinov@samsung.com>
 
 	[BZ #21289]
diff --git a/malloc/malloc.c b/malloc/malloc.c
index 4885793905..4e076638b0 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -4902,7 +4902,7 @@ __libc_mallopt (int param_number, int value)
 
     case M_ARENA_MAX:
       if (value > 0)
-	do_set_arena_test (value);
+	do_set_arena_max (value);
       break;
     }
   __libc_lock_unlock (av->mutex);

commit df29db0bec24211cfc917db52024bf8deecac2c9
Author: Mike Frysinger <vapier@gentoo.org>
Date:   Wed Mar 15 23:59:31 2017 -0700

    posix_spawn: use a larger min stack for -fstack-check [BZ #21253]
    
    When glibc is built with -fstack-check, trying to use posix_spawn can
    lead to segfaults due to gcc internally probing stack memory too far.
    The new spawn API will allocate a minimum of 1 page, but the stack
    checking logic might probe a couple of pages.  When it tries to walk
    them, everything falls apart.
    
    The gcc internal docs [1] state the default interval checking is one
    page.  Which means we need two pages (the current one, and the next
    probed).  No target currently defines it larger.
    
    Further, it mentions that the default minimum stack size needed to
    recover from an overflow is 4/8KiB for sjlj or 8/12KiB for others.
    But some Linux targets (like mips and ppc) go up to 16KiB (and some
    non-Linux targets go up to 24KiB).
    
    Let's create each child with a minimum of 32KiB slack space to support
    them all, and give us future breathing room.
    
    No test is added as existing ones crash.  Even a simple call is
    enough to trigger the problem:
            char *argv[] = { "/bin/ls", NULL };
            posix_spawn(NULL, "/bin/ls", NULL, NULL, argv, NULL);
    
    [1] https://gcc.gnu.org/onlinedocs/gcc-6.3.0/gccint/Stack-Checking.html
    
    (cherry picked from commit 21f042c804835d1f7a4a8e06f2c93ca35a182042)

diff --git a/ChangeLog b/ChangeLog
index 321bf53191..b37a054bae 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2017-04-03  Mike Frysinger  <vapier@gentoo.org>
+
+	[BZ #21253]
+	* sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size
+	slack space by 32KiB.
+
 2017-04-03  Wladimir van der Laan  <laanwj@gmail.com>
 
 	[BZ# 21338]
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index c96aac889d..29d8f25ab5 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -319,6 +319,11 @@ __spawnix (pid_t * pid, const char *file,
 
   /* Add a slack area for child's stack.  */
   size_t argv_size = (argc * sizeof (void *)) + 512;
+  /* We need at least a few pages in case the compiler's stack checking is
+     enabled.  In some configs, it is known to use at least 24KiB.  We use
+     32KiB to be "safe" from anything the compiler might do.  Besides, the
+     extra pages won't actually be allocated unless they get used.  */
+  argv_size += (32 * 1024);
   size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
   void *stack = __mmap (NULL, stack_size, prot,
 			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);

commit 903b77defb6f2ee2552c06472339f33091e3c7b4
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Tue Mar 21 10:59:31 2017 -0700

    x86-64: Improve branch predication in _dl_runtime_resolve_avx512_opt [BZ #21258]
    
    On Skylake server, _dl_runtime_resolve_avx512_opt is used to preserve
    the first 8 vector registers.  The code layout is
    
      if only %xmm0 - %xmm7 registers are used
         preserve %xmm0 - %xmm7 registers
      if only %ymm0 - %ymm7 registers are used
         preserve %ymm0 - %ymm7 registers
      preserve %zmm0 - %zmm7 registers
    
    Branch predication always executes the fallthrough code path to preserve
    %zmm0 - %zmm7 registers speculatively, even though only %xmm0 - %xmm7
    registers are used.  This leads to lower CPU frequency on Skylake
    server.  This patch changes the fallthrough code path to preserve
    %xmm0 - %xmm7 registers instead:
    
      if whole %zmm0 - %zmm7 registers are used
        preserve %zmm0 - %zmm7 registers
      if only %ymm0 - %ymm7 registers are used
         preserve %ymm0 - %ymm7 registers
      preserve %xmm0 - %xmm7 registers
    
    Tested on Skylake server.
    
            [BZ #21258]
            * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt):
            Define only if _dl_runtime_resolve is defined to
            _dl_runtime_resolve_sse_vex.
            * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt):
            Fallthrough to _dl_runtime_resolve_sse_vex.
    
    (cherry picked from commit c15f8eb50cea7ad1a4ccece6e0982bf426d52c00)

diff --git a/ChangeLog b/ChangeLog
index b37a054bae..8479fba8c4 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2017-04-07  H.J. Lu  <hongjiu.lu@intel.com>
+
+	[BZ #21258]
+	* sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt):
+	Define only if _dl_runtime_resolve is defined to
+	_dl_runtime_resolve_sse_vex.
+	* sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt):
+	Fallthrough to _dl_runtime_resolve_sse_vex.
+
 2017-04-03  Mike Frysinger  <vapier@gentoo.org>
 
 	[BZ #21253]
diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S
index 33d7fcf7d0..c14c61aa58 100644
--- a/sysdeps/x86_64/dl-trampoline.S
+++ b/sysdeps/x86_64/dl-trampoline.S
@@ -87,11 +87,9 @@
 #endif
 #define VEC(i)			zmm##i
 #define _dl_runtime_resolve	_dl_runtime_resolve_avx512
-#define _dl_runtime_resolve_opt	_dl_runtime_resolve_avx512_opt
 #define _dl_runtime_profile	_dl_runtime_profile_avx512
 #include "dl-trampoline.h"
 #undef _dl_runtime_resolve
-#undef _dl_runtime_resolve_opt
 #undef _dl_runtime_profile
 #undef VEC
 #undef VMOV
@@ -145,4 +143,5 @@
 # define VMOV			vmovdqu
 #endif
 #define _dl_runtime_resolve	_dl_runtime_resolve_sse_vex
+#define _dl_runtime_resolve_opt	_dl_runtime_resolve_avx512_opt
 #include "dl-trampoline.h"
diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h
index b27fa06974..8db24c16ac 100644
--- a/sysdeps/x86_64/dl-trampoline.h
+++ b/sysdeps/x86_64/dl-trampoline.h
@@ -129,19 +129,20 @@ _dl_runtime_resolve_opt:
 	# YMM state isn't in use.
 	PRESERVE_BND_REGS_PREFIX
 	jz _dl_runtime_resolve_sse_vex
-# elif VEC_SIZE == 64
+# elif VEC_SIZE == 16
 	# For ZMM registers, check if YMM state and ZMM state are in
 	# use.
 	andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d
 	cmpl $bit_YMM_state, %r11d
-	# Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
-	# neither YMM state nor ZMM state are in use.
+	# Preserve %zmm0 - %zmm7 registers if ZMM state is in use.
 	PRESERVE_BND_REGS_PREFIX
-	jl _dl_runtime_resolve_sse_vex
+	jg _dl_runtime_resolve_avx512
 	# Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if
 	# ZMM state isn't in use.
 	PRESERVE_BND_REGS_PREFIX
 	je _dl_runtime_resolve_avx
+	# Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
+	# neither YMM state nor ZMM state are in use.
 # else
 #  error Unsupported VEC_SIZE!
 # endif
