vapier 17/03/15 23:54:35
Modified: README.history
Added:
00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch
00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch
00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch
00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch
00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch
00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch
Log:
grab more fixes from upstream
Revision Changes Path
1.2 src/patchsets/glibc/2.25/README.history
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/README.history?rev=1.2&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/README.history?rev=1.2&content-type=text/plain
diff :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/README.history?r1=1.1&r2=1.2
Index: README.history
===================================================================
RCS file: /var/cvsroot/gentoo/src/patchsets/glibc/2.25/README.history,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- README.history 9 Feb 2017 12:18:54 -0000 1.1
+++ README.history 15 Mar 2017 23:54:35 -0000 1.2
@@ -1,3 +1,11 @@
+2 15 Mar 2017
+ + 00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch
+ + 00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch
+ + 00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch
+ + 00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch
+ + 00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch
+ + 00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch
+
1 09 Feb 2017
+ 00_all_0001-disable-ldconfig-during-install.patch
+ 00_all_0002-reload-etc-resolv.conf-when-it-has-changed.patch
1.1
src/patchsets/glibc/2.25/00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch?rev=1.1&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch?rev=1.1&content-type=text/plain
Index: 00_all_0006-Fix-getting-tunable-values-on-big-endian-BZ-21109.patch
===================================================================
>From 0232af1ad6cbd8378025e804f535ce9449ad49de Mon Sep 17 00:00:00 2001
From: Siddhesh Poyarekar <[email protected]>
Date: Thu, 9 Feb 2017 17:28:54 +0100
Subject: [PATCH] Fix getting tunable values on big-endian (BZ #21109)
The code to set value passed a tunable_val_t, which when cast to
int32_t on big-endian gives the wrong value. Instead, use
tunable_val_t.numval instead, which can then be safely cast into
int32_t.
(cherry picked from commit 8cbc826c37c0221ada65a7a622fe079b4e89a4b0)
(cherry picked from commit 58520986c38e34db60e07260c64c563e3efcf353)
---
elf/dl-tunable-types.h | 4 ++--
elf/dl-tunables.c | 2 ++
malloc/arena.c | 8 ++++----
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h
index a986f0b5930d..37a4e8021f8f 100644
--- a/elf/dl-tunable-types.h
+++ b/elf/dl-tunable-types.h
@@ -21,8 +21,6 @@
# define _TUNABLE_TYPES_H_
#include <stddef.h>
-typedef void (*tunable_callback_t) (void *);
-
typedef enum
{
TUNABLE_TYPE_INT_32,
@@ -43,6 +41,8 @@ typedef union
const char *strval;
} tunable_val_t;
+typedef void (*tunable_callback_t) (tunable_val_t *);
+
/* Security level for tunables. This decides what to do with individual
tunables for AT_SECURE binaries. */
typedef enum
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
index a8d53d6a311d..e42aa6700331 100644
--- a/elf/dl-tunables.c
+++ b/elf/dl-tunables.c
@@ -455,6 +455,8 @@ __tunable_set_val (tunable_id_t id, void *valp,
tunable_callback_t callback)
if (cur->strval == NULL)
return;
+ /* Caller does not need the value, just call the callback with our tunable
+ value. */
if (valp == NULL)
goto cb;
diff --git a/malloc/arena.c b/malloc/arena.c
index b91d7d6b16cd..d49e4a21c840 100644
--- a/malloc/arena.c
+++ b/malloc/arena.c
@@ -212,9 +212,9 @@ __malloc_fork_unlock_child (void)
#if HAVE_TUNABLES
static inline int do_set_mallopt_check (int32_t value);
void
-DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp)
+DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp)
{
- int32_t value = *(int32_t *) valp;
+ int32_t value = (int32_t) valp->numval;
do_set_mallopt_check (value);
if (check_action != 0)
__malloc_check_init ();
@@ -223,9 +223,9 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp)
# define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \
static inline int do_ ## __name (__type value);
\
void \
-DL_TUNABLE_CALLBACK (__name) (void *valp) \
+DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \
{ \
- __type value = *(__type *) valp; \
+ __type value = (__type) (valp)->numval; \
do_ ## __name (value); \
}
--
2.12.0
1.1
src/patchsets/glibc/2.25/00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch?rev=1.1&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch?rev=1.1&content-type=text/plain
Index: 00_all_0007-sunrpc-Avoid-use-after-free-read-access-in-clntudp_c.patch
===================================================================
>From 55df1000167b0143106e063f23159515d0c9c61c Mon Sep 17 00:00:00 2001
From: Florian Weimer <[email protected]>
Date: Tue, 28 Feb 2017 17:05:46 +0100
Subject: [PATCH] sunrpc: Avoid use-after-free read access in clntudp_call [BZ
#21115]
After commit bc779a1a5b3035133024b21e2f339fe4219fb11c
(CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call
[BZ #20112]), ancillary data is stored on the heap,
but it is accessed after it has been freed.
The test case must be run under a heap debugger such as valgrind
to observe the invalid access. A malloc implementation which
immediately calls munmap on free would catch this bug as well.
(cherry picked from commit d42eed4a044e5e10dfb885cf9891c2518a72a491)
(cherry picked from commit 045e368799cd253ddbf8bdec42ed92e8ebb3ce67)
---
sunrpc/Makefile | 3 ++-
sunrpc/clnt_udp.c | 2 +-
sunrpc/tst-udp-error.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 65 insertions(+), 2 deletions(-)
create mode 100644 sunrpc/tst-udp-error.c
diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index 0c1e6124ff4b..daf8a28f1aee 100644
--- a/sunrpc/Makefile
+++ b/sunrpc/Makefile
@@ -93,7 +93,7 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
others += rpcgen
-tests = tst-xdrmem tst-xdrmem2 test-rpcent
+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error
xtests := tst-getmyaddr
ifeq ($(have-thread-library),yes)
@@ -155,6 +155,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
$(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
$(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
$(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
$(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index 4d9acb1e6a6b..1de25cb77116 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -421,9 +421,9 @@ send_again:
cmsg = CMSG_NXTHDR (&msg, cmsg))
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
{
- free (cbuf);
e = (struct sock_extended_err *) CMSG_DATA(cmsg);
cu->cu_error.re_errno = e->ee_errno;
+ free (cbuf);
return (cu->cu_error.re_status = RPC_CANTRECV);
}
free (cbuf);
diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c
new file mode 100644
index 000000000000..1efc02f5c60a
--- /dev/null
+++ b/sunrpc/tst-udp-error.c
@@ -0,0 +1,62 @@
+/* Check for use-after-free in clntudp_call (bug 21115).
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xsocket.h>
+#include <unistd.h>
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ support_enter_network_namespace ();
+
+ /* Obtain a likely-unused port number. */
+ struct sockaddr_in sin =
+ {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+ };
+ {
+ int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ xbind (fd, (struct sockaddr *) &sin, sizeof (sin));
+ socklen_t sinlen = sizeof (sin);
+ xgetsockname (fd, (struct sockaddr *) &sin, &sinlen);
+ /* Close the socket, so that we will receive an error below. */
+ close (fd);
+ }
+
+ int sock = RPC_ANYSOCK;
+ CLIENT *clnt = clntudp_create
+ (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock);
+ TEST_VERIFY_EXIT (clnt != NULL);
+ TEST_VERIFY (clnt_call (clnt, 3,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL,
+ ((struct timeval) { 3, 0 }))
+ == RPC_CANTRECV);
+ clnt_destroy (clnt);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
--
2.12.0
1.1
src/patchsets/glibc/2.25/00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch?rev=1.1&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch?rev=1.1&content-type=text/plain
Index: 00_all_0008-sunrpc-Improvements-for-UDP-client-timeout-handling-.patch
===================================================================
>From 23b0289cf5f7abf984f5f15f54e8feb21938eece Mon Sep 17 00:00:00 2001
From: Florian Weimer <[email protected]>
Date: Tue, 28 Feb 2017 17:36:00 +0100
Subject: [PATCH] sunrpc: Improvements for UDP client timeout handling [BZ
#20257]
This commit fixes various aspects in the UDP client timeout handling.
Timeouts are now applied in a more consistent fashion. Discarded UDP
packets no longer prevent the timeout from happening at all.
(cherry picked from commit cf0bd2f73bd65beab613865bba567d7787836888)
(cherry picked from commit 93cf93e06ce123439e41d3d62790601c313134cb)
---
inet/Makefile | 8 +-
inet/deadline.c | 122 +++++++++++++
inet/net-internal.h | 89 ++++++++++
inet/tst-deadline.c | 188 ++++++++++++++++++++
sunrpc/Makefile | 10 +-
sunrpc/clnt_udp.c | 127 ++++++++------
sunrpc/tst-udp-garbage.c | 104 +++++++++++
sunrpc/tst-udp-nonblocking.c | 333 +++++++++++++++++++++++++++++++++++
sunrpc/tst-udp-timeout.c | 402 +++++++++++++++++++++++++++++++++++++++++++
9 files changed, 1324 insertions(+), 59 deletions(-)
create mode 100644 inet/deadline.c
create mode 100644 inet/tst-deadline.c
create mode 100644 sunrpc/tst-udp-garbage.c
create mode 100644 sunrpc/tst-udp-nonblocking.c
create mode 100644 sunrpc/tst-udp-timeout.c
diff --git a/inet/Makefile b/inet/Makefile
index 010792af8f3d..6a7d3e066416 100644
--- a/inet/Makefile
+++ b/inet/Makefile
@@ -45,14 +45,18 @@ routines := htonl htons \
in6_addr getnameinfo if_index ifaddrs inet6_option \
getipv4sourcefilter setipv4sourcefilter \
getsourcefilter setsourcefilter inet6_opt inet6_rth \
- inet6_scopeid_pton
+ inet6_scopeid_pton deadline
aux := check_pf check_native ifreq
tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \
- tst-sockaddr tst-inet6_scopeid_pton test-hnto-types
+ tst-sockaddr tst-inet6_scopeid_pton test-hnto-types tst-deadline
+
+# tst-deadline must be linked statically so that we can access
+# internal functions.
+tests-static += tst-deadline
include ../Rules
diff --git a/inet/deadline.c b/inet/deadline.c
new file mode 100644
index 000000000000..c1fa415a39f7
--- /dev/null
+++ b/inet/deadline.c
@@ -0,0 +1,122 @@
+/* Computing deadlines for timeouts.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <net-internal.h>
+
+#include <assert.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <time.h>
+
+struct deadline_current_time internal_function
+__deadline_current_time (void)
+{
+ struct deadline_current_time result;
+ if (__clock_gettime (CLOCK_MONOTONIC, &result.current) != 0)
+ {
+ struct timeval current_tv;
+ if (__gettimeofday (¤t_tv, NULL) == 0)
+ __libc_fatal ("Fatal error: gettimeofday system call failed\n");
+ result.current.tv_sec = current_tv.tv_sec;
+ result.current.tv_nsec = current_tv.tv_usec * 1000;
+ }
+ assert (result.current.tv_sec >= 0);
+ return result;
+}
+
+/* A special deadline value for which __deadline_is_infinite is
+ true. */
+static inline struct deadline
+infinite_deadline (void)
+{
+ return (struct deadline) { { -1, -1 } };
+}
+
+struct deadline internal_function
+__deadline_from_timeval (struct deadline_current_time current,
+ struct timeval tv)
+{
+ assert (__is_timeval_valid_timeout (tv));
+
+ /* Compute second-based deadline. Perform the addition in
+ uintmax_t, which is unsigned, to simply overflow detection. */
+ uintmax_t sec = current.current.tv_sec;
+ sec += tv.tv_sec;
+ if (sec < (uintmax_t) tv.tv_sec)
+ return infinite_deadline ();
+
+ /* Compute nanosecond deadline. */
+ int nsec = current.current.tv_nsec + tv.tv_usec * 1000;
+ if (nsec >= 1000 * 1000 * 1000)
+ {
+ /* Carry nanosecond overflow to seconds. */
+ nsec -= 1000 * 1000 * 1000;
+ if (sec + 1 < sec)
+ return infinite_deadline ();
+ ++sec;
+ }
+ /* This uses a GCC extension, otherwise these casts for detecting
+ overflow would not be defined. */
+ if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec)
+ return infinite_deadline ();
+
+ return (struct deadline) { { sec, nsec } };
+}
+
+int internal_function
+__deadline_to_ms (struct deadline_current_time current,
+ struct deadline deadline)
+{
+ if (__deadline_is_infinite (deadline))
+ return INT_MAX;
+
+ if (current.current.tv_sec > deadline.absolute.tv_sec
+ || (current.current.tv_sec == deadline.absolute.tv_sec
+ && current.current.tv_nsec >= deadline.absolute.tv_nsec))
+ return 0;
+ time_t sec = deadline.absolute.tv_sec - current.current.tv_sec;
+ if (sec >= INT_MAX)
+ /* This value will overflow below. */
+ return INT_MAX;
+ int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec;
+ if (nsec < 0)
+ {
+ /* Borrow from the seconds field. */
+ assert (sec > 0);
+ --sec;
+ nsec += 1000 * 1000 * 1000;
+ }
+
+ /* Prepare for rounding up to milliseconds. */
+ nsec += 999999;
+ if (nsec > 1000 * 1000 * 1000)
+ {
+ assert (sec < INT_MAX);
+ ++sec;
+ nsec -= 1000 * 1000 * 1000;
+ }
+
+ unsigned int msec = nsec / (1000 * 1000);
+ if (sec > INT_MAX / 1000)
+ return INT_MAX;
+ msec += sec * 1000;
+ if (msec > INT_MAX)
+ return INT_MAX;
+ return msec;
+}
diff --git a/inet/net-internal.h b/inet/net-internal.h
index 087597ed9923..2b2632c7ba84 100644
--- a/inet/net-internal.h
+++ b/inet/net-internal.h
@@ -20,11 +20,100 @@
#define _NET_INTERNAL_H 1
#include <arpa/inet.h>
+#include <stdbool.h>
#include <stdint.h>
+#include <sys/time.h>
int __inet6_scopeid_pton (const struct in6_addr *address,
const char *scope, uint32_t *result)
internal_function attribute_hidden;
libc_hidden_proto (__inet6_scopeid_pton)
+
+/* Deadline handling for enforcing timeouts.
+
+ Code should call __deadline_current_time to obtain the current time
+ and cache it locally. The cache needs updating after every
+ long-running or potentially blocking operation. Deadlines relative
+ to the current time can be computed using __deadline_from_timeval.
+ The deadlines may have to be recomputed in response to certain
+ events (such as an incoming packet), but they are absolute (not
+ relative to the current time). A timeout suitable for use with the
+ poll function can be computed from such a deadline using
+ __deadline_to_ms.
+
+ The fields in the structs defined belowed should only be used
+ within the implementation. */
+
+/* Cache of the current time. Used to compute deadlines from relative
+ timeouts and vice versa. */
+struct deadline_current_time
+{
+ struct timespec current;
+};
+
+/* Return the current time. Terminates the process if the current
+ time is not available. */
+struct deadline_current_time __deadline_current_time (void)
+ internal_function attribute_hidden;
+
+/* Computed absolute deadline. */
+struct deadline
+{
+ struct timespec absolute;
+};
+
+
+/* For internal use only. */
+static inline bool
+__deadline_is_infinite (struct deadline deadline)
+{
+ return deadline.absolute.tv_nsec < 0;
+}
+
+/* Return true if the current time is at the deadline or past it. */
+static inline bool
+__deadline_elapsed (struct deadline_current_time current,
+ struct deadline deadline)
+{
+ return !__deadline_is_infinite (deadline)
+ && (current.current.tv_sec > deadline.absolute.tv_sec
+ || (current.current.tv_sec == deadline.absolute.tv_sec
+ && current.current.tv_nsec >= deadline.absolute.tv_nsec));
+}
+
+/* Return the deadline which occurs first. */
+static inline struct deadline
+__deadline_first (struct deadline left, struct deadline right)
+{
+ if (__deadline_is_infinite (right)
+ || left.absolute.tv_sec < right.absolute.tv_sec
+ || (left.absolute.tv_sec == right.absolute.tv_sec
+ && left.absolute.tv_nsec < right.absolute.tv_nsec))
+ return left;
+ else
+ return right;
+}
+
+/* Add TV to the current time and return it. Returns a special
+ infinite absolute deadline on overflow. */
+struct deadline __deadline_from_timeval (struct deadline_current_time,
+ struct timeval tv)
+ internal_function attribute_hidden;
+
+/* Compute the number of milliseconds until the specified deadline,
+ from the current time in the argument. The result is mainly for
+ use with poll. If the deadline has already passed, return 0. If
+ the result would overflow an int, return INT_MAX. */
+int __deadline_to_ms (struct deadline_current_time, struct deadline)
+ internal_function attribute_hidden;
+
+/* Return true if TV.tv_sec is non-negative and TV.tv_usec is in the
+ interval [0, 999999]. */
+static inline bool
+__is_timeval_valid_timeout (struct timeval tv)
+{
+ return tv.tv_sec >= 0 && tv.tv_usec >= 0 && tv.tv_usec < 1000 * 1000;
+}
+
#endif /* _NET_INTERNAL_H */
diff --git a/inet/tst-deadline.c b/inet/tst-deadline.c
new file mode 100644
index 000000000000..ed04345c3513
--- /dev/null
+++ b/inet/tst-deadline.c
@@ -0,0 +1,188 @@
+/* Tests for computing deadlines for timeouts.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <inet/net-internal.h>
+#include <limits.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <support/check.h>
+
+/* Find the maximum value which can be represented in a time_t. */
+static time_t
+time_t_max (void)
+{
+ _Static_assert (0 > (time_t) -1, "time_t is signed");
+ uintmax_t current = 1;
+ while (true)
+ {
+ uintmax_t next = current * 2;
+ /* This cannot happen because time_t is signed. */
+ TEST_VERIFY_EXIT (next > current);
+ ++next;
+ if ((time_t) next < 0 || next != (uintmax_t) (time_t) next)
+ /* Value cannot be represented in time_t. Return the previous
+ value. */
+ return current;
+ current = next;
+ }
+}
+
+static int
+do_test (void)
+{
+ {
+ struct deadline_current_time current_time = __deadline_current_time ();
+ TEST_VERIFY (current_time.current.tv_sec >= 0);
+ current_time = __deadline_current_time ();
+ /* Due to CLOCK_MONOTONIC, either seconds or nanoseconds are
+ greater than zero. This is also true for the gettimeofday
+ fallback. */
+ TEST_VERIFY (current_time.current.tv_sec >= 0);
+ TEST_VERIFY (current_time.current.tv_sec > 0
+ || current_time.current.tv_nsec > 0);
+ }
+
+ /* Check basic computations of deadlines. */
+ struct deadline_current_time current_time = { { 1, 123456789 } };
+ struct deadline deadline = __deadline_from_timeval
+ (current_time, (struct timeval) { 0, 1 });
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 123457789);
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1);
+
+ deadline = __deadline_from_timeval
+ (current_time, ((struct timeval) { 0, 2 }));
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 123458789);
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1);
+
+ deadline = __deadline_from_timeval
+ (current_time, ((struct timeval) { 1, 0 }));
+ TEST_VERIFY (deadline.absolute.tv_sec == 2);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 123456789);
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+
+ /* Check if timeouts are correctly rounded up to the next
+ millisecond. */
+ for (int i = 0; i < 999999; ++i)
+ {
+ ++current_time.current.tv_nsec;
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+ }
+
+ /* A full millisecond has elapsed, so the time to the deadline is
+ now less than 1000. */
+ ++current_time.current.tv_nsec;
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999);
+
+ /* Check __deadline_to_ms carry-over. */
+ current_time = (struct deadline_current_time) { { 9, 123456789 } };
+ deadline = (struct deadline) { { 10, 122456789 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999);
+ deadline = (struct deadline) { { 10, 122456790 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+ deadline = (struct deadline) { { 10, 123456788 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+ deadline = (struct deadline) { { 10, 123456789 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
+
+ /* Check __deadline_to_ms overflow. */
+ deadline = (struct deadline) { { INT_MAX - 1, 1 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == INT_MAX);
+
+ /* Check __deadline_to_ms for elapsed deadlines. */
+ current_time = (struct deadline_current_time) { { 9, 123456789 } };
+ deadline.absolute = current_time.current;
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+ current_time = (struct deadline_current_time) { { 9, 123456790 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+ current_time = (struct deadline_current_time) { { 10, 0 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+ current_time = (struct deadline_current_time) { { 10, 123456788 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+ current_time = (struct deadline_current_time) { { 10, 123456789 } };
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
+
+ /* Check carry-over in __deadline_from_timeval. */
+ current_time = (struct deadline_current_time) { { 9, 998000001 } };
+ for (int i = 0; i < 2000; ++i)
+ {
+ deadline = __deadline_from_timeval
+ (current_time, (struct timeval) { 1, i });
+ TEST_VERIFY (deadline.absolute.tv_sec == 10);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 998000001 + i * 1000);
+ }
+ for (int i = 2000; i < 3000; ++i)
+ {
+ deadline = __deadline_from_timeval
+ (current_time, (struct timeval) { 2, i });
+ TEST_VERIFY (deadline.absolute.tv_sec == 12);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 1 + (i - 2000) * 1000);
+ }
+
+ /* Check infinite deadlines. */
+ deadline = __deadline_from_timeval
+ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1000 } },
+ (struct timeval) { time_t_max (), 1 });
+ TEST_VERIFY (__deadline_is_infinite (deadline));
+ deadline = __deadline_from_timeval
+ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1001 } },
+ (struct timeval) { time_t_max (), 1 });
+ TEST_VERIFY (!__deadline_is_infinite (deadline));
+ deadline = __deadline_from_timeval
+ ((struct deadline_current_time)
+ { { time_t_max (), 1000 * 1000 * 1000 - 1000 } },
+ (struct timeval) { 0, 1 });
+ TEST_VERIFY (__deadline_is_infinite (deadline));
+ deadline = __deadline_from_timeval
+ ((struct deadline_current_time)
+ { { time_t_max () / 2 + 1, 0 } },
+ (struct timeval) { time_t_max () / 2 + 1, 0 });
+ TEST_VERIFY (__deadline_is_infinite (deadline));
+
+ /* Check __deadline_first behavior. */
+ deadline = __deadline_first
+ ((struct deadline) { { 1, 2 } },
+ (struct deadline) { { 1, 3 } });
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+ deadline = __deadline_first
+ ((struct deadline) { { 1, 3 } },
+ (struct deadline) { { 1, 2 } });
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+ deadline = __deadline_first
+ ((struct deadline) { { 1, 2 } },
+ (struct deadline) { { 2, 1 } });
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+ deadline = __deadline_first
+ ((struct deadline) { { 1, 2 } },
+ (struct deadline) { { 2, 4 } });
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+ deadline = __deadline_first
+ ((struct deadline) { { 2, 4 } },
+ (struct deadline) { { 1, 2 } });
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/Makefile b/sunrpc/Makefile
index daf8a28f1aee..7e5d2955a0f4 100644
--- a/sunrpc/Makefile
+++ b/sunrpc/Makefile
@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
others += rpcgen
-tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error
+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
+ tst-udp-nonblocking
xtests := tst-getmyaddr
ifeq ($(have-thread-library),yes)
-xtests += thrsvc
+xtests += thrsvc tst-udp-garbage
endif
ifeq ($(run-built-tests),yes)
@@ -235,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen
$(built-program-cmd) -c $< -o $@; \
$(evaluate-test)
endif
+
+$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
+$(objpfx)tst-udp-garbage: \
+ $(common-objpfx)linkobj/libc.so $(shared-thread-library)
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
index 1de25cb77116..6ce16eb2988c 100644
--- a/sunrpc/clnt_udp.c
+++ b/sunrpc/clnt_udp.c
@@ -55,6 +55,7 @@
#endif
#include <kernel-features.h>
+#include <inet/net-internal.h>
extern u_long _create_xid (void);
@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops =
};
/*
- * Private data kept per client handle
+ * Private data kept per client handle. This private struct is
+ * unfortunately part of the ABI; ypbind contains a copy of it and
+ * accesses it through CLIENT::cl_private field.
*/
struct cu_data
{
@@ -278,28 +281,38 @@ clntudp_call (/* client handle */
int inlen;
socklen_t fromlen;
struct pollfd fd;
- int milliseconds = (cu->cu_wait.tv_sec * 1000) +
- (cu->cu_wait.tv_usec / 1000);
struct sockaddr_in from;
struct rpc_msg reply_msg;
XDR reply_xdrs;
- struct timeval time_waited;
bool_t ok;
int nrefreshes = 2; /* number of times to refresh cred */
- struct timeval timeout;
int anyup; /* any network interface up */
- if (cu->cu_total.tv_usec == -1)
- {
- timeout = utimeout; /* use supplied timeout */
- }
- else
+ struct deadline_current_time current_time = __deadline_current_time ();
+ struct deadline total_deadline; /* Determined once by overall timeout. */
+ struct deadline response_deadline; /* Determined anew for each query. */
+
+ /* Choose the timeout value. For non-sending usage (xargs == NULL),
+ the total deadline does not matter, only cu->cu_wait is used
+ below. */
+ if (xargs != NULL)
{
- timeout = cu->cu_total; /* use default timeout */
+ struct timeval tv;
+ if (cu->cu_total.tv_usec == -1)
+ /* Use supplied timeout. */
+ tv = utimeout;
+ else
+ /* Use default timeout. */
+ tv = cu->cu_total;
+ if (!__is_timeval_valid_timeout (tv))
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
+ total_deadline = __deadline_from_timeval (current_time, tv);
}
- time_waited.tv_sec = 0;
- time_waited.tv_usec = 0;
+ /* Guard against bad timeout specification. */
+ if (!__is_timeval_valid_timeout (cu->cu_wait))
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
+
call_again:
xdrs = &(cu->cu_outxdrs);
if (xargs == NULL)
@@ -325,27 +338,46 @@ send_again:
return (cu->cu_error.re_status = RPC_CANTSEND);
}
- /*
- * Hack to provide rpc-based message passing
- */
- if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
- {
- return (cu->cu_error.re_status = RPC_TIMEDOUT);
- }
+ /* sendto may have blocked, so recompute the current time. */
+ current_time = __deadline_current_time ();
get_reply:
- /*
- * sub-optimal code appears here because we have
- * some clock time to spare while the packets are in flight.
- * (We assume that this is actually only executed once.)
- */
+ response_deadline = __deadline_from_timeval (current_time, cu->cu_wait);
+
reply_msg.acpted_rply.ar_verf = _null_auth;
reply_msg.acpted_rply.ar_results.where = resultsp;
reply_msg.acpted_rply.ar_results.proc = xresults;
fd.fd = cu->cu_sock;
fd.events = POLLIN;
anyup = 0;
+
+ /* Per-response retry loop. current_time must be up-to-date at the
+ top of the loop. */
for (;;)
{
+ int milliseconds;
+ if (xargs != NULL)
+ {
+ if (__deadline_elapsed (current_time, total_deadline))
+ /* Overall timeout expired. */
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
+ milliseconds = __deadline_to_ms
+ (current_time, __deadline_first (total_deadline,
+ response_deadline));
+ if (milliseconds == 0)
+ /* Per-query timeout expired. */
+ goto send_again;
+ }
+ else
+ {
+ /* xatgs == NULL. Collect a response without sending a
+ query. In this mode, we need to ignore the total
+ deadline. */
+ milliseconds = __deadline_to_ms (current_time, response_deadline);
+ if (milliseconds == 0)
+ /* Cannot send again, so bail out. */
+ return (cu->cu_error.re_status = RPC_CANTSEND);
+ }
+
switch (__poll (&fd, 1, milliseconds))
{
@@ -356,27 +388,10 @@ send_again:
if (!anyup)
return (cu->cu_error.re_status = RPC_CANTRECV);
}
-
- time_waited.tv_sec += cu->cu_wait.tv_sec;
- time_waited.tv_usec += cu->cu_wait.tv_usec;
- while (time_waited.tv_usec >= 1000000)
- {
- time_waited.tv_sec++;
- time_waited.tv_usec -= 1000000;
- }
- if ((time_waited.tv_sec < timeout.tv_sec) ||
- ((time_waited.tv_sec == timeout.tv_sec) &&
- (time_waited.tv_usec < timeout.tv_usec)))
- goto send_again;
- return (cu->cu_error.re_status = RPC_TIMEDOUT);
-
- /*
- * buggy in other cases because time_waited is not being
- * updated.
- */
+ goto next_response;
case -1:
if (errno == EINTR)
- continue;
+ goto next_response;
cu->cu_error.re_errno = errno;
return (cu->cu_error.re_status = RPC_CANTRECV);
}
@@ -440,20 +455,22 @@ send_again:
if (inlen < 0)
{
if (errno == EWOULDBLOCK)
- continue;
+ goto next_response;
cu->cu_error.re_errno = errno;
return (cu->cu_error.re_status = RPC_CANTRECV);
}
- if (inlen < 4)
- continue;
-
- /* see if reply transaction id matches sent id.
- Don't do this if we only wait for a replay */
- if (xargs != NULL
- && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0)
- continue;
- /* we now assume we have the proper reply */
- break;
+ /* Accept the response if the packet is sufficiently long and
+ the transaction ID matches the query (if available). */
+ if (inlen >= 4
+ && (xargs == NULL
+ || memcmp (cu->cu_inbuf, cu->cu_outbuf,
+ sizeof (u_int32_t)) == 0))
+ break;
+
+ next_response:
+ /* Update the current time because poll and recvmsg waited for
+ an unknown time. */
+ current_time = __deadline_current_time ();
}
/*
diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c
new file mode 100644
index 000000000000..4abda93f0855
--- /dev/null
+++ b/sunrpc/tst-udp-garbage.c
@@ -0,0 +1,104 @@
+/* Test that garbage packets do not affect timeout handling.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <stdbool.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/xsocket.h>
+#include <support/xthread.h>
+#include <sys/socket.h>
+#include <unistd.h>
+
+/* Descriptor for the server UDP socket. */
+static int server_fd;
+
+static void *
+garbage_sender_thread (void *unused)
+{
+ while (true)
+ {
+ struct sockaddr_storage sa;
+ socklen_t salen = sizeof (sa);
+ char buf[1];
+ if (recvfrom (server_fd, buf, sizeof (buf), 0,
+ (struct sockaddr *) &sa, &salen) < 0)
+ FAIL_EXIT1 ("recvfrom: %m");
+
+ /* Send garbage packets indefinitely. */
+ buf[0] = 0;
+ while (true)
+ {
+ /* sendto can fail if the client closed the socket. */
+ if (sendto (server_fd, buf, sizeof (buf), 0,
+ (struct sockaddr *) &sa, salen) < 0)
+ break;
+
+ /* Wait a bit, to avoid burning too many CPU cycles in a
+ tight loop. The wait period must be much shorter than
+ the client timeouts configured below. */
+ usleep (50 * 1000);
+ }
+ }
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ support_enter_network_namespace ();
+
+ server_fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
+ struct sockaddr_in server_address =
+ {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+ };
+ xbind (server_fd,
+ (struct sockaddr *) &server_address, sizeof (server_address));
+ {
+ socklen_t sinlen = sizeof (server_address);
+ xgetsockname (server_fd, (struct sockaddr *) &server_address, &sinlen);
+ TEST_VERIFY (sizeof (server_address) == sinlen);
+ }
+
+ /* Garbage packet source. */
+ xpthread_detach (xpthread_create (NULL, garbage_sender_thread, NULL));
+
+ /* Test client. Use an arbitrary timeout of one second, which is
+ much longer than the garbage packet interval, but still
+ reasonably short, so that the test completes quickly. */
+ int client_fd = RPC_ANYSOCK;
+ CLIENT *clnt = clntudp_create (&server_address,
+ 1, 2, /* Arbitrary RPC endpoint numbers. */
+ (struct timeval) { 1, 0 },
+ &client_fd);
+ if (clnt == NULL)
+ FAIL_EXIT1 ("clntudp_create: %m");
+
+ TEST_VERIFY (clnt_call (clnt, 3, /* Arbitrary RPC procedure number. */
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL,
+ ((struct timeval) { 1, 0 })));
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c
new file mode 100644
index 000000000000..1d6a7f4b56f7
--- /dev/null
+++ b/sunrpc/tst-udp-nonblocking.c
@@ -0,0 +1,333 @@
+/* Test non-blocking use of the UDP client.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <stdbool.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/test-driver.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Test data serialization and deserialization. */
+
+struct test_query
+{
+ uint32_t a;
+ uint32_t b;
+ uint32_t timeout_ms;
+};
+
+static bool_t
+xdr_test_query (XDR *xdrs, void *data, ...)
+{
+ struct test_query *p = data;
+ return xdr_uint32_t (xdrs, &p->a)
+ && xdr_uint32_t (xdrs, &p->b)
+ && xdr_uint32_t (xdrs, &p->timeout_ms);
+}
+
+struct test_response
+{
+ uint32_t server_id;
+ uint32_t seq;
+ uint32_t sum;
+};
+
+static bool_t
+xdr_test_response (XDR *xdrs, void *data, ...)
+{
+ struct test_response *p = data;
+ return xdr_uint32_t (xdrs, &p->server_id)
+ && xdr_uint32_t (xdrs, &p->seq)
+ && xdr_uint32_t (xdrs, &p->sum);
+}
+
+/* Implementation of the test server. */
+
+enum
+ {
+ /* Number of test servers to run. */
+ SERVER_COUNT = 3,
+
+ /* RPC parameters, chosen at random. */
+ PROGNUM = 8242,
+ VERSNUM = 19654,
+
+ /* Main RPC operation. */
+ PROC_ADD = 1,
+
+ /* Request process termination. */
+ PROC_EXIT,
+
+ /* Special exit status to mark successful processing. */
+ EXIT_MARKER = 55,
+ };
+
+/* Set by the parent process to tell test servers apart. */
+static int server_id;
+
+/* Implementation of the test server. */
+static void
+server_dispatch (struct svc_req *request, SVCXPRT *transport)
+{
+ /* Query sequence number. */
+ static uint32_t seq = 0;
+ ++seq;
+ static bool proc_add_seen;
+
+ if (test_verbose)
+ printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n",
+ server_id, seq, request->rq_proc);
+
+ switch (request->rq_proc)
+ {
+ case PROC_ADD:
+ {
+ struct test_query query;
+ memset (&query, 0xc0, sizeof (query));
+ TEST_VERIFY_EXIT
+ (svc_getargs (transport, xdr_test_query,
+ (void *) &query));
+
+ if (test_verbose)
+ printf (" a=%u b=%u timeout_ms=%u\n",
+ query.a, query.b, query.timeout_ms);
+
+ usleep (query.timeout_ms * 1000);
+
+ struct test_response response =
+ {
+ .server_id = server_id,
+ .seq = seq,
+ .sum = query.a + query.b,
+ };
+ TEST_VERIFY (svc_sendreply (transport, xdr_test_response,
+ (void *) &response));
+ if (test_verbose)
+ printf (" server id %d response seq=%u sent\n", server_id, seq);
+ proc_add_seen = true;
+ }
+ break;
+
+ case PROC_EXIT:
+ TEST_VERIFY (proc_add_seen);
+ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
+ _exit (EXIT_MARKER);
+ break;
+
+ default:
+ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
+ break;
+ }
+}
+
+/* Return the number seconds since an arbitrary point in time. */
+static double
+get_ticks (void)
+{
+ {
+ struct timespec ts;
+ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
+ }
+ {
+ struct timeval tv;
+ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0);
+ return tv.tv_sec + tv.tv_usec * 1e-6;
+ }
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ support_enter_network_namespace ();
+
+ /* Information about the test servers. */
+ struct
+ {
+ SVCXPRT *transport;
+ struct sockaddr_in address;
+ pid_t pid;
+ uint32_t xid;
+ } servers[SERVER_COUNT];
+
+ /* Spawn the test servers. */
+ for (int i = 0; i < SERVER_COUNT; ++i)
+ {
+ servers[i].transport = svcudp_create (RPC_ANYSOCK);
+ TEST_VERIFY_EXIT (servers[i].transport != NULL);
+ servers[i].address = (struct sockaddr_in)
+ {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+ .sin_port = htons (servers[i].transport->xp_port),
+ };
+ servers[i].xid = 0xabcd0101 + i;
+ if (test_verbose)
+ printf ("info: setting up server %d xid=%x on port %d\n",
+ i, servers[i].xid, servers[i].transport->xp_port);
+
+ server_id = i;
+ servers[i].pid = xfork ();
+ if (servers[i].pid == 0)
+ {
+ TEST_VERIFY (svc_register (servers[i].transport,
+ PROGNUM, VERSNUM, server_dispatch, 0));
+ svc_run ();
+ FAIL_EXIT1 ("supposed to be unreachable");
+ }
+ /* We need to close the socket so that we do not accidentally
+ consume the request. */
+ TEST_VERIFY (close (servers[i].transport->xp_sock) == 0);
+ }
+
+
+ /* The following code mirrors what ypbind does. */
+
+ /* Copied from clnt_udp.c (like ypbind). */
+ struct cu_data
+ {
+ int cu_sock;
+ bool_t cu_closeit;
+ struct sockaddr_in cu_raddr;
+ int cu_rlen;
+ struct timeval cu_wait;
+ struct timeval cu_total;
+ struct rpc_err cu_error;
+ XDR cu_outxdrs;
+ u_int cu_xdrpos;
+ u_int cu_sendsz;
+ char *cu_outbuf;
+ u_int cu_recvsz;
+ char cu_inbuf[1];
+ };
+
+ int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
+ CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM,
+ /* 5 seconds per-response timeout. */
+ ((struct timeval) { 5, 0 }),
+ &client_socket);
+ TEST_VERIFY (clnt != NULL);
+ clnt->cl_auth = authunix_create_default ();
+ {
+ struct timeval zero = { 0, 0 };
+ TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero));
+ }
+
+ /* Poke at internal data structures (like ypbind). */
+ struct cu_data *cu = (struct cu_data *) clnt->cl_private;
+
+ /* Send a ping to each server. */
+ double before_pings = get_ticks ();
+ for (int i = 0; i < SERVER_COUNT; ++i)
+ {
+ if (test_verbose)
+ printf ("info: sending server %d ping\n", i);
+ /* Reset the xid because it is changed by each invocation of
+ clnt_call. Subtract one to compensate for the xid update
+ during the call. */
+ *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1;
+ cu->cu_raddr = servers[i].address;
+
+ struct test_query query = { .a = 100, .b = i + 1 };
+ if (i == 1)
+ /* Shorter timeout to prefer this server. These timeouts must
+ be much shorter than the 5-second per-response timeout
+ configured with clntudp_create. */
+ query.timeout_ms = 700;
+ else
+ query.timeout_ms = 1400;
+ struct test_response response = { 0 };
+ /* NB: Do not check the return value. The server reply will
+ prove that the call worked. */
+ double before_one_ping = get_ticks ();
+ clnt_call (clnt, PROC_ADD,
+ xdr_test_query, (void *) &query,
+ xdr_test_response, (void *) &response,
+ ((struct timeval) { 0, 0 }));
+ double after_one_ping = get_ticks ();
+ if (test_verbose)
+ printf ("info: non-blocking send took %f seconds\n",
+ after_one_ping - before_one_ping);
+ /* clnt_call should return immediately. Accept some delay in
+ case the process is descheduled. */
+ TEST_VERIFY (after_one_ping - before_one_ping < 0.3);
+ }
+
+ /* Collect the non-blocking response. */
+ if (test_verbose)
+ printf ("info: collecting response\n");
+ struct test_response response = { 0 };
+ TEST_VERIFY
+ (clnt_call (clnt, PROC_ADD, NULL, NULL,
+ xdr_test_response, (void *) &response,
+ ((struct timeval) { 0, 0 })) == RPC_SUCCESS);
+ double after_pings = get_ticks ();
+ if (test_verbose)
+ printf ("info: send/receive took %f seconds\n",
+ after_pings - before_pings);
+ /* Expected timeout is 0.7 seconds. */
+ TEST_VERIFY (0.7 <= after_pings - before_pings);
+ TEST_VERIFY (after_pings - before_pings < 1.2);
+
+ uint32_t xid;
+ memcpy (&xid, &cu->cu_inbuf, sizeof (xid));
+ if (test_verbose)
+ printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n",
+ xid, response.server_id, response.seq, response.sum);
+ /* Check that the reply from the preferred server was used. */
+ TEST_VERIFY (servers[1].xid == xid);
+ TEST_VERIFY (response.server_id == 1);
+ TEST_VERIFY (response.seq == 1);
+ TEST_VERIFY (response.sum == 102);
+
+ auth_destroy (clnt->cl_auth);
+ clnt_destroy (clnt);
+
+ for (int i = 0; i < SERVER_COUNT; ++i)
+ {
+ if (test_verbose)
+ printf ("info: requesting server %d termination\n", i);
+ client_socket = RPC_ANYSOCK;
+ clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM,
+ ((struct timeval) { 5, 0 }),
+ &client_socket);
+ TEST_VERIFY_EXIT (clnt != NULL);
+ TEST_VERIFY (clnt_call (clnt, PROC_EXIT,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL,
+ ((struct timeval) { 3, 0 })) == RPC_SUCCESS);
+ clnt_destroy (clnt);
+
+ int status;
+ xwaitpid (servers[i].pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER);
+ }
+
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c
new file mode 100644
index 000000000000..db9943a03e3d
--- /dev/null
+++ b/sunrpc/tst-udp-timeout.c
@@ -0,0 +1,402 @@
+/* Test timeout handling in the UDP client.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <netinet/in.h>
+#include <rpc/clnt.h>
+#include <rpc/svc.h>
+#include <stdbool.h>
+#include <string.h>
+#include <support/check.h>
+#include <support/namespace.h>
+#include <support/test-driver.h>
+#include <support/xsocket.h>
+#include <support/xunistd.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <unistd.h>
+
+/* Test data serialization and deserialization. */
+
+struct test_query
+{
+ uint32_t a;
+ uint32_t b;
+ uint32_t timeout_ms;
+ uint32_t wait_for_seq;
+ uint32_t garbage_packets;
+};
+
+static bool_t
+xdr_test_query (XDR *xdrs, void *data, ...)
+{
+ struct test_query *p = data;
+ return xdr_uint32_t (xdrs, &p->a)
+ && xdr_uint32_t (xdrs, &p->b)
+ && xdr_uint32_t (xdrs, &p->timeout_ms)
+ && xdr_uint32_t (xdrs, &p->wait_for_seq)
+ && xdr_uint32_t (xdrs, &p->garbage_packets);
+}
+
+struct test_response
+{
+ uint32_t seq;
+ uint32_t sum;
+};
+
+static bool_t
+xdr_test_response (XDR *xdrs, void *data, ...)
+{
+ struct test_response *p = data;
+ return xdr_uint32_t (xdrs, &p->seq)
+ && xdr_uint32_t (xdrs, &p->sum);
+}
+
+/* Implementation of the test server. */
+
+enum
+ {
+ /* RPC parameters, chosen at random. */
+ PROGNUM = 15717,
+ VERSNUM = 13689,
+
+ /* Main RPC operation. */
+ PROC_ADD = 1,
+
+ /* Reset the sequence number. */
+ PROC_RESET_SEQ,
+
+ /* Request process termination. */
+ PROC_EXIT,
+
+ /* Special exit status to mark successful processing. */
+ EXIT_MARKER = 55,
+ };
+
+static void
+server_dispatch (struct svc_req *request, SVCXPRT *transport)
+{
+ /* Query sequence number. */
+ static uint32_t seq = 0;
+ ++seq;
+
+ if (test_verbose)
+ printf ("info: server_dispatch seq=%u rq_proc=%lu\n",
+ seq, request->rq_proc);
+
+ switch (request->rq_proc)
+ {
+ case PROC_ADD:
+ {
+ struct test_query query;
+ memset (&query, 0xc0, sizeof (query));
+ TEST_VERIFY_EXIT
+ (svc_getargs (transport, xdr_test_query,
+ (void *) &query));
+
+ if (test_verbose)
+ printf (" a=%u b=%u timeout_ms=%u wait_for_seq=%u"
+ " garbage_packets=%u\n",
+ query.a, query.b, query.timeout_ms, query.wait_for_seq,
+ query.garbage_packets);
+
+ if (seq < query.wait_for_seq)
+ {
+ /* No response at this point. */
+ if (test_verbose)
+ printf (" skipped response\n");
+ break;
+ }
+
+ if (query.garbage_packets > 0)
+ {
+ int per_packet_timeout;
+ if (query.timeout_ms > 0)
+ per_packet_timeout
+ = query.timeout_ms * 1000 / query.garbage_packets;
+ else
+ per_packet_timeout = 0;
+
+ char buf[20];
+ memset (&buf, 0xc0, sizeof (buf));
+ for (int i = 0; i < query.garbage_packets; ++i)
+ {
+ /* 13 is relatively prime to 20 = sizeof (buf) + 1, so
+ the len variable will cover the entire interval
+ [0, 20] if query.garbage_packets is sufficiently
+ large. */
+ size_t len = (i * 13 + 1) % (sizeof (buf) + 1);
+ TEST_VERIFY (sendto (transport->xp_sock,
+ buf, len, MSG_NOSIGNAL,
+ (struct sockaddr *) &transport->xp_raddr,
+ transport->xp_addrlen) == len);
+ if (per_packet_timeout > 0)
+ usleep (per_packet_timeout);
+ }
+ }
+ else if (query.timeout_ms > 0)
+ usleep (query.timeout_ms * 1000);
+
+ struct test_response response =
+ {
+ .seq = seq,
+ .sum = query.a + query.b,
+ };
+ TEST_VERIFY (svc_sendreply (transport, xdr_test_response,
+ (void *) &response));
+ }
+ break;
+
+ case PROC_RESET_SEQ:
+ seq = 0;
+ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
+ break;
+
+ case PROC_EXIT:
+ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
+ _exit (EXIT_MARKER);
+ break;
+
+ default:
+ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
+ break;
+ }
+}
+
+/* Implementation of the test client. */
+
+static struct test_response
+test_call (CLIENT *clnt, int proc, struct test_query query,
+ struct timeval timeout)
+{
+ if (test_verbose)
+ printf ("info: test_call proc=%d timeout=%lu.%06lu\n",
+ proc, (unsigned long) timeout.tv_sec,
+ (unsigned long) timeout.tv_usec);
+ struct test_response response;
+ TEST_VERIFY_EXIT (clnt_call (clnt, proc,
+ xdr_test_query, (void *) &query,
+ xdr_test_response, (void *) &response,
+ timeout)
+ == RPC_SUCCESS);
+ return response;
+}
+
+static void
+test_call_timeout (CLIENT *clnt, int proc, struct test_query query,
+ struct timeval timeout)
+{
+ struct test_response response;
+ TEST_VERIFY (clnt_call (clnt, proc,
+ xdr_test_query, (void *) &query,
+ xdr_test_response, (void *) &response,
+ timeout)
+ == RPC_TIMEDOUT);
+}
+
+/* Complete one regular RPC call to drain the server socket
+ buffer. Resets the sequence number. */
+static void
+test_call_flush (CLIENT *clnt)
+{
+ /* This needs a longer timeout to flush out all pending requests.
+ The choice of 5 seconds is larger than the per-response timeouts
+ requested via the timeout_ms field. */
+ if (test_verbose)
+ printf ("info: flushing pending queries\n");
+ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_RESET_SEQ,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL,
+ ((struct timeval) { 5, 0 }))
+ == RPC_SUCCESS);
+}
+
+/* Return the number seconds since an arbitrary point in time. */
+static double
+get_ticks (void)
+{
+ {
+ struct timespec ts;
+ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
+ }
+ {
+ struct timeval tv;
+ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0);
+ return tv.tv_sec + tv.tv_usec * 1e-6;
+ }
+}
+
+static void
+test_udp_server (int port)
+{
+ struct sockaddr_in sin =
+ {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
+ .sin_port = htons (port)
+ };
+ int sock = RPC_ANYSOCK;
+
+ /* The client uses a 1.5 second timeout for retries. The timeouts
+ are arbitrary, but chosen so that there is a substantial gap
+ between them, but the total time spent waiting is not too
+ large. */
+ CLIENT *clnt = clntudp_create (&sin, PROGNUM, VERSNUM,
+ (struct timeval) { 1, 500 * 1000 },
+ &sock);
+ TEST_VERIFY_EXIT (clnt != NULL);
+
+ /* Basic call/response test. */
+ struct test_response response = test_call
+ (clnt, PROC_ADD,
+ (struct test_query) { .a = 17, .b = 4 },
+ (struct timeval) { 3, 0 });
+ TEST_VERIFY (response.sum == 21);
+ TEST_VERIFY (response.seq == 1);
+
+ /* Check that garbage packets do not interfere with timeout
+ processing. */
+ double before = get_ticks ();
+ response = test_call
+ (clnt, PROC_ADD,
+ (struct test_query) {
+ .a = 19, .b = 4, .timeout_ms = 500, .garbage_packets = 21,
+ },
+ (struct timeval) { 3, 0 });
+ TEST_VERIFY (response.sum == 23);
+ TEST_VERIFY (response.seq == 2);
+ double after = get_ticks ();
+ if (test_verbose)
+ printf ("info: 21 garbage packets took %f seconds\n", after - before);
+ /* Expected timeout is 0.5 seconds. Add some slack in case process
+ scheduling delays processing the query or response, but do not
+ accept a retry (which would happen at 1.5 seconds). */
+ TEST_VERIFY (0.5 <= after - before);
+ TEST_VERIFY (after - before < 1.2);
+ test_call_flush (clnt);
+
+ /* Check that missing a response introduces a 1.5 second timeout, as
+ requested when calling clntudp_create. */
+ before = get_ticks ();
+ response = test_call
+ (clnt, PROC_ADD,
+ (struct test_query) { .a = 170, .b = 40, .wait_for_seq = 2 },
+ (struct timeval) { 3, 0 });
+ TEST_VERIFY (response.sum == 210);
+ TEST_VERIFY (response.seq == 2);
+ after = get_ticks ();
+ if (test_verbose)
+ printf ("info: skipping one response took %f seconds\n",
+ after - before);
+ /* Expected timeout is 1.5 seconds. Do not accept a second retry
+ (which would happen at 3 seconds). */
+ TEST_VERIFY (1.5 <= after - before);
+ TEST_VERIFY (after - before < 2.9);
+ test_call_flush (clnt);
+
+ /* Check that the overall timeout wins against the per-query
+ timeout. */
+ before = get_ticks ();
+ test_call_timeout
+ (clnt, PROC_ADD,
+ (struct test_query) { .a = 170, .b = 41, .wait_for_seq = 2 },
+ (struct timeval) { 0, 750 * 1000 });
+ after = get_ticks ();
+ if (test_verbose)
+ printf ("info: 0.75 second timeout took %f seconds\n",
+ after - before);
+ TEST_VERIFY (0.75 <= after - before);
+ TEST_VERIFY (after - before < 1.4);
+ test_call_flush (clnt);
+
+ for (int with_garbage = 0; with_garbage < 2; ++with_garbage)
+ {
+ /* Check that no response at all causes the client to bail out. */
+ before = get_ticks ();
+ test_call_timeout
+ (clnt, PROC_ADD,
+ (struct test_query) {
+ .a = 170, .b = 40, .timeout_ms = 1200,
+ .garbage_packets = with_garbage * 21
+ },
+ (struct timeval) { 0, 750 * 1000 });
+ after = get_ticks ();
+ if (test_verbose)
+ printf ("info: test_udp_server: 0.75 second timeout took %f seconds"
+ " (garbage %d)\n",
+ after - before, with_garbage);
+ TEST_VERIFY (0.75 <= after - before);
+ TEST_VERIFY (after - before < 1.4);
+ test_call_flush (clnt);
+
+ /* As above, but check the total timeout. */
+ before = get_ticks ();
+ test_call_timeout
+ (clnt, PROC_ADD,
+ (struct test_query) {
+ .a = 170, .b = 40, .timeout_ms = 3000,
+ .garbage_packets = with_garbage * 30
+ },
+ (struct timeval) { 2, 300 * 1000 });
+ after = get_ticks ();
+ if (test_verbose)
+ printf ("info: test_udp_server: 2.3 second timeout took %f seconds"
+ " (garbage %d)\n",
+ after - before, with_garbage);
+ TEST_VERIFY (2.3 <= after - before);
+ TEST_VERIFY (after - before < 3.0);
+ test_call_flush (clnt);
+ }
+
+ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_EXIT,
+ (xdrproc_t) xdr_void, NULL,
+ (xdrproc_t) xdr_void, NULL,
+ ((struct timeval) { 5, 0 }))
+ == RPC_SUCCESS);
+ clnt_destroy (clnt);
+}
+
+static int
+do_test (void)
+{
+ support_become_root ();
+ support_enter_network_namespace ();
+
+ SVCXPRT *transport = svcudp_create (RPC_ANYSOCK);
+ TEST_VERIFY_EXIT (transport != NULL);
+ TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM, server_dispatch, 0));
+
+ pid_t pid = xfork ();
+ if (pid == 0)
+ {
+ svc_run ();
+ FAIL_EXIT1 ("supposed to be unreachable");
+ }
+ test_udp_server (transport->xp_port);
+
+ int status;
+ xwaitpid (pid, &status, 0);
+ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER);
+
+ SVC_DESTROY (transport);
+ return 0;
+}
+
+/* The minimum run time is around 17 seconds. */
+#define TIMEOUT 25
+#include <support/test-driver.c>
--
2.12.0
1.1
src/patchsets/glibc/2.25/00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch?rev=1.1&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch?rev=1.1&content-type=text/plain
Index: 00_all_0009-Document-and-fix-enable-bind-now-BZ-21015.patch
===================================================================
>From 32b4c41fb6d814551fa6d6e5e07ecbe2119407a7 Mon Sep 17 00:00:00 2001
From: Florian Weimer <[email protected]>
Date: Thu, 2 Mar 2017 20:11:27 +0100
Subject: [PATCH] Document and fix --enable-bind-now [BZ #21015]
(cherry picked from commit 2d6ab5df3b675e96ee587ae6a8c2ce004c6b1ba9)
(cherry picked from commit 69e0a87cc4c570e3b7218392fc3e743b5bddcce2)
---
INSTALL | 6 ++++++
Makeconfig | 7 +++++++
Makerules | 9 +++------
iconvdata/Makefile | 5 +++++
manual/install.texi | 6 ++++++
sysdeps/unix/sysv/linux/alpha/localplt.data | 2 +-
sysdeps/unix/sysv/linux/i386/localplt.data | 2 +-
sysdeps/x86_64/localplt.data | 2 +-
8 files changed, 30 insertions(+), 9 deletions(-)
diff --git a/INSTALL b/INSTALL
index 3b3fd121b232..e77cb2d4e294 100644
--- a/INSTALL
+++ b/INSTALL
@@ -146,6 +146,12 @@ will be used, and CFLAGS sets optimization options for the
compiler.
of routines called directly from assembler are excluded from this
protection.
+'--enable-bind-now'
+ Disable lazy binding for installed shared objects. This provides
+ additional security hardening because it enables full RELRO and a
+ read-only global offset table (GOT), at the cost of slightly
+ increased program load times.
+
'--enable-pt_chown'
The file 'pt_chown' is a helper binary for 'grantpt' (*note
Pseudo-Terminals: Allocation.) that is installed setuid root to fix
diff --git a/Makeconfig b/Makeconfig
index d944cd5db654..fcd2a5d7b1dd 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -386,6 +386,13 @@ LDFLAGS.so += $(hashstyle-LDFLAGS)
LDFLAGS-rtld += $(hashstyle-LDFLAGS)
endif
+# If lazy relocations are disabled, add the -z now flag. Use
+# LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to
+# test modules.
+ifeq ($(bind-now),yes)
+LDFLAGS-lib.so += -Wl,-z,now
+endif
+
# Command to run after every final link (executable or shared object).
# This is invoked with $(call after-link,...), so it should operate on
# the file $1. This can be set to do some sort of post-processing on
diff --git a/Makerules b/Makerules
index e9194e54cf67..7f0eef8096cc 100644
--- a/Makerules
+++ b/Makerules
@@ -588,7 +588,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
$(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
$(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
-Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
- $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
+ $(LDFLAGS.so) $(LDFLAGS-lib.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
-L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
endef
@@ -686,10 +686,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles
LDLIBS-c.so += $(libc.so-gnulib)
# Give libc.so an entry point and make it directly runnable itself.
LDFLAGS-c.so += -e __libc_main
-# If lazy relocation is disabled add the -z now flag.
-ifeq ($(bind-now),yes)
-LDFLAGS-c.so += -Wl,-z,now
-endif
# Pre-link the objects of libc_pic.a so that we can locally resolve
# COMMON symbols before we link against ld.so. This is because ld.so
# contains some of libc_pic.a already, which will prevent the COMMONs
@@ -1104,7 +1100,8 @@ $(common-objpfx)format.lds:
$(..)scripts/output-format.sed \
ifneq (unknown,$(output-format))
echo > [email protected] '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 [email protected] -Wl,--verbose -v 2>&1 \
| sed -n -f $< > [email protected]
test -s [email protected]
diff --git a/iconvdata/Makefile b/iconvdata/Makefile
index 04157b25c5cc..e4845871f559 100644
--- a/iconvdata/Makefile
+++ b/iconvdata/Makefile
@@ -63,6 +63,11 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4
ISO8859-5 \
MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \
CP770 CP771 CP772 CP773 CP774
+# If lazy binding is disabled, use BIND_NOW for the gconv modules.
+ifeq ($(bind-now),yes)
+LDFLAGS.so += -Wl,-z,now
+endif
+
modules.so := $(addsuffix .so, $(modules))
ifeq (yes,$(build-shared))
diff --git a/manual/install.texi b/manual/install.texi
index 266add8ba9f4..3398cfab02b5 100644
--- a/manual/install.texi
+++ b/manual/install.texi
@@ -175,6 +175,12 @@ options to detect stack overruns. Only the dynamic linker
and a small
number of routines called directly from assembler are excluded from this
protection.
+@item --enable-bind-now
+Disable lazy binding for installed shared objects. This provides
+additional security hardening because it enables full RELRO and a
+read-only global offset table (GOT), at the cost of slightly increased
+program load times.
+
@pindex pt_chown
@findex grantpt
@item --enable-pt_chown
diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data
b/sysdeps/unix/sysv/linux/alpha/localplt.data
index cca17f1e34bd..1f0e3b494e90 100644
--- a/sysdeps/unix/sysv/linux/alpha/localplt.data
+++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
@@ -20,7 +20,7 @@ libc.so: free + RELA R_ALPHA_GLOB_DAT
libc.so: malloc + RELA R_ALPHA_GLOB_DAT
libc.so: memalign + RELA R_ALPHA_GLOB_DAT
libc.so: realloc + RELA R_ALPHA_GLOB_DAT
-libm.so: matherr
+libm.so: matherr + RELA R_ALPHA_GLOB_DAT
# We used to offer inline functions that used this, so it must be exported.
# Ought to reorg things such that carg isn't thus forced to use a plt.
libm.so: __atan2
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data
b/sysdeps/unix/sysv/linux/i386/localplt.data
index 2c2584956d03..8ea4333846df 100644
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
@@ -6,7 +6,7 @@ libc.so: free + REL R_386_GLOB_DAT
libc.so: malloc + REL R_386_GLOB_DAT
libc.so: memalign + REL R_386_GLOB_DAT
libc.so: realloc + REL R_386_GLOB_DAT
-libm.so: matherr
+libm.so: matherr + REL R_386_GLOB_DAT
# The main malloc is interposed into the dynamic linker, for
# allocations after the initial link (when dlopen is used).
ld.so: malloc + REL R_386_GLOB_DAT
diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
index 014a9f455430..a1840cff31cf 100644
--- a/sysdeps/x86_64/localplt.data
+++ b/sysdeps/x86_64/localplt.data
@@ -8,7 +8,7 @@ libc.so: free + RELA R_X86_64_GLOB_DAT
libc.so: malloc + RELA R_X86_64_GLOB_DAT
libc.so: memalign + RELA R_X86_64_GLOB_DAT
libc.so: realloc + RELA R_X86_64_GLOB_DAT
-libm.so: matherr
+libm.so: matherr + RELA R_X86_64_GLOB_DAT
# The main malloc is interposed into the dynamic linker, for
# allocations after the initial link (when dlopen is used).
ld.so: malloc + RELA R_X86_64_GLOB_DAT
--
2.12.0
1.1
src/patchsets/glibc/2.25/00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch?rev=1.1&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch?rev=1.1&content-type=text/plain
Index: 00_all_0010-hppa-Fix-setting-of-__libc_stack_end.patch
===================================================================
>From 883dae86d69153092f73a223f226c85fa4fb9a35 Mon Sep 17 00:00:00 2001
From: John David Anglin <[email protected]>
Date: Mon, 20 Feb 2017 20:31:57 -0500
Subject: [PATCH] hppa: Fix setting of __libc_stack_end
The binutils package was recently changed to fix -z relro support on hppa.
See ld/21000 for details:
https://sourceware.org/bugzilla/show_bug.cgi?id=21000
This exposed a problem with the _dl_start_user function in the RTLD_START
define. We need to set __libc_stack_end before it is made read only. For
this, we need to define DL_STACK_END. The offset of 0x160 gives the same
stack end as the code in _dl_start_user.
A build log with the attached patch is here:
https://buildd.debian.org/status/fetch.php?pkg=glibc&arch=hppa&ver=2.24-9&stamp=1487639205&raw=0
(cherry picked from commit 5d20a49aaccef5ef7adac93d5ca159f6b7ba0105)
(cherry picked from commit 8b3caa41b9cb82651e72a0c87aa56719c134000e)
---
sysdeps/hppa/dl-machine.h | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
index 339c7bb77129..787b95f5022e 100644
--- a/sysdeps/hppa/dl-machine.h
+++ b/sysdeps/hppa/dl-machine.h
@@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy,
int profile)
#define ARCH_LA_PLTENTER hppa_gnu_pltenter
#define ARCH_LA_PLTEXIT hppa_gnu_pltexit
+/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */
+#define DL_STACK_END(cookie) \
+ ((void *) (((long) (cookie)) + 0x160))
+
/* Initial entry point code for the dynamic linker.
The C function `_dl_start' is the real entry point;
its return value is the user program's entry point. */
@@ -401,11 +405,6 @@ asm (
\
/* Save the entry point in %r3. */ \
" copy %ret0,%r3\n" \
\
- /* Remember the lowest stack address. */ \
-" addil LT'__libc_stack_end,%r19\n" \
-" ldw RT'__libc_stack_end(%r1),%r20\n" \
-" stw %sp,0(%r20)\n" \
- \
/* See if we were called as a command with the executable file \
name as an extra leading argument. */ \
" addil LT'_dl_skip_args,%r19\n" \
--
2.12.0
1.1
src/patchsets/glibc/2.25/00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch
file :
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch?rev=1.1&view=markup
plain:
http://sources.gentoo.org/viewvc.cgi/gentoo/src/patchsets/glibc/2.25/00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch?rev=1.1&content-type=text/plain
Index: 00_all_0011-x86_64-fix-static-build-of-__mempcpy_chk-for-compile.patch
===================================================================
>From 92bec3dad990b1dda9a82966913fce04b5c99c02 Mon Sep 17 00:00:00 2001
From: Mike Frysinger <[email protected]>
Date: Sun, 12 Mar 2017 15:12:21 -0700
Subject: [PATCH] x86_64: fix static build of __mempcpy_chk for compilers
defaulting to PIC/PIE
When glibc is compiled with gcc 6.2 that has been configured with
to default to PIC/PIE, the static version of __mempcpy_chk is not built,
as the test is done on PIC instead of SHARED. Fix the test to check for
SHARED, like it is done for similar functions like __memcpy_chk.
2017-03-12 Mike Frysinger <[email protected]>
* sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED
instead of PIC.
(cherry picked from commit fbe355fbd1973d6e29561084b3eaeb4bfe9d515a)
(cherry picked from commit 0889003c67f9c2f520a37281c4b5c3b8a9861f46)
---
sysdeps/x86_64/mempcpy_chk.S | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S
index f8a9260e6ea8..f91229157690 100644
--- a/sysdeps/x86_64/mempcpy_chk.S
+++ b/sysdeps/x86_64/mempcpy_chk.S
@@ -19,7 +19,7 @@
#include <sysdep.h>
#include "asm-syntax.h"
-#ifndef PIC
+#ifndef SHARED
/* For libc.so this is defined in memcpy.S.
For libc.a, this is a separate source to avoid
mempcpy bringing in __chk_fail and all routines
--
2.12.0