commit 58520986c38e34db60e07260c64c563e3efcf353 Author: Siddhesh Poyarekar 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 f140ee6..c88238e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2017-02-08 Siddhesh Poyarekar + + [BZ #21109] + * elf/dl-tunable-types.h (tunable_callback_t): Accept + tunable_val_t as argument. + * elf/dl-tunables.c (__tunable_set_val): Add comment. + * malloc/arena.c (set_mallopt_check): Take tunable_val_t as + argument. + (DL_TUNABLE_CALLBACK_FNDECL): Likewise. + 2017-02-05 Siddhesh Poyarekar * version.h (RELEASE): Set to "stable" diff --git a/NEWS b/NEWS index ec15dde..325cac7 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,12 @@ See the end for copying conditions. Please send GNU C library bug reports via using `glibc' in the "product" field. +Version 2.25.1 + +The following bugs are resolved with this release: + + [21109] Tunables broken on big-endian + Version 2.25 * The feature test macro __STDC_WANT_LIB_EXT2__, from ISO/IEC TR diff --git a/elf/dl-tunable-types.h b/elf/dl-tunable-types.h index a986f0b..37a4e80 100644 --- a/elf/dl-tunable-types.h +++ b/elf/dl-tunable-types.h @@ -21,8 +21,6 @@ # define _TUNABLE_TYPES_H_ #include -typedef void (*tunable_callback_t) (void *); - typedef enum { TUNABLE_TYPE_INT_32, @@ -43,6 +41,8 @@ typedef union const char *strval; } tunable_val_t; +typedef void (*tunable_callback_t) (tunable_val_t *); + /* Security level for tunables. This decides what to do with individual tunables for AT_SECURE binaries. */ typedef enum diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c index a8d53d6..e42aa67 100644 --- a/elf/dl-tunables.c +++ b/elf/dl-tunables.c @@ -455,6 +455,8 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback) if (cur->strval == NULL) return; + /* Caller does not need the value, just call the callback with our tunable + value. */ if (valp == NULL) goto cb; diff --git a/malloc/arena.c b/malloc/arena.c index b91d7d6..d49e4a2 100644 --- a/malloc/arena.c +++ b/malloc/arena.c @@ -212,9 +212,9 @@ __malloc_fork_unlock_child (void) #if HAVE_TUNABLES static inline int do_set_mallopt_check (int32_t value); void -DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) +DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp) { - int32_t value = *(int32_t *) valp; + int32_t value = (int32_t) valp->numval; do_set_mallopt_check (value); if (check_action != 0) __malloc_check_init (); @@ -223,9 +223,9 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp) # define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \ static inline int do_ ## __name (__type value); \ void \ -DL_TUNABLE_CALLBACK (__name) (void *valp) \ +DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \ { \ - __type value = *(__type *) valp; \ + __type value = (__type) (valp)->numval; \ do_ ## __name (value); \ } commit 045e368799cd253ddbf8bdec42ed92e8ebb3ce67 Author: Florian Weimer 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 c88238e..3d781a3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-02-27 Florian Weimer + + [BZ #21115] + * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later. + * sunrpc/Makefile (tests): Add tst-udp-error. + (tst-udp-error): Link against libc.so explicitly. + * sunrpc/tst-udp-error: New file. + 2017-02-08 Siddhesh Poyarekar [BZ #21109] diff --git a/NEWS b/NEWS index 325cac7..5ecc565 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,7 @@ Version 2.25.1 The following bugs are resolved with this release: [21109] Tunables broken on big-endian + [21115] sunrpc: Use-after-free in error path in clntudp_call Version 2.25 diff --git a/sunrpc/Makefile b/sunrpc/Makefile index 0c1e612..daf8a28 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -93,7 +93,7 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) others += rpcgen -tests = tst-xdrmem tst-xdrmem2 test-rpcent +tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error xtests := tst-getmyaddr ifeq ($(have-thread-library),yes) @@ -155,6 +155,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS) $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so +$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs)) diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c index 4d9acb1..1de25cb 100644 --- a/sunrpc/clnt_udp.c +++ b/sunrpc/clnt_udp.c @@ -421,9 +421,9 @@ send_again: cmsg = CMSG_NXTHDR (&msg, cmsg)) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { - free (cbuf); e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; + free (cbuf); return (cu->cu_error.re_status = RPC_CANTRECV); } free (cbuf); diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c new file mode 100644 index 0000000..1efc02f --- /dev/null +++ b/sunrpc/tst-udp-error.c @@ -0,0 +1,62 @@ +/* Check for use-after-free in clntudp_call (bug 21115). + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + support_become_root (); + support_enter_network_namespace (); + + /* Obtain a likely-unused port number. */ + struct sockaddr_in sin = + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl (INADDR_LOOPBACK), + }; + { + int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + xbind (fd, (struct sockaddr *) &sin, sizeof (sin)); + socklen_t sinlen = sizeof (sin); + xgetsockname (fd, (struct sockaddr *) &sin, &sinlen); + /* Close the socket, so that we will receive an error below. */ + close (fd); + } + + int sock = RPC_ANYSOCK; + CLIENT *clnt = clntudp_create + (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock); + TEST_VERIFY_EXIT (clnt != NULL); + TEST_VERIFY (clnt_call (clnt, 3, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 3, 0 })) + == RPC_CANTRECV); + clnt_destroy (clnt); + + return 0; +} + +#include commit 93cf93e06ce123439e41d3d62790601c313134cb Author: Florian Weimer 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 3d781a3..510ca42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2017-02-28 Florian Weimer + + [BZ #20257] + * inet/Makefile (routines): Add deadline. + (tests-static): Add tst-deadline. + * inet/net-internal.h (struct deadline_current_time) + (__deadline_current_time, struct deadline, __deadline_is_infinite) + (__deadline_elapsed, __deadline_first, __deadline_from_timeval) + (__deadline_to_ms, __is_timeval_valid_timeout): Declare. + * inet/deadline.c: New file. + * inet/tst-deadline.c: Likewise. + * sunrpc/Makefile (tests): Add tst-udp-nonblocking, + tst-udp-timeout, tst-udp-garbage. + (tst-udp-nonblocking, tst-udp-timeout): Link against libc.so + explicitly. + (tst-udp-garbage): Likewise. Also link against thread library. + * sunrpc/clnt_udp.c (struct cu_data): Mention in comment that the + struct layout is part of the ABI. + (clntudp_call): Rework timeout handling. + * sunrpc/tst-udp-garbage.c: New file. + * sunrpc/tst-udp-nonblocking.c: Likewise. + * sunrpc/tst-udp-timeout.c: Likewise. + 2017-02-27 Florian Weimer [BZ #21115] diff --git a/NEWS b/NEWS index 5ecc565..e7d6668 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,7 @@ The following bugs are resolved with this release: [21109] Tunables broken on big-endian [21115] sunrpc: Use-after-free in error path in clntudp_call + [20257] sunrpc: clntudp_call does not enforce timeout when receiving data Version 2.25 diff --git a/inet/Makefile b/inet/Makefile index 010792a..6a7d3e0 100644 --- a/inet/Makefile +++ b/inet/Makefile @@ -45,14 +45,18 @@ routines := htonl htons \ in6_addr getnameinfo if_index ifaddrs inet6_option \ getipv4sourcefilter setipv4sourcefilter \ getsourcefilter setsourcefilter inet6_opt inet6_rth \ - inet6_scopeid_pton + inet6_scopeid_pton deadline aux := check_pf check_native ifreq tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \ tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \ tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \ - tst-sockaddr tst-inet6_scopeid_pton test-hnto-types + tst-sockaddr tst-inet6_scopeid_pton test-hnto-types tst-deadline + +# tst-deadline must be linked statically so that we can access +# internal functions. +tests-static += tst-deadline include ../Rules diff --git a/inet/deadline.c b/inet/deadline.c new file mode 100644 index 0000000..c1fa415 --- /dev/null +++ b/inet/deadline.c @@ -0,0 +1,122 @@ +/* Computing deadlines for timeouts. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +struct deadline_current_time internal_function +__deadline_current_time (void) +{ + struct deadline_current_time result; + if (__clock_gettime (CLOCK_MONOTONIC, &result.current) != 0) + { + struct timeval current_tv; + if (__gettimeofday (¤t_tv, NULL) == 0) + __libc_fatal ("Fatal error: gettimeofday system call failed\n"); + result.current.tv_sec = current_tv.tv_sec; + result.current.tv_nsec = current_tv.tv_usec * 1000; + } + assert (result.current.tv_sec >= 0); + return result; +} + +/* A special deadline value for which __deadline_is_infinite is + true. */ +static inline struct deadline +infinite_deadline (void) +{ + return (struct deadline) { { -1, -1 } }; +} + +struct deadline internal_function +__deadline_from_timeval (struct deadline_current_time current, + struct timeval tv) +{ + assert (__is_timeval_valid_timeout (tv)); + + /* Compute second-based deadline. Perform the addition in + uintmax_t, which is unsigned, to simply overflow detection. */ + uintmax_t sec = current.current.tv_sec; + sec += tv.tv_sec; + if (sec < (uintmax_t) tv.tv_sec) + return infinite_deadline (); + + /* Compute nanosecond deadline. */ + int nsec = current.current.tv_nsec + tv.tv_usec * 1000; + if (nsec >= 1000 * 1000 * 1000) + { + /* Carry nanosecond overflow to seconds. */ + nsec -= 1000 * 1000 * 1000; + if (sec + 1 < sec) + return infinite_deadline (); + ++sec; + } + /* This uses a GCC extension, otherwise these casts for detecting + overflow would not be defined. */ + if ((time_t) sec < 0 || sec != (uintmax_t) (time_t) sec) + return infinite_deadline (); + + return (struct deadline) { { sec, nsec } }; +} + +int internal_function +__deadline_to_ms (struct deadline_current_time current, + struct deadline deadline) +{ + if (__deadline_is_infinite (deadline)) + return INT_MAX; + + if (current.current.tv_sec > deadline.absolute.tv_sec + || (current.current.tv_sec == deadline.absolute.tv_sec + && current.current.tv_nsec >= deadline.absolute.tv_nsec)) + return 0; + time_t sec = deadline.absolute.tv_sec - current.current.tv_sec; + if (sec >= INT_MAX) + /* This value will overflow below. */ + return INT_MAX; + int nsec = deadline.absolute.tv_nsec - current.current.tv_nsec; + if (nsec < 0) + { + /* Borrow from the seconds field. */ + assert (sec > 0); + --sec; + nsec += 1000 * 1000 * 1000; + } + + /* Prepare for rounding up to milliseconds. */ + nsec += 999999; + if (nsec > 1000 * 1000 * 1000) + { + assert (sec < INT_MAX); + ++sec; + nsec -= 1000 * 1000 * 1000; + } + + unsigned int msec = nsec / (1000 * 1000); + if (sec > INT_MAX / 1000) + return INT_MAX; + msec += sec * 1000; + if (msec > INT_MAX) + return INT_MAX; + return msec; +} diff --git a/inet/net-internal.h b/inet/net-internal.h index 087597e..2b2632c 100644 --- a/inet/net-internal.h +++ b/inet/net-internal.h @@ -20,11 +20,100 @@ #define _NET_INTERNAL_H 1 #include +#include #include +#include int __inet6_scopeid_pton (const struct in6_addr *address, const char *scope, uint32_t *result) internal_function attribute_hidden; libc_hidden_proto (__inet6_scopeid_pton) + +/* Deadline handling for enforcing timeouts. + + Code should call __deadline_current_time to obtain the current time + and cache it locally. The cache needs updating after every + long-running or potentially blocking operation. Deadlines relative + to the current time can be computed using __deadline_from_timeval. + The deadlines may have to be recomputed in response to certain + events (such as an incoming packet), but they are absolute (not + relative to the current time). A timeout suitable for use with the + poll function can be computed from such a deadline using + __deadline_to_ms. + + The fields in the structs defined belowed should only be used + within the implementation. */ + +/* Cache of the current time. Used to compute deadlines from relative + timeouts and vice versa. */ +struct deadline_current_time +{ + struct timespec current; +}; + +/* Return the current time. Terminates the process if the current + time is not available. */ +struct deadline_current_time __deadline_current_time (void) + internal_function attribute_hidden; + +/* Computed absolute deadline. */ +struct deadline +{ + struct timespec absolute; +}; + + +/* For internal use only. */ +static inline bool +__deadline_is_infinite (struct deadline deadline) +{ + return deadline.absolute.tv_nsec < 0; +} + +/* Return true if the current time is at the deadline or past it. */ +static inline bool +__deadline_elapsed (struct deadline_current_time current, + struct deadline deadline) +{ + return !__deadline_is_infinite (deadline) + && (current.current.tv_sec > deadline.absolute.tv_sec + || (current.current.tv_sec == deadline.absolute.tv_sec + && current.current.tv_nsec >= deadline.absolute.tv_nsec)); +} + +/* Return the deadline which occurs first. */ +static inline struct deadline +__deadline_first (struct deadline left, struct deadline right) +{ + if (__deadline_is_infinite (right) + || left.absolute.tv_sec < right.absolute.tv_sec + || (left.absolute.tv_sec == right.absolute.tv_sec + && left.absolute.tv_nsec < right.absolute.tv_nsec)) + return left; + else + return right; +} + +/* Add TV to the current time and return it. Returns a special + infinite absolute deadline on overflow. */ +struct deadline __deadline_from_timeval (struct deadline_current_time, + struct timeval tv) + internal_function attribute_hidden; + +/* Compute the number of milliseconds until the specified deadline, + from the current time in the argument. The result is mainly for + use with poll. If the deadline has already passed, return 0. If + the result would overflow an int, return INT_MAX. */ +int __deadline_to_ms (struct deadline_current_time, struct deadline) + internal_function attribute_hidden; + +/* Return true if TV.tv_sec is non-negative and TV.tv_usec is in the + interval [0, 999999]. */ +static inline bool +__is_timeval_valid_timeout (struct timeval tv) +{ + return tv.tv_sec >= 0 && tv.tv_usec >= 0 && tv.tv_usec < 1000 * 1000; +} + #endif /* _NET_INTERNAL_H */ diff --git a/inet/tst-deadline.c b/inet/tst-deadline.c new file mode 100644 index 0000000..ed04345 --- /dev/null +++ b/inet/tst-deadline.c @@ -0,0 +1,188 @@ +/* Tests for computing deadlines for timeouts. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +/* Find the maximum value which can be represented in a time_t. */ +static time_t +time_t_max (void) +{ + _Static_assert (0 > (time_t) -1, "time_t is signed"); + uintmax_t current = 1; + while (true) + { + uintmax_t next = current * 2; + /* This cannot happen because time_t is signed. */ + TEST_VERIFY_EXIT (next > current); + ++next; + if ((time_t) next < 0 || next != (uintmax_t) (time_t) next) + /* Value cannot be represented in time_t. Return the previous + value. */ + return current; + current = next; + } +} + +static int +do_test (void) +{ + { + struct deadline_current_time current_time = __deadline_current_time (); + TEST_VERIFY (current_time.current.tv_sec >= 0); + current_time = __deadline_current_time (); + /* Due to CLOCK_MONOTONIC, either seconds or nanoseconds are + greater than zero. This is also true for the gettimeofday + fallback. */ + TEST_VERIFY (current_time.current.tv_sec >= 0); + TEST_VERIFY (current_time.current.tv_sec > 0 + || current_time.current.tv_nsec > 0); + } + + /* Check basic computations of deadlines. */ + struct deadline_current_time current_time = { { 1, 123456789 } }; + struct deadline deadline = __deadline_from_timeval + (current_time, (struct timeval) { 0, 1 }); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 123457789); + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1); + + deadline = __deadline_from_timeval + (current_time, ((struct timeval) { 0, 2 })); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 123458789); + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1); + + deadline = __deadline_from_timeval + (current_time, ((struct timeval) { 1, 0 })); + TEST_VERIFY (deadline.absolute.tv_sec == 2); + TEST_VERIFY (deadline.absolute.tv_nsec == 123456789); + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); + + /* Check if timeouts are correctly rounded up to the next + millisecond. */ + for (int i = 0; i < 999999; ++i) + { + ++current_time.current.tv_nsec; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); + } + + /* A full millisecond has elapsed, so the time to the deadline is + now less than 1000. */ + ++current_time.current.tv_nsec; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999); + + /* Check __deadline_to_ms carry-over. */ + current_time = (struct deadline_current_time) { { 9, 123456789 } }; + deadline = (struct deadline) { { 10, 122456789 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999); + deadline = (struct deadline) { { 10, 122456790 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); + deadline = (struct deadline) { { 10, 123456788 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); + deadline = (struct deadline) { { 10, 123456789 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000); + + /* Check __deadline_to_ms overflow. */ + deadline = (struct deadline) { { INT_MAX - 1, 1 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == INT_MAX); + + /* Check __deadline_to_ms for elapsed deadlines. */ + current_time = (struct deadline_current_time) { { 9, 123456789 } }; + deadline.absolute = current_time.current; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); + current_time = (struct deadline_current_time) { { 9, 123456790 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); + current_time = (struct deadline_current_time) { { 10, 0 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); + current_time = (struct deadline_current_time) { { 10, 123456788 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); + current_time = (struct deadline_current_time) { { 10, 123456789 } }; + TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0); + + /* Check carry-over in __deadline_from_timeval. */ + current_time = (struct deadline_current_time) { { 9, 998000001 } }; + for (int i = 0; i < 2000; ++i) + { + deadline = __deadline_from_timeval + (current_time, (struct timeval) { 1, i }); + TEST_VERIFY (deadline.absolute.tv_sec == 10); + TEST_VERIFY (deadline.absolute.tv_nsec == 998000001 + i * 1000); + } + for (int i = 2000; i < 3000; ++i) + { + deadline = __deadline_from_timeval + (current_time, (struct timeval) { 2, i }); + TEST_VERIFY (deadline.absolute.tv_sec == 12); + TEST_VERIFY (deadline.absolute.tv_nsec == 1 + (i - 2000) * 1000); + } + + /* Check infinite deadlines. */ + deadline = __deadline_from_timeval + ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1000 } }, + (struct timeval) { time_t_max (), 1 }); + TEST_VERIFY (__deadline_is_infinite (deadline)); + deadline = __deadline_from_timeval + ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1001 } }, + (struct timeval) { time_t_max (), 1 }); + TEST_VERIFY (!__deadline_is_infinite (deadline)); + deadline = __deadline_from_timeval + ((struct deadline_current_time) + { { time_t_max (), 1000 * 1000 * 1000 - 1000 } }, + (struct timeval) { 0, 1 }); + TEST_VERIFY (__deadline_is_infinite (deadline)); + deadline = __deadline_from_timeval + ((struct deadline_current_time) + { { time_t_max () / 2 + 1, 0 } }, + (struct timeval) { time_t_max () / 2 + 1, 0 }); + TEST_VERIFY (__deadline_is_infinite (deadline)); + + /* Check __deadline_first behavior. */ + deadline = __deadline_first + ((struct deadline) { { 1, 2 } }, + (struct deadline) { { 1, 3 } }); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 2); + deadline = __deadline_first + ((struct deadline) { { 1, 3 } }, + (struct deadline) { { 1, 2 } }); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 2); + deadline = __deadline_first + ((struct deadline) { { 1, 2 } }, + (struct deadline) { { 2, 1 } }); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 2); + deadline = __deadline_first + ((struct deadline) { { 1, 2 } }, + (struct deadline) { { 2, 4 } }); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 2); + deadline = __deadline_first + ((struct deadline) { { 2, 4 } }, + (struct deadline) { { 1, 2 } }); + TEST_VERIFY (deadline.absolute.tv_sec == 1); + TEST_VERIFY (deadline.absolute.tv_nsec == 2); + + return 0; +} + +#include diff --git a/sunrpc/Makefile b/sunrpc/Makefile index daf8a28..7e5d295 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) others += rpcgen -tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error +tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \ + tst-udp-nonblocking xtests := tst-getmyaddr ifeq ($(have-thread-library),yes) -xtests += thrsvc +xtests += thrsvc tst-udp-garbage endif ifeq ($(run-built-tests),yes) @@ -235,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen $(built-program-cmd) -c $< -o $@; \ $(evaluate-test) endif + +$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so +$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so +$(objpfx)tst-udp-garbage: \ + $(common-objpfx)linkobj/libc.so $(shared-thread-library) diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c index 1de25cb..6ce16eb 100644 --- a/sunrpc/clnt_udp.c +++ b/sunrpc/clnt_udp.c @@ -55,6 +55,7 @@ #endif #include +#include extern u_long _create_xid (void); @@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops = }; /* - * Private data kept per client handle + * Private data kept per client handle. This private struct is + * unfortunately part of the ABI; ypbind contains a copy of it and + * accesses it through CLIENT::cl_private field. */ struct cu_data { @@ -278,28 +281,38 @@ clntudp_call (/* client handle */ int inlen; socklen_t fromlen; struct pollfd fd; - int milliseconds = (cu->cu_wait.tv_sec * 1000) + - (cu->cu_wait.tv_usec / 1000); struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; - struct timeval time_waited; bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ - struct timeval timeout; int anyup; /* any network interface up */ - if (cu->cu_total.tv_usec == -1) - { - timeout = utimeout; /* use supplied timeout */ - } - else + struct deadline_current_time current_time = __deadline_current_time (); + struct deadline total_deadline; /* Determined once by overall timeout. */ + struct deadline response_deadline; /* Determined anew for each query. */ + + /* Choose the timeout value. For non-sending usage (xargs == NULL), + the total deadline does not matter, only cu->cu_wait is used + below. */ + if (xargs != NULL) { - timeout = cu->cu_total; /* use default timeout */ + struct timeval tv; + if (cu->cu_total.tv_usec == -1) + /* Use supplied timeout. */ + tv = utimeout; + else + /* Use default timeout. */ + tv = cu->cu_total; + if (!__is_timeval_valid_timeout (tv)) + return (cu->cu_error.re_status = RPC_TIMEDOUT); + total_deadline = __deadline_from_timeval (current_time, tv); } - time_waited.tv_sec = 0; - time_waited.tv_usec = 0; + /* Guard against bad timeout specification. */ + if (!__is_timeval_valid_timeout (cu->cu_wait)) + return (cu->cu_error.re_status = RPC_TIMEDOUT); + call_again: xdrs = &(cu->cu_outxdrs); if (xargs == NULL) @@ -325,27 +338,46 @@ send_again: return (cu->cu_error.re_status = RPC_CANTSEND); } - /* - * Hack to provide rpc-based message passing - */ - if (timeout.tv_sec == 0 && timeout.tv_usec == 0) - { - return (cu->cu_error.re_status = RPC_TIMEDOUT); - } + /* sendto may have blocked, so recompute the current time. */ + current_time = __deadline_current_time (); get_reply: - /* - * sub-optimal code appears here because we have - * some clock time to spare while the packets are in flight. - * (We assume that this is actually only executed once.) - */ + response_deadline = __deadline_from_timeval (current_time, cu->cu_wait); + reply_msg.acpted_rply.ar_verf = _null_auth; reply_msg.acpted_rply.ar_results.where = resultsp; reply_msg.acpted_rply.ar_results.proc = xresults; fd.fd = cu->cu_sock; fd.events = POLLIN; anyup = 0; + + /* Per-response retry loop. current_time must be up-to-date at the + top of the loop. */ for (;;) { + int milliseconds; + if (xargs != NULL) + { + if (__deadline_elapsed (current_time, total_deadline)) + /* Overall timeout expired. */ + return (cu->cu_error.re_status = RPC_TIMEDOUT); + milliseconds = __deadline_to_ms + (current_time, __deadline_first (total_deadline, + response_deadline)); + if (milliseconds == 0) + /* Per-query timeout expired. */ + goto send_again; + } + else + { + /* xatgs == NULL. Collect a response without sending a + query. In this mode, we need to ignore the total + deadline. */ + milliseconds = __deadline_to_ms (current_time, response_deadline); + if (milliseconds == 0) + /* Cannot send again, so bail out. */ + return (cu->cu_error.re_status = RPC_CANTSEND); + } + switch (__poll (&fd, 1, milliseconds)) { @@ -356,27 +388,10 @@ send_again: if (!anyup) return (cu->cu_error.re_status = RPC_CANTRECV); } - - time_waited.tv_sec += cu->cu_wait.tv_sec; - time_waited.tv_usec += cu->cu_wait.tv_usec; - while (time_waited.tv_usec >= 1000000) - { - time_waited.tv_sec++; - time_waited.tv_usec -= 1000000; - } - if ((time_waited.tv_sec < timeout.tv_sec) || - ((time_waited.tv_sec == timeout.tv_sec) && - (time_waited.tv_usec < timeout.tv_usec))) - goto send_again; - return (cu->cu_error.re_status = RPC_TIMEDOUT); - - /* - * buggy in other cases because time_waited is not being - * updated. - */ + goto next_response; case -1: if (errno == EINTR) - continue; + goto next_response; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } @@ -440,20 +455,22 @@ send_again: if (inlen < 0) { if (errno == EWOULDBLOCK) - continue; + goto next_response; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } - if (inlen < 4) - continue; - - /* see if reply transaction id matches sent id. - Don't do this if we only wait for a replay */ - if (xargs != NULL - && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0) - continue; - /* we now assume we have the proper reply */ - break; + /* Accept the response if the packet is sufficiently long and + the transaction ID matches the query (if available). */ + if (inlen >= 4 + && (xargs == NULL + || memcmp (cu->cu_inbuf, cu->cu_outbuf, + sizeof (u_int32_t)) == 0)) + break; + + next_response: + /* Update the current time because poll and recvmsg waited for + an unknown time. */ + current_time = __deadline_current_time (); } /* diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c new file mode 100644 index 0000000..4abda93 --- /dev/null +++ b/sunrpc/tst-udp-garbage.c @@ -0,0 +1,104 @@ +/* Test that garbage packets do not affect timeout handling. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Descriptor for the server UDP socket. */ +static int server_fd; + +static void * +garbage_sender_thread (void *unused) +{ + while (true) + { + struct sockaddr_storage sa; + socklen_t salen = sizeof (sa); + char buf[1]; + if (recvfrom (server_fd, buf, sizeof (buf), 0, + (struct sockaddr *) &sa, &salen) < 0) + FAIL_EXIT1 ("recvfrom: %m"); + + /* Send garbage packets indefinitely. */ + buf[0] = 0; + while (true) + { + /* sendto can fail if the client closed the socket. */ + if (sendto (server_fd, buf, sizeof (buf), 0, + (struct sockaddr *) &sa, salen) < 0) + break; + + /* Wait a bit, to avoid burning too many CPU cycles in a + tight loop. The wait period must be much shorter than + the client timeouts configured below. */ + usleep (50 * 1000); + } + } +} + +static int +do_test (void) +{ + support_become_root (); + support_enter_network_namespace (); + + server_fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP); + struct sockaddr_in server_address = + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl (INADDR_LOOPBACK), + }; + xbind (server_fd, + (struct sockaddr *) &server_address, sizeof (server_address)); + { + socklen_t sinlen = sizeof (server_address); + xgetsockname (server_fd, (struct sockaddr *) &server_address, &sinlen); + TEST_VERIFY (sizeof (server_address) == sinlen); + } + + /* Garbage packet source. */ + xpthread_detach (xpthread_create (NULL, garbage_sender_thread, NULL)); + + /* Test client. Use an arbitrary timeout of one second, which is + much longer than the garbage packet interval, but still + reasonably short, so that the test completes quickly. */ + int client_fd = RPC_ANYSOCK; + CLIENT *clnt = clntudp_create (&server_address, + 1, 2, /* Arbitrary RPC endpoint numbers. */ + (struct timeval) { 1, 0 }, + &client_fd); + if (clnt == NULL) + FAIL_EXIT1 ("clntudp_create: %m"); + + TEST_VERIFY (clnt_call (clnt, 3, /* Arbitrary RPC procedure number. */ + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 1, 0 }))); + + return 0; +} + +#include diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c new file mode 100644 index 0000000..1d6a7f4 --- /dev/null +++ b/sunrpc/tst-udp-nonblocking.c @@ -0,0 +1,333 @@ +/* Test non-blocking use of the UDP client. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Test data serialization and deserialization. */ + +struct test_query +{ + uint32_t a; + uint32_t b; + uint32_t timeout_ms; +}; + +static bool_t +xdr_test_query (XDR *xdrs, void *data, ...) +{ + struct test_query *p = data; + return xdr_uint32_t (xdrs, &p->a) + && xdr_uint32_t (xdrs, &p->b) + && xdr_uint32_t (xdrs, &p->timeout_ms); +} + +struct test_response +{ + uint32_t server_id; + uint32_t seq; + uint32_t sum; +}; + +static bool_t +xdr_test_response (XDR *xdrs, void *data, ...) +{ + struct test_response *p = data; + return xdr_uint32_t (xdrs, &p->server_id) + && xdr_uint32_t (xdrs, &p->seq) + && xdr_uint32_t (xdrs, &p->sum); +} + +/* Implementation of the test server. */ + +enum + { + /* Number of test servers to run. */ + SERVER_COUNT = 3, + + /* RPC parameters, chosen at random. */ + PROGNUM = 8242, + VERSNUM = 19654, + + /* Main RPC operation. */ + PROC_ADD = 1, + + /* Request process termination. */ + PROC_EXIT, + + /* Special exit status to mark successful processing. */ + EXIT_MARKER = 55, + }; + +/* Set by the parent process to tell test servers apart. */ +static int server_id; + +/* Implementation of the test server. */ +static void +server_dispatch (struct svc_req *request, SVCXPRT *transport) +{ + /* Query sequence number. */ + static uint32_t seq = 0; + ++seq; + static bool proc_add_seen; + + if (test_verbose) + printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n", + server_id, seq, request->rq_proc); + + switch (request->rq_proc) + { + case PROC_ADD: + { + struct test_query query; + memset (&query, 0xc0, sizeof (query)); + TEST_VERIFY_EXIT + (svc_getargs (transport, xdr_test_query, + (void *) &query)); + + if (test_verbose) + printf (" a=%u b=%u timeout_ms=%u\n", + query.a, query.b, query.timeout_ms); + + usleep (query.timeout_ms * 1000); + + struct test_response response = + { + .server_id = server_id, + .seq = seq, + .sum = query.a + query.b, + }; + TEST_VERIFY (svc_sendreply (transport, xdr_test_response, + (void *) &response)); + if (test_verbose) + printf (" server id %d response seq=%u sent\n", server_id, seq); + proc_add_seen = true; + } + break; + + case PROC_EXIT: + TEST_VERIFY (proc_add_seen); + TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); + _exit (EXIT_MARKER); + break; + + default: + FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); + break; + } +} + +/* Return the number seconds since an arbitrary point in time. */ +static double +get_ticks (void) +{ + { + struct timespec ts; + if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) + return ts.tv_sec + ts.tv_nsec * 1e-9; + } + { + struct timeval tv; + TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); + return tv.tv_sec + tv.tv_usec * 1e-6; + } +} + +static int +do_test (void) +{ + support_become_root (); + support_enter_network_namespace (); + + /* Information about the test servers. */ + struct + { + SVCXPRT *transport; + struct sockaddr_in address; + pid_t pid; + uint32_t xid; + } servers[SERVER_COUNT]; + + /* Spawn the test servers. */ + for (int i = 0; i < SERVER_COUNT; ++i) + { + servers[i].transport = svcudp_create (RPC_ANYSOCK); + TEST_VERIFY_EXIT (servers[i].transport != NULL); + servers[i].address = (struct sockaddr_in) + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl (INADDR_LOOPBACK), + .sin_port = htons (servers[i].transport->xp_port), + }; + servers[i].xid = 0xabcd0101 + i; + if (test_verbose) + printf ("info: setting up server %d xid=%x on port %d\n", + i, servers[i].xid, servers[i].transport->xp_port); + + server_id = i; + servers[i].pid = xfork (); + if (servers[i].pid == 0) + { + TEST_VERIFY (svc_register (servers[i].transport, + PROGNUM, VERSNUM, server_dispatch, 0)); + svc_run (); + FAIL_EXIT1 ("supposed to be unreachable"); + } + /* We need to close the socket so that we do not accidentally + consume the request. */ + TEST_VERIFY (close (servers[i].transport->xp_sock) == 0); + } + + + /* The following code mirrors what ypbind does. */ + + /* Copied from clnt_udp.c (like ypbind). */ + struct cu_data + { + int cu_sock; + bool_t cu_closeit; + struct sockaddr_in cu_raddr; + int cu_rlen; + struct timeval cu_wait; + struct timeval cu_total; + struct rpc_err cu_error; + XDR cu_outxdrs; + u_int cu_xdrpos; + u_int cu_sendsz; + char *cu_outbuf; + u_int cu_recvsz; + char cu_inbuf[1]; + }; + + int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); + CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM, + /* 5 seconds per-response timeout. */ + ((struct timeval) { 5, 0 }), + &client_socket); + TEST_VERIFY (clnt != NULL); + clnt->cl_auth = authunix_create_default (); + { + struct timeval zero = { 0, 0 }; + TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero)); + } + + /* Poke at internal data structures (like ypbind). */ + struct cu_data *cu = (struct cu_data *) clnt->cl_private; + + /* Send a ping to each server. */ + double before_pings = get_ticks (); + for (int i = 0; i < SERVER_COUNT; ++i) + { + if (test_verbose) + printf ("info: sending server %d ping\n", i); + /* Reset the xid because it is changed by each invocation of + clnt_call. Subtract one to compensate for the xid update + during the call. */ + *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1; + cu->cu_raddr = servers[i].address; + + struct test_query query = { .a = 100, .b = i + 1 }; + if (i == 1) + /* Shorter timeout to prefer this server. These timeouts must + be much shorter than the 5-second per-response timeout + configured with clntudp_create. */ + query.timeout_ms = 700; + else + query.timeout_ms = 1400; + struct test_response response = { 0 }; + /* NB: Do not check the return value. The server reply will + prove that the call worked. */ + double before_one_ping = get_ticks (); + clnt_call (clnt, PROC_ADD, + xdr_test_query, (void *) &query, + xdr_test_response, (void *) &response, + ((struct timeval) { 0, 0 })); + double after_one_ping = get_ticks (); + if (test_verbose) + printf ("info: non-blocking send took %f seconds\n", + after_one_ping - before_one_ping); + /* clnt_call should return immediately. Accept some delay in + case the process is descheduled. */ + TEST_VERIFY (after_one_ping - before_one_ping < 0.3); + } + + /* Collect the non-blocking response. */ + if (test_verbose) + printf ("info: collecting response\n"); + struct test_response response = { 0 }; + TEST_VERIFY + (clnt_call (clnt, PROC_ADD, NULL, NULL, + xdr_test_response, (void *) &response, + ((struct timeval) { 0, 0 })) == RPC_SUCCESS); + double after_pings = get_ticks (); + if (test_verbose) + printf ("info: send/receive took %f seconds\n", + after_pings - before_pings); + /* Expected timeout is 0.7 seconds. */ + TEST_VERIFY (0.7 <= after_pings - before_pings); + TEST_VERIFY (after_pings - before_pings < 1.2); + + uint32_t xid; + memcpy (&xid, &cu->cu_inbuf, sizeof (xid)); + if (test_verbose) + printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n", + xid, response.server_id, response.seq, response.sum); + /* Check that the reply from the preferred server was used. */ + TEST_VERIFY (servers[1].xid == xid); + TEST_VERIFY (response.server_id == 1); + TEST_VERIFY (response.seq == 1); + TEST_VERIFY (response.sum == 102); + + auth_destroy (clnt->cl_auth); + clnt_destroy (clnt); + + for (int i = 0; i < SERVER_COUNT; ++i) + { + if (test_verbose) + printf ("info: requesting server %d termination\n", i); + client_socket = RPC_ANYSOCK; + clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM, + ((struct timeval) { 5, 0 }), + &client_socket); + TEST_VERIFY_EXIT (clnt != NULL); + TEST_VERIFY (clnt_call (clnt, PROC_EXIT, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 3, 0 })) == RPC_SUCCESS); + clnt_destroy (clnt); + + int status; + xwaitpid (servers[i].pid, &status, 0); + TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); + } + + return 0; +} + +#include diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c new file mode 100644 index 0000000..db9943a --- /dev/null +++ b/sunrpc/tst-udp-timeout.c @@ -0,0 +1,402 @@ +/* Test timeout handling in the UDP client. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Test data serialization and deserialization. */ + +struct test_query +{ + uint32_t a; + uint32_t b; + uint32_t timeout_ms; + uint32_t wait_for_seq; + uint32_t garbage_packets; +}; + +static bool_t +xdr_test_query (XDR *xdrs, void *data, ...) +{ + struct test_query *p = data; + return xdr_uint32_t (xdrs, &p->a) + && xdr_uint32_t (xdrs, &p->b) + && xdr_uint32_t (xdrs, &p->timeout_ms) + && xdr_uint32_t (xdrs, &p->wait_for_seq) + && xdr_uint32_t (xdrs, &p->garbage_packets); +} + +struct test_response +{ + uint32_t seq; + uint32_t sum; +}; + +static bool_t +xdr_test_response (XDR *xdrs, void *data, ...) +{ + struct test_response *p = data; + return xdr_uint32_t (xdrs, &p->seq) + && xdr_uint32_t (xdrs, &p->sum); +} + +/* Implementation of the test server. */ + +enum + { + /* RPC parameters, chosen at random. */ + PROGNUM = 15717, + VERSNUM = 13689, + + /* Main RPC operation. */ + PROC_ADD = 1, + + /* Reset the sequence number. */ + PROC_RESET_SEQ, + + /* Request process termination. */ + PROC_EXIT, + + /* Special exit status to mark successful processing. */ + EXIT_MARKER = 55, + }; + +static void +server_dispatch (struct svc_req *request, SVCXPRT *transport) +{ + /* Query sequence number. */ + static uint32_t seq = 0; + ++seq; + + if (test_verbose) + printf ("info: server_dispatch seq=%u rq_proc=%lu\n", + seq, request->rq_proc); + + switch (request->rq_proc) + { + case PROC_ADD: + { + struct test_query query; + memset (&query, 0xc0, sizeof (query)); + TEST_VERIFY_EXIT + (svc_getargs (transport, xdr_test_query, + (void *) &query)); + + if (test_verbose) + printf (" a=%u b=%u timeout_ms=%u wait_for_seq=%u" + " garbage_packets=%u\n", + query.a, query.b, query.timeout_ms, query.wait_for_seq, + query.garbage_packets); + + if (seq < query.wait_for_seq) + { + /* No response at this point. */ + if (test_verbose) + printf (" skipped response\n"); + break; + } + + if (query.garbage_packets > 0) + { + int per_packet_timeout; + if (query.timeout_ms > 0) + per_packet_timeout + = query.timeout_ms * 1000 / query.garbage_packets; + else + per_packet_timeout = 0; + + char buf[20]; + memset (&buf, 0xc0, sizeof (buf)); + for (int i = 0; i < query.garbage_packets; ++i) + { + /* 13 is relatively prime to 20 = sizeof (buf) + 1, so + the len variable will cover the entire interval + [0, 20] if query.garbage_packets is sufficiently + large. */ + size_t len = (i * 13 + 1) % (sizeof (buf) + 1); + TEST_VERIFY (sendto (transport->xp_sock, + buf, len, MSG_NOSIGNAL, + (struct sockaddr *) &transport->xp_raddr, + transport->xp_addrlen) == len); + if (per_packet_timeout > 0) + usleep (per_packet_timeout); + } + } + else if (query.timeout_ms > 0) + usleep (query.timeout_ms * 1000); + + struct test_response response = + { + .seq = seq, + .sum = query.a + query.b, + }; + TEST_VERIFY (svc_sendreply (transport, xdr_test_response, + (void *) &response)); + } + break; + + case PROC_RESET_SEQ: + seq = 0; + TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); + break; + + case PROC_EXIT: + TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL)); + _exit (EXIT_MARKER); + break; + + default: + FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc); + break; + } +} + +/* Implementation of the test client. */ + +static struct test_response +test_call (CLIENT *clnt, int proc, struct test_query query, + struct timeval timeout) +{ + if (test_verbose) + printf ("info: test_call proc=%d timeout=%lu.%06lu\n", + proc, (unsigned long) timeout.tv_sec, + (unsigned long) timeout.tv_usec); + struct test_response response; + TEST_VERIFY_EXIT (clnt_call (clnt, proc, + xdr_test_query, (void *) &query, + xdr_test_response, (void *) &response, + timeout) + == RPC_SUCCESS); + return response; +} + +static void +test_call_timeout (CLIENT *clnt, int proc, struct test_query query, + struct timeval timeout) +{ + struct test_response response; + TEST_VERIFY (clnt_call (clnt, proc, + xdr_test_query, (void *) &query, + xdr_test_response, (void *) &response, + timeout) + == RPC_TIMEDOUT); +} + +/* Complete one regular RPC call to drain the server socket + buffer. Resets the sequence number. */ +static void +test_call_flush (CLIENT *clnt) +{ + /* This needs a longer timeout to flush out all pending requests. + The choice of 5 seconds is larger than the per-response timeouts + requested via the timeout_ms field. */ + if (test_verbose) + printf ("info: flushing pending queries\n"); + TEST_VERIFY_EXIT (clnt_call (clnt, PROC_RESET_SEQ, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 5, 0 })) + == RPC_SUCCESS); +} + +/* Return the number seconds since an arbitrary point in time. */ +static double +get_ticks (void) +{ + { + struct timespec ts; + if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0) + return ts.tv_sec + ts.tv_nsec * 1e-9; + } + { + struct timeval tv; + TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0); + return tv.tv_sec + tv.tv_usec * 1e-6; + } +} + +static void +test_udp_server (int port) +{ + struct sockaddr_in sin = + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl (INADDR_LOOPBACK), + .sin_port = htons (port) + }; + int sock = RPC_ANYSOCK; + + /* The client uses a 1.5 second timeout for retries. The timeouts + are arbitrary, but chosen so that there is a substantial gap + between them, but the total time spent waiting is not too + large. */ + CLIENT *clnt = clntudp_create (&sin, PROGNUM, VERSNUM, + (struct timeval) { 1, 500 * 1000 }, + &sock); + TEST_VERIFY_EXIT (clnt != NULL); + + /* Basic call/response test. */ + struct test_response response = test_call + (clnt, PROC_ADD, + (struct test_query) { .a = 17, .b = 4 }, + (struct timeval) { 3, 0 }); + TEST_VERIFY (response.sum == 21); + TEST_VERIFY (response.seq == 1); + + /* Check that garbage packets do not interfere with timeout + processing. */ + double before = get_ticks (); + response = test_call + (clnt, PROC_ADD, + (struct test_query) { + .a = 19, .b = 4, .timeout_ms = 500, .garbage_packets = 21, + }, + (struct timeval) { 3, 0 }); + TEST_VERIFY (response.sum == 23); + TEST_VERIFY (response.seq == 2); + double after = get_ticks (); + if (test_verbose) + printf ("info: 21 garbage packets took %f seconds\n", after - before); + /* Expected timeout is 0.5 seconds. Add some slack in case process + scheduling delays processing the query or response, but do not + accept a retry (which would happen at 1.5 seconds). */ + TEST_VERIFY (0.5 <= after - before); + TEST_VERIFY (after - before < 1.2); + test_call_flush (clnt); + + /* Check that missing a response introduces a 1.5 second timeout, as + requested when calling clntudp_create. */ + before = get_ticks (); + response = test_call + (clnt, PROC_ADD, + (struct test_query) { .a = 170, .b = 40, .wait_for_seq = 2 }, + (struct timeval) { 3, 0 }); + TEST_VERIFY (response.sum == 210); + TEST_VERIFY (response.seq == 2); + after = get_ticks (); + if (test_verbose) + printf ("info: skipping one response took %f seconds\n", + after - before); + /* Expected timeout is 1.5 seconds. Do not accept a second retry + (which would happen at 3 seconds). */ + TEST_VERIFY (1.5 <= after - before); + TEST_VERIFY (after - before < 2.9); + test_call_flush (clnt); + + /* Check that the overall timeout wins against the per-query + timeout. */ + before = get_ticks (); + test_call_timeout + (clnt, PROC_ADD, + (struct test_query) { .a = 170, .b = 41, .wait_for_seq = 2 }, + (struct timeval) { 0, 750 * 1000 }); + after = get_ticks (); + if (test_verbose) + printf ("info: 0.75 second timeout took %f seconds\n", + after - before); + TEST_VERIFY (0.75 <= after - before); + TEST_VERIFY (after - before < 1.4); + test_call_flush (clnt); + + for (int with_garbage = 0; with_garbage < 2; ++with_garbage) + { + /* Check that no response at all causes the client to bail out. */ + before = get_ticks (); + test_call_timeout + (clnt, PROC_ADD, + (struct test_query) { + .a = 170, .b = 40, .timeout_ms = 1200, + .garbage_packets = with_garbage * 21 + }, + (struct timeval) { 0, 750 * 1000 }); + after = get_ticks (); + if (test_verbose) + printf ("info: test_udp_server: 0.75 second timeout took %f seconds" + " (garbage %d)\n", + after - before, with_garbage); + TEST_VERIFY (0.75 <= after - before); + TEST_VERIFY (after - before < 1.4); + test_call_flush (clnt); + + /* As above, but check the total timeout. */ + before = get_ticks (); + test_call_timeout + (clnt, PROC_ADD, + (struct test_query) { + .a = 170, .b = 40, .timeout_ms = 3000, + .garbage_packets = with_garbage * 30 + }, + (struct timeval) { 2, 300 * 1000 }); + after = get_ticks (); + if (test_verbose) + printf ("info: test_udp_server: 2.3 second timeout took %f seconds" + " (garbage %d)\n", + after - before, with_garbage); + TEST_VERIFY (2.3 <= after - before); + TEST_VERIFY (after - before < 3.0); + test_call_flush (clnt); + } + + TEST_VERIFY_EXIT (clnt_call (clnt, PROC_EXIT, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 5, 0 })) + == RPC_SUCCESS); + clnt_destroy (clnt); +} + +static int +do_test (void) +{ + support_become_root (); + support_enter_network_namespace (); + + SVCXPRT *transport = svcudp_create (RPC_ANYSOCK); + TEST_VERIFY_EXIT (transport != NULL); + TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM, server_dispatch, 0)); + + pid_t pid = xfork (); + if (pid == 0) + { + svc_run (); + FAIL_EXIT1 ("supposed to be unreachable"); + } + test_udp_server (transport->xp_port); + + int status; + xwaitpid (pid, &status, 0); + TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER); + + SVC_DESTROY (transport); + return 0; +} + +/* The minimum run time is around 17 seconds. */ +#define TIMEOUT 25 +#include commit 69e0a87cc4c570e3b7218392fc3e743b5bddcce2 Author: Florian Weimer 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 510ca42..8aaf9f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2017-03-02 Florian Weimer + + [BZ #21015] + * manual/install.texi (Configuring and compiling): Document + --enable-bind-now. + * Makeconfig [bind-now] (LDFLAGS-lib.so): Set. + (build-shlib-helper): Use $(LDFLAGS-lib.so). + (format.lds): Likewise. + [bind-now] (LDFLAGS-c.so): Remove. + * sysdeps/x86_64/localplt.data (libm.so): matherr relocation can + be R_X86_64_GLOB_DAT. + * sysdeps/unix/sysv/linux/i386/localplt.data (libm.so): matherr + relocation can be R_386_GLOB_DAT. + * sysdeps/unix/sysv/linux/alpha/localplt.data (libm.so): matherr + relocaiton can be R_ALPHA_GLOB_DAT. + * iconvdata/Makefile [bind-now] (LDFLAGS.so): Add -Wl,-z,now. + 2017-02-28 Florian Weimer [BZ #20257] diff --git a/INSTALL b/INSTALL index 3b3fd12..e77cb2d 100644 --- a/INSTALL +++ b/INSTALL @@ -146,6 +146,12 @@ will be used, and CFLAGS sets optimization options for the compiler. of routines called directly from assembler are excluded from this protection. +'--enable-bind-now' + Disable lazy binding for installed shared objects. This provides + additional security hardening because it enables full RELRO and a + read-only global offset table (GOT), at the cost of slightly + increased program load times. + '--enable-pt_chown' The file 'pt_chown' is a helper binary for 'grantpt' (*note Pseudo-Terminals: Allocation.) that is installed setuid root to fix diff --git a/Makeconfig b/Makeconfig index 97a15b5..1c81511 100644 --- a/Makeconfig +++ b/Makeconfig @@ -386,6 +386,13 @@ LDFLAGS.so += $(hashstyle-LDFLAGS) LDFLAGS-rtld += $(hashstyle-LDFLAGS) endif +# If lazy relocations are disabled, add the -z now flag. Use +# LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to +# test modules. +ifeq ($(bind-now),yes) +LDFLAGS-lib.so += -Wl,-z,now +endif + # Command to run after every final link (executable or shared object). # This is invoked with $(call after-link,...), so it should operate on # the file $1. This can be set to do some sort of post-processing on diff --git a/Makerules b/Makerules index e9194e5..7f0eef8 100644 --- a/Makerules +++ b/Makerules @@ -588,7 +588,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \ $(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \ $(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \ -Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \ - $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \ + $(LDFLAGS.so) $(LDFLAGS-lib.so) $(LDFLAGS-$(@F:lib%.so=%).so) \ -L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link) endef @@ -686,10 +686,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles LDLIBS-c.so += $(libc.so-gnulib) # Give libc.so an entry point and make it directly runnable itself. LDFLAGS-c.so += -e __libc_main -# If lazy relocation is disabled add the -z now flag. -ifeq ($(bind-now),yes) -LDFLAGS-c.so += -Wl,-z,now -endif # Pre-link the objects of libc_pic.a so that we can locally resolve # COMMON symbols before we link against ld.so. This is because ld.so # contains some of libc_pic.a already, which will prevent the COMMONs @@ -1104,7 +1100,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \ ifneq (unknown,$(output-format)) echo > $@.new 'OUTPUT_FORMAT($(output-format))' else - $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \ + $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \ + $(LDFLAGS.so) $(LDFLAGS-lib.so) \ -x c /dev/null -o $@.so -Wl,--verbose -v 2>&1 \ | sed -n -f $< > $@.new test -s $@.new diff --git a/NEWS b/NEWS index e7d6668..9bf8c10 100644 --- a/NEWS +++ b/NEWS @@ -12,6 +12,7 @@ The following bugs are resolved with this release: [21109] Tunables broken on big-endian [21115] sunrpc: Use-after-free in error path in clntudp_call [20257] sunrpc: clntudp_call does not enforce timeout when receiving data + [21015] Document and fix --enable-bind-now Version 2.25 diff --git a/iconvdata/Makefile b/iconvdata/Makefile index 04157b2..e484587 100644 --- a/iconvdata/Makefile +++ b/iconvdata/Makefile @@ -63,6 +63,11 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \ MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \ CP770 CP771 CP772 CP773 CP774 +# If lazy binding is disabled, use BIND_NOW for the gconv modules. +ifeq ($(bind-now),yes) +LDFLAGS.so += -Wl,-z,now +endif + modules.so := $(addsuffix .so, $(modules)) ifeq (yes,$(build-shared)) diff --git a/manual/install.texi b/manual/install.texi index 266add8..3398cfa 100644 --- a/manual/install.texi +++ b/manual/install.texi @@ -175,6 +175,12 @@ options to detect stack overruns. Only the dynamic linker and a small number of routines called directly from assembler are excluded from this protection. +@item --enable-bind-now +Disable lazy binding for installed shared objects. This provides +additional security hardening because it enables full RELRO and a +read-only global offset table (GOT), at the cost of slightly increased +program load times. + @pindex pt_chown @findex grantpt @item --enable-pt_chown diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data index cca17f1..1f0e3b4 100644 --- a/sysdeps/unix/sysv/linux/alpha/localplt.data +++ b/sysdeps/unix/sysv/linux/alpha/localplt.data @@ -20,7 +20,7 @@ libc.so: free + RELA R_ALPHA_GLOB_DAT libc.so: malloc + RELA R_ALPHA_GLOB_DAT libc.so: memalign + RELA R_ALPHA_GLOB_DAT libc.so: realloc + RELA R_ALPHA_GLOB_DAT -libm.so: matherr +libm.so: matherr + RELA R_ALPHA_GLOB_DAT # We used to offer inline functions that used this, so it must be exported. # Ought to reorg things such that carg isn't thus forced to use a plt. libm.so: __atan2 diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data index 2c25849..8ea4333 100644 --- a/sysdeps/unix/sysv/linux/i386/localplt.data +++ b/sysdeps/unix/sysv/linux/i386/localplt.data @@ -6,7 +6,7 @@ libc.so: free + REL R_386_GLOB_DAT libc.so: malloc + REL R_386_GLOB_DAT libc.so: memalign + REL R_386_GLOB_DAT libc.so: realloc + REL R_386_GLOB_DAT -libm.so: matherr +libm.so: matherr + REL R_386_GLOB_DAT # The main malloc is interposed into the dynamic linker, for # allocations after the initial link (when dlopen is used). ld.so: malloc + REL R_386_GLOB_DAT diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data index 014a9f4..a1840cf 100644 --- a/sysdeps/x86_64/localplt.data +++ b/sysdeps/x86_64/localplt.data @@ -8,7 +8,7 @@ libc.so: free + RELA R_X86_64_GLOB_DAT libc.so: malloc + RELA R_X86_64_GLOB_DAT libc.so: memalign + RELA R_X86_64_GLOB_DAT libc.so: realloc + RELA R_X86_64_GLOB_DAT -libm.so: matherr +libm.so: matherr + RELA R_X86_64_GLOB_DAT # The main malloc is interposed into the dynamic linker, for # allocations after the initial link (when dlopen is used). ld.so: malloc + RELA R_X86_64_GLOB_DAT commit 8b3caa41b9cb82651e72a0c87aa56719c134000e Author: John David Anglin 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 8aaf9f8..d8ed2e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-03-15 John David Anglin + + * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. + (RTLD_START): Don't record stack end address in _dl_start_user. + 2017-03-02 Florian Weimer [BZ #21015] diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h index 339c7bb..787b95f 100644 --- a/sysdeps/hppa/dl-machine.h +++ b/sysdeps/hppa/dl-machine.h @@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) #define ARCH_LA_PLTENTER hppa_gnu_pltenter #define ARCH_LA_PLTEXIT hppa_gnu_pltexit +/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */ +#define DL_STACK_END(cookie) \ + ((void *) (((long) (cookie)) + 0x160)) + /* Initial entry point code for the dynamic linker. The C function `_dl_start' is the real entry point; its return value is the user program's entry point. */ @@ -401,11 +405,6 @@ asm ( \ /* Save the entry point in %r3. */ \ " copy %ret0,%r3\n" \ \ - /* Remember the lowest stack address. */ \ -" addil LT'__libc_stack_end,%r19\n" \ -" ldw RT'__libc_stack_end(%r1),%r20\n" \ -" stw %sp,0(%r20)\n" \ - \ /* See if we were called as a command with the executable file \ name as an extra leading argument. */ \ " addil LT'_dl_skip_args,%r19\n" \ commit 0889003c67f9c2f520a37281c4b5c3b8a9861f46 Author: Mike Frysinger 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 * 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 d8ed2e4..c29a70a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-03-15 Mike Frysinger + + * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED + instead of PIC. + 2017-03-15 John David Anglin * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define. diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S index f8a9260..f912291 100644 --- a/sysdeps/x86_64/mempcpy_chk.S +++ b/sysdeps/x86_64/mempcpy_chk.S @@ -19,7 +19,7 @@ #include #include "asm-syntax.h" -#ifndef PIC +#ifndef SHARED /* For libc.so this is defined in memcpy.S. For libc.a, this is a separate source to avoid mempcpy bringing in __chk_fail and all routines commit 27ab0d9518746dfb59ed2ba59daefc981dc10e38 Author: Mike Frysinger 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 (cherry picked from commit ddc3fb333469c2997798742dc0509dc1e3201d91) diff --git a/ChangeLog b/ChangeLog index c29a70a..ef5388c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-03-20 Mike Frysinger + + [BZ #21275] + * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename + __stack to __stackbase. + (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of + checks so we can include defined(__ia64__) first. + 2017-03-15 Mike Frysinger * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index 2daf0c5..c96aac8 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -61,17 +61,18 @@ #define SPAWN_ERROR 127 #ifdef __ia64__ -# define CLONE(__fn, __stack, __stacksize, __flags, __args) \ - __clone2 (__fn, __stack, __stacksize, __flags, __args, 0, 0, 0) +# define CLONE(__fn, __stackbase, __stacksize, __flags, __args) \ + __clone2 (__fn, __stackbase, __stacksize, __flags, __args, 0, 0, 0) #else # define CLONE(__fn, __stack, __stacksize, __flags, __args) \ __clone (__fn, __stack, __flags, __args) #endif -#if _STACK_GROWS_DOWN -# define STACK(__stack, __stack_size) (__stack + __stack_size) -#elif _STACK_GROWS_UP +/* Since ia64 wants the stackbase w/clone2, re-use the grows-up macro. */ +#if _STACK_GROWS_UP || defined (__ia64__) # define STACK(__stack, __stack_size) (__stack) +#elif _STACK_GROWS_DOWN +# define STACK(__stack, __stack_size) (__stack + __stack_size) #endif commit f035c8d055f25eaf6c93772f308afac10ce31ef2 Author: Slava Barinov 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 ef5388c..85d6fc6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-03-31 Slava Barinov + + [BZ #21289] + * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH. + 2017-03-20 Mike Frysinger [BZ #21275] diff --git a/NEWS b/NEWS index 9bf8c10..fee1cf8 100644 --- a/NEWS +++ b/NEWS @@ -9,10 +9,11 @@ Version 2.25.1 The following bugs are resolved with this release: - [21109] Tunables broken on big-endian - [21115] sunrpc: Use-after-free in error path in clntudp_call [20257] sunrpc: clntudp_call does not enforce timeout when receiving data [21015] Document and fix --enable-bind-now + [21109] Tunables broken on big-endian + [21115] sunrpc: Use-after-free in error path in clntudp_call + [21289] Fix symbol redirect for fts_set Version 2.25 diff --git a/io/fts.h b/io/fts.h index b9cff53..ab15567 100644 --- a/io/fts.h +++ b/io/fts.h @@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int, int (*)(const FTSENT **, const FTSENT **)), fts64_open); FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read); -int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW; +int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set); # else # define fts_children fts64_children # define fts_close fts64_close commit 74522eeeaa4a39809a28f44171e71d36a69edb58 Author: Wladimir J. van der Laan 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 85d6fc6..321bf53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-04-03 Wladimir van der Laan + + [BZ# 21338] + * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX + instead of incorrect do_set_arena_test + 2017-03-31 Slava Barinov [BZ #21289] diff --git a/malloc/malloc.c b/malloc/malloc.c index 4885793..4e07663 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -4902,7 +4902,7 @@ __libc_mallopt (int param_number, int value) case M_ARENA_MAX: if (value > 0) - do_set_arena_test (value); + do_set_arena_max (value); break; } __libc_lock_unlock (av->mutex); commit df29db0bec24211cfc917db52024bf8deecac2c9 Author: Mike Frysinger 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 321bf53..b37a054 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-04-03 Mike Frysinger + + [BZ #21253] + * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size + slack space by 32KiB. + 2017-04-03 Wladimir van der Laan [BZ# 21338] diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c index c96aac8..29d8f25 100644 --- a/sysdeps/unix/sysv/linux/spawni.c +++ b/sysdeps/unix/sysv/linux/spawni.c @@ -319,6 +319,11 @@ __spawnix (pid_t * pid, const char *file, /* Add a slack area for child's stack. */ size_t argv_size = (argc * sizeof (void *)) + 512; + /* We need at least a few pages in case the compiler's stack checking is + enabled. In some configs, it is known to use at least 24KiB. We use + 32KiB to be "safe" from anything the compiler might do. Besides, the + extra pages won't actually be allocated unless they get used. */ + argv_size += (32 * 1024); size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize)); void *stack = __mmap (NULL, stack_size, prot, MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); commit 903b77defb6f2ee2552c06472339f33091e3c7b4 Author: H.J. Lu 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 b37a054..8479fba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017-04-07 H.J. Lu + + [BZ #21258] + * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt): + Define only if _dl_runtime_resolve is defined to + _dl_runtime_resolve_sse_vex. + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt): + Fallthrough to _dl_runtime_resolve_sse_vex. + 2017-04-03 Mike Frysinger [BZ #21253] diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S index 33d7fcf..c14c61a 100644 --- a/sysdeps/x86_64/dl-trampoline.S +++ b/sysdeps/x86_64/dl-trampoline.S @@ -87,11 +87,9 @@ #endif #define VEC(i) zmm##i #define _dl_runtime_resolve _dl_runtime_resolve_avx512 -#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt #define _dl_runtime_profile _dl_runtime_profile_avx512 #include "dl-trampoline.h" #undef _dl_runtime_resolve -#undef _dl_runtime_resolve_opt #undef _dl_runtime_profile #undef VEC #undef VMOV @@ -145,4 +143,5 @@ # define VMOV vmovdqu #endif #define _dl_runtime_resolve _dl_runtime_resolve_sse_vex +#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt #include "dl-trampoline.h" diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h index b27fa06..8db24c1 100644 --- a/sysdeps/x86_64/dl-trampoline.h +++ b/sysdeps/x86_64/dl-trampoline.h @@ -129,19 +129,20 @@ _dl_runtime_resolve_opt: # YMM state isn't in use. PRESERVE_BND_REGS_PREFIX jz _dl_runtime_resolve_sse_vex -# elif VEC_SIZE == 64 +# elif VEC_SIZE == 16 # For ZMM registers, check if YMM state and ZMM state are in # use. andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d cmpl $bit_YMM_state, %r11d - # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if - # neither YMM state nor ZMM state are in use. + # Preserve %zmm0 - %zmm7 registers if ZMM state is in use. PRESERVE_BND_REGS_PREFIX - jl _dl_runtime_resolve_sse_vex + jg _dl_runtime_resolve_avx512 # Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if # ZMM state isn't in use. PRESERVE_BND_REGS_PREFIX je _dl_runtime_resolve_avx + # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if + # neither YMM state nor ZMM state are in use. # else # error Unsupported VEC_SIZE! # endif commit b30b1c97ccfe72e82b0c95bb55274b5660bc539e Author: Adhemerval Zanella Date: Tue Apr 11 15:08:02 2017 -0300 posix: Add cleanup on the trap list for globtest.sh This patch prevents lingering files for SIGSEGV failures by adding a cleanup handler on trap handler. Checked on x86_64-linux-gnu. * posix/globtest.sh: Add cleanup routine on trap 0. Cherry-pick of 4fee33f. diff --git a/ChangeLog b/ChangeLog index 8479fba..4962000 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-04-11 Adhemerval Zanella + + * posix/globtest.sh: Add cleanup routine on trap 0. + 2017-04-07 H.J. Lu [BZ #21258] diff --git a/posix/globtest.sh b/posix/globtest.sh index f9cc80b..73f7ae3 100755 --- a/posix/globtest.sh +++ b/posix/globtest.sh @@ -47,7 +47,12 @@ testout=${common_objpfx}posix/globtest-out rm -rf $testdir $testout mkdir $testdir -trap 'chmod 777 $testdir/noread; rm -fr $testdir $testout' 1 2 3 15 +cleanup() { + chmod 777 $testdir/noread + rm -fr $testdir $testout +} + +trap cleanup 0 HUP INT QUIT TERM echo 1 > $testdir/file1 echo 2 > $testdir/file2 @@ -811,8 +816,6 @@ if test $failed -ne 0; then fi if test $result -eq 0; then - chmod 777 $testdir/noread - rm -fr $testdir $testout echo "All OK." > $logfile fi commit 4c6f97798fe1854a32b1199c42370eac1620eebf Author: H.J. Lu Date: Fri Apr 28 10:03:09 2017 -0700 x86: Set Prefer_No_VZEROUPPER if AVX512ER is available AVX512ER won't be implemented in any Xeon processors and will be in all Xeon Phi processors. Don't check CPU model number when setting Prefer_No_VZEROUPPER for Xeon Phi. Instead, set Prefer_No_VZEROUPPER if AVX512ER is available. It works with current and future Xeon Phi and non-Xeon Phi processors. * sysdeps/x86/cpu-features.c (init_cpu_features): Set Prefer_No_VZEROUPPER if AVX512ER is available. * sysdeps/x86/cpu-features.h (bit_cpu_AVX512PF): New. (bit_cpu_AVX512ER): Likewise. (bit_cpu_AVX512CD): Likewise. (bit_cpu_AVX512BW): Likewise. (bit_cpu_AVX512VL): Likewise. (index_cpu_AVX512PF): Likewise. (index_cpu_AVX512ER): Likewise. (index_cpu_AVX512CD): Likewise. (index_cpu_AVX512BW): Likewise. (index_cpu_AVX512VL): Likewise. (reg_AVX512PF): Likewise. (reg_AVX512ER): Likewise. (reg_AVX512CD): Likewise. (reg_AVX512BW): Likewise. (reg_AVX512VL): Likewise. (cherry picked from commit 1c53cb49de6d82d9469ccbd5aa0c55924502bd8b) diff --git a/ChangeLog b/ChangeLog index 4962000..dc49c78 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2017-04-28 H.J. Lu + + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_VZEROUPPER if AVX512ER is available. + * sysdeps/x86/cpu-features.h + (bit_cpu_AVX512PF): New. + (bit_cpu_AVX512ER): Likewise. + (bit_cpu_AVX512CD): Likewise. + (bit_cpu_AVX512BW): Likewise. + (bit_cpu_AVX512VL): Likewise. + (index_cpu_AVX512PF): Likewise. + (index_cpu_AVX512ER): Likewise. + (index_cpu_AVX512CD): Likewise. + (index_cpu_AVX512BW): Likewise. + (index_cpu_AVX512VL): Likewise. + (reg_AVX512PF): Likewise. + (reg_AVX512ER): Likewise. + (reg_AVX512CD): Likewise. + (reg_AVX512BW): Likewise. + (reg_AVX512VL): Likewise. + 2017-04-11 Adhemerval Zanella * posix/globtest.sh: Add cleanup routine on trap 0. diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 1c714a4..41d0be2 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -139,8 +139,6 @@ init_cpu_features (struct cpu_features *cpu_features) case 0x57: /* Knights Landing. Enable Silvermont optimizations. */ - cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] - |= bit_arch_Prefer_No_VZEROUPPER; case 0x5c: case 0x5f: @@ -226,6 +224,12 @@ init_cpu_features (struct cpu_features *cpu_features) cpu_features->feature[index_arch_AVX_Fast_Unaligned_Load] |= bit_arch_AVX_Fast_Unaligned_Load; + /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER + if AVX512ER is available. */ + if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) + cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] + |= bit_arch_Prefer_No_VZEROUPPER; + /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h index 95f0fcf..2ee8a0a 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/cpu-features.h @@ -62,6 +62,11 @@ #define bit_cpu_AVX2 (1 << 5) #define bit_cpu_AVX512F (1 << 16) #define bit_cpu_AVX512DQ (1 << 17) +#define bit_cpu_AVX512PF (1 << 26) +#define bit_cpu_AVX512ER (1 << 27) +#define bit_cpu_AVX512CD (1 << 28) +#define bit_cpu_AVX512BW (1 << 30) +#define bit_cpu_AVX512VL (1u << 31) /* XCR0 Feature flags. */ #define bit_XMM_state (1 << 1) @@ -236,6 +241,11 @@ extern const struct cpu_features *__get_cpu_features (void) # define index_cpu_AVX2 COMMON_CPUID_INDEX_7 # define index_cpu_AVX512F COMMON_CPUID_INDEX_7 # define index_cpu_AVX512DQ COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512PF COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512ER COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512CD COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512BW COMMON_CPUID_INDEX_7 +# define index_cpu_AVX512VL COMMON_CPUID_INDEX_7 # define index_cpu_ERMS COMMON_CPUID_INDEX_7 # define index_cpu_RTM COMMON_CPUID_INDEX_7 # define index_cpu_FMA COMMON_CPUID_INDEX_1 @@ -254,6 +264,11 @@ extern const struct cpu_features *__get_cpu_features (void) # define reg_AVX2 ebx # define reg_AVX512F ebx # define reg_AVX512DQ ebx +# define reg_AVX512PF ebx +# define reg_AVX512ER ebx +# define reg_AVX512CD ebx +# define reg_AVX512BW ebx +# define reg_AVX512VL ebx # define reg_ERMS ebx # define reg_RTM ebx # define reg_FMA ecx commit 06d79808f6faf6025c5a7d4e27d949a8216275cc Author: H.J. Lu Date: Fri Apr 28 10:04:15 2017 -0700 x86: Use AVX2 memcpy/memset on Skylake server [BZ #21396] On Skylake server, AVX512 load/store instructions in memcpy/memset may lead to lower CPU turbo frequency in certain situations. Use of AVX2 in memcpy/memset has been observed to have improved overall performance in many workloads due to the higher frequency. Since AVX512ER is unique to Xeon Phi, this patch sets Prefer_No_AVX512 if AVX512ER isn't available so that AVX2 versions of memcpy/memset are used on Skylake server. [BZ #21396] * sysdeps/x86/cpu-features.c (init_cpu_features): Set Prefer_No_AVX512 if AVX512ER isn't available. * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. (index_arch_Prefer_No_AVX512): Likewise. * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use AVX512 version if Prefer_No_AVX512 is set. * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): Likewise. * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): Likewise. * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): Likewise. * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): Likewise. (cherry picked from commit 4cb334c4d6249686653137ec273d081371b3672d) diff --git a/ChangeLog b/ChangeLog index dc49c78..adebc03 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,26 @@ 2017-04-28 H.J. Lu + [BZ #21396] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + Prefer_No_AVX512 if AVX512ER isn't available. + * sysdeps/x86/cpu-features.h (bit_arch_Prefer_No_AVX512): New. + (index_arch_Prefer_No_AVX512): Likewise. + * sysdeps/x86_64/multiarch/memcpy.S (__new_memcpy): Don't use + AVX512 version if Prefer_No_AVX512 is set. + * sysdeps/x86_64/multiarch/memcpy_chk.S (__memcpy_chk): + Likewise. + * sysdeps/x86_64/multiarch/memmove.S (__libc_memmove): Likewise. + * sysdeps/x86_64/multiarch/memmove_chk.S (__memmove_chk): + Likewise. + * sysdeps/x86_64/multiarch/mempcpy.S (__mempcpy): Likewise. + * sysdeps/x86_64/multiarch/mempcpy_chk.S (__mempcpy_chk): + Likewise. + * sysdeps/x86_64/multiarch/memset.S (memset): Likewise. + * sysdeps/x86_64/multiarch/memset_chk.S (__memset_chk): + Likewise. + +2017-04-28 H.J. Lu + * sysdeps/x86/cpu-features.c (init_cpu_features): Set Prefer_No_VZEROUPPER if AVX512ER is available. * sysdeps/x86/cpu-features.h diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 41d0be2..9afd74c 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -225,10 +225,14 @@ init_cpu_features (struct cpu_features *cpu_features) |= bit_arch_AVX_Fast_Unaligned_Load; /* Since AVX512ER is unique to Xeon Phi, set Prefer_No_VZEROUPPER - if AVX512ER is available. */ + if AVX512ER is available. Don't use AVX512 to avoid lower CPU + frequency if AVX512ER isn't available. */ if (CPU_FEATURES_CPU_P (cpu_features, AVX512ER)) cpu_features->feature[index_arch_Prefer_No_VZEROUPPER] |= bit_arch_Prefer_No_VZEROUPPER; + else + cpu_features->feature[index_arch_Prefer_No_AVX512] + |= bit_arch_Prefer_No_AVX512; /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h index 2ee8a0a..a409db6 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/cpu-features.h @@ -39,6 +39,7 @@ #define bit_arch_Prefer_ERMS (1 << 19) #define bit_arch_Use_dl_runtime_resolve_opt (1 << 20) #define bit_arch_Use_dl_runtime_resolve_slow (1 << 21) +#define bit_arch_Prefer_No_AVX512 (1 << 22) /* CPUID Feature flags. */ @@ -116,6 +117,7 @@ # define index_arch_Prefer_ERMS FEATURE_INDEX_1*FEATURE_SIZE # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1*FEATURE_SIZE # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1*FEATURE_SIZE +# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1*FEATURE_SIZE # if defined (_LIBC) && !IS_IN (nonlib) @@ -298,6 +300,7 @@ extern const struct cpu_features *__get_cpu_features (void) # define index_arch_Prefer_ERMS FEATURE_INDEX_1 # define index_arch_Use_dl_runtime_resolve_opt FEATURE_INDEX_1 # define index_arch_Use_dl_runtime_resolve_slow FEATURE_INDEX_1 +# define index_arch_Prefer_No_AVX512 FEATURE_INDEX_1 #endif /* !__ASSEMBLER__ */ diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S index 1f83ee3..af27703 100644 --- a/sysdeps/x86_64/multiarch/memcpy.S +++ b/sysdeps/x86_64/multiarch/memcpy.S @@ -32,6 +32,8 @@ ENTRY(__new_memcpy) lea __memcpy_erms(%rip), %RAX_LP HAS_ARCH_FEATURE (Prefer_ERMS) jnz 2f + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memcpy_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memcpy_chk.S b/sysdeps/x86_64/multiarch/memcpy_chk.S index 5492342..8737fb9 100644 --- a/sysdeps/x86_64/multiarch/memcpy_chk.S +++ b/sysdeps/x86_64/multiarch/memcpy_chk.S @@ -30,6 +30,8 @@ ENTRY(__memcpy_chk) .type __memcpy_chk, @gnu_indirect_function LOAD_RTLD_GLOBAL_RO_RDX + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memmove.S b/sysdeps/x86_64/multiarch/memmove.S index 2021bfc..8c534e8 100644 --- a/sysdeps/x86_64/multiarch/memmove.S +++ b/sysdeps/x86_64/multiarch/memmove.S @@ -30,6 +30,8 @@ ENTRY(__libc_memmove) lea __memmove_erms(%rip), %RAX_LP HAS_ARCH_FEATURE (Prefer_ERMS) jnz 2f + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memmove_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memmove_chk.S b/sysdeps/x86_64/multiarch/memmove_chk.S index 8a252ad..7870dd0 100644 --- a/sysdeps/x86_64/multiarch/memmove_chk.S +++ b/sysdeps/x86_64/multiarch/memmove_chk.S @@ -29,6 +29,8 @@ ENTRY(__memmove_chk) .type __memmove_chk, @gnu_indirect_function LOAD_RTLD_GLOBAL_RO_RDX + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __memmove_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/mempcpy.S b/sysdeps/x86_64/multiarch/mempcpy.S index 79c840d..b8b2b28 100644 --- a/sysdeps/x86_64/multiarch/mempcpy.S +++ b/sysdeps/x86_64/multiarch/mempcpy.S @@ -32,6 +32,8 @@ ENTRY(__mempcpy) lea __mempcpy_erms(%rip), %RAX_LP HAS_ARCH_FEATURE (Prefer_ERMS) jnz 2f + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __mempcpy_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/mempcpy_chk.S b/sysdeps/x86_64/multiarch/mempcpy_chk.S index 6927962..072b22c 100644 --- a/sysdeps/x86_64/multiarch/mempcpy_chk.S +++ b/sysdeps/x86_64/multiarch/mempcpy_chk.S @@ -30,6 +30,8 @@ ENTRY(__mempcpy_chk) .type __mempcpy_chk, @gnu_indirect_function LOAD_RTLD_GLOBAL_RO_RDX + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 1f HAS_ARCH_FEATURE (AVX512F_Usable) jz 1f lea __mempcpy_chk_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memset.S b/sysdeps/x86_64/multiarch/memset.S index c958b2f..9d33118 100644 --- a/sysdeps/x86_64/multiarch/memset.S +++ b/sysdeps/x86_64/multiarch/memset.S @@ -41,6 +41,8 @@ ENTRY(memset) jnz L(AVX512F) lea __memset_avx2_unaligned(%rip), %RAX_LP L(AVX512F): + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 2f HAS_ARCH_FEATURE (AVX512F_Usable) jz 2f lea __memset_avx512_no_vzeroupper(%rip), %RAX_LP diff --git a/sysdeps/x86_64/multiarch/memset_chk.S b/sysdeps/x86_64/multiarch/memset_chk.S index 79eaa37..7e08311 100644 --- a/sysdeps/x86_64/multiarch/memset_chk.S +++ b/sysdeps/x86_64/multiarch/memset_chk.S @@ -38,6 +38,8 @@ ENTRY(__memset_chk) jnz L(AVX512F) lea __memset_chk_avx2_unaligned(%rip), %RAX_LP L(AVX512F): + HAS_ARCH_FEATURE (Prefer_No_AVX512) + jnz 2f HAS_ARCH_FEATURE (AVX512F_Usable) jz 2f lea __memset_chk_avx512_no_vzeroupper(%rip), %RAX_LP commit ccb4fd7a657b0fbc4890c98f4586d58a135fc583 Author: Adhemerval Zanella Date: Tue Mar 14 14:16:13 2017 -0300 Fix i686 memchr overflow calculation (BZ#21182) This patch fixes the regression added by 23d2770 for final address overflow calculation. The subtraction of the considered size (16) at line 120 is at wrong place, for sizes less than 16 subsequent overflow check will not take in consideration an invalid size (since the subtraction will be negative). Also, the lea instruction also does not raise the carry flag (CF) that is used in subsequent jbe to check for overflow. The fix is to follow x86_64 logic from 3daef2c where the overflow is first check and a sub instruction is issued. In case of resulting negative size, CF will be set by the sub instruction and a NULL result will be returned. The patch also add similar tests reported in bug report. Checked on i686-linux-gnu and x86_64-linux-gnu. * string/test-memchr.c (do_test): Add BZ#21182 checks for address near end of a page. * sysdeps/i386/i686/multiarch/memchr-sse2.S (__memchr): Fix overflow calculation. Cherry-pick of 3abeeec5f46ff036bd9df60bb096e20314ccd078. diff --git a/ChangeLog b/ChangeLog index adebc03..ac19e98 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-05-01 Adhemerval Zanella + + [BZ# 21182] + * string/test-memchr.c (do_test): Add BZ#21182 checks for address + near end of a page. + * sysdeps/i386/i686/multiarch/memchr-sse2.S (__memchr): Fix + overflow calculation. + 2017-04-28 H.J. Lu [BZ #21396] diff --git a/string/test-memchr.c b/string/test-memchr.c index d62889f..6431605 100644 --- a/string/test-memchr.c +++ b/string/test-memchr.c @@ -208,6 +208,12 @@ test_main (void) do_test (0, i, i + 1, i + 1, 0); } + /* BZ#21182 - wrong overflow calculation for i686 implementation + with address near end of the page. */ + for (i = 2; i < 16; ++i) + /* page_size is in fact getpagesize() * 2. */ + do_test (page_size / 2 - i, i, i, 1, 0x9B); + do_random_tests (); return ret; } diff --git a/sysdeps/i386/i686/multiarch/memchr-sse2.S b/sysdeps/i386/i686/multiarch/memchr-sse2.S index 910679c..e41f324 100644 --- a/sysdeps/i386/i686/multiarch/memchr-sse2.S +++ b/sysdeps/i386/i686/multiarch/memchr-sse2.S @@ -117,7 +117,6 @@ L(crosscache): # ifndef USE_AS_RAWMEMCHR jnz L(match_case2_prolog1) - lea -16(%edx), %edx /* Calculate the last acceptable address and check for possible addition overflow by using satured math: edx = ecx + edx @@ -125,6 +124,7 @@ L(crosscache): add %ecx, %edx sbb %eax, %eax or %eax, %edx + sub $16, %edx jbe L(return_null) lea 16(%edi), %edi # else commit 34b6f41c14d09fe627c6a6224880d76d0959079e Author: Joseph Myers Date: Wed Mar 15 17:32:46 2017 +0000 Fix test-math-vector-sincos.h aliasing. x86_64 libmvec tests have been failing to build lately with GCC mainline with -Wuninitialized errors, and Markus Trippelsdorf traced this to an aliasing issue . This patch fixes the aliasing issue, so that the vectors-of-pointers are initialized using a union instead of pointer casts. This also fixes the testsuite build failures with GCC mainline. Tested for x86_64 (full testsuite with GCC 6; testsuite build with GCC mainline with build-many-glibcs.py). * sysdeps/x86/fpu/test-math-vector-sincos.h (INIT_VEC_PTRS_LOOP): Use a union when storing pointers. (VECTOR_WRAPPER_fFF_2): Do not take address of integer vector and cast result when passing to INIT_VEC_PTRS_LOOP. (VECTOR_WRAPPER_fFF_3): Likewise. (VECTOR_WRAPPER_fFF_4): Likewise. (cherry picked from commit ffe308e4fcf2f276c87fd405596569ba52ad0a29) diff --git a/ChangeLog b/ChangeLog index ac19e98..290515a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017-03-15 Joseph Myers + + * sysdeps/x86/fpu/test-math-vector-sincos.h (INIT_VEC_PTRS_LOOP): + Use a union when storing pointers. + (VECTOR_WRAPPER_fFF_2): Do not take address of integer vector and + cast result when passing to INIT_VEC_PTRS_LOOP. + (VECTOR_WRAPPER_fFF_3): Likewise. + (VECTOR_WRAPPER_fFF_4): Likewise. + 2017-05-01 Adhemerval Zanella [BZ# 21182] diff --git a/sysdeps/x86/fpu/test-math-vector-sincos.h b/sysdeps/x86/fpu/test-math-vector-sincos.h index 5043b32..95282a3 100644 --- a/sysdeps/x86/fpu/test-math-vector-sincos.h +++ b/sysdeps/x86/fpu/test-math-vector-sincos.h @@ -17,14 +17,14 @@ License along with the GNU C Library; if not, see . */ -#define INIT_VEC_PTRS_LOOP(vec, val, len) \ - do \ - { \ - for (i = 0; i < len; i++) \ - { \ - vec[i] = &val[i]; \ - } \ - } \ +#define INIT_VEC_PTRS_LOOP(vec, val, len) \ + do \ + { \ + union { VEC_INT_TYPE v; __typeof__ ((val)[0]) *a[(len)]; } u; \ + for (i = 0; i < len; i++) \ + u.a[i] = &(val)[i]; \ + (vec) = u.v; \ + } \ while (0) /* Wrapper for vector sincos/sincosf compatible with x86_64 and x32 variants @@ -40,8 +40,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1) \ VEC_TYPE mx; \ VEC_INT_TYPE mr, mr1; \ INIT_VEC_LOOP (mx, x, VEC_LEN); \ - INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN); \ - INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN); \ + INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN); \ + INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN); \ vector_func (mx, mr, mr1); \ TEST_VEC_LOOP (r_loc, VEC_LEN); \ TEST_VEC_LOOP (r1_loc, VEC_LEN); \ @@ -63,8 +63,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1) \ VEC_TYPE mx; \ VEC_INT_TYPE mr, mr1; \ INIT_VEC_LOOP (mx, x, VEC_LEN); \ - INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN/2); \ - INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN/2); \ + INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN/2); \ + INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN/2); \ vector_func (mx, mr, mr, mr1, mr1); \ TEST_VEC_LOOP (r_loc, VEC_LEN/2); \ TEST_VEC_LOOP (r1_loc, VEC_LEN/2); \ @@ -87,8 +87,8 @@ void scalar_func (FLOAT x, FLOAT * r, FLOAT * r1) \ VEC_TYPE mx; \ VEC_INT_TYPE mr, mr1; \ INIT_VEC_LOOP (mx, x, VEC_LEN); \ - INIT_VEC_PTRS_LOOP (((FLOAT **) &mr), r_loc, VEC_LEN/4); \ - INIT_VEC_PTRS_LOOP (((FLOAT **) &mr1), r1_loc, VEC_LEN/4); \ + INIT_VEC_PTRS_LOOP (mr, r_loc, VEC_LEN/4); \ + INIT_VEC_PTRS_LOOP (mr1, r1_loc, VEC_LEN/4); \ vector_func (mx, mr, mr, mr, mr, mr1, mr1, mr1, mr1); \ TEST_VEC_LOOP (r_loc, VEC_LEN/4); \ TEST_VEC_LOOP (r1_loc, VEC_LEN/4); \ commit b8d2e394a2900cef5bbbe0503f15960f64a943b1 Author: Florian Weimer Date: Fri Jun 9 13:21:43 2017 +0200 fork: Remove bogus parent PID assertions [BZ #21386] (cherry picked from commit 1d2bc2eae969543b89850e35e532f3144122d80a) diff --git a/ChangeLog b/ChangeLog index 290515a..d44aff0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-05-12 Florian Weimer + + [BZ #21386] + * sysdeps/nptl/fork.c (__libc_fork): Remove assertions on the + parent PID. The assertion in the child is incorrect with PID + namespaces. + 2017-03-15 Joseph Myers * sysdeps/x86/fpu/test-math-vector-sincos.h (INIT_VEC_PTRS_LOOP): diff --git a/NEWS b/NEWS index fee1cf8..d528723 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,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 [21289] Fix symbol redirect for fts_set + [21386] Assertion in fork for distinct parent PID is incorrect Version 2.25 diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c index db6d721..4bb87e2 100644 --- a/sysdeps/nptl/fork.c +++ b/sysdeps/nptl/fork.c @@ -131,10 +131,6 @@ __libc_fork (void) call_function_static_weak (__malloc_fork_lock_parent); } -#ifndef NDEBUG - pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); -#endif - #ifdef ARCH_FORK pid = ARCH_FORK (); #else @@ -147,8 +143,6 @@ __libc_fork (void) { struct pthread *self = THREAD_SELF; - assert (THREAD_GETMEM (self, tid) != ppid); - /* See __pthread_once. */ if (__fork_generation_pointer != NULL) *__fork_generation_pointer += __PTHREAD_ONCE_FORK_GEN_INCR; @@ -230,8 +224,6 @@ __libc_fork (void) } else { - assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); - /* Release acquired locks in the multi-threaded case. */ if (multiple_threads) { commit f92b1025980a939645b1ec7e550411a05ac7c76f Author: Santhosh Thottingal Date: Sun Jun 11 10:08:37 2017 -0400 Correct collation rules for Malayalam. [BZ #19922] * locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF. [BZ #19919] * locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37. diff --git a/localedata/ChangeLog b/localedata/ChangeLog index 0cdb097..127c1cf 100644 --- a/localedata/ChangeLog +++ b/localedata/ChangeLog @@ -1,3 +1,11 @@ +2017-06-11 Santhosh Thottingal + + [BZ #19922] + * locales/iso14651_t1_common: Add collation rules for U+07DA to U+07DF. + + [BZ #19919] + * locales/iso14651_t1_common: Correct collation of U+0D36 and U+0D37. + 2017-01-01 Joseph Myers * All files with FSF copyright notices: Update copyright dates diff --git a/localedata/locales/iso14651_t1_common b/localedata/locales/iso14651_t1_common index eef75ba..0e64f26 100644 --- a/localedata/locales/iso14651_t1_common +++ b/localedata/locales/iso14651_t1_common @@ -1042,9 +1042,9 @@ collating-element from "" collating-element from "" collating-element from "" collating-element from "" -collating-element from "" collating-element from "" collating-element from "" +collating-element from "" collating-element from "" collating-element from "" collating-element from "" @@ -1103,8 +1103,8 @@ collating-symbol collating-symbol collating-symbol collating-symbol -collating-symbol collating-symbol +collating-symbol collating-symbol collating-symbol collating-symbol @@ -1126,6 +1126,12 @@ collating-symbol collating-symbol collating-symbol collating-symbol +collating-symbol +collating-symbol +collating-symbol +collating-symbol +collating-symbol +collating-symbol # # # @@ -4552,6 +4558,12 @@ collating-symbol + + + + + + # # # @@ -7252,6 +7264,7 @@ order_start ;forward;forward;forward;forward,position ;;;IGNORE ;;;IGNORE "";;;IGNORE + "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE @@ -7280,6 +7293,7 @@ order_start ;forward;forward;forward;forward,position "";;;IGNORE "";;;IGNORE "";;;IGNORE # ണ്‍ = ണ + ് + zwj + "";;;IGNORE "";;;IGNORE # ണ = ണ + ് + അ "";;;IGNORE "";;;IGNORE @@ -7290,6 +7304,7 @@ order_start ;forward;forward;forward;forward,position "";;;IGNORE "";;;IGNORE "";;;IGNORE # ന്‍= ന + ് + zwj + "";;;IGNORE "";;;IGNORE #ന = ന + ് + അ "";;;IGNORE "";;;IGNORE @@ -7305,20 +7320,23 @@ order_start ;forward;forward;forward;forward,position "";;;IGNORE "";;;IGNORE "";;;IGNORE # ര = ര + ് + zwj + "";;;IGNORE "";;;IGNORE # ര = ര + ് + അ ;;;IGNORE # ല്‍ = ല + ് + zwj + "";;;IGNORE "";;;IGNORE # ല = ല + ് + അ "";;;IGNORE "";;;IGNORE "";;;IGNORE - "";;;IGNORE + "";;;IGNORE "";;;IGNORE - "";;;IGNORE + "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE "";;;IGNORE # ള്‍ = ള + ് + zwj + "";;;IGNORE "";;;IGNORE # ള = ള + ് + അ "";;;IGNORE "";;;IGNORE commit 3c7cd21290cabdadd72984fb69bc51e64ff1002d Author: Florian Weimer Date: Mon Jun 19 18:31:27 2017 +0200 CVE-2017-1000366: Ignore LD_LIBRARY_PATH for AT_SECURE=1 programs [BZ #21624] LD_LIBRARY_PATH can only be used to reorder system search paths, which is not useful functionality. This makes an exploitable unbounded alloca in _dl_init_paths unreachable for AT_SECURE=1 programs. (cherry picked from commit f6110a8fee2ca36f8e2d2abecf3cba9fa7b8ea7d) diff --git a/ChangeLog b/ChangeLog index d44aff0..14ff8b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-06-19 Florian Weimer + + [BZ #21624] + CVE-2017-1000366 + * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for + __libc_enable_secure. + 2017-05-12 Florian Weimer [BZ #21386] diff --git a/NEWS b/NEWS index d528723..29079e8 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,7 @@ The following bugs are resolved with this release: [21115] sunrpc: Use-after-free in error path in clntudp_call [21289] Fix symbol redirect for fts_set [21386] Assertion in fork for distinct parent PID is incorrect + [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) Version 2.25 diff --git a/elf/rtld.c b/elf/rtld.c index a036ece..2fc33a6 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2418,7 +2418,8 @@ process_envvars (enum mode *modep) case 12: /* The library search path. */ - if (memcmp (envline, "LIBRARY_PATH", 12) == 0) + if (!__libc_enable_secure + && memcmp (envline, "LIBRARY_PATH", 12) == 0) { library_path = &envline[13]; break; commit 46703a3995aa3ca2b816814aa4ad05ed524194dd Author: Florian Weimer Date: Mon Jun 19 22:31:04 2017 +0200 ld.so: Reject overly long LD_PRELOAD path elements (cherry picked from commit 6d0ba622891bed9d8394eef1935add53003b12e8) diff --git a/ChangeLog b/ChangeLog index 14ff8b8..fbe4db2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2017-06-19 Florian Weimer + * elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define. + (dso_name_valid_for_suid): New function. + (handle_ld_preload): Likewise. + (dl_main): Call it. Remove alloca. + +2017-06-19 Florian Weimer + [BZ #21624] CVE-2017-1000366 * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for diff --git a/elf/rtld.c b/elf/rtld.c index 2fc33a6..4badcf6 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -99,6 +99,35 @@ uintptr_t __pointer_chk_guard_local strong_alias (__pointer_chk_guard_local, __pointer_chk_guard) #endif +/* Length limits for names and paths, to protect the dynamic linker, + particularly when __libc_enable_secure is active. */ +#ifdef NAME_MAX +# define SECURE_NAME_LIMIT NAME_MAX +#else +# define SECURE_NAME_LIMIT 255 +#endif +#ifdef PATH_MAX +# define SECURE_PATH_LIMIT PATH_MAX +#else +# define SECURE_PATH_LIMIT 1024 +#endif + +/* Check that AT_SECURE=0, or that the passed name does not contain + directories and is not overly long. Reject empty names + unconditionally. */ +static bool +dso_name_valid_for_suid (const char *p) +{ + if (__glibc_unlikely (__libc_enable_secure)) + { + /* Ignore pathnames with directories for AT_SECURE=1 + programs, and also skip overlong names. */ + size_t len = strlen (p); + if (len >= SECURE_NAME_LIMIT || memchr (p, '/', len) != NULL) + return false; + } + return *p != '\0'; +} /* List of auditing DSOs. */ static struct audit_list @@ -716,6 +745,42 @@ static const char *preloadlist attribute_relro; /* Nonzero if information about versions has to be printed. */ static int version_info attribute_relro; +/* The LD_PRELOAD environment variable gives list of libraries + separated by white space or colons that are loaded before the + executable's dependencies and prepended to the global scope list. + (If the binary is running setuid all elements containing a '/' are + ignored since it is insecure.) Return the number of preloads + performed. */ +unsigned int +handle_ld_preload (const char *preloadlist, struct link_map *main_map) +{ + unsigned int npreloads = 0; + const char *p = preloadlist; + char fname[SECURE_PATH_LIMIT]; + + while (*p != '\0') + { + /* Split preload list at space/colon. */ + size_t len = strcspn (p, " :"); + if (len > 0 && len < sizeof (fname)) + { + memcpy (fname, p, len); + fname[len] = '\0'; + } + else + fname[0] = '\0'; + + /* Skip over the substring and the following delimiter. */ + p += len; + if (*p != '\0') + ++p; + + if (dso_name_valid_for_suid (fname)) + npreloads += do_preload (fname, main_map, "LD_PRELOAD"); + } + return npreloads; +} + static void dl_main (const ElfW(Phdr) *phdr, ElfW(Word) phnum, @@ -1462,23 +1527,8 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", if (__glibc_unlikely (preloadlist != NULL)) { - /* The LD_PRELOAD environment variable gives list of libraries - separated by white space or colons that are loaded before the - executable's dependencies and prepended to the global scope - list. If the binary is running setuid all elements - containing a '/' are ignored since it is insecure. */ - char *list = strdupa (preloadlist); - char *p; - HP_TIMING_NOW (start); - - /* Prevent optimizing strsep. Speed is not important here. */ - while ((p = (strsep) (&list, " :")) != NULL) - if (p[0] != '\0' - && (__builtin_expect (! __libc_enable_secure, 1) - || strchr (p, '/') == NULL)) - npreloads += do_preload (p, main_map, "LD_PRELOAD"); - + npreloads += handle_ld_preload (preloadlist, main_map); HP_TIMING_NOW (stop); HP_TIMING_DIFF (diff, start, stop); HP_TIMING_ACCUM_NT (load_time, diff); commit c69d4a0f680a24fdbe323764a50382ad324041e9 Author: Florian Weimer Date: Mon Jun 19 22:32:12 2017 +0200 ld.so: Reject overly long LD_AUDIT path elements Also only process the last LD_AUDIT entry. (cherry picked from commit 81b82fb966ffbd94353f793ad17116c6088dedd9) diff --git a/ChangeLog b/ChangeLog index fbe4db2..67ce0aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,16 @@ 2017-06-19 Florian Weimer + * elf/rtld.c (audit_list_string): New variable. + (audit_list): Update comment. + (struct audit_list_iter): Define. + (audit_list_iter_init, audit_list_iter_next): New function. + (dl_main): Use struct audit_list_iter to process audit modules. + (process_dl_audit): Call dso_name_valid_for_suid. + (process_envvars): Set audit_list_string instead of calling + process_dl_audit. + +2017-06-19 Florian Weimer + * elf/rtld.c (SECURE_NAME_LIMIT, SECURE_PATH_LIMIT): Define. (dso_name_valid_for_suid): New function. (handle_ld_preload): Likewise. diff --git a/elf/rtld.c b/elf/rtld.c index 4badcf6..369724b 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -129,13 +129,91 @@ dso_name_valid_for_suid (const char *p) return *p != '\0'; } -/* List of auditing DSOs. */ +/* LD_AUDIT variable contents. Must be processed before the + audit_list below. */ +const char *audit_list_string; + +/* Cyclic list of auditing DSOs. audit_list->next is the first + element. */ static struct audit_list { const char *name; struct audit_list *next; } *audit_list; +/* Iterator for audit_list_string followed by audit_list. */ +struct audit_list_iter +{ + /* Tail of audit_list_string still needing processing, or NULL. */ + const char *audit_list_tail; + + /* The list element returned in the previous iteration. NULL before + the first element. */ + struct audit_list *previous; + + /* Scratch buffer for returning a name which is part of + audit_list_string. */ + char fname[SECURE_NAME_LIMIT]; +}; + +/* Initialize an audit list iterator. */ +static void +audit_list_iter_init (struct audit_list_iter *iter) +{ + iter->audit_list_tail = audit_list_string; + iter->previous = NULL; +} + +/* Iterate through both audit_list_string and audit_list. */ +static const char * +audit_list_iter_next (struct audit_list_iter *iter) +{ + if (iter->audit_list_tail != NULL) + { + /* First iterate over audit_list_string. */ + while (*iter->audit_list_tail != '\0') + { + /* Split audit list at colon. */ + size_t len = strcspn (iter->audit_list_tail, ":"); + if (len > 0 && len < sizeof (iter->fname)) + { + memcpy (iter->fname, iter->audit_list_tail, len); + iter->fname[len] = '\0'; + } + else + /* Do not return this name to the caller. */ + iter->fname[0] = '\0'; + + /* Skip over the substring and the following delimiter. */ + iter->audit_list_tail += len; + if (*iter->audit_list_tail == ':') + ++iter->audit_list_tail; + + /* If the name is valid, return it. */ + if (dso_name_valid_for_suid (iter->fname)) + return iter->fname; + /* Otherwise, wrap around and try the next name. */ + } + /* Fall through to the procesing of audit_list. */ + } + + if (iter->previous == NULL) + { + if (audit_list == NULL) + /* No pre-parsed audit list. */ + return NULL; + /* Start of audit list. The first list element is at + audit_list->next (cyclic list). */ + iter->previous = audit_list->next; + return iter->previous->name; + } + if (iter->previous == audit_list) + /* Cyclic list wrap-around. */ + return NULL; + iter->previous = iter->previous->next; + return iter->previous->name; +} + #ifndef HAVE_INLINED_SYSCALLS /* Set nonzero during loading and initialization of executable and libraries, cleared before the executable's entry point runs. This @@ -1303,11 +1381,13 @@ of this helper program; chances are you did not intend to run this program.\n\ GL(dl_rtld_map).l_tls_modid = _dl_next_tls_modid (); /* If we have auditing DSOs to load, do it now. */ - if (__glibc_unlikely (audit_list != NULL)) + bool need_security_init = true; + if (__glibc_unlikely (audit_list != NULL) + || __glibc_unlikely (audit_list_string != NULL)) { - /* Iterate over all entries in the list. The order is important. */ struct audit_ifaces *last_audit = NULL; - struct audit_list *al = audit_list->next; + struct audit_list_iter al_iter; + audit_list_iter_init (&al_iter); /* Since we start using the auditing DSOs right away we need to initialize the data structures now. */ @@ -1318,9 +1398,14 @@ of this helper program; chances are you did not intend to run this program.\n\ use different values (especially the pointer guard) and will fail later on. */ security_init (); + need_security_init = false; - do + while (true) { + const char *name = audit_list_iter_next (&al_iter); + if (name == NULL) + break; + int tls_idx = GL(dl_tls_max_dtv_idx); /* Now it is time to determine the layout of the static TLS @@ -1329,7 +1414,7 @@ of this helper program; chances are you did not intend to run this program.\n\ no DF_STATIC_TLS bit is set. The reason is that we know glibc will use the static model. */ struct dlmopen_args dlmargs; - dlmargs.fname = al->name; + dlmargs.fname = name; dlmargs.map = NULL; const char *objname; @@ -1342,7 +1427,7 @@ of this helper program; chances are you did not intend to run this program.\n\ not_loaded: _dl_error_printf ("\ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", - al->name, err_str); + name, err_str); if (malloced) free ((char *) err_str); } @@ -1446,10 +1531,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", goto not_loaded; } } - - al = al->next; } - while (al != audit_list->next); /* If we have any auditing modules, announce that we already have two objects loaded. */ @@ -1713,7 +1795,7 @@ ERROR: ld.so: object '%s' cannot be loaded as audit interface: %s; ignored.\n", if (tcbp == NULL) tcbp = init_tls (); - if (__glibc_likely (audit_list == NULL)) + if (__glibc_likely (need_security_init)) /* Initialize security features. But only if we have not done it earlier. */ security_init (); @@ -2344,9 +2426,7 @@ process_dl_audit (char *str) char *p; while ((p = (strsep) (&str, ":")) != NULL) - if (p[0] != '\0' - && (__builtin_expect (! __libc_enable_secure, 1) - || strchr (p, '/') == NULL)) + if (dso_name_valid_for_suid (p)) { /* This is using the local malloc, not the system malloc. The memory can never be freed. */ @@ -2410,7 +2490,7 @@ process_envvars (enum mode *modep) break; } if (memcmp (envline, "AUDIT", 5) == 0) - process_dl_audit (&envline[6]); + audit_list_string = &envline[6]; break; case 7: commit 3776f38fcd267c127ba5eb222e2c614c191744aa Author: Siddhesh Poyarekar Date: Tue Jun 20 05:59:17 2017 +0200 Ignore and remove LD_HWCAP_MASK for AT_SECURE programs (bug #21209) The LD_HWCAP_MASK environment variable may alter the selection of function variants for some architectures. For AT_SECURE process it means that if an outdated routine has a bug that would otherwise not affect newer platforms by default, LD_HWCAP_MASK will allow that bug to be exploited. To be on the safe side, ignore and disable LD_HWCAP_MASK for setuid binaries. [BZ #21209] * elf/rtld.c (process_envvars): Ignore LD_HWCAP_MASK for AT_SECURE processes. * sysdeps/generic/unsecvars.h: Add LD_HWCAP_MASK. * elf/tst-env-setuid.c (test_parent): Test LD_HWCAP_MASK. (test_child): Likewise. * elf/Makefile (tst-env-setuid-ENV): Add LD_HWCAP_MASK. (cherry picked from commit 1c1243b6fc33c029488add276e56570a07803bfd) diff --git a/ChangeLog b/ChangeLog index 67ce0aa..85f1e0a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2017-03-07 Siddhesh Poyarekar + + [BZ #21209] + * elf/rtld.c (process_envvars): Ignore LD_HWCAP_MASK for + AT_SECURE processes. + * sysdeps/generic/unsecvars.h: Add LD_HWCAP_MASK. + * elf/tst-env-setuid.c (test_parent): Test LD_HWCAP_MASK. + (test_child): Likewise. + * elf/Makefile (tst-env-setuid-ENV): Add LD_HWCAP_MASK. + 2017-06-19 Florian Weimer * elf/rtld.c (audit_list_string): New variable. diff --git a/NEWS b/NEWS index 29079e8..7be238c 100644 --- a/NEWS +++ b/NEWS @@ -13,6 +13,7 @@ The following bugs are resolved with this release: [21015] Document and fix --enable-bind-now [21109] Tunables broken on big-endian [21115] sunrpc: Use-after-free in error path in clntudp_call + [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs [21289] Fix symbol redirect for fts_set [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) diff --git a/elf/Makefile b/elf/Makefile index 61abeb5..cc4aeb2 100644 --- a/elf/Makefile +++ b/elf/Makefile @@ -1398,6 +1398,7 @@ $(objpfx)tst-nodelete-dlclose: $(objpfx)tst-nodelete-dlclose-dso.so $(objpfx)tst-nodelete-dlclose.out: $(objpfx)tst-nodelete-dlclose-dso.so \ $(objpfx)tst-nodelete-dlclose-plugin.so -tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 +tst-env-setuid-ENV = MALLOC_CHECK_=2 MALLOC_MMAP_THRESHOLD_=4096 \ + LD_HWCAP_MASK=0xffffffff tst-env-setuid-tunables-ENV = \ GLIBC_TUNABLES=glibc.malloc.check=2:glibc.malloc.mmap_threshold=4096 diff --git a/elf/rtld.c b/elf/rtld.c index 369724b..9362a21 100644 --- a/elf/rtld.c +++ b/elf/rtld.c @@ -2534,7 +2534,8 @@ process_envvars (enum mode *modep) case 10: /* Mask for the important hardware capabilities. */ - if (memcmp (envline, "HWCAP_MASK", 10) == 0) + if (!__libc_enable_secure + && memcmp (envline, "HWCAP_MASK", 10) == 0) GLRO(dl_hwcap_mask) = __strtoul_internal (&envline[11], NULL, 0, 0); break; diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c index 6ec3fa5..eec408e 100644 --- a/elf/tst-env-setuid.c +++ b/elf/tst-env-setuid.c @@ -213,6 +213,12 @@ test_child (void) return 1; } + if (getenv ("LD_HWCAP_MASK") != NULL) + { + printf ("LD_HWCAP_MASK still set\n"); + return 1; + } + return 0; } #endif @@ -233,6 +239,12 @@ test_parent (void) return 1; } + if (getenv ("LD_HWCAP_MASK") == NULL) + { + printf ("LD_HWCAP_MASK lost\n"); + return 1; + } + return 0; } #endif diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h index a740837..5ea8a4a 100644 --- a/sysdeps/generic/unsecvars.h +++ b/sysdeps/generic/unsecvars.h @@ -16,6 +16,7 @@ "LD_DEBUG\0" \ "LD_DEBUG_OUTPUT\0" \ "LD_DYNAMIC_WEAK\0" \ + "LD_HWCAP_MASK\0" \ "LD_LIBRARY_PATH\0" \ "LD_ORIGIN_PATH\0" \ "LD_PRELOAD\0" \ commit adc7e06fb412a2a1ee52f8cb788caf436335b9f3 Author: Florian Weimer Date: Wed Jun 14 08:11:22 2017 +0200 i686: Add missing IS_IN (libc) guards to vectorized strcspn Since commit d957c4d3fa48d685ff2726c605c988127ef99395 (i386: Compile rtld-*.os with -mno-sse -mno-mmx -mfpmath=387), vector intrinsics can no longer be used in ld.so, even if the compiled code never makes it into the final ld.so link. This commit adds the missing IS_IN (libc) guard to the SSE 4.2 strcspn implementation, so that it can be used from ld.so in the future. (cherry picked from commit 69052a3a95da37169a08f9e59b2cc1808312753c) diff --git a/ChangeLog b/ChangeLog index 85f1e0a..73546da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-06-14 Florian Weimer + + * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. + * sysdeps/i386/i686/multiarch/varshift.c: Likewise. + 2017-03-07 Siddhesh Poyarekar [BZ #21209] diff --git a/sysdeps/i386/i686/multiarch/strcspn-c.c b/sysdeps/i386/i686/multiarch/strcspn-c.c index 6d61e19..ec230fb 100644 --- a/sysdeps/i386/i686/multiarch/strcspn-c.c +++ b/sysdeps/i386/i686/multiarch/strcspn-c.c @@ -1,2 +1,4 @@ -#define __strcspn_sse2 __strcspn_ia32 -#include +#if IS_IN (libc) +# define __strcspn_sse2 __strcspn_ia32 +# include +#endif diff --git a/sysdeps/i386/i686/multiarch/varshift.c b/sysdeps/i386/i686/multiarch/varshift.c index 7760b96..6742a35 100644 --- a/sysdeps/i386/i686/multiarch/varshift.c +++ b/sysdeps/i386/i686/multiarch/varshift.c @@ -1 +1,3 @@ -#include +#if IS_IN (libc) +# include +#endif commit 49f97e641e4e84a42246655d30adbc4756e67114 Author: H.J. Lu Date: Thu Jul 6 04:43:06 2017 -0700 x86-64: Align the stack in __tls_get_addr [BZ #21609] This change forces realignment of the stack pointer in __tls_get_addr, so that binaries compiled by GCCs older than GCC 4.9: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 continue to work even if vector instructions are used in glibc which require the ABI stack realignment. __tls_get_addr_slow is added to handle the slow paths in the default implementation of__tls_get_addr in elf/dl-tls.c. The new __tls_get_addr calls __tls_get_addr_slow after realigning the stack. Internal calls within ld.so go directly to the default implementation of __tls_get_addr because they do not need stack realignment. [BZ #21609] * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr. (gen-as-const-headers): Add rtld-offsets.sym. * sysdeps/x86_64/dl-tls.c: New file. * sysdeps/x86_64/rtld-offsets.sym: Likwise. * sysdeps/x86_64/tls_get_addr.S: Likewise. * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards. * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New. (TI_OFFSET_OFFSET): Likwise. (cherry picked from commit 031e519c95c069abe4e4c7c59e2b4b67efccdee5) diff --git a/ChangeLog b/ChangeLog index 73546da..e3f6a29 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2017-07-06 Florian Weimer + H.J. Lu + + [BZ #21609] + * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr. + (gen-as-const-headers): Add rtld-offsets.sym. + * sysdeps/x86_64/dl-tls.c: New file. + * sysdeps/x86_64/rtld-offsets.sym: Likwise. + * sysdeps/x86_64/tls_get_addr.S: Likewise. + * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards. + * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New. + (TI_OFFSET_OFFSET): Likwise. + 2017-06-14 Florian Weimer * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile index 5f25893..c896e22 100644 --- a/sysdeps/x86_64/Makefile +++ b/sysdeps/x86_64/Makefile @@ -27,7 +27,7 @@ ifeq ($(subdir),elf) CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\ -mno-mmx) -sysdep-dl-routines += tlsdesc dl-tlsdesc +sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr tests += ifuncmain8 modules-names += ifuncmod8 @@ -108,5 +108,5 @@ endif endif ifeq ($(subdir),csu) -gen-as-const-headers += tlsdesc.sym +gen-as-const-headers += tlsdesc.sym rtld-offsets.sym endif diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c new file mode 100644 index 0000000..3584805 --- /dev/null +++ b/sysdeps/x86_64/dl-tls.c @@ -0,0 +1,53 @@ +/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. + 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 + . */ + +#ifdef SHARED +/* Work around GCC PR58066, due to which __tls_get_addr may be called + with an unaligned stack. The compat implementation is in + tls_get_addr-compat.S. */ + +# include + +/* Define __tls_get_addr within elf/dl-tls.c under a different + name. */ +extern __typeof__ (__tls_get_addr) ___tls_get_addr; + +# define __tls_get_addr ___tls_get_addr +# include +# undef __tls_get_addr + +hidden_ver (___tls_get_addr, __tls_get_addr) + +/* Only handle slow paths for __tls_get_addr. */ +attribute_hidden +void * +__tls_get_addr_slow (GET_ADDR_ARGS) +{ + dtv_t *dtv = THREAD_DTV (); + + if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) + return update_get_addr (GET_ADDR_PARAM); + + return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); +} +#else + +/* No compatibility symbol needed. */ +# include + +#endif diff --git a/sysdeps/x86_64/dl-tls.h b/sysdeps/x86_64/dl-tls.h index 4a59d2a..c2fb56c 100644 --- a/sysdeps/x86_64/dl-tls.h +++ b/sysdeps/x86_64/dl-tls.h @@ -16,6 +16,9 @@ License along with the GNU C Library; if not, see . */ +#ifndef _X86_64_DL_TLS_H +#define _X86_64_DL_TLS_H + #include /* Type used for the representation of TLS information in the GOT. */ @@ -27,3 +30,5 @@ typedef struct dl_tls_index extern void *__tls_get_addr (tls_index *ti); + +#endif /* _X86_64_DL_TLS_H */ diff --git a/sysdeps/x86_64/rtld-offsets.sym b/sysdeps/x86_64/rtld-offsets.sym new file mode 100644 index 0000000..fd41b51 --- /dev/null +++ b/sysdeps/x86_64/rtld-offsets.sym @@ -0,0 +1,6 @@ +#define SHARED +#include + +-- + +GL_TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation) diff --git a/sysdeps/x86_64/tls_get_addr.S b/sysdeps/x86_64/tls_get_addr.S new file mode 100644 index 0000000..9d38fb3 --- /dev/null +++ b/sysdeps/x86_64/tls_get_addr.S @@ -0,0 +1,61 @@ +/* Stack-aligning implementation of __tls_get_addr. x86-64 version. + 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 + . */ + +#ifdef SHARED + +# include +# include "tlsdesc.h" +# include "rtld-offsets.h" + +/* See __tls_get_addr and __tls_get_addr_slow in dl-tls.c. This function + call __tls_get_addr_slow on both slow paths. It realigns the stack + before the call to work around GCC PR58066. */ + +ENTRY (__tls_get_addr) + mov %fs:DTV_OFFSET, %RDX_LP + mov GL_TLS_GENERATION_OFFSET+_rtld_local(%rip), %RAX_LP + /* GL(dl_tls_generation) == dtv[0].counter */ + cmp %RAX_LP, (%rdx) + jne 1f + mov TI_MODULE_OFFSET(%rdi), %RAX_LP + /* dtv[ti->ti_module] */ +# ifdef __LP64__ + salq $4, %rax + movq (%rdx,%rax), %rax +# else + movl (%rdx,%rax, 8), %eax +# endif + cmp $-1, %RAX_LP + je 1f + add TI_OFFSET_OFFSET(%rdi), %RAX_LP + ret +1: + /* On the slow path, align the stack. */ + pushq %rbp + cfi_def_cfa_offset (16) + cfi_offset (%rbp, -16) + mov %RSP_LP, %RBP_LP + cfi_def_cfa_register (%rbp) + and $-16, %RSP_LP + call __tls_get_addr_slow + mov %RBP_LP, %RSP_LP + popq %rbp + cfi_def_cfa (%rsp, 8) + ret +END (__tls_get_addr) +#endif /* SHARED */ diff --git a/sysdeps/x86_64/tlsdesc.sym b/sysdeps/x86_64/tlsdesc.sym index 3385497..fc897ab 100644 --- a/sysdeps/x86_64/tlsdesc.sym +++ b/sysdeps/x86_64/tlsdesc.sym @@ -15,3 +15,6 @@ TLSDESC_ARG offsetof(struct tlsdesc, arg) TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) + +TI_MODULE_OFFSET offsetof(tls_index, ti_module) +TI_OFFSET_OFFSET offsetof(tls_index, ti_offset) commit 7cdbe5b6f929b820b9dc92dbfa6ff48b4e6e133d Author: Szabolcs Nagy Date: Wed Jun 21 13:47:07 2017 +0100 [AArch64] Use hidden __GI__dl_argv in rtld startup code We rely on the symbol being locally defined so using extern symbol is not correct and the linker may complain about the relocations. diff --git a/ChangeLog b/ChangeLog index e3f6a29..31d18f5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-12 Szabolcs Nagy + + * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the + hidden __GI__dl_argv symbol. + 2017-07-06 Florian Weimer H.J. Lu diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h index 84b8aec..6067a1d 100644 --- a/sysdeps/aarch64/dl-machine.h +++ b/sysdeps/aarch64/dl-machine.h @@ -193,8 +193,8 @@ _dl_start_user: \n\ cmp " PTR "0, #0 \n\ bne 1b \n\ // Update _dl_argv \n\ - adrp x3, _dl_argv \n\ - str " PTR "2, [x3, #:lo12:_dl_argv] \n\ + adrp x3, __GI__dl_argv \n\ + str " PTR "2, [x3, #:lo12:__GI__dl_argv] \n\ .L_done_stack_adjust: \n\ // compute envp \n\ add " PTR "3, " PTR "2, " PTR "1, lsl #" PTR_SIZE_LOG " \n\ commit 0edeadc0d396aa713b808ae50a0058aca5d3837e Author: H.J. Lu Date: Wed Jul 26 10:08:46 2017 -0700 Avoid .symver on common symbols [BZ #21666] The .symver directive on common symbol just creates a new common symbol, not an alias and the newer assembler with the bug fix for https://sourceware.org/bugzilla/show_bug.cgi?id=21661 will issue an error. Before the fix, we got $ readelf -sW libc.so | grep "loc[12s]" 5109: 00000000003a0608 8 OBJECT LOCAL DEFAULT 36 loc1 5188: 00000000003a0610 8 OBJECT LOCAL DEFAULT 36 loc2 5455: 00000000003a0618 8 OBJECT LOCAL DEFAULT 36 locs 6575: 00000000003a05f0 8 OBJECT GLOBAL DEFAULT 36 locs@GLIBC_2.2.5 7156: 00000000003a05f8 8 OBJECT GLOBAL DEFAULT 36 loc1@GLIBC_2.2.5 7312: 00000000003a0600 8 OBJECT GLOBAL DEFAULT 36 loc2@GLIBC_2.2.5 in libc.so. The versioned loc1, loc2 and locs have the wrong addresses. After the fix, we got $ readelf -sW libc.so | grep "loc[12s]" 6570: 000000000039e3b8 8 OBJECT GLOBAL DEFAULT 34 locs@GLIBC_2.2.5 7151: 000000000039e3c8 8 OBJECT GLOBAL DEFAULT 34 loc1@GLIBC_2.2.5 7307: 000000000039e3c0 8 OBJECT GLOBAL DEFAULT 34 loc2@GLIBC_2.2.5 [BZ #21666] * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); (loc2): Likewise. (locs): Likewise. (cherry picked from commit 388b4f1a02f3a801965028bbfcd48d905638b797) diff --git a/ChangeLog b/ChangeLog index 31d18f5..ff0853d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-07-26 H.J. Lu + + [BZ #21666] + * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); + (loc2): Likewise. + (locs): Likewise. + 2017-07-12 Szabolcs Nagy * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the diff --git a/misc/regexp.c b/misc/regexp.c index 19d76c0..eaea7c3 100644 --- a/misc/regexp.c +++ b/misc/regexp.c @@ -29,14 +29,15 @@ #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23) -/* Define the variables used for the interface. */ -char *loc1; -char *loc2; +/* Define the variables used for the interface. Avoid .symver on common + symbol, which just creates a new common symbol, not an alias. */ +char *loc1 __attribute__ ((nocommon)); +char *loc2 __attribute__ ((nocommon)); compat_symbol (libc, loc1, loc1, GLIBC_2_0); compat_symbol (libc, loc2, loc2, GLIBC_2_0); /* Although we do not support the use we define this variable as well. */ -char *locs; +char *locs __attribute__ ((nocommon)); compat_symbol (libc, locs, locs, GLIBC_2_0); commit da3e97f94c80c5d05c0d999e87179aad35f7e975 Author: Tulio Magno Quites Machado Filho Date: Fri Apr 28 19:45:52 2017 -0300 powerpc: Fix logbl on power7 [BZ# 21280] 1. Fix the results for negative subnormals by ignoring the signal when normalizing the value. 2. Fix the output when the high part is a power of 2 and the low part is a nonzero number with opposite sign. This fix is based on commit 380bd0fd2418f8988217de950f8b8ff18af0cb2b. After applying this patch, logbl() tests pass cleanly on POWER >= 7. Tested on powerpc, powerpc64 and powerpc64le [BZ #21280] * sysdeps/powerpc/power7/fpu/s_logbl.c (__logbl): Ignore the signal of subnormals and adjust the exponent of power of 2 down when low part has opposite sign. (cherry picked from commit c064f6a613844181f411aabb2662384a6aefb69e) diff --git a/ChangeLog b/ChangeLog index ff0853d..b70096a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-04-28 Tulio Magno Quites Machado Filho + + [BZ #21280] + * sysdeps/powerpc/power7/fpu/s_logbl.c (__logbl): Ignore the + signal of subnormals and adjust the exponent of power of 2 down + when low part has opposite sign. + 2017-07-26 H.J. Lu [BZ #21666] diff --git a/sysdeps/powerpc/power7/fpu/s_logbl.c b/sysdeps/powerpc/power7/fpu/s_logbl.c index f7ecbd1..3ae383a 100644 --- a/sysdeps/powerpc/power7/fpu/s_logbl.c +++ b/sysdeps/powerpc/power7/fpu/s_logbl.c @@ -35,14 +35,16 @@ static const union { long double __logbl (long double x) { - double xh; + double xh, xl; double ret; + int64_t hx; if (__builtin_expect (x == 0.0L, 0)) /* Raise FE_DIVBYZERO and return -HUGE_VAL[LF]. */ return -1.0L / __builtin_fabsl (x); - xh = ldbl_high (x); + ldbl_unpack (x, &xh, &xl); + EXTRACT_WORDS64 (hx, xh); /* ret = x & 0x7ff0000000000000; */ asm ( "xxland %x0,%x1,%x2\n" @@ -58,10 +60,20 @@ __logbl (long double x) { /* POSIX specifies that denormal number is treated as though it were normalized. */ - int64_t hx; - - EXTRACT_WORDS64 (hx, xh); - return (long double) (-1023 - (__builtin_clzll (hx) - 12)); + return (long double) (- (__builtin_clzll (hx & 0x7fffffffffffffffLL) \ + - 12) - 1023); + } + else if ((hx & 0x000fffffffffffffLL) == 0) + { + /* If the high part is a power of 2, and the low part is nonzero + with the opposite sign, the low part affects the + exponent. */ + int64_t lx, rhx; + EXTRACT_WORDS64 (lx, xl); + rhx = (hx & 0x7ff0000000000000LL) >> 52; + if ((hx ^ lx) < 0 && (lx & 0x7fffffffffffffffLL) != 0) + rhx--; + return (long double) (rhx - 1023); } /* Test to avoid logb_downward (0.0) == -0.0. */ return ret == -0.0 ? 0.0 : ret; commit e249a1e2a33f7134a4510b06ec7809e563777bba Author: Aurelien Jarno Date: Thu Aug 3 22:35:48 2017 +0000 Fix the return type of the getentropy stub The return type of the getentropy stub is wrongly defined as ssize_t, while both the header and the Linux implementation define it as int. This patch fixes that. Changelog: * stdlib/getentropy.c (getentropy): Change return type to int. (cherry picked from commit 2b34e2716f1e84b2c3457ffc868c3dc775b55845) diff --git a/ChangeLog b/ChangeLog index b70096a..acb4b80 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-08-03 Aurelien Jarno + + * stdlib/getentropy.c (getentropy): Change return type to int. + 2017-04-28 Tulio Magno Quites Machado Filho [BZ #21280] diff --git a/stdlib/getentropy.c b/stdlib/getentropy.c index a71d4cd..a88bbf8 100644 --- a/stdlib/getentropy.c +++ b/stdlib/getentropy.c @@ -21,7 +21,7 @@ /* Write LENGTH bytes of randomness starting at BUFFER. Return 0 on success and -1 on failure. */ -ssize_t +int getentropy (void *buffer, size_t length) { __set_errno (ENOSYS); commit ea60566c17148fa837339df9d327034d8e9576a1 Author: Aurelien Jarno Date: Fri Aug 4 03:07:39 2017 +0200 i686/multiarch: Regenerate ulps This comes from running “make regen-ulps” on an AMD Opteron 2378 CPU. Changelog: * sysdeps/i386/i686/fpu/multiarch/libm-test-ulps: Regenerated. diff --git a/ChangeLog b/ChangeLog index acb4b80..897a69b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-08-04 Aurelien Jarno + + * sysdeps/i386/i686/fpu/multiarch/libm-test-ulps: Regenerated. + 2017-08-03 Aurelien Jarno * stdlib/getentropy.c (getentropy): Change return type to int. diff --git a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps index cb82d3e..275dbbe 100644 --- a/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps +++ b/sysdeps/i386/i686/fpu/multiarch/libm-test-ulps @@ -42,7 +42,7 @@ ldouble: 4 Function: "acosh_upward": double: 1 idouble: 1 -ildouble: 4 +ildouble: 5 ldouble: 3 Function: "asin": @@ -900,8 +900,8 @@ double: 3 float: 3 idouble: 3 ifloat: 3 -ildouble: 7 -ldouble: 7 +ildouble: 8 +ldouble: 8 Function: Imaginary part of "clog10_upward": double: 1 @@ -1591,8 +1591,8 @@ double: 3 float: 4 idouble: 3 ifloat: 4 -ildouble: 5 -ldouble: 5 +ildouble: 6 +ldouble: 6 Function: "hypot": double: 1 @@ -1743,8 +1743,8 @@ double: 3 float: 4 idouble: 3 ifloat: 4 -ildouble: 5 -ldouble: 5 +ildouble: 6 +ldouble: 6 Function: "log": double: 1 commit 05dcf1ea88ff65052e8b8079519429e424d6f2d8 Author: H.J. Lu Date: Sun Aug 6 10:44:30 2017 -0700 x86-64: Use _dl_runtime_resolve_opt only with AVX512F [BZ #21871] On AVX machines with XGETBV (ECX == 1) like Skylake processors, (gdb) disass _dl_runtime_resolve_avx_opt Dump of assembler code for function _dl_runtime_resolve_avx_opt: 0x0000000000015890 <+0>: push %rax 0x0000000000015891 <+1>: push %rcx 0x0000000000015892 <+2>: push %rdx 0x0000000000015893 <+3>: mov $0x1,%ecx 0x0000000000015898 <+8>: xgetbv 0x000000000001589b <+11>: mov %eax,%r11d 0x000000000001589e <+14>: pop %rdx 0x000000000001589f <+15>: pop %rcx 0x00000000000158a0 <+16>: pop %rax 0x00000000000158a1 <+17>: and $0x4,%r11d 0x00000000000158a5 <+21>: bnd je 0x16200 <_dl_runtime_resolve_sse_vex> End of assembler dump. is slower than: (gdb) disass _dl_runtime_resolve_avx_slow Dump of assembler code for function _dl_runtime_resolve_avx_slow: 0x0000000000015850 <+0>: vorpd %ymm0,%ymm1,%ymm8 0x0000000000015854 <+4>: vorpd %ymm2,%ymm3,%ymm9 0x0000000000015858 <+8>: vorpd %ymm4,%ymm5,%ymm10 0x000000000001585c <+12>: vorpd %ymm6,%ymm7,%ymm11 0x0000000000015860 <+16>: vorpd %ymm8,%ymm9,%ymm9 0x0000000000015865 <+21>: vorpd %ymm10,%ymm11,%ymm10 0x000000000001586a <+26>: vpcmpeqd %xmm8,%xmm8,%xmm8 0x000000000001586f <+31>: vorpd %ymm9,%ymm10,%ymm10 0x0000000000015874 <+36>: vptest %ymm10,%ymm8 0x0000000000015879 <+41>: bnd jae 0x158b0 <_dl_runtime_resolve_avx> 0x000000000001587c <+44>: vzeroupper 0x000000000001587f <+47>: bnd jmpq 0x16200 <_dl_runtime_resolve_sse_vex> End of assembler dump. (gdb) since xgetbv takes much more cycles than single cycle operations like vpord/vvpcmpeq/ptest. _dl_runtime_resolve_opt should be used only with AVX512 where AVX512 instructions lead to lower CPU frequency on Skylake server. [BZ #21871] * sysdeps/x86/cpu-features.c (init_cpu_features): Set bit_arch_Use_dl_runtime_resolve_opt only with AVX512F. (cherry picked from commit d2cf37c0a2a375cf2fde69f1afbcc49e45368fc4) diff --git a/ChangeLog b/ChangeLog index 897a69b..35b2d94 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-08-06 H.J. Lu + + [BZ #21871] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + bit_arch_Use_dl_runtime_resolve_opt only with AVX512F. + 2017-08-04 Aurelien Jarno * sysdeps/i386/i686/fpu/multiarch/libm-test-ulps: Regenerated. diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 9afd74c..5019f15 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -235,10 +235,13 @@ init_cpu_features (struct cpu_features *cpu_features) |= bit_arch_Prefer_No_AVX512; /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. - If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ + If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. + Use _dl_runtime_resolve_opt only with AVX512F since it is + slower than _dl_runtime_resolve_slow with AVX. */ cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] |= bit_arch_Use_dl_runtime_resolve_slow; - if (cpu_features->max_cpuid >= 0xd) + if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) + && cpu_features->max_cpuid >= 0xd) { unsigned int eax; commit 5b3f978ccf92e3c5213266500d70d3b0359b5efc Author: John David Anglin Date: Tue Aug 8 21:29:21 2017 -0400 hppa: Fix register corruption in __longjmp. [BZ #21049] * sysdeps/hppa/__longjmp.c (__longjmp): Move call to CHECK_SP up to avoid clobbering r26. diff --git a/ChangeLog b/ChangeLog index 35b2d94..16b1f25 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-08-08 Helge Deller + + [BZ #21049] + * sysdeps/hppa/__longjmp.c (__longjmp): Move call to CHECK_SP up + to avoid clobbering r26. + 2017-08-06 H.J. Lu [BZ #21871] diff --git a/sysdeps/hppa/__longjmp.c b/sysdeps/hppa/__longjmp.c index a7eefc7..2fedb1d 100644 --- a/sysdeps/hppa/__longjmp.c +++ b/sysdeps/hppa/__longjmp.c @@ -24,15 +24,15 @@ void __longjmp (__jmp_buf env, int val) { +#ifdef CHECK_SP + CHECK_SP (env[0].__jmp_buf.__sp); +#endif + /* We must use one of the non-callee saves registers for env. */ register unsigned long r26 asm ("r26") = (unsigned long)&env[0]; register unsigned long r25 asm ("r25") = (unsigned long)(val == 0 ? 1 : val); -#ifdef CHECK_SP - CHECK_SP (env[0].__jmp_buf.__sp); -#endif - asm volatile( /* Set return value. */ "copy %0, %%r28\n\t" @@ -79,6 +79,7 @@ __longjmp (__jmp_buf env, int val) : /* No outputs. */ : "r" (r25), "r" (r26) : /* No point in clobbers. */ ); + /* Avoid `volatile function does return' warnings. */ for (;;); } commit f827b1cec3e87c282727f8f90b9d4a660eff8443 Author: Florian Weimer Date: Fri Aug 11 16:02:55 2017 +0200 assert: Suppress pedantic warning caused by statement expression [BZ #21242] (cherry picked from commit 8b2c63e4e2ad1fd161f80004ed30624f2a37b57b) diff --git a/ChangeLog b/ChangeLog index 16b1f25..2c5c991 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-08-11 Florian Weimer + + [BZ #21242] + * assert/assert.h [__GNUC__ && !__STRICT_ANSI__] (assert): + Suppress pedantic warning resulting from statement expression. + (__ASSERT_FUNCTION): Add missing __extension__. + 2017-08-08 Helge Deller [BZ #21049] diff --git a/NEWS b/NEWS index 7be238c..e27fd4c 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,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 [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs + [21242] assert: Suppress pedantic warning caused by statement expression [21289] Fix symbol redirect for fts_set [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) diff --git a/assert/assert.h b/assert/assert.h index 22f0195..6801cfe 100644 --- a/assert/assert.h +++ b/assert/assert.h @@ -91,13 +91,19 @@ __END_DECLS ? __ASSERT_VOID_CAST (0) \ : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) # else +/* The first occurrence of EXPR is not evaluated due to the sizeof, + but will trigger any pedantic warnings masked by the __extension__ + for the second occurrence. The explicit comparison against zero is + required to support function pointers and bit fields in this + context, and to suppress the evaluation of variable length + arrays. */ # define assert(expr) \ - ({ \ + ((void) sizeof ((expr) == 0), __extension__ ({ \ if (expr) \ ; /* empty */ \ else \ __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION); \ - }) + })) # endif # ifdef __USE_GNU @@ -113,7 +119,7 @@ __END_DECLS C9x has a similar variable called __func__, but prefer the GCC one since it demangles C++ function names. */ # if defined __cplusplus ? __GNUC_PREREQ (2, 6) : __GNUC_PREREQ (2, 4) -# define __ASSERT_FUNCTION __PRETTY_FUNCTION__ +# define __ASSERT_FUNCTION __extension__ __PRETTY_FUNCTION__ # else # if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L # define __ASSERT_FUNCTION __func__ commit 241af18538d25e020428c66a50884f7cc37f0385 Author: John David Anglin Date: Sat Aug 12 13:02:52 2017 -0400 Use generic pthread support on hppa. [BZ #21016] * sysdeps/hppa/nptl/bits/pthreadtypes.h: Update pthread_cond_t typedef. * sysdeps/unix/sysv/linux/hppa/pthread.h: Include bits/types/struct_timespec.h. (PTHREAD_MUTEX_INITIALIZER): Revise define. (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise. (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise. (PTHREAD_RWLOCK_INITIALIZER): Likewise. (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise. (PTHREAD_COND_INITIALIZER): Likewise. Remove old definitions. * sysdeps/unix/sysv/linux/hppa/internaltypes.h: Delete. * sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c: Delete. * sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c: Delete. * sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c: Delete. * sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c: Delete. * sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c: Delete. diff --git a/ChangeLog b/ChangeLog index 2c5c991..2a0f14d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2017-08-12 John David Anglin + + [BZ #21016] + * sysdeps/hppa/nptl/bits/pthreadtypes.h: Update pthread_cond_t typedef. + * sysdeps/unix/sysv/linux/hppa/pthread.h: Include + bits/types/struct_timespec.h. + (PTHREAD_MUTEX_INITIALIZER): Revise define. + (PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP): Likewise. + (PTHREAD_RWLOCK_INITIALIZER): Likewise. + (PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP): Likewise. + (PTHREAD_COND_INITIALIZER): Likewise. + Remove old definitions. + * sysdeps/unix/sysv/linux/hppa/internaltypes.h: Delete. + * sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c: Delete. + * sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c: Delete. + * sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c: Delete. + * sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c: Delete. + * sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c: Delete. + 2017-08-11 Florian Weimer [BZ #21242] diff --git a/sysdeps/hppa/nptl/bits/pthreadtypes.h b/sysdeps/hppa/nptl/bits/pthreadtypes.h index e37111a..579047b 100644 --- a/sysdeps/hppa/nptl/bits/pthreadtypes.h +++ b/sysdeps/hppa/nptl/bits/pthreadtypes.h @@ -106,36 +106,34 @@ typedef union /* Data structure for conditional variable handling. The structure of the attribute type is not exposed on purpose. However, this structure - is exposed via PTHREAD_COND_INITIALIZER, and because of this, the - Linuxthreads version sets the first four ints to one. In the NPTL - version we must check, in every function using pthread_cond_t, - for the static Linuxthreads initializer and clear the appropriate - words. */ + is exposed via PTHREAD_COND_INITIALIZER. Support for Linuxthreads has + been dropped but we still need to retain the alignment of the original + lock field from Linuxthreads. */ typedef union { struct { - /* In the old Linuxthreads pthread_cond_t, this is the - start of the 4-word lock structure, the next four words - are set all to 1 by the Linuxthreads - PTHREAD_COND_INITIALIZER. */ - int __lock __attribute__ ((__aligned__(16))); - /* Tracks the initialization of this structure: - 0 initialized with NPTL PTHREAD_COND_INITIALIZER. - 1 initialized with Linuxthreads PTHREAD_COND_INITIALIZER. - 2 initialization in progress. */ - int __initializer; - unsigned int __futex; - void *__mutex; - /* In the old Linuxthreads this would have been the start - of the pthread_fastlock status word. */ - __extension__ unsigned long long int __total_seq; - __extension__ unsigned long long int __wakeup_seq; - __extension__ unsigned long long int __woken_seq; - unsigned int __nwaiters; - unsigned int __broadcast_seq; - /* The NPTL pthread_cond_t is exactly the same size as - the Linuxthreads version, there are no words to spare. */ + __extension__ union + { + __extension__ unsigned long long int __wseq; + struct { + unsigned int __low; + unsigned int __high; + } __wseq32; + }; + __extension__ union + { + __extension__ unsigned long long int __g1_start; + struct { + unsigned int __low; + unsigned int __high; + } __g1_start32; + }; + unsigned int __g_refs[2] __attribute__ ((__aligned__(16))); + unsigned int __g_size[2]; + unsigned int __g1_orig_size; + unsigned int __wrefs; + unsigned int __g_signals[2]; } __data; char __size[__SIZEOF_PTHREAD_COND_T]; __extension__ long long int __align; diff --git a/sysdeps/unix/sysv/linux/hppa/internaltypes.h b/sysdeps/unix/sysv/linux/hppa/internaltypes.h deleted file mode 100644 index d649657..0000000 --- a/sysdeps/unix/sysv/linux/hppa/internaltypes.h +++ /dev/null @@ -1,84 +0,0 @@ -#include_next -#ifndef _INTERNAL_TYPES_H_HPPA_ -#define _INTERNAL_TYPES_H_HPPA_ 1 -#include - -/* In GLIBC 2.10 HPPA switched from Linuxthreads to NPTL, and in order -to maintain ABI compatibility with pthread_cond_t, some care had to be -taken. - -The NPTL pthread_cond_t grew in size. When HPPA switched to NPTL, we -dropped the use of ldcw, and switched to the kernel helper routine for -compare-and-swap. This allowed HPPA to use the 4-word 16-byte aligned -lock words, and alignment words to store the additional pthread_cond_t -data. Once organized properly the new NPTL pthread_cond_t was 1 word -smaller than the Linuxthreads version. - -However, we were faced with the case that users may have initialized the -pthread_cond_t with PTHREAD_COND_INITIALIZER. In this case, the first -four words were set to one, and must be cleared before any NPTL code -used these words. - -We didn't want to use LDCW, because it continues to be a source of bugs -when applications memset pthread_cond_t to all zeroes by accident. This -works on all other architectures where lock words are unlocked at zero. -Remember that because of the semantics of LDCW, a locked word is set to -zero, and an unlocked word is set to 1. - -Instead we used atomic_compare_and_exchange_val_acq, but we couldn't use -this on any of the pthread_cond_t words, otherwise it might interfere -with the current operation of the structure. To solve this problem we -used the left over word. - -If the stucture was initialized by a legacy Linuxthread -PTHREAD_COND_INITIALIZER it contained a 1, and this indicates that the -structure requires zeroing for NPTL. The first thread to come upon a -pthread_cond_t with a 1 in the __initializer field, will -compare-and-swap the value, placing a 2 there which will cause all other -threads using the same pthread_cond_t to wait for the completion of the -initialization. Lastly, we use a store (with memory barrier) to change -__initializer from 2 to 0. Note that the store is strongly ordered, but -we use the PA 1.1 compatible form which is ",ma" with zero offset. - -In the future, when the application is recompiled with NPTL -PTHREAD_COND_INITIALIZER it will be a quick compare-and-swap, which -fails because __initializer is zero, and the structure will be used as -is correctly. */ - -#define cond_compat_clear(var) \ -({ \ - int tmp = 0; \ - var->__data.__wseq = 0; \ - var->__data.__signals_sent = 0; \ - var->__data.__confirmed = 0; \ - var->__data.__generation = 0; \ - var->__data.__mutex = NULL; \ - var->__data.__quiescence_waiters = 0; \ - var->__data.__clockid = 0; \ - /* Clear __initializer last, to indicate initialization is done. */ \ - /* This synchronizes-with the acquire load below. */ \ - atomic_store_release (&var->__data.__initializer, 0); \ -}) - -#define cond_compat_check_and_clear(var) \ -({ \ - int v; \ - int *value = &var->__data.__initializer; \ - /* This synchronizes-with the release store above. */ \ - while ((v = atomic_load_acquire (value)) != 0) \ - { \ - if (v == 1 \ - /* Relaxed MO is fine; it only matters who's first. */ \ - && atomic_compare_exchange_acquire_weak_relaxed (value, 1, 2)) \ - { \ - /* We're first; initialize structure. */ \ - cond_compat_clear (var); \ - break; \ - } \ - else \ - /* Yield before we re-check initialization status. */ \ - sched_yield (); \ - } \ -}) - -#endif diff --git a/sysdeps/unix/sysv/linux/hppa/pthread.h b/sysdeps/unix/sysv/linux/hppa/pthread.h index ac61720..806072c 100644 --- a/sysdeps/unix/sysv/linux/hppa/pthread.h +++ b/sysdeps/unix/sysv/linux/hppa/pthread.h @@ -26,6 +26,7 @@ #include #include #include +#include /* Detach state. */ @@ -82,32 +83,18 @@ enum #endif -#ifdef __PTHREAD_MUTEX_HAVE_PREV -# define PTHREAD_MUTEX_INITIALIZER \ - { { 0, 0, 0, 0, 0, __PTHREAD_SPINS, { 0, 0 } } } -# ifdef __USE_GNU -# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } -# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, __PTHREAD_SPINS, { 0, 0 } } } -# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } -# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, __PTHREAD_SPINS, { 0, 0 } } } - -# endif -#else -# define PTHREAD_MUTEX_INITIALIZER \ - { { 0, 0, 0, 0, 0, { __PTHREAD_SPINS } } } -# ifdef __USE_GNU -# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, 0, { __PTHREAD_SPINS } } } -# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, 0, { __PTHREAD_SPINS } } } -# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, 0, { __PTHREAD_SPINS } } } - -# endif +#define PTHREAD_MUTEX_INITIALIZER \ + { { 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, { __PTHREAD_SPINS }, 0, 0 } } +#ifdef __USE_GNU +# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0, 0, 0 }, 0, \ + { __PTHREAD_SPINS }, 0, 0 } } +# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, { 0, 0, 0, 0 }, 0, \ + { __PTHREAD_SPINS }, 0, 0 } } +# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ + { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, { 0, 0, 0, 0 }, 0, \ + { __PTHREAD_SPINS }, 0, 0 } } #endif @@ -130,25 +117,14 @@ enum # endif #endif + /* Read-write lock initializers. */ # define PTHREAD_RWLOCK_INITIALIZER \ - { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } } + { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } # ifdef __USE_GNU -# ifdef __PTHREAD_RWLOCK_INT_FLAGS_SHARED -# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ - { { 0, 0, 0, 0, 0, 0, 0, 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, \ - PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP } } -# else -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ - { { 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, \ - 0, __PTHREAD_RWLOCK_ELISION_EXTRA, 0, 0 } } -# else -# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ - { { 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\ - 0 } } -# endif -# endif +# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ + { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP, 0, 0, 0 } } # endif #endif /* Unix98 or XOpen2K */ @@ -183,9 +159,8 @@ enum }; - /* Conditional variable handling. */ -#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, 0, 0, (void *) 0, 0, 0 } } +#define PTHREAD_COND_INITIALIZER { { {0}, {0}, {0, 0}, {0, 0}, 0, 0, {0, 0} } } /* Cleanup buffers */ @@ -1161,43 +1136,3 @@ __NTH (pthread_equal (pthread_t __thread1, pthread_t __thread2)) __END_DECLS #endif /* pthread.h */ - -#ifndef _PTHREAD_H_HPPA_ -#define _PTHREAD_H_HPPA_ 1 - -/* The pthread_cond_t initializer is compatible only with NPTL. We do not - want to be forwards compatible, we eventually want to drop the code - that has to clear the old LT initializer. */ -#undef PTHREAD_COND_INITIALIZER -#define PTHREAD_COND_INITIALIZER { { 0, 0, 0, (void *) 0, 0, 0, 0, 0, 0 } } - -/* The pthread_mutex_t and pthread_rwlock_t initializers are compatible - only with NPTL. NPTL assumes pthread_rwlock_t is all zero. */ -#undef PTHREAD_MUTEX_INITIALIZER -#undef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP -#undef PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP -#undef PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP -/* Mutex initializers. */ -#define PTHREAD_MUTEX_INITIALIZER \ - { { 0, 0, 0, 0, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } -#ifdef __USE_GNU -# define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, PTHREAD_MUTEX_RECURSIVE_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } -# define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } -# define PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP \ - { { 0, 0, 0, PTHREAD_MUTEX_ADAPTIVE_NP, { 0, 0, 0, 0 }, 0, { 0 }, 0, 0 } } -#endif - -#undef PTHREAD_RWLOCK_INITIALIZER -#undef PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP -/* Read-write lock initializers. */ -#define PTHREAD_RWLOCK_INITIALIZER \ - { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } } -#ifdef __USE_GNU -# define PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP \ - { { { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP,\ - 0, 0, 0 } } -#endif /* Unix98 or XOpen2K */ - -#endif diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c deleted file mode 100644 index a6f9f5d..0000000 --- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_broadcast.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2009-2017 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Carlos O'Donell , 2009. - - 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 - . */ - -#ifndef INCLUDED_SELF -# define INCLUDED_SELF -# include -#else -# include -# include -# include -# include -int -__pthread_cond_broadcast (pthread_cond_t *cond) -{ - cond_compat_check_and_clear (cond); - return __pthread_cond_broadcast_internal (cond); -} -versioned_symbol (libpthread, __pthread_cond_broadcast, pthread_cond_broadcast, - GLIBC_2_3_2); -# undef versioned_symbol -# define versioned_symbol(lib, local, symbol, version) -# undef __pthread_cond_broadcast -# define __pthread_cond_broadcast __pthread_cond_broadcast_internal -# include_next -#endif diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c deleted file mode 100644 index 49af087..0000000 --- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_destroy.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2009-2017 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Carlos O'Donell , 2009. - - 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 - . */ - -#ifndef INCLUDED_SELF -# define INCLUDED_SELF -# include -#else -# include -# include -# include -# include -int -__pthread_cond_destroy (pthread_cond_t *cond) -{ - cond_compat_check_and_clear (cond); - return __pthread_cond_destroy_internal (cond); -} -versioned_symbol (libpthread, __pthread_cond_destroy, pthread_cond_destroy, - GLIBC_2_3_2); -# undef versioned_symbol -# define versioned_symbol(lib, local, symbol, version) -# undef __pthread_cond_destroy -# define __pthread_cond_destroy __pthread_cond_destroy_internal -# include_next -#endif diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c deleted file mode 100644 index ccb3de0..0000000 --- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_init.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2009-2017 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Carlos O'Donell , 2009. - - 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 - . */ - -#ifndef INCLUDED_SELF -# define INCLUDED_SELF -# include -#else -# include -# include -# include -# include -int -__pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *cond_attr) -{ - cond_compat_clear (cond); - return __pthread_cond_init_internal (cond, cond_attr); -} -versioned_symbol (libpthread, __pthread_cond_init, pthread_cond_init, - GLIBC_2_3_2); -# undef versioned_symbol -# define versioned_symbol(lib, local, symbol, version) -# undef __pthread_cond_init -# define __pthread_cond_init __pthread_cond_init_internal -# include_next -#endif diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c deleted file mode 100644 index 2bf32af..0000000 --- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_signal.c +++ /dev/null @@ -1,40 +0,0 @@ -/* Copyright (C) 2009-2017 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Carlos O'Donell , 2009. - - 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 - . */ - -#ifndef INCLUDED_SELF -# define INCLUDED_SELF -# include -#else -# include -# include -# include -# include -int -__pthread_cond_signal (pthread_cond_t *cond) -{ - cond_compat_check_and_clear (cond); - return __pthread_cond_signal_internal (cond); -} -versioned_symbol (libpthread, __pthread_cond_signal, pthread_cond_signal, - GLIBC_2_3_2); -# undef versioned_symbol -# define versioned_symbol(lib, local, symbol, version) -# undef __pthread_cond_signal -# define __pthread_cond_signal __pthread_cond_signal_internal -# include_next -#endif diff --git a/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c b/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c deleted file mode 100644 index 1cc2fc1..0000000 --- a/sysdeps/unix/sysv/linux/hppa/pthread_cond_wait.c +++ /dev/null @@ -1,53 +0,0 @@ -/* Copyright (C) 2009-2017 Free Software Foundation, Inc. - This file is part of the GNU C Library. - Contributed by Carlos O'Donell , 2009. - - 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 - . */ - -#ifndef INCLUDED_SELF -# define INCLUDED_SELF -# include -#else -# include -# include -# include -# include -int -__pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex) -{ - cond_compat_check_and_clear (cond); - return __pthread_cond_wait_internal (cond, mutex); -} -versioned_symbol (libpthread, __pthread_cond_wait, pthread_cond_wait, - GLIBC_2_3_2); -int -__pthread_cond_timedwait (cond, mutex, abstime) - pthread_cond_t *cond; - pthread_mutex_t *mutex; - const struct timespec *abstime; -{ - cond_compat_check_and_clear (cond); - return __pthread_cond_timedwait_internal (cond, mutex, abstime); -} -versioned_symbol (libpthread, __pthread_cond_timedwait, pthread_cond_timedwait, - GLIBC_2_3_2); -# undef versioned_symbol -# define versioned_symbol(lib, local, symbol, version) -# undef __pthread_cond_wait -# define __pthread_cond_wait __pthread_cond_wait_internal -# undef __pthread_cond_timedwait -# define __pthread_cond_timedwait __pthread_cond_timedwait_internal -# include_next -#endif commit f40b4e86f5c31560a1073a907943fd619485c74d Author: John David Anglin Date: Sat Aug 12 13:43:57 2017 -0400 Fix failing sNaN tests on hppa. * sysdeps/hppa/math-tests.h: New. diff --git a/ChangeLog b/ChangeLog index 2a0f14d..519ead0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2017-08-12 John David Anglin + * sysdeps/hppa/math-tests.h: New. + [BZ #21016] * sysdeps/hppa/nptl/bits/pthreadtypes.h: Update pthread_cond_t typedef. * sysdeps/unix/sysv/linux/hppa/pthread.h: Include diff --git a/sysdeps/hppa/math-tests.h b/sysdeps/hppa/math-tests.h new file mode 100644 index 0000000..bb20590 --- /dev/null +++ b/sysdeps/hppa/math-tests.h @@ -0,0 +1,22 @@ +/* Configuration for math tests. hppa version. + 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 + . */ + +/* SNaN tests do not preserve payloads. */ +#define SNAN_TESTS_PRESERVE_PAYLOAD 0 + +#include_next commit d215bbdff33323854ff5e3a3716459aaf2239f2f Author: John David Anglin Date: Sat Aug 12 14:39:53 2017 -0400 Fix guard alignment in allocate_stack when stack grows up. * nptl/allocatestack.c (allocate_stack): Align old and new guard addresses to page boundaries when the stack grows up. diff --git a/ChangeLog b/ChangeLog index 519ead0..8c03103 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2017-08-12 John David Anglin + * nptl/allocatestack.c (allocate_stack): Align old and new guard + addresses to page boundaries when the stack grows up. + * sysdeps/hppa/math-tests.h: New. [BZ #21016] diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c index 8a228ab..368fe3c 100644 --- a/nptl/allocatestack.c +++ b/nptl/allocatestack.c @@ -683,8 +683,14 @@ allocate_stack (const struct pthread_attr *attr, struct pthread **pdp, prot) != 0) goto mprot_error; #elif _STACK_GROWS_UP - if (mprotect ((char *) pd - pd->guardsize, - pd->guardsize - guardsize, prot) != 0) + char *new_guard = (char *)(((uintptr_t) pd - guardsize) + & ~pagesize_m1); + char *old_guard = (char *)(((uintptr_t) pd - pd->guardsize) + & ~pagesize_m1); + /* The guard size difference might be > 0, but once rounded + to the nearest page the size difference might be zero. */ + if (new_guard > old_guard + && mprotect (old_guard, new_guard - old_guard, prot) != 0) goto mprot_error; #endif commit 4a60d7e30a3152dc2dfc24ff65d7705aaff1a4b9 Author: John David Anglin Date: Sat Aug 12 15:09:25 2017 -0400 Fix [BZ locale/19838]. [BZ locale/19838] * sysdeps/unix/sysv/linux/hppa/bits/shm.h (SHMLBA): Set to page size. diff --git a/ChangeLog b/ChangeLog index 8c03103..4593409 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2017-08-12 John David Anglin + [BZ locale/19838] + * sysdeps/unix/sysv/linux/hppa/bits/shm.h (SHMLBA): Set to page size. + * nptl/allocatestack.c (allocate_stack): Align old and new guard addresses to page boundaries when the stack grows up. diff --git a/sysdeps/unix/sysv/linux/hppa/bits/shm.h b/sysdeps/unix/sysv/linux/hppa/bits/shm.h index 794f0ab..495dae8 100644 --- a/sysdeps/unix/sysv/linux/hppa/bits/shm.h +++ b/sysdeps/unix/sysv/linux/hppa/bits/shm.h @@ -37,7 +37,7 @@ #define SHM_UNLOCK 12 /* unlock segment (root only) */ /* Segment low boundary address multiple. */ -#define SHMLBA 0x00400000 /* address needs to be 4 Mb aligned */ +#define SHMLBA 0x1000 /* Type to count number of attaches. */ typedef unsigned long int shmatt_t; commit fa13872f59b4f42946a905060208086ce147322e Author: John David Anglin Date: Sat Aug 12 15:45:28 2017 -0400 Fix [BZ 20098]. [BZ 20098] * sysdeps/hppa/dl-fptr.c (_dl_read_access_allowed): New. (_dl_lookup_address): Return address if it is not consistent with being a linker defined function pointer. Likewise, return address if address and function descriptor addresses are not accessible. diff --git a/ChangeLog b/ChangeLog index 4593409..9919f22 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,11 @@ 2017-08-12 John David Anglin + [BZ 20098] + * sysdeps/hppa/dl-fptr.c (_dl_read_access_allowed): New. + (_dl_lookup_address): Return address if it is not consistent with + being a linker defined function pointer. Likewise, return address + if address and function descriptor addresses are not accessible. + [BZ locale/19838] * sysdeps/unix/sysv/linux/hppa/bits/shm.h (SHMLBA): Set to page size. diff --git a/sysdeps/hppa/dl-fptr.c b/sysdeps/hppa/dl-fptr.c index 83bdb91..f74abc0 100644 --- a/sysdeps/hppa/dl-fptr.c +++ b/sysdeps/hppa/dl-fptr.c @@ -181,24 +181,29 @@ make_fdesc (ElfW(Addr) ip, ElfW(Addr) gp) static inline ElfW(Addr) * __attribute__ ((always_inline)) make_fptr_table (struct link_map *map) { - const ElfW(Sym) *symtab - = (const void *) D_PTR (map, l_info[DT_SYMTAB]); + const ElfW(Sym) *symtab = (const void *) D_PTR (map, l_info[DT_SYMTAB]); const char *strtab = (const void *) D_PTR (map, l_info[DT_STRTAB]); ElfW(Addr) *fptr_table; size_t size; size_t len; + const ElfW(Sym) *symtabend; - /* XXX Apparently the only way to find out the size of the dynamic - symbol section is to assume that the string table follows right - afterwards... */ - len = ((strtab - (char *) symtab) + /* Determine the end of the dynamic symbol table using the hash. */ + if (map->l_info[DT_HASH] != NULL) + symtabend = (symtab + ((Elf_Symndx *) D_PTR (map, l_info[DT_HASH]))[1]); + else + /* There is no direct way to determine the number of symbols in the + dynamic symbol table and no hash table is present. The ELF + binary is ill-formed but what shall we do? Use the beginning of + the string table which generally follows the symbol table. */ + symtabend = (const ElfW(Sym) *) strtab; + + len = (((char *) symtabend - (char *) symtab) / map->l_info[DT_SYMENT]->d_un.d_val); - size = ((len * sizeof (fptr_table[0]) + GLRO(dl_pagesize) - 1) - & -GLRO(dl_pagesize)); - /* XXX We don't support here in the moment systems without MAP_ANON. - There probably are none for IA-64. In case this is proven wrong - we will have to open /dev/null here and use the file descriptor - instead of the hard-coded -1. */ + size = ALIGN_UP (len * sizeof (fptr_table[0]), GLRO(dl_pagesize)); + + /* We don't support systems without MAP_ANON. We avoid using malloc + because this might get called before malloc is setup. */ fptr_table = __mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); @@ -331,22 +336,45 @@ elf_machine_resolve (void) return addr; } +static inline int +_dl_read_access_allowed (unsigned int *addr) +{ + int result; + + asm ("proberi (%1),3,%0" : "=r" (result) : "r" (addr) : ); + + return result; +} + ElfW(Addr) _dl_lookup_address (const void *address) { ElfW(Addr) addr = (ElfW(Addr)) address; unsigned int *desc, *gptr; - /* Check for special cases. */ - if ((int) addr == -1 - || (unsigned int) addr < 4096 - || !((unsigned int) addr & 2)) + /* Return ADDR if the least-significant two bits of ADDR are not consistent + with ADDR being a linker defined function pointer. The normal value for + a code address in a backtrace is 3. */ + if (((unsigned int) addr & 3) != 2) + return addr; + + /* Handle special case where ADDR points to page 0. */ + if ((unsigned int) addr < 4096) return addr; /* Clear least-significant two bits from descriptor address. */ desc = (unsigned int *) ((unsigned int) addr & ~3); + if (!_dl_read_access_allowed (desc)) + return addr; - /* Check if descriptor requires resolution. The following trampoline is + /* Load first word of candidate descriptor. It should be a pointer + with word alignment and point to memory that can be read. */ + gptr = (unsigned int *) desc[0]; + if (((unsigned int) gptr & 3) != 0 + || !_dl_read_access_allowed (gptr)) + return addr; + + /* See if descriptor requires resolution. The following trampoline is used in each global offset table for function resolution: ldw 0(r20),r22 @@ -358,7 +386,6 @@ _dl_lookup_address (const void *address) .word "_dl_runtime_resolve ltp" got: .word _DYNAMIC .word "struct link map address" */ - gptr = (unsigned int *) desc[0]; if (gptr[0] == 0xea9f1fdd /* b,l .-12,r20 */ && gptr[1] == 0xd6801c1e /* depwi 0,31,2,r20 */ && (ElfW(Addr)) gptr[2] == elf_machine_resolve ()) commit 725118c013c9828b08f7dfbc64a522a8eaf87d30 Author: John David Anglin Date: Sat Aug 12 16:11:36 2017 -0400 Fix syscall cancellation on hppa. * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h (PSEUDO): Fix CFA offset. Use .cfi_def_cfa_offset instead of .cfi_offset. Don't record stack pointer offset. Correct PIC register offset. Don't mention frame related instructions in epilogue. (PUSHARGS_1): Correct offset. (PUSHARGS_2): Likewise. (PUSHARGS_3): Likewise. (PUSHARGS_4): Likewise. (PUSHARGS_5): Likewise. (PUSHARGS_6): Likewise. (POPARGS_1): Don't mention register restore. (POPARGS_2): Likewise. (POPARGS_3): Likewise. (POPARGS_4): Likewise. (POPARGS_5): Likewise. (POPARGS_6): Likewise. * sysdeps/unix/sysv/linux/hppa/sysdep.h (SAVE_PIC): Don't mention copy of PIC register. (LOAD_PIC): Likewise don't mention restore. (DO_CALL): Fix CFA offset. Use .cfi_def_cfa_offset instead of .cfi_offset. Don't record stack pointer offset. Correct PIC register offset. Don't mention frame related instructions in epilogue. diff --git a/ChangeLog b/ChangeLog index 9919f22..3419e73 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,28 @@ 2017-08-12 John David Anglin + * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h (PSEUDO): Fix CFA offset. + Use .cfi_def_cfa_offset instead of .cfi_offset. Don't record stack + pointer offset. Correct PIC register offset. Don't mention frame + related instructions in epilogue. + (PUSHARGS_1): Correct offset. + (PUSHARGS_2): Likewise. + (PUSHARGS_3): Likewise. + (PUSHARGS_4): Likewise. + (PUSHARGS_5): Likewise. + (PUSHARGS_6): Likewise. + (POPARGS_1): Don't mention register restore. + (POPARGS_2): Likewise. + (POPARGS_3): Likewise. + (POPARGS_4): Likewise. + (POPARGS_5): Likewise. + (POPARGS_6): Likewise. + * sysdeps/unix/sysv/linux/hppa/sysdep.h (SAVE_PIC): Don't mention + copy of PIC register. + (LOAD_PIC): Likewise don't mention restore. + (DO_CALL): Fix CFA offset. Use .cfi_def_cfa_offset instead of + .cfi_offset. Don't record stack pointer offset. Correct PIC register + offset. Don't mention frame related instructions in epilogue. + [BZ 20098] * sysdeps/hppa/dl-fptr.c (_dl_read_access_allowed): New. (_dl_lookup_address): Return address if it is not consistent with diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h b/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h index 5ea2972..8b7f2b2 100644 --- a/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h +++ b/sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h @@ -62,12 +62,11 @@ ENTRY (__##syscall_name##_nocancel) \ DOARGS_##args ASM_LINE_SEP \ stwm TREG, 64(%sp) ASM_LINE_SEP \ + .cfi_def_cfa_offset -64 ASM_LINE_SEP \ .cfi_offset TREG, 0 ASM_LINE_SEP \ - .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ stw %sp, -4(%sp) ASM_LINE_SEP \ - .cfi_offset 30, -4 ASM_LINE_SEP \ stw %r19, -32(%sp) ASM_LINE_SEP \ - .cfi_offset 19, -32 ASM_LINE_SEP \ + .cfi_offset 19, 32 ASM_LINE_SEP \ /* Save r19 */ ASM_LINE_SEP \ SAVE_PIC(TREG) ASM_LINE_SEP \ /* Do syscall, delay loads # */ ASM_LINE_SEP \ @@ -91,21 +90,19 @@ L(pre_nc_end): ASM_LINE_SEP \ /* No need to LOAD_PIC */ ASM_LINE_SEP \ /* Undo frame */ ASM_LINE_SEP \ ldwm -64(%sp),TREG ASM_LINE_SEP \ - .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ /* Restore rp before exit */ ASM_LINE_SEP \ ldw -20(%sp), %rp ASM_LINE_SEP \ - .cfi_restore 2 ASM_LINE_SEP \ ret ASM_LINE_SEP \ END(__##syscall_name##_nocancel) ASM_LINE_SEP \ /**********************************************/ASM_LINE_SEP \ ENTRY (name) \ DOARGS_##args ASM_LINE_SEP \ stwm TREG, 64(%sp) ASM_LINE_SEP \ - .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ + .cfi_def_cfa_offset -64 ASM_LINE_SEP \ + .cfi_offset TREG, 0 ASM_LINE_SEP \ stw %sp, -4(%sp) ASM_LINE_SEP \ - .cfi_offset 30, -4 ASM_LINE_SEP \ stw %r19, -32(%sp) ASM_LINE_SEP \ - .cfi_offset 19, -32 ASM_LINE_SEP \ + .cfi_offset 19, 32 ASM_LINE_SEP \ /* Done setting up frame, continue... */ ASM_LINE_SEP \ SINGLE_THREAD_P ASM_LINE_SEP \ cmpib,<>,n 0,%ret0,L(pseudo_cancel) ASM_LINE_SEP \ @@ -168,40 +165,32 @@ L(pre_end): ASM_LINE_SEP \ /* No need to LOAD_PIC */ ASM_LINE_SEP \ /* Undo frame */ ASM_LINE_SEP \ ldwm -64(%sp),TREG ASM_LINE_SEP \ - .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ /* Restore rp before exit */ ASM_LINE_SEP \ - ldw -20(%sp), %rp ASM_LINE_SEP \ - .cfi_restore 2 ASM_LINE_SEP + ldw -20(%sp), %rp ASM_LINE_SEP /* Save arguments into our frame */ # define PUSHARGS_0 /* nothing to do */ # define PUSHARGS_1 PUSHARGS_0 stw %r26, -36(%sr0,%sp) ASM_LINE_SEP \ - .cfi_offset 26, -36 ASM_LINE_SEP + .cfi_offset 26, 28 ASM_LINE_SEP # define PUSHARGS_2 PUSHARGS_1 stw %r25, -40(%sr0,%sp) ASM_LINE_SEP \ - .cfi_offset 25, -40 ASM_LINE_SEP + .cfi_offset 25, 24 ASM_LINE_SEP # define PUSHARGS_3 PUSHARGS_2 stw %r24, -44(%sr0,%sp) ASM_LINE_SEP \ - .cfi_offset 24, -44 ASM_LINE_SEP + .cfi_offset 24, 20 ASM_LINE_SEP # define PUSHARGS_4 PUSHARGS_3 stw %r23, -48(%sr0,%sp) ASM_LINE_SEP \ - .cfi_offset 23, -48 ASM_LINE_SEP + .cfi_offset 23, 16 ASM_LINE_SEP # define PUSHARGS_5 PUSHARGS_4 stw %r22, -52(%sr0,%sp) ASM_LINE_SEP \ - .cfi_offset 22, -52 ASM_LINE_SEP + .cfi_offset 22, 12 ASM_LINE_SEP # define PUSHARGS_6 PUSHARGS_5 stw %r21, -56(%sr0,%sp) ASM_LINE_SEP \ - .cfi_offset 21, -56 ASM_LINE_SEP + .cfi_offset 21, 8 ASM_LINE_SEP /* Bring them back from the stack */ # define POPARGS_0 /* nothing to do */ -# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP \ - .cfi_restore 26 ASM_LINE_SEP -# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP \ - .cfi_restore 25 ASM_LINE_SEP -# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP \ - .cfi_restore 24 ASM_LINE_SEP -# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP \ - .cfi_restore 23 ASM_LINE_SEP -# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP \ - .cfi_restore 22 ASM_LINE_SEP -# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP \ - .cfi_restore 21 ASM_LINE_SEP +# define POPARGS_1 POPARGS_0 ldw -36(%sr0,%sp), %r26 ASM_LINE_SEP +# define POPARGS_2 POPARGS_1 ldw -40(%sr0,%sp), %r25 ASM_LINE_SEP +# define POPARGS_3 POPARGS_2 ldw -44(%sr0,%sp), %r24 ASM_LINE_SEP +# define POPARGS_4 POPARGS_3 ldw -48(%sr0,%sp), %r23 ASM_LINE_SEP +# define POPARGS_5 POPARGS_4 ldw -52(%sr0,%sp), %r22 ASM_LINE_SEP +# define POPARGS_6 POPARGS_5 ldw -56(%sr0,%sp), %r21 ASM_LINE_SEP # if IS_IN (libpthread) # ifdef PIC diff --git a/sysdeps/unix/sysv/linux/hppa/sysdep.h b/sysdeps/unix/sysv/linux/hppa/sysdep.h index d8dd043..c0cd59e 100644 --- a/sysdeps/unix/sysv/linux/hppa/sysdep.h +++ b/sysdeps/unix/sysv/linux/hppa/sysdep.h @@ -49,11 +49,9 @@ to another function */ #define TREG 4 #define SAVE_PIC(SREG) \ - copy %r19, SREG ASM_LINE_SEP \ - .cfi_register 19, SREG + copy %r19, SREG #define LOAD_PIC(LREG) \ - copy LREG , %r19 ASM_LINE_SEP \ - .cfi_restore 19 + copy LREG , %r19 /* Inline assembly defines */ #define TREG_ASM "%r4" /* Cant clobber r3, it holds framemarker */ #define SAVE_ASM_PIC " copy %%r19, %" TREG_ASM "\n" @@ -292,12 +290,11 @@ #define DO_CALL(syscall_name, args) \ /* Create a frame */ ASM_LINE_SEP \ stwm TREG, 64(%sp) ASM_LINE_SEP \ + .cfi_def_cfa_offset -64 ASM_LINE_SEP \ .cfi_offset TREG, 0 ASM_LINE_SEP \ - .cfi_adjust_cfa_offset 64 ASM_LINE_SEP \ stw %sp, -4(%sp) ASM_LINE_SEP \ - .cfi_offset 30, -4 ASM_LINE_SEP \ stw %r19, -32(%sp) ASM_LINE_SEP \ - .cfi_offset 19, -32 ASM_LINE_SEP \ + .cfi_offset 19, 32 ASM_LINE_SEP \ /* Save r19 */ ASM_LINE_SEP \ SAVE_PIC(TREG) ASM_LINE_SEP \ /* Do syscall, delay loads # */ ASM_LINE_SEP \ @@ -320,10 +317,8 @@ L(pre_end): ASM_LINE_SEP \ /* Restore our frame, restoring TREG */ ASM_LINE_SEP \ ldwm -64(%sp), TREG ASM_LINE_SEP \ - .cfi_adjust_cfa_offset -64 ASM_LINE_SEP \ /* Restore return pointer */ ASM_LINE_SEP \ - ldw -20(%sp),%rp ASM_LINE_SEP \ - .cfi_restore 2 ASM_LINE_SEP + ldw -20(%sp),%rp ASM_LINE_SEP /* We do nothing with the return, except hand it back to someone else */ #undef DO_CALL_NOERRNO commit 604c01c69ab365cdc3bcb16f0ec7b856dc2d56cb Author: John David Anglin Date: Sat Aug 12 16:28:32 2017 -0400 Fix __setcontext return value on hppa. * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Return 0. diff --git a/ChangeLog b/ChangeLog index 3419e73..00e9103 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,7 @@ 2017-08-12 John David Anglin + * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Return 0. + * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h (PSEUDO): Fix CFA offset. Use .cfi_def_cfa_offset instead of .cfi_offset. Don't record stack pointer offset. Correct PIC register offset. Don't mention frame diff --git a/sysdeps/unix/sysv/linux/hppa/setcontext.S b/sysdeps/unix/sysv/linux/hppa/setcontext.S index 3f4da79..848d02e 100644 --- a/sysdeps/unix/sysv/linux/hppa/setcontext.S +++ b/sysdeps/unix/sysv/linux/hppa/setcontext.S @@ -141,7 +141,7 @@ ENTRY(__setcontext) /* No further context available. Exit now. */ bl HIDDEN_JUMPTARGET(exit), %r2 - ldi -1, %r26 + ldi 0, %r26 .Lerror: commit c6f84dffdf38f75e1978dfada09bc69d567f65b3 Author: John David Anglin Date: Sat Aug 12 16:46:35 2017 -0400 Fix stack offset for r19 load in __getcontext. * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Fix stack offset for r19 load. diff --git a/ChangeLog b/ChangeLog index 00e9103..54a444c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 2017-08-12 John David Anglin + * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Fix stack + offset for r19 load. + * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Return 0. * sysdeps/unix/sysv/linux/hppa/sysdep-cancel.h (PSEUDO): Fix CFA offset. diff --git a/sysdeps/unix/sysv/linux/hppa/getcontext.S b/sysdeps/unix/sysv/linux/hppa/getcontext.S index 6f52f21..2d7529b 100644 --- a/sysdeps/unix/sysv/linux/hppa/getcontext.S +++ b/sysdeps/unix/sysv/linux/hppa/getcontext.S @@ -156,7 +156,7 @@ ENTRY(__getcontext) /* Epilogue */ ldw -84(%sp), %r2 #ifdef PIC - ldw -96(%sp), %r19 + ldw -32(%sp), %r19 #endif bv %r0(%r2) ldwm -64(%sp), %r4 commit a707dc9bd2ab10c0ceecb7b42d11faef147a0b33 Author: John David Anglin Date: Sat Aug 12 16:59:50 2017 -0400 Add CFI annotation. * sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Add .cfi annotation. * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Likewise. * sysdeps/unix/sysv/linux/hppa/pt-vfork.S (__vfork): Likewise. * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Likewise. diff --git a/ChangeLog b/ChangeLog index 54a444c..5b4679c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,10 @@ 2017-08-12 John David Anglin + * sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Add .cfi annotation. + * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Likewise. + * sysdeps/unix/sysv/linux/hppa/pt-vfork.S (__vfork): Likewise. + * sysdeps/unix/sysv/linux/hppa/setcontext.S (__setcontext): Likewise. + * sysdeps/unix/sysv/linux/hppa/getcontext.S (__getcontext): Fix stack offset for r19 load. diff --git a/sysdeps/unix/sysv/linux/hppa/clone.S b/sysdeps/unix/sysv/linux/hppa/clone.S index d36b302..46ee697 100644 --- a/sysdeps/unix/sysv/linux/hppa/clone.S +++ b/sysdeps/unix/sysv/linux/hppa/clone.S @@ -64,9 +64,12 @@ ENTRY(__clone) /* Prologue */ stwm %r4, 64(%sp) + .cfi_def_cfa_offset -64 + .cfi_offset 4, 0 stw %sp, -4(%sp) #ifdef PIC stw %r19, -32(%sp) + .cfi_offset 19, 32 #endif /* Sanity check arguments. */ diff --git a/sysdeps/unix/sysv/linux/hppa/getcontext.S b/sysdeps/unix/sysv/linux/hppa/getcontext.S index 2d7529b..68a74a0 100644 --- a/sysdeps/unix/sysv/linux/hppa/getcontext.S +++ b/sysdeps/unix/sysv/linux/hppa/getcontext.S @@ -130,8 +130,11 @@ ENTRY(__getcontext) /* Prologue */ stwm %r4, 64(%sp) + .cfi_def_cfa_offset -64 + .cfi_offset 4, 0 #ifdef PIC stw %r19, -32(%sp) + .cfi_offset 19, 32 #endif /* Set up the trampoline registers. diff --git a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S index fc4573c..8b7d7df 100644 --- a/sysdeps/unix/sysv/linux/hppa/pt-vfork.S +++ b/sysdeps/unix/sysv/linux/hppa/pt-vfork.S @@ -58,7 +58,10 @@ ENTRY(__vfork) that there is no child now, so it's safe to create a frame. */ stw %rp, -20(%sp) + .cfi_offset 2, -20 stwm %r3, 64(%sp) + .cfi_def_cfa_offset -64 + .cfi_offset 3, 0 stw %sp, -4(%sp) sub %r0,%ret0,%r3 diff --git a/sysdeps/unix/sysv/linux/hppa/setcontext.S b/sysdeps/unix/sysv/linux/hppa/setcontext.S index 848d02e..92cb204 100644 --- a/sysdeps/unix/sysv/linux/hppa/setcontext.S +++ b/sysdeps/unix/sysv/linux/hppa/setcontext.S @@ -26,8 +26,11 @@ ENTRY(__setcontext) /* Prologue */ stwm %r3, 64(%sp) + .cfi_def_cfa_offset -64 + .cfi_offset 3, 0 #ifdef PIC stw %r19, -32(%sp) + .cfi_offset 19, 32 #endif /* Save ucp. */ commit 80fadd69ca373f02fc6a9f7fe3791d7b00ad0f93 Author: John David Anglin Date: Sat Aug 12 17:19:59 2017 -0400 hppa: set __IPC_64 as zero for SysV IPC calls In 1e5834c38a22 ("Refactor Linux ipc_priv header") a different approach to passing __IPC_64 as zero was created. Hppa kernel ABI requires to oass __IPC_64 as zero since it does not set CONFIG_ARCH_WANT_IPC_PARSE_VERSION in the kernel. Checked on hppa-linux-gnu with some adjustments to avoid BZ#21016 (basically by removing hppa compat implementations and adjusting required headers). * sysdeps/unix/sysv/linux/hppa/ipc_priv.h: New file. diff --git a/ChangeLog b/ChangeLog index 5b4679c..38d1f0d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2017-08-12 Adhemerval Zanella + + * sysdeps/unix/sysv/linux/hppa/ipc_priv.h: New file. + 2017-08-12 John David Anglin * sysdeps/unix/sysv/linux/hppa/clone.S (__clone): Add .cfi annotation. diff --git a/sysdeps/unix/sysv/linux/hppa/ipc_priv.h b/sysdeps/unix/sysv/linux/hppa/ipc_priv.h new file mode 100644 index 0000000..d880f50 --- /dev/null +++ b/sysdeps/unix/sysv/linux/hppa/ipc_priv.h @@ -0,0 +1,21 @@ +/* Old SysV permission definition for Linux. Hppa version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include /* For __key_t */ + +#define __IPC_64 0x0 commit 42f78808b15a775552946eccc4aefbd99617130a Author: John David Anglin Date: Sat Aug 12 17:37:14 2017 -0400 Call exit directly in clone (BZ #21512) [BZ #21512] * sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Call exit syscall instead of jump to _exit. * sysdeps/unix/sysv/linux/hppa/localplt.data: Remove _exit entry. diff --git a/ChangeLog b/ChangeLog index 38d1f0d..38dceba 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-08-12 John David Anglin + Adhemerval Zanella + + [BZ #21512] + * sysdeps/unix/sysv/linux/aarch64/clone.S (__clone): Call exit + syscall instead of jump to _exit. + * sysdeps/unix/sysv/linux/hppa/localplt.data: Remove _exit entry. + 2017-08-12 Adhemerval Zanella * sysdeps/unix/sysv/linux/hppa/ipc_priv.h: New file. diff --git a/sysdeps/unix/sysv/linux/hppa/clone.S b/sysdeps/unix/sysv/linux/hppa/clone.S index 46ee697..f6b4e3e 100644 --- a/sysdeps/unix/sysv/linux/hppa/clone.S +++ b/sysdeps/unix/sysv/linux/hppa/clone.S @@ -150,9 +150,9 @@ ENTRY(__clone) #ifdef PIC copy %r4, %r19 #endif - /* The call to _exit needs saved r19. */ - bl _exit, %rp - copy %ret0, %arg0 + copy %r28, %r26 + ble 0x100(%sr2, %r0) + ldi __NR_exit, %r20 /* We should not return from _exit. We do not restore r4, or the stack state. */ diff --git a/sysdeps/unix/sysv/linux/hppa/localplt.data b/sysdeps/unix/sysv/linux/hppa/localplt.data index 9dd81b4..db9e24b 100644 --- a/sysdeps/unix/sysv/linux/hppa/localplt.data +++ b/sysdeps/unix/sysv/linux/hppa/localplt.data @@ -6,7 +6,6 @@ libc.so: free libc.so: malloc libc.so: memalign libc.so: realloc -libc.so: _exit libc.so: __sigsetjmp libc.so: _IO_funlockfile libc.so: sigprocmask commit 092788065e3e7353b65d461e0756171cf36ed70c Author: John David Anglin Date: Sat Aug 12 17:54:26 2017 -0400 Return to caller if dl_fixup fails to resolve callee on hppa. [BZ 19170] * sysdeps/hppa/dl-trampoline.S (_dl_runtime_resolve): Return to caller if _dl_fixup fails. diff --git a/ChangeLog b/ChangeLog index 38dceba..c80eedb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,10 @@ 2017-08-12 John David Anglin + + [BZ 19170] + * sysdeps/hppa/dl-trampoline.S (_dl_runtime_resolve): Return to caller + if _dl_fixup fails. + +2017-08-12 John David Anglin Adhemerval Zanella [BZ #21512] diff --git a/sysdeps/hppa/dl-trampoline.S b/sysdeps/hppa/dl-trampoline.S index 856339b..3165c6f 100644 --- a/sysdeps/hppa/dl-trampoline.S +++ b/sysdeps/hppa/dl-trampoline.S @@ -82,6 +82,21 @@ _dl_runtime_resolve: bl _dl_fixup,%rp copy %r21,%r19 /* set fixup func ltp */ + /* While the linker will set a function pointer to NULL when it + encounters an undefined weak function, we need to dynamically + detect removed weak functions. The issue arises because a weak + __gmon_start__ function was added to shared executables to work + around issues in _init that are now resolved. The presence of + __gmon_start__ in every shared library breaks the linker + `--as-needed' option. This __gmon_start__ function does nothing + but removal is tricky. Depending on the binding, removal can + cause an application using it to fault. The call to _dl_fixup + returns NULL when a function isn't resolved. In order to help + with __gmon_start__ removal, we return directly to the caller + when _dl_fixup returns NULL. This check could be removed when + BZ 19170 is fixed. */ + comib,= 0,%r28,1f + /* Load up the returned func descriptor */ copy %r28, %r22 copy %r29, %r19 @@ -107,6 +122,13 @@ _dl_runtime_resolve: /* Jump to new function, but return to previous function */ bv %r0(%r22) ldw -20(%sp),%rp + +1: + /* Return to previous function */ + ldw -148(%sp),%rp + bv %r0(%rp) + ldo -128(%sp),%sp + .EXIT .PROCEND cfi_endproc commit 47db584c74e2bbcf1ba55e62d949c1a738da5e0a Author: Florian Weimer Date: Thu Apr 13 13:09:38 2017 +0200 resolv: Reduce EDNS payload size to 1200 bytes [BZ #21361] This hardens the stub resolver against fragmentation-based attacks. (cherry picked from commit e14a27723cc3a154d67f3f26e719d08c0ba9ad25) diff --git a/ChangeLog b/ChangeLog index c80eedb..2bb46f4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2017-04-13 Florian Weimer + + [BZ #21361] + Limit EDNS buffer size to 1200 bytes. + * include/resolv.h (__res_nopt): Remove declaration. + * resolv/Makefile (tests): tst-resolv-edns. + (tst-resolv-edns): Link with -lresolv, -lpthread. + * resolv/res_mkquery.c (__res_ntop): Limit EDNS buffer size to the + interval [512, 1200]. + * resolv/res_query.c (__libc_res_nquery): Use 1200 buffer size if + we can resize the buffer. + * resolv/resolv-internal.h (RESOLV_EDNS_BUFFER_SIZE): Define. + (__res_nopt): Declare. + * resolv/tst-resolv-edns.c: New file. + * resolv/resolv_test.h (struct resolv_edns_info): Define. + (struct resolv_response_context): Add edns member. + * resolv/resolv_test.c (struct query_info): Add edns member. + (parse_query): Extract EDNS information from the query. + (server_thread_udp_process_one): Propagate EDNS data. + (server_thread_tcp_client): Likewise. + 2017-08-12 John David Anglin [BZ 19170] diff --git a/NEWS b/NEWS index e27fd4c..a2435cc 100644 --- a/NEWS +++ b/NEWS @@ -7,6 +7,11 @@ using `glibc' in the "product" field. Version 2.25.1 +Security related changes: + +* The DNS stub resolver limits the advertised UDP buffer size to 1200 bytes, + to avoid fragmentation-based spoofing attacks. + The following bugs are resolved with this release: [20257] sunrpc: clntudp_call does not enforce timeout when receiving data diff --git a/include/resolv.h b/include/resolv.h index 95dcd3c..e8f477c 100644 --- a/include/resolv.h +++ b/include/resolv.h @@ -37,8 +37,6 @@ extern void res_pquery (const res_state __statp, const unsigned char *__msg, extern int res_ourserver_p (const res_state __statp, const struct sockaddr_in6 *__inp); extern void __res_iclose (res_state statp, bool free_addr); -extern int __res_nopt(res_state statp, int n0, unsigned char *buf, int buflen, - int anslen); libc_hidden_proto (__res_ninit) libc_hidden_proto (__res_maybe_init) libc_hidden_proto (__res_nclose) @@ -91,7 +89,6 @@ libresolv_hidden_proto (__res_nameinquery) libresolv_hidden_proto (__res_queriesmatch) libresolv_hidden_proto (__res_nsend) libresolv_hidden_proto (__b64_ntop) -libresolv_hidden_proto (__res_nopt) libresolv_hidden_proto (__dn_count_labels) libresolv_hidden_proto (__p_secstodate) diff --git a/resolv/Makefile b/resolv/Makefile index fdc37ed..01086d5 100644 --- a/resolv/Makefile +++ b/resolv/Makefile @@ -46,6 +46,7 @@ tests += \ tst-res_hconf_reorder \ tst-res_use_inet6 \ tst-resolv-basic \ + tst-resolv-edns \ tst-resolv-network \ tst-resolv-search \ @@ -124,6 +125,7 @@ $(objpfx)tst-bug18665-tcp: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-bug18665: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-res_use_inet6: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-basic: $(objpfx)libresolv.so $(shared-thread-library) +$(objpfx)tst-resolv-edns: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-network: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-qtypes: $(objpfx)libresolv.so $(shared-thread-library) $(objpfx)tst-resolv-search: $(objpfx)libresolv.so $(shared-thread-library) diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c index d80b531..5a0bb10 100644 --- a/resolv/res_mkquery.c +++ b/resolv/res_mkquery.c @@ -69,7 +69,7 @@ #include #include #include -#include +#include #include #include #include @@ -243,7 +243,30 @@ __res_nopt(res_state statp, *cp++ = 0; /* "." */ NS_PUT16(T_OPT, cp); /* TYPE */ - NS_PUT16(MIN(anslen, 0xffff), cp); /* CLASS = UDP payload size */ + + /* Lowering the advertised buffer size based on the actual + answer buffer size is desirable because the server will + minimize the reply to fit into the UDP packet (and A + non-minimal response might not fit the buffer). + + The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP + fallback and a non-minimal response which has to be + hard-truncated in the stub resolver, but this is price to + pay for avoiding fragmentation. (This issue does not + affect the nss_dns functions because they use the stub + resolver in such a way that it allocates a properly sized + response buffer.) */ + { + uint16_t buffer_size; + if (anslen < 512) + buffer_size = 512; + else if (anslen > RESOLV_EDNS_BUFFER_SIZE) + buffer_size = RESOLV_EDNS_BUFFER_SIZE; + else + buffer_size = anslen; + NS_PUT16 (buffer_size, cp); + } + *cp++ = NOERROR; /* extended RCODE */ *cp++ = 0; /* EDNS version */ @@ -261,4 +284,3 @@ __res_nopt(res_state statp, return cp - buf; } -libresolv_hidden_def (__res_nopt) diff --git a/resolv/res_query.c b/resolv/res_query.c index 07dc6f6..57156d0 100644 --- a/resolv/res_query.c +++ b/resolv/res_query.c @@ -77,6 +77,7 @@ #include #include #include +#include /* Options. Leave them on. */ /* #undef DEBUG */ @@ -146,7 +147,10 @@ __libc_res_nquery(res_state statp, if ((oflags & RES_F_EDNS0ERR) == 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) { - n = __res_nopt(statp, n, query1, bufsize, anslen / 2); + /* Use RESOLV_EDNS_BUFFER_SIZE because the receive + buffer can be reallocated. */ + n = __res_nopt (statp, n, query1, bufsize, + RESOLV_EDNS_BUFFER_SIZE); if (n < 0) goto unspec_nomem; } @@ -167,8 +171,10 @@ __libc_res_nquery(res_state statp, if (n > 0 && (oflags & RES_F_EDNS0ERR) == 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) - n = __res_nopt(statp, n, query2, bufsize - nused - n, - anslen / 2); + /* Use RESOLV_EDNS_BUFFER_SIZE because the receive + buffer can be reallocated. */ + n = __res_nopt (statp, n, query2, bufsize, + RESOLV_EDNS_BUFFER_SIZE); nquery2 = n; } @@ -182,7 +188,16 @@ __libc_res_nquery(res_state statp, if (n > 0 && (oflags & RES_F_EDNS0ERR) == 0 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0) - n = __res_nopt(statp, n, query1, bufsize, anslen); + { + /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer + can be reallocated. */ + size_t advertise; + if (answerp == NULL) + advertise = anslen; + else + advertise = RESOLV_EDNS_BUFFER_SIZE; + n = __res_nopt (statp, n, query1, bufsize, advertise); + } nquery1 = n; } diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h index 99fc17c..76fbe2f 100644 --- a/resolv/resolv-internal.h +++ b/resolv/resolv-internal.h @@ -32,4 +32,22 @@ res_use_inet6 (void) return _res.options & DEPRECATED_RES_USE_INET6; } +enum + { + /* The advertized EDNS buffer size. The value 1200 is derived + from the IPv6 minimum MTU (1280 bytes) minus some arbitrary + space for tunneling overhead. If the DNS server does not react + to ICMP Fragmentation Needed But DF Set messages, this should + avoid all UDP fragments on current networks. Avoiding UDP + fragments is desirable because it prevents fragmentation-based + spoofing attacks because the randomness in a DNS packet is + concentrated in the first fragment (with the headers) and does + not protect subsequent fragments. */ + RESOLV_EDNS_BUFFER_SIZE = 1200, + }; + +/* Add an OPT record to a DNS query. */ +int __res_nopt (res_state, int n0, unsigned char *buf, int buflen, + int anslen) attribute_hidden; + #endif /* _RESOLV_INTERNAL_H */ diff --git a/resolv/tst-resolv-edns.c b/resolv/tst-resolv-edns.c new file mode 100644 index 0000000..f17dbc3 --- /dev/null +++ b/resolv/tst-resolv-edns.c @@ -0,0 +1,501 @@ +/* Test EDNS handling in the stub resolver. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Data produced by a test query. */ +struct response_data +{ + char *qname; + uint16_t qtype; + struct resolv_edns_info edns; +}; + +/* Global array used by put_response and get_response to record + response data. The test DNS server returns the index of the array + element which contains the actual response data. This enables the + test case to return arbitrary amounts of data with the limited + number of bits which fit into an IP addres. + + The volatile specifier is needed because the test case accesses + these variables from a callback function called from a function + which is marked as __THROW (i.e., a leaf function which actually is + not). */ +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +static struct response_data ** volatile response_data_array; +volatile static size_t response_data_count; + +/* Extract information from the query, store it in a struct + response_data object, and return its index in the + response_data_array. */ +static unsigned int +put_response (const struct resolv_response_context *ctx, + const char *qname, uint16_t qtype) +{ + xpthread_mutex_lock (&mutex); + ++response_data_count; + /* We only can represent 2**24 indexes in 10.0.0.0/8. */ + TEST_VERIFY (response_data_count < (1 << 24)); + response_data_array = xrealloc + (response_data_array, sizeof (*response_data_array) * response_data_count); + unsigned int index = response_data_count - 1; + struct response_data *data = xmalloc (sizeof (*data)); + *data = (struct response_data) + { + .qname = xstrdup (qname), + .qtype = qtype, + .edns = ctx->edns, + }; + response_data_array[index] = data; + xpthread_mutex_unlock (&mutex); + return index; +} + +/* Verify the index into the response_data array and return the data + at it. */ +static struct response_data * +get_response (unsigned int index) +{ + xpthread_mutex_lock (&mutex); + TEST_VERIFY_EXIT (index < response_data_count); + struct response_data *result = response_data_array[index]; + xpthread_mutex_unlock (&mutex); + return result; +} + +/* Deallocate all response data. */ +static void +free_response_data (void) +{ + xpthread_mutex_lock (&mutex); + size_t count = response_data_count; + struct response_data **array = response_data_array; + for (unsigned int i = 0; i < count; ++i) + { + struct response_data *data = array[i]; + free (data->qname); + free (data); + } + free (array); + response_data_array = NULL; + response_data_count = 0; + xpthread_mutex_unlock (&mutex); +} + +#define EDNS_PROBE_EXAMPLE "edns-probe.example" + +static void +response (const struct resolv_response_context *ctx, + struct resolv_response_builder *b, + const char *qname, uint16_t qclass, uint16_t qtype) +{ + TEST_VERIFY_EXIT (qname != NULL); + + /* The "tcp." prefix can be used to request TCP fallback. */ + const char *qname_compare = qname; + bool force_tcp; + if (strncmp ("tcp.", qname_compare, strlen ("tcp.")) == 0) + { + force_tcp = true; + qname_compare += strlen ("tcp."); + } + else + force_tcp = false; + + enum {edns_probe} requested_qname; + if (strcmp (qname_compare, EDNS_PROBE_EXAMPLE) == 0) + requested_qname = edns_probe; + else + { + support_record_failure (); + printf ("error: unexpected QNAME: %s\n", qname); + return; + } + TEST_VERIFY_EXIT (qclass == C_IN); + struct resolv_response_flags flags = {.tc = force_tcp && !ctx->tcp}; + resolv_response_init (b, flags); + resolv_response_add_question (b, qname, qclass, qtype); + if (flags.tc) + return; + + if (test_verbose) + printf ("info: edns=%d payload_size=%d\n", + ctx->edns.active, ctx->edns.payload_size); + + /* Encode the response_data object in multiple address records. + Each record carries two bytes of payload data, and an index. */ + resolv_response_section (b, ns_s_an); + switch (requested_qname) + { + case edns_probe: + { + unsigned int index = put_response (ctx, qname, qtype); + switch (qtype) + { + case T_A: + { + uint32_t addr = htonl (0x0a000000 | index); + resolv_response_open_record (b, qname, qclass, qtype, 0); + resolv_response_add_data (b, &addr, sizeof (addr)); + resolv_response_close_record (b); + } + break; + case T_AAAA: + { + char addr[16] + = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, + index >> 16, index >> 8, index}; + resolv_response_open_record (b, qname, qclass, qtype, 0); + resolv_response_add_data (b, &addr, sizeof (addr)); + resolv_response_close_record (b); + } + } + } + break; + } +} + +/* Update *DATA with data from ADDRESS of SIZE. Set the corresponding + flag in SHADOW for each byte written. */ +static struct response_data * +decode_address (const void *address, size_t size) +{ + switch (size) + { + case 4: + TEST_VERIFY (memcmp (address, "\x0a", 1) == 0); + break; + case 16: + TEST_VERIFY (memcmp (address, "\x20\x01\x0d\xb8", 4) == 0); + break; + default: + FAIL_EXIT1 ("unexpected address size %zu", size); + } + const unsigned char *addr = address; + unsigned int index = addr[size - 3] * 256 * 256 + + addr[size - 2] * 256 + + addr[size - 1]; + return get_response (index); +} + +static struct response_data * +decode_hostent (struct hostent *e) +{ + TEST_VERIFY_EXIT (e != NULL); + TEST_VERIFY_EXIT (e->h_addr_list[0] != NULL); + TEST_VERIFY (e->h_addr_list[1] == NULL); + return decode_address (e->h_addr_list[0], e->h_length); +} + +static struct response_data * +decode_addrinfo (struct addrinfo *ai, int family) +{ + struct response_data *data = NULL; + while (ai != NULL) + { + if (ai->ai_family == family) + { + struct response_data *new_data; + switch (family) + { + case AF_INET: + { + struct sockaddr_in *pin = (struct sockaddr_in *) ai->ai_addr; + new_data = decode_address (&pin->sin_addr.s_addr, 4); + } + break; + case AF_INET6: + { + struct sockaddr_in6 *pin = (struct sockaddr_in6 *) ai->ai_addr; + new_data = decode_address (&pin->sin6_addr.s6_addr, 16); + } + break; + default: + FAIL_EXIT1 ("invalid address family %d", ai->ai_family); + } + if (data == NULL) + data = new_data; + else + /* Check pointer equality because this should be the same + response (same index). */ + TEST_VERIFY (data == new_data); + } + ai = ai->ai_next; + } + TEST_VERIFY_EXIT (data != NULL); + return data; +} + +/* Updated by the main test loop in accordance with what is set in + _res.options. */ +static bool use_edns; +static bool use_dnssec; + +/* Verify the decoded response data against the flags above. */ +static void +verify_response_data_payload (struct response_data *data, + size_t expected_payload) +{ + bool edns = use_edns || use_dnssec; + TEST_VERIFY (data->edns.active == edns); + if (!edns) + expected_payload = 0; + if (data->edns.payload_size != expected_payload) + { + support_record_failure (); + printf ("error: unexpected payload size %d (edns=%d)\n", + (int) data->edns.payload_size, edns); + } + uint16_t expected_flags = 0; + if (use_dnssec) + expected_flags |= 0x8000; /* DO flag. */ + if (data->edns.flags != expected_flags) + { + support_record_failure (); + printf ("error: unexpected EDNS flags 0x%04x (edns=%d)\n", + (int) data->edns.flags, edns); + } +} + +/* Same as verify_response_data_payload, but use the default + payload. */ +static void +verify_response_data (struct response_data *data) +{ + verify_response_data_payload (data, 1200); +} + +static void +check_hostent (struct hostent *e) +{ + TEST_VERIFY_EXIT (e != NULL); + verify_response_data (decode_hostent (e)); +} + +static void +do_ai (int family) +{ + struct addrinfo hints = { .ai_family = family }; + struct addrinfo *ai; + int ret = getaddrinfo (EDNS_PROBE_EXAMPLE, "80", &hints, &ai); + TEST_VERIFY_EXIT (ret == 0); + switch (family) + { + case AF_INET: + case AF_INET6: + verify_response_data (decode_addrinfo (ai, family)); + break; + case AF_UNSPEC: + verify_response_data (decode_addrinfo (ai, AF_INET)); + verify_response_data (decode_addrinfo (ai, AF_INET6)); + break; + default: + FAIL_EXIT1 ("invalid address family %d", family); + } + freeaddrinfo (ai); +} + +enum res_op +{ + res_op_search, + res_op_query, + res_op_querydomain, + res_op_nsearch, + res_op_nquery, + res_op_nquerydomain, + + res_op_last = res_op_nquerydomain, +}; + +static const char * +res_op_string (enum res_op op) +{ + switch (op) + { + case res_op_search: + return "res_search"; + case res_op_query: + return "res_query"; + case res_op_querydomain: + return "res_querydomain"; + case res_op_nsearch: + return "res_nsearch"; + case res_op_nquery: + return "res_nquery"; + case res_op_nquerydomain: + return "res_nquerydomain"; + } + FAIL_EXIT1 ("invalid res_op value %d", (int) op); +} + +/* Call libresolv function OP to look up PROBE_NAME, with an answer + buffer of SIZE bytes. Check that the advertised UDP buffer size is + in fact EXPECTED_BUFFER_SIZE. */ +static void +do_res_search (const char *probe_name, enum res_op op, size_t size, + size_t expected_buffer_size) +{ + if (test_verbose) + printf ("info: testing %s with buffer size %zu\n", + res_op_string (op), size); + unsigned char *buffer = xmalloc (size); + int ret = -1; + switch (op) + { + case res_op_search: + ret = res_search (probe_name, C_IN, T_A, buffer, size); + break; + case res_op_query: + ret = res_query (probe_name, C_IN, T_A, buffer, size); + break; + case res_op_nsearch: + ret = res_nsearch (&_res, probe_name, C_IN, T_A, buffer, size); + break; + case res_op_nquery: + ret = res_nquery (&_res, probe_name, C_IN, T_A, buffer, size); + break; + case res_op_querydomain: + case res_op_nquerydomain: + { + char *example_stripped = xstrdup (probe_name); + char *dot_example = strstr (example_stripped, ".example"); + if (dot_example != NULL && strcmp (dot_example, ".example") == 0) + { + /* Truncate the domain name. */ + *dot_example = '\0'; + if (op == res_op_querydomain) + ret = res_querydomain + (example_stripped, "example", C_IN, T_A, buffer, size); + else + ret = res_nquerydomain + (&_res, example_stripped, "example", C_IN, T_A, buffer, size); + } + else + FAIL_EXIT1 ("invalid probe name: %s", probe_name); + free (example_stripped); + } + break; + } + TEST_VERIFY_EXIT (ret > 12); + unsigned char *end = buffer + ret; + + HEADER *hd = (HEADER *) buffer; + TEST_VERIFY (ntohs (hd->qdcount) == 1); + TEST_VERIFY (ntohs (hd->ancount) == 1); + /* Skip over the header. */ + unsigned char *p = buffer + sizeof (*hd); + /* Skip over the question. */ + ret = dn_skipname (p, end); + TEST_VERIFY_EXIT (ret > 0); + p += ret; + TEST_VERIFY_EXIT (end - p >= 4); + p += 4; + /* Skip over the RNAME and the RR header, but stop at the RDATA + length. */ + ret = dn_skipname (p, end); + TEST_VERIFY_EXIT (ret > 0); + p += ret; + TEST_VERIFY_EXIT (end - p >= 2 + 2 + 4 + 2 + 4); + p += 2 + 2 + 4; + /* The IP address should be 4 bytes long. */ + TEST_VERIFY_EXIT (p[0] == 0); + TEST_VERIFY_EXIT (p[1] == 4); + /* Extract the address information. */ + p += 2; + struct response_data *data = decode_address (p, 4); + + verify_response_data_payload (data, expected_buffer_size); + + free (buffer); +} + +static void +run_test (const char *probe_name) +{ + if (test_verbose) + printf ("\ninfo: * use_edns=%d use_dnssec=%d\n", + use_edns, use_dnssec); + check_hostent (gethostbyname (probe_name)); + check_hostent (gethostbyname2 (probe_name, AF_INET)); + check_hostent (gethostbyname2 (probe_name, AF_INET6)); + do_ai (AF_UNSPEC); + do_ai (AF_INET); + do_ai (AF_INET6); + + for (int op = 0; op <= res_op_last; ++op) + { + do_res_search (probe_name, op, 301, 512); + do_res_search (probe_name, op, 511, 512); + do_res_search (probe_name, op, 512, 512); + do_res_search (probe_name, op, 513, 513); + do_res_search (probe_name, op, 657, 657); + do_res_search (probe_name, op, 1199, 1199); + do_res_search (probe_name, op, 1200, 1200); + do_res_search (probe_name, op, 1201, 1200); + do_res_search (probe_name, op, 65535, 1200); + } +} + +static int +do_test (void) +{ + for (int do_edns = 0; do_edns < 2; ++do_edns) + for (int do_dnssec = 0; do_dnssec < 2; ++do_dnssec) + for (int do_tcp = 0; do_tcp < 2; ++do_tcp) + { + struct resolv_test *aux = resolv_test_start + ((struct resolv_redirect_config) + { + .response_callback = response, + }); + + use_edns = do_edns; + if (do_edns) + _res.options |= RES_USE_EDNS0; + use_dnssec = do_dnssec; + if (do_dnssec) + _res.options |= RES_USE_DNSSEC; + + char *probe_name = xstrdup (EDNS_PROBE_EXAMPLE); + if (do_tcp) + { + char *n = xasprintf ("tcp.%s", probe_name); + free (probe_name); + probe_name = n; + } + + run_test (probe_name); + + free (probe_name); + resolv_test_end (aux); + } + + free_response_data (); + return 0; +} + +#include diff --git a/support/resolv_test.c b/support/resolv_test.c index 2d0ea3c..6b3554f 100644 --- a/support/resolv_test.c +++ b/support/resolv_test.c @@ -428,6 +428,7 @@ struct query_info char qname[MAXDNAME]; uint16_t qclass; uint16_t qtype; + struct resolv_edns_info edns; }; /* Update *INFO from the specified DNS packet. */ @@ -435,10 +436,26 @@ static void parse_query (struct query_info *info, const unsigned char *buffer, size_t length) { - if (length < 12) + HEADER hd; + _Static_assert (sizeof (hd) == 12, "DNS header size"); + if (length < sizeof (hd)) FAIL_EXIT1 ("malformed DNS query: too short: %zu bytes", length); - - int ret = dn_expand (buffer, buffer + length, buffer + 12, + memcpy (&hd, buffer, sizeof (hd)); + + if (ntohs (hd.qdcount) != 1) + FAIL_EXIT1 ("malformed DNS query: wrong question count: %d", + (int) ntohs (hd.qdcount)); + if (ntohs (hd.ancount) != 0) + FAIL_EXIT1 ("malformed DNS query: wrong answer count: %d", + (int) ntohs (hd.ancount)); + if (ntohs (hd.nscount) != 0) + FAIL_EXIT1 ("malformed DNS query: wrong authority count: %d", + (int) ntohs (hd.nscount)); + if (ntohs (hd.arcount) > 1) + FAIL_EXIT1 ("malformed DNS query: wrong additional count: %d", + (int) ntohs (hd.arcount)); + + int ret = dn_expand (buffer, buffer + length, buffer + sizeof (hd), info->qname, sizeof (info->qname)); if (ret < 0) FAIL_EXIT1 ("malformed DNS query: cannot uncompress QNAME"); @@ -456,6 +473,37 @@ parse_query (struct query_info *info, memcpy (&qtype_qclass, buffer + 12 + ret, sizeof (qtype_qclass)); info->qclass = ntohs (qtype_qclass.qclass); info->qtype = ntohs (qtype_qclass.qtype); + + memset (&info->edns, 0, sizeof (info->edns)); + if (ntohs (hd.arcount) > 0) + { + /* Parse EDNS record. */ + struct __attribute__ ((packed, aligned (1))) + { + uint8_t root; + uint16_t rtype; + uint16_t payload; + uint8_t edns_extended_rcode; + uint8_t edns_version; + uint16_t flags; + uint16_t rdatalen; + } rr; + _Static_assert (sizeof (rr) == 11, "EDNS record size"); + + if (remaining < 4 + sizeof (rr)) + FAIL_EXIT1 ("mailformed DNS query: no room for EDNS record"); + memcpy (&rr, buffer + 12 + ret + 4, sizeof (rr)); + if (rr.root != 0) + FAIL_EXIT1 ("malformed DNS query: invalid OPT RNAME: %d\n", rr.root); + if (rr.rtype != htons (41)) + FAIL_EXIT1 ("malformed DNS query: invalid OPT type: %d\n", + ntohs (rr.rtype)); + info->edns.active = true; + info->edns.extended_rcode = rr.edns_extended_rcode; + info->edns.version = rr.edns_version; + info->edns.flags = ntohs (rr.flags); + info->edns.payload_size = ntohs (rr.payload); + } } @@ -585,6 +633,7 @@ server_thread_udp_process_one (struct resolv_test *obj, int server_index) .query_length = length, .server_index = server_index, .tcp = false, + .edns = qinfo.edns, }; struct resolv_response_builder *b = response_builder_allocate (query, length); obj->config.response_callback @@ -820,6 +869,7 @@ server_thread_tcp_client (void *arg) .query_length = query_length, .server_index = closure->server_index, .tcp = true, + .edns = qinfo.edns, }; struct resolv_response_builder *b = response_builder_allocate (query_buffer, query_length); diff --git a/support/resolv_test.h b/support/resolv_test.h index 7a9f1f7..6498751 100644 --- a/support/resolv_test.h +++ b/support/resolv_test.h @@ -25,6 +25,16 @@ __BEGIN_DECLS +/* Information about EDNS properties of a DNS query. */ +struct resolv_edns_info +{ + bool active; + uint8_t extended_rcode; + uint8_t version; + uint16_t flags; + uint16_t payload_size; +}; + /* This struct provides context information when the response callback specified in struct resolv_redirect_config is invoked. */ struct resolv_response_context @@ -33,6 +43,7 @@ struct resolv_response_context size_t query_length; int server_index; bool tcp; + struct resolv_edns_info edns; }; /* This opaque struct is used to construct responses from within the commit 02aaa3c749bf18a3dbafff4c1f0180f135cad7ed Author: Florian Weimer Date: Mon Aug 21 16:15:47 2017 +0200 assert: Support types without operator== (int) [BZ #21972] (cherry picked from commit b5889d25e9bf944a89fdd7bcabf3b6c6f6bb6f7c) diff --git a/ChangeLog b/ChangeLog index 2bb46f4..de780da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2017-08-21 Florian Weimer + + [BZ #21972] + * assert/assert.h (assert): Use static_cast (bool) for C++. + Use the ternary operator in the warning branch for GNU C. + * assert/Makefile (tests): Add tst-assert-c++, tst-assert-g++. + (CFLAGS-tst-assert-c++.o): Compile in C++11 mode. + (CFLAGS-tst-assert-g++.o): Compile in GnU C++11 mode. + (LDLIBS-tst-assert-c++, LDLIBS-tst-assert-g++): Link with libstdc++. + * assert/tst-assert-c++.cc, assert/tst-assert-g++.cc: New files. + 2017-04-13 Florian Weimer [BZ #21361] diff --git a/NEWS b/NEWS index a2435cc..6abe902 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ The following bugs are resolved with this release: [21289] Fix symbol redirect for fts_set [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) + [21972] assert macro requires operator== (int) for its argument type Version 2.25 diff --git a/assert/Makefile b/assert/Makefile index 1c3be9b..9ec1be8 100644 --- a/assert/Makefile +++ b/assert/Makefile @@ -25,6 +25,15 @@ include ../Makeconfig headers := assert.h routines := assert assert-perr __assert -tests := test-assert test-assert-perr +tests := test-assert test-assert-perr tst-assert-c++ tst-assert-g++ include ../Rules + +ifeq ($(have-cxx-thread_local),yes) +CFLAGS-tst-assert-c++.o = -std=c++11 +LDLIBS-tst-assert-c++ = -lstdc++ +CFLAGS-tst-assert-g++.o = -std=gnu++11 +LDLIBS-tst-assert-g++ = -lstdc++ +else +tests-unsupported += tst-assert-c++ tst-assert-g++ +endif diff --git a/assert/assert.h b/assert/assert.h index 6801cfe..640c95c 100644 --- a/assert/assert.h +++ b/assert/assert.h @@ -85,7 +85,12 @@ __END_DECLS /* When possible, define assert so that it does not add extra parentheses around EXPR. Otherwise, those added parentheses would suppress warnings we'd expect to be detected by gcc's -Wparentheses. */ -# if !defined __GNUC__ || defined __STRICT_ANSI__ +# if defined __cplusplus +# define assert(expr) \ + (static_cast (expr) \ + ? void (0) \ + : __assert_fail (#expr, __FILE__, __LINE__, __ASSERT_FUNCTION)) +# elif !defined __GNUC__ || defined __STRICT_ANSI__ # define assert(expr) \ ((expr) \ ? __ASSERT_VOID_CAST (0) \ @@ -93,12 +98,11 @@ __END_DECLS # else /* The first occurrence of EXPR is not evaluated due to the sizeof, but will trigger any pedantic warnings masked by the __extension__ - for the second occurrence. The explicit comparison against zero is - required to support function pointers and bit fields in this - context, and to suppress the evaluation of variable length - arrays. */ + for the second occurrence. The ternary operator is required to + support function pointers and bit fields in this context, and to + suppress the evaluation of variable length arrays. */ # define assert(expr) \ - ((void) sizeof ((expr) == 0), __extension__ ({ \ + ((void) sizeof ((expr) ? 1 : 0), __extension__ ({ \ if (expr) \ ; /* empty */ \ else \ diff --git a/assert/tst-assert-c++.cc b/assert/tst-assert-c++.cc new file mode 100644 index 0000000..12a5e69 --- /dev/null +++ b/assert/tst-assert-c++.cc @@ -0,0 +1,78 @@ +/* Tests for interactions between C++ and assert. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +/* The C++ standard requires that if the assert argument is a constant + subexpression, then the assert itself is one, too. */ +constexpr int +check_constexpr () +{ + return (assert (true), 1); +} + +/* Objects of this class can be contextually converted to bool, but + cannot be compared to int. */ +struct no_int +{ + no_int () = default; + no_int (const no_int &) = delete; + + explicit operator bool () const + { + return true; + } + + bool operator! () const; /* No definition. */ + template bool operator== (T) const; /* No definition. */ + template bool operator!= (T) const; /* No definition. */ +}; + +/* This class tests that operator== is not used by assert. */ +struct bool_and_int +{ + bool_and_int () = default; + bool_and_int (const no_int &) = delete; + + explicit operator bool () const + { + return true; + } + + bool operator! () const; /* No definition. */ + template bool operator== (T) const; /* No definition. */ + template bool operator!= (T) const; /* No definition. */ +}; + +static int +do_test () +{ + { + no_int value; + assert (value); + } + + { + bool_and_int value; + assert (value); + } + + return 0; +} + +#include diff --git a/assert/tst-assert-g++.cc b/assert/tst-assert-g++.cc new file mode 100644 index 0000000..8c06402 --- /dev/null +++ b/assert/tst-assert-g++.cc @@ -0,0 +1,19 @@ +/* Tests for interactions between C++ and assert. GNU C++11 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include commit 92a0e0c6175cdc8d46d2f6efb51c62bd81bf897e Author: Florian Weimer Date: Mon Aug 28 14:38:52 2017 +0200 Synchronize support/ infrastructure with master This commit updates the support/ subdirectory to commit faf8c066df0d6bccb54bd74dd696eeb65e1b3bbc on the master branch. diff --git a/scripts/backport-support.sh b/scripts/backport-support.sh new file mode 100644 index 0000000..2ece7ce --- /dev/null +++ b/scripts/backport-support.sh @@ -0,0 +1,110 @@ +#!/bin/bash +# Create a patch which backports the support/ subdirectory. +# 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 +# . + +# This script does not backport the Makefile tweaks outside the +# support/ directory (which need to be backported separately), or the +# changes to test-skeleton.c (which should not be backported). + +set -e + +export LC_ALL=C +export GIT_CONFIG=/dev/null +export GTT_CONFIG_NOSYSTEM=0 +export GIT_PAGER= + +usage () { + cat >&2 <&2 + echo "# rm -rf $patch_targets" >&2 +} + +command_commit () { + git status --porcelain | while read line ; do + echo "error: working copy is not clean, cannot commit" >&2 + exit 1 + done + for path in $patch_targets; do + echo "# Processing $path" >&2 + case "$path" in + [a-zA-Z0-9]*/) + # Directory. + git rm --cached --ignore-unmatch -r "$path" + rm -rf "$path" + git read-tree --prefix="$path" "$latest_commit":"$path" + git checkout "$path" + ;; + *) + # File. + git show "$latest_commit":"$path" > "$path" + git add "$path" + esac + done + git commit -m "Synchronize support/ infrastructure with $branch_name + +This commit updates the support/ subdirectory to +commit $latest_commit +on the $branch_name branch. +" +} + +command_$command diff --git a/support/Makefile b/support/Makefile index 2ace559..2ace3fa 100644 --- a/support/Makefile +++ b/support/Makefile @@ -35,7 +35,12 @@ libsupport-routines = \ oom_error \ resolv_test \ set_fortify_handler \ + support-xstat \ support_become_root \ + support_can_chroot \ + support_capture_subprocess \ + support_capture_subprocess_check \ + support_chroot \ support_enter_network_namespace \ support_format_address_family \ support_format_addrinfo \ @@ -43,17 +48,24 @@ libsupport-routines = \ support_format_herrno \ support_format_hostent \ support_format_netent \ + support_isolate_in_subprocess \ support_record_failure \ support_run_diff \ + support_shared_allocate \ + support_write_file_string \ support_test_main \ support_test_verify_impl \ temp_file \ write_message \ xaccept \ + xaccept4 \ xasprintf \ xbind \ xcalloc \ + xchroot \ + xclose \ xconnect \ + xdup2 \ xfclose \ xfopen \ xfork \ @@ -61,13 +73,18 @@ libsupport-routines = \ xlisten \ xmalloc \ xmemstream \ + xmkdir \ xmmap \ + xmprotect \ xmunmap \ + xopen \ + xpipe \ xpoll \ xpthread_attr_destroy \ xpthread_attr_init \ xpthread_attr_setdetachstate \ xpthread_attr_setstacksize \ + xpthread_attr_setguardsize \ xpthread_barrier_destroy \ xpthread_barrier_init \ xpthread_barrier_wait \ @@ -89,6 +106,12 @@ libsupport-routines = \ xpthread_mutexattr_setrobust \ xpthread_mutexattr_settype \ xpthread_once \ + xpthread_rwlock_init \ + xpthread_rwlock_rdlock \ + xpthread_rwlock_wrlock \ + xpthread_rwlock_unlock \ + xpthread_rwlockattr_init \ + xpthread_rwlockattr_setkind_np \ xpthread_sigmask \ xpthread_spin_lock \ xpthread_spin_unlock \ @@ -111,6 +134,8 @@ endif tests = \ README-testing \ tst-support-namespace \ + tst-support_capture_subprocess \ + tst-support_format_dns_packet \ tst-support_record_failure \ ifeq ($(run-built-tests),yes) @@ -125,4 +150,6 @@ $(objpfx)tst-support_record_failure-2.out: tst-support_record_failure-2.sh \ $(evaluate-test) endif +$(objpfx)tst-support_format_dns_packet: $(common-objpfx)resolv/libresolv.so + include ../Rules diff --git a/support/capture_subprocess.h b/support/capture_subprocess.h new file mode 100644 index 0000000..43caf9b --- /dev/null +++ b/support/capture_subprocess.h @@ -0,0 +1,61 @@ +/* Capture output from a subprocess. + 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 + . */ + +#ifndef SUPPORT_CAPTURE_SUBPROCESS_H +#define SUPPORT_CAPTURE_SUBPROCESS_H + +#include + +struct support_capture_subprocess +{ + struct xmemstream out; + struct xmemstream err; + int status; +}; + +/* Invoke CALLBACK (CLOSURE) in a subprocess and capture standard + output, standard error, and the exit status. The out.buffer and + err.buffer members in the result are null-terminated strings which + can be examined by the caller (out.out and err.out are NULL). */ +struct support_capture_subprocess support_capture_subprocess + (void (*callback) (void *), void *closure); + +/* Deallocate the subprocess data captured by + support_capture_subprocess. */ +void support_capture_subprocess_free (struct support_capture_subprocess *); + +enum support_capture_allow +{ + /* No output is allowed. */ + sc_allow_none = 0x01, + /* Output to stdout is permitted. */ + sc_allow_stdout = 0x02, + /* Output to standard error is permitted. */ + sc_allow_stderr = 0x04, +}; + +/* Check that the subprocess exited with STATUS and that only the + allowed outputs happened. ALLOWED is a combination of + support_capture_allow flags. Report errors under the CONTEXT + message. */ +void support_capture_subprocess_check (struct support_capture_subprocess *, + const char *context, int status, + int allowed) + __attribute__ ((nonnull (1, 2))); + +#endif /* SUPPORT_CAPTURE_SUBPROCESS_H */ diff --git a/support/check.h b/support/check.h index 1d244a3..bdcd129 100644 --- a/support/check.h +++ b/support/check.h @@ -51,7 +51,7 @@ __BEGIN_DECLS if (expr) \ ; \ else \ - support_test_verify_impl (-1, __FILE__, __LINE__, #expr); \ + support_test_verify_impl (__FILE__, __LINE__, #expr); \ }) /* Record a test failure and exit if EXPR evaluates to false. */ @@ -60,7 +60,8 @@ __BEGIN_DECLS if (expr) \ ; \ else \ - support_test_verify_impl (1, __FILE__, __LINE__, #expr); \ + support_test_verify_exit_impl \ + (1, __FILE__, __LINE__, #expr); \ }) int support_print_failure_impl (const char *file, int line, @@ -70,8 +71,11 @@ void support_exit_failure_impl (int exit_status, const char *file, int line, const char *format, ...) __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5))); -void support_test_verify_impl (int status, const char *file, int line, +void support_test_verify_impl (const char *file, int line, const char *expr); +void support_test_verify_exit_impl (int status, const char *file, int line, + const char *expr) + __attribute__ ((noreturn)); /* Record a test failure. This function returns and does not terminate the process. The failure counter is stored in a shared diff --git a/support/namespace.h b/support/namespace.h index 6bc82d6..859c2fd 100644 --- a/support/namespace.h +++ b/support/namespace.h @@ -35,6 +35,13 @@ __BEGIN_DECLS single-threaded processes. */ bool support_become_root (void); +/* Return true if this process can perform a chroot operation. In + general, this is only possible if support_become_root has been + called. Note that the actual test is performed in a subprocess, + after fork, so that the file system root of the original process is + not changed. */ +bool support_can_chroot (void); + /* Enter a network namespace (and a UTS namespace if possible) and configure the loopback interface. Return true if a network namespace could be created. Print diagnostics to standard output. @@ -48,6 +55,43 @@ bool support_enter_network_namespace (void); UTS namespace. */ bool support_in_uts_namespace (void); +/* Invoke CALLBACK (CLOSURE) in a subprocess created using fork. + Terminate the calling process if the subprocess exits with a + non-zero exit status. */ +void support_isolate_in_subprocess (void (*callback) (void *), void *closure); + +/* Describe the setup of a chroot environment, for + support_chroot_create below. */ +struct support_chroot_configuration +{ + /* File contents. The files are not created if the field is + NULL. */ + const char *resolv_conf; +}; + +/* The result of the creation of a chroot. */ +struct support_chroot +{ + /* Path information. All these paths are relative to the parent + chroot. */ + + /* Path to the chroot directory. */ + char *path_chroot; + + /* Path to the /etc/resolv.conf file. */ + char *path_resolv_conf; +}; + +/* Create a chroot environment. The returned data should be freed + using support_chroot_free below. The files will be deleted when + the process exits. This function does not enter the chroot. */ +struct support_chroot *support_chroot_create + (struct support_chroot_configuration); + +/* Deallocate the chroot information created by + support_chroot_create. */ +void support_chroot_free (struct support_chroot *); + __END_DECLS #endif diff --git a/support/resolv_test.c b/support/resolv_test.c index 6b3554f..1625dcf 100644 --- a/support/resolv_test.c +++ b/support/resolv_test.c @@ -32,9 +32,11 @@ #include #include #include +#include +#include #include -/* Response builder. */ +/* Response builder. */ enum { @@ -910,7 +912,7 @@ server_thread_tcp_client (void *arg) break; } - close (closure->client_socket); + xclose (closure->client_socket); free (closure); return NULL; } @@ -931,7 +933,7 @@ server_thread_tcp (struct resolv_test *obj, int server_index) if (obj->termination_requested) { xpthread_mutex_unlock (&obj->lock); - close (client_socket); + xclose (client_socket); break; } xpthread_mutex_unlock (&obj->lock); @@ -991,8 +993,8 @@ make_server_sockets (struct resolv_test_server *server) next local UDP address randomly. */ if (errno == EADDRINUSE) { - close (server->socket_udp); - close (server->socket_tcp); + xclose (server->socket_udp); + xclose (server->socket_tcp); continue; } FAIL_EXIT1 ("TCP bind: %m"); @@ -1002,6 +1004,29 @@ make_server_sockets (struct resolv_test_server *server) } } +/* Like make_server_sockets, but the caller supplies the address to + use. */ +static void +make_server_sockets_for_address (struct resolv_test_server *server, + const struct sockaddr *addr) +{ + server->socket_udp = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + server->socket_tcp = xsocket (AF_INET, SOCK_STREAM, IPPROTO_TCP); + + if (addr->sa_family == AF_INET) + server->address = *(const struct sockaddr_in *) addr; + else + /* We cannot store the server address in the socket. This should + not matter if disable_redirect is used. */ + server->address = (struct sockaddr_in) { .sin_family = 0, }; + + xbind (server->socket_udp, + (struct sockaddr *)&server->address, sizeof (server->address)); + xbind (server->socket_tcp, + (struct sockaddr *)&server->address, sizeof (server->address)); + xlisten (server->socket_tcp, 5); +} + /* One-time initialization of NSS. */ static void resolv_redirect_once (void) @@ -1062,11 +1087,17 @@ resolv_test_start (struct resolv_redirect_config config) .lock = PTHREAD_MUTEX_INITIALIZER, }; - resolv_test_init (); + if (!config.disable_redirect) + resolv_test_init (); /* Create all the servers, to reserve the necessary ports. */ for (int server_index = 0; server_index < config.nscount; ++server_index) - make_server_sockets (obj->servers + server_index); + if (config.disable_redirect && config.server_address_overrides != NULL) + make_server_sockets_for_address + (obj->servers + server_index, + config.server_address_overrides[server_index]); + else + make_server_sockets (obj->servers + server_index); /* Start server threads. Disable the server ports, as requested. */ @@ -1075,7 +1106,7 @@ resolv_test_start (struct resolv_redirect_config config) struct resolv_test_server *server = obj->servers + server_index; if (config.servers[server_index].disable_udp) { - close (server->socket_udp); + xclose (server->socket_udp); server->socket_udp = -1; } else if (!config.single_thread_udp) @@ -1083,7 +1114,7 @@ resolv_test_start (struct resolv_redirect_config config) server_thread_udp); if (config.servers[server_index].disable_tcp) { - close (server->socket_tcp); + xclose (server->socket_tcp); server->socket_tcp = -1; } else @@ -1093,6 +1124,9 @@ resolv_test_start (struct resolv_redirect_config config) if (config.single_thread_udp) start_server_thread_udp_single (obj); + if (config.disable_redirect) + return obj; + int timeout = 1; /* Initialize libresolv. */ @@ -1127,6 +1161,7 @@ resolv_test_start (struct resolv_redirect_config config) } for (int server_index = 0; server_index < config.nscount; ++server_index) { + TEST_VERIFY_EXIT (obj->servers[server_index].address.sin_port != 0); _res.nsaddr_list[server_index] = obj->servers[server_index].address; if (test_verbose) { @@ -1164,7 +1199,7 @@ resolv_test_end (struct resolv_test *obj) xsendto (sock, "", 1, 0, (struct sockaddr *) &obj->servers[server_index].address, sizeof (obj->servers[server_index].address)); - close (sock); + xclose (sock); } if (!obj->config.servers[server_index].disable_tcp) { @@ -1172,7 +1207,7 @@ resolv_test_end (struct resolv_test *obj) xconnect (sock, (struct sockaddr *) &obj->servers[server_index].address, sizeof (obj->servers[server_index].address)); - close (sock); + xclose (sock); } } @@ -1187,12 +1222,12 @@ resolv_test_end (struct resolv_test *obj) { if (!obj->config.single_thread_udp) xpthread_join (obj->servers[server_index].thread_udp); - close (obj->servers[server_index].socket_udp); + xclose (obj->servers[server_index].socket_udp); } if (!obj->config.servers[server_index].disable_tcp) { xpthread_join (obj->servers[server_index].thread_tcp); - close (obj->servers[server_index].socket_tcp); + xclose (obj->servers[server_index].socket_tcp); } } diff --git a/support/resolv_test.h b/support/resolv_test.h index 6498751..b953dc1 100644 --- a/support/resolv_test.h +++ b/support/resolv_test.h @@ -93,6 +93,16 @@ struct resolv_redirect_config may results in more predictable ordering of queries and responses. */ bool single_thread_udp; + + /* Do not rewrite the _res variable or change NSS defaults. Use + server_address_overrides below to tell the testing framework on + which addresses to create the servers. */ + bool disable_redirect; + + /* Use these addresses for creating the DNS servers. The array must + have ns_count (or resolv_max_test_servers) sockaddr * elements if + not NULL. */ + const struct sockaddr *const *server_address_overrides; }; /* Configure NSS to use, nss_dns only for aplicable databases, and try diff --git a/support/support-xstat.c b/support/support-xstat.c new file mode 100644 index 0000000..86a81ec --- /dev/null +++ b/support/support-xstat.c @@ -0,0 +1,30 @@ +/* stat64 with error checking. + 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 + . */ + +/* NB: Non-standard file name to avoid sysdeps override for xstat. */ + +#include +#include +#include + +void +xstat (const char *path, struct stat64 *result) +{ + if (stat64 (path, result) != 0) + FAIL_EXIT1 ("stat64 (\"%s\"): %m", path); +} diff --git a/support/support.h b/support/support.h index 7292e2a..4b5f04c 100644 --- a/support/support.h +++ b/support/support.h @@ -44,6 +44,21 @@ void set_fortify_handler (void (*handler) (int sig)); void oom_error (const char *function, size_t size) __attribute__ ((nonnull (1))); +/* Return a pointer to a memory region of SIZE bytes. The memory is + initialized to zero and will be shared with subprocesses (across + fork). The returned pointer must be freed using + support_shared_free; it is not compatible with the malloc + functions. */ +void *support_shared_allocate (size_t size); + +/* Deallocate a pointer returned by support_shared_allocate. */ +void support_shared_free (void *); + +/* Write CONTENTS to the file PATH. Create or truncate the file as + needed. The file mode is 0666 masked by the umask. Terminate the + process on error. */ +void support_write_file_string (const char *path, const char *contents); + /* Error-checking wrapper functions which terminate the process on error. */ diff --git a/support/support_can_chroot.c b/support/support_can_chroot.c new file mode 100644 index 0000000..0dfd2de --- /dev/null +++ b/support/support_can_chroot.c @@ -0,0 +1,65 @@ +/* Return true if the process can perform a chroot operation. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +static void +callback (void *closure) +{ + int *result = closure; + struct stat64 before; + xstat ("/dev", &before); + if (chroot ("/dev") != 0) + { + *result = errno; + return; + } + struct stat64 after; + xstat ("/", &after); + TEST_VERIFY (before.st_dev == after.st_dev); + TEST_VERIFY (before.st_ino == after.st_ino); + *result = 0; +} + +bool +support_can_chroot (void) +{ + int *result = support_shared_allocate (sizeof (*result)); + *result = 0; + support_isolate_in_subprocess (callback, result); + bool ok = *result == 0; + if (!ok) + { + static bool already_warned; + if (!already_warned) + { + already_warned = true; + errno = *result; + printf ("warning: this process does not support chroot: %m\n"); + } + } + support_shared_free (result); + return ok; +} diff --git a/support/support_capture_subprocess.c b/support/support_capture_subprocess.c new file mode 100644 index 0000000..030f124 --- /dev/null +++ b/support/support_capture_subprocess.c @@ -0,0 +1,108 @@ +/* Capture output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include +#include +#include + +static void +transfer (const char *what, struct pollfd *pfd, struct xmemstream *stream) +{ + if (pfd->revents != 0) + { + char buf[1024]; + ssize_t ret = TEMP_FAILURE_RETRY (read (pfd->fd, buf, sizeof (buf))); + if (ret < 0) + { + support_record_failure (); + printf ("error: reading from subprocess %s: %m", what); + pfd->events = 0; + pfd->revents = 0; + } + else if (ret == 0) + { + /* EOF reached. Stop listening. */ + pfd->events = 0; + pfd->revents = 0; + } + else + /* Store the data just read. */ + TEST_VERIFY (fwrite (buf, ret, 1, stream->out) == 1); + } +} + +struct support_capture_subprocess +support_capture_subprocess (void (*callback) (void *), void *closure) +{ + struct support_capture_subprocess result; + xopen_memstream (&result.out); + xopen_memstream (&result.err); + + int stdout_pipe[2]; + xpipe (stdout_pipe); + int stderr_pipe[2]; + xpipe (stderr_pipe); + + TEST_VERIFY (fflush (stdout) == 0); + TEST_VERIFY (fflush (stderr) == 0); + + pid_t pid = xfork (); + if (pid == 0) + { + xclose (stdout_pipe[0]); + xclose (stderr_pipe[0]); + xdup2 (stdout_pipe[1], STDOUT_FILENO); + xdup2 (stderr_pipe[1], STDERR_FILENO); + callback (closure); + _exit (0); + } + xclose (stdout_pipe[1]); + xclose (stderr_pipe[1]); + + struct pollfd fds[2] = + { + { .fd = stdout_pipe[0], .events = POLLIN }, + { .fd = stderr_pipe[0], .events = POLLIN }, + }; + + do + { + xpoll (fds, 2, -1); + transfer ("stdout", &fds[0], &result.out); + transfer ("stderr", &fds[1], &result.err); + } + while (fds[0].events != 0 || fds[1].events != 0); + xclose (stdout_pipe[0]); + xclose (stderr_pipe[0]); + + xfclose_memstream (&result.out); + xfclose_memstream (&result.err); + xwaitpid (pid, &result.status, 0); + return result; +} + +void +support_capture_subprocess_free (struct support_capture_subprocess *p) +{ + free (p->out.buffer); + free (p->err.buffer); +} diff --git a/support/support_capture_subprocess_check.c b/support/support_capture_subprocess_check.c new file mode 100644 index 0000000..e1cf73b --- /dev/null +++ b/support/support_capture_subprocess_check.c @@ -0,0 +1,67 @@ +/* Verify capture output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +static void +print_context (const char *context, bool *failed) +{ + if (*failed) + /* Do not duplicate message. */ + return; + support_record_failure (); + printf ("error: subprocess failed: %s\n", context); +} + +void +support_capture_subprocess_check (struct support_capture_subprocess *proc, + const char *context, int status, + int allowed) +{ + TEST_VERIFY ((allowed & sc_allow_none) + || (allowed & sc_allow_stdout) + || (allowed & sc_allow_stderr)); + TEST_VERIFY (!((allowed & sc_allow_none) + && ((allowed & sc_allow_stdout) + || (allowed & sc_allow_stderr)))); + + bool failed = false; + if (proc->status != status) + { + print_context (context, &failed); + printf ("error: expected exit status: %d\n", status); + printf ("error: actual exit status: %d\n", proc->status); + } + if (!(allowed & sc_allow_stdout) && proc->out.length != 0) + { + print_context (context, &failed); + printf ("error: unexpected output from subprocess\n"); + fwrite (proc->out.buffer, proc->out.length, 1, stdout); + puts ("\n"); + } + if (!(allowed & sc_allow_stderr) && proc->err.length != 0) + { + print_context (context, &failed); + printf ("error: unexpected error output from subprocess\n"); + fwrite (proc->err.buffer, proc->err.length, 1, stdout); + puts ("\n"); + } +} diff --git a/support/support_chroot.c b/support/support_chroot.c new file mode 100644 index 0000000..c0807b3 --- /dev/null +++ b/support/support_chroot.c @@ -0,0 +1,71 @@ +/* Setup a chroot environment for use within tests. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +struct support_chroot * +support_chroot_create (struct support_chroot_configuration conf) +{ + struct support_chroot *chroot = xmalloc (sizeof (*chroot)); + + chroot->path_chroot = xasprintf ("%s/tst-resolv-res_init-XXXXXX", test_dir); + if (mkdtemp (chroot->path_chroot) == NULL) + FAIL_EXIT1 ("mkdtemp (\"%s\"): %m", chroot->path_chroot); + add_temp_file (chroot->path_chroot); + + /* Create the /etc directory in the chroot environment. */ + char *path_etc = xasprintf ("%s/etc", chroot->path_chroot); + xmkdir (path_etc, 0777); + add_temp_file (path_etc); + + if (conf.resolv_conf != NULL) + { + /* Create an empty resolv.conf file. */ + chroot->path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc); + add_temp_file (chroot->path_resolv_conf); + support_write_file_string (chroot->path_resolv_conf, conf.resolv_conf); + } + else + chroot->path_resolv_conf = NULL; + + free (path_etc); + + /* valgrind needs a temporary directory in the chroot. */ + { + char *path_tmp = xasprintf ("%s/tmp", chroot->path_chroot); + xmkdir (path_tmp, 0777); + add_temp_file (path_tmp); + free (path_tmp); + } + + return chroot; +} + +void +support_chroot_free (struct support_chroot *chroot) +{ + free (chroot->path_chroot); + free (chroot->path_resolv_conf); + free (chroot); +} diff --git a/support/support_enter_network_namespace.c b/support/support_enter_network_namespace.c index d2e78fe..28b0ee2 100644 --- a/support/support_enter_network_namespace.c +++ b/support/support_enter_network_namespace.c @@ -23,9 +23,10 @@ #include #include #include +#include +#include #include #include -#include static bool in_uts_namespace; @@ -58,7 +59,7 @@ support_enter_network_namespace (void) req.ifr_flags |= IFF_UP | IFF_RUNNING; TEST_VERIFY_EXIT (ioctl (fd, SIOCSIFFLAGS, &req) == 0); } - close (fd); + xclose (fd); return !already_up; } diff --git a/support/support_format_addrinfo.c b/support/support_format_addrinfo.c index 262e0df..eedb030 100644 --- a/support/support_format_addrinfo.c +++ b/support/support_format_addrinfo.c @@ -39,8 +39,8 @@ socket_address_length (int family) } static void -format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name, - int * flags_printed) +format_ai_flags_1 (FILE *out, struct addrinfo *ai, int flag, const char *name, + int * flags_printed) { if ((ai->ai_flags & flag) != 0) fprintf (out, " %s", name); @@ -48,14 +48,16 @@ format_ai_flags (FILE *out, struct addrinfo *ai, int flag, const char *name, } static void -format_ai_one (FILE *out, struct addrinfo *ai, int *flags) +format_ai_flags (FILE *out, struct addrinfo *ai) { - /* ai_flags */ - if (ai->ai_flags != *flags) + if (ai == NULL) + return; + + if (ai->ai_flags != 0) { fprintf (out, "flags:"); int flags_printed = 0; -#define FLAG(flag) format_ai_flags (out, ai, flag, #flag, &flags_printed) +#define FLAG(flag) format_ai_flags_1 (out, ai, flag, #flag, &flags_printed) FLAG (AI_PASSIVE); FLAG (AI_CANONNAME); FLAG (AI_NUMERICHOST); @@ -72,9 +74,47 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags) if (remaining != 0) fprintf (out, " %08x", remaining); fprintf (out, "\n"); - *flags = ai->ai_flags; } + /* Report flag mismatches within the list. */ + int flags = ai->ai_flags; + int index = 1; + ai = ai->ai_next; + while (ai != NULL) + { + if (ai->ai_flags != flags) + fprintf (out, "error: flags at %d: 0x%x expected, 0x%x actual\n", + index, flags, ai->ai_flags); + ai = ai->ai_next; + ++index; + } +} + +static void +format_ai_canonname (FILE *out, struct addrinfo *ai) +{ + if (ai == NULL) + return; + if (ai->ai_canonname != NULL) + fprintf (out, "canonname: %s\n", ai->ai_canonname); + + /* Report incorrectly set ai_canonname fields on subsequent list + entries. */ + int index = 1; + ai = ai->ai_next; + while (ai != NULL) + { + if (ai->ai_canonname != NULL) + fprintf (out, "error: canonname set at %d: %s\n", + index, ai->ai_canonname); + ai = ai->ai_next; + ++index; + } +} + +static void +format_ai_one (FILE *out, struct addrinfo *ai) +{ { char type_buf[32]; const char *type_str; @@ -156,20 +196,16 @@ format_ai_one (FILE *out, struct addrinfo *ai, int *flags) else fprintf (out, " %s %u\n", buf, ntohs (port)); } - - /* ai_canonname */ - if (ai->ai_canonname != NULL) - fprintf (out, "canonname: %s\n", ai->ai_canonname); } /* Format all the addresses in one address family. */ static void -format_ai_family (FILE *out, struct addrinfo *ai, int family, int *flags) +format_ai_family (FILE *out, struct addrinfo *ai, int family) { while (ai) { if (ai->ai_family == family) - format_ai_one (out, ai, flags); + format_ai_one (out, ai); ai = ai->ai_next; } } @@ -192,9 +228,10 @@ support_format_addrinfo (struct addrinfo *ai, int ret) } else { - int flags = 0; - format_ai_family (mem.out, ai, AF_INET, &flags); - format_ai_family (mem.out, ai, AF_INET6, &flags); + format_ai_flags (mem.out, ai); + format_ai_canonname (mem.out, ai); + format_ai_family (mem.out, ai, AF_INET); + format_ai_family (mem.out, ai, AF_INET6); } xfclose_memstream (&mem); diff --git a/support/support_format_dns_packet.c b/support/support_format_dns_packet.c index 21fe7e5..2992c57 100644 --- a/support/support_format_dns_packet.c +++ b/support/support_format_dns_packet.c @@ -174,7 +174,7 @@ support_format_dns_packet (const unsigned char *buffer, size_t length) goto out; } /* Skip non-matching record types. */ - if (rtype != qtype || rclass != qclass) + if ((rtype != qtype && rtype != T_CNAME) || rclass != qclass) continue; switch (rtype) { @@ -186,22 +186,29 @@ support_format_dns_packet (const unsigned char *buffer, size_t length) rdata.data[2], rdata.data[3]); else - fprintf (mem.out, "error: A record of size %d: %s\n", rdlen, rname.name); + fprintf (mem.out, "error: A record of size %d: %s\n", + rdlen, rname.name); break; case T_AAAA: { - char buf[100]; - if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL) - fprintf (mem.out, "error: AAAA record decoding failed: %m\n"); + if (rdlen == 16) + { + char buf[100]; + if (inet_ntop (AF_INET6, rdata.data, buf, sizeof (buf)) == NULL) + fprintf (mem.out, "error: AAAA record decoding failed: %m\n"); + else + fprintf (mem.out, "address: %s\n", buf); + } else - fprintf (mem.out, "address: %s\n", buf); + fprintf (mem.out, "error: AAAA record of size %d: %s\n", + rdlen, rname.name); } break; case T_CNAME: case T_PTR: { struct dname name; - if (extract_name (full, &in, &name)) + if (extract_name (full, &rdata, &name)) fprintf (mem.out, "name: %s\n", name.name); else fprintf (mem.out, "error: malformed CNAME/PTR record\n"); diff --git a/support/support_isolate_in_subprocess.c b/support/support_isolate_in_subprocess.c new file mode 100644 index 0000000..cf48614 --- /dev/null +++ b/support/support_isolate_in_subprocess.c @@ -0,0 +1,38 @@ +/* Run a function in a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void +support_isolate_in_subprocess (void (*callback) (void *), void *closure) +{ + pid_t pid = xfork (); + if (pid == 0) + { + /* Child process. */ + callback (closure); + _exit (0); + } + + /* Parent process. */ + int status; + xwaitpid (pid, &status, 0); + if (status != 0) + FAIL_EXIT1 ("child process exited with status %d", status); +} diff --git a/support/support_run_diff.c b/support/support_run_diff.c index 3085037..f5155de 100644 --- a/support/support_run_diff.c +++ b/support/support_run_diff.c @@ -24,8 +24,8 @@ #include #include #include +#include #include -#include static char * write_to_temp_file (const char *prefix, const char *str) @@ -36,7 +36,7 @@ write_to_temp_file (const char *prefix, const char *str) TEST_VERIFY_EXIT (fd >= 0); free (template); xwrite (fd, str, strlen (str)); - TEST_VERIFY_EXIT (close (fd) == 0); + xclose (fd); return name; } diff --git a/support/support_shared_allocate.c b/support/support_shared_allocate.c new file mode 100644 index 0000000..61d088e --- /dev/null +++ b/support/support_shared_allocate.c @@ -0,0 +1,57 @@ +/* Allocate a memory region shared across processes. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include + +/* Header for the allocation. It contains the size of the allocation + for subsequent unmapping. */ +struct header +{ + size_t total_size; + char data[] __attribute__ ((aligned (__alignof__ (max_align_t)))); +}; + +void * +support_shared_allocate (size_t size) +{ + size_t total_size = size + offsetof (struct header, data); + if (total_size < size) + { + errno = ENOMEM; + oom_error (__func__, size); + return NULL; + } + else + { + struct header *result = xmmap (NULL, total_size, PROT_READ | PROT_WRITE, + MAP_ANONYMOUS | MAP_SHARED, -1); + result->total_size = total_size; + return &result->data; + } +} + +void +support_shared_free (void *data) +{ + struct header *header = data - offsetof (struct header, data); + xmunmap (header, header->total_size); +} diff --git a/support/support_test_main.c b/support/support_test_main.c index 914d64f..3c411a4 100644 --- a/support/support_test_main.c +++ b/support/support_test_main.c @@ -211,7 +211,8 @@ support_test_main (int argc, char **argv, const struct test_config *config) mallopt (M_PERTURB, 42); } - while ((opt = getopt_long (argc, argv, "+", options, NULL)) != -1) + while ((opt = getopt_long (argc, argv, config->optstring, options, NULL)) + != -1) switch (opt) { case '?': diff --git a/support/support_test_verify_impl.c b/support/support_test_verify_impl.c index 5bae38f..55ab211 100644 --- a/support/support_test_verify_impl.c +++ b/support/support_test_verify_impl.c @@ -22,12 +22,16 @@ #include void -support_test_verify_impl (int status, const char *file, int line, - const char *expr) +support_test_verify_impl (const char *file, int line, const char *expr) { support_record_failure (); printf ("error: %s:%d: not true: %s\n", file, line, expr); - if (status >= 0) - exit (status); +} +void +support_test_verify_exit_impl (int status, const char *file, int line, + const char *expr) +{ + support_test_verify_impl (file, line, expr); + exit (status); } diff --git a/support/support_write_file_string.c b/support/support_write_file_string.c new file mode 100644 index 0000000..48e8959 --- /dev/null +++ b/support/support_write_file_string.c @@ -0,0 +1,39 @@ +/* Write a string to a file. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include + +void +support_write_file_string (const char *path, const char *contents) +{ + int fd = xopen (path, O_CREAT | O_TRUNC | O_WRONLY, 0666); + const char *end = contents + strlen (contents); + for (const char *p = contents; p < end; ) + { + ssize_t ret = write (fd, p, end - p); + if (ret < 0) + FAIL_EXIT1 ("cannot write to \"%s\": %m", path); + if (ret == 0) + FAIL_EXIT1 ("zero-length write to \"%s\"", path); + p += ret; + } + xclose (fd); +} diff --git a/support/temp_file.c b/support/temp_file.c index f06647a..fdb2477 100644 --- a/support/temp_file.c +++ b/support/temp_file.c @@ -25,16 +25,17 @@ #include #include -#include #include #include #include +#include /* List of temporary files. */ static struct temp_name_list { - struct qelem q; + struct temp_name_list *next; char *name; + pid_t owner; } *temp_name_list; /* Location of the temporary files. Set by the test skeleton via @@ -50,10 +51,9 @@ add_temp_file (const char *name) if (newname != NULL) { newp->name = newname; - if (temp_name_list == NULL) - temp_name_list = (struct temp_name_list *) &newp->q; - else - insque (newp, temp_name_list); + newp->next = temp_name_list; + newp->owner = getpid (); + temp_name_list = newp; } else free (newp); @@ -97,13 +97,22 @@ support_set_test_dir (const char *path) void support_delete_temp_files (void) { + pid_t pid = getpid (); while (temp_name_list != NULL) { - remove (temp_name_list->name); + /* Only perform the removal if the path was registed in the same + process, as identified by the PID. (This assumes that the + parent process which registered the temporary file sticks + around, to prevent PID reuse.) */ + if (temp_name_list->owner == pid) + { + if (remove (temp_name_list->name) != 0) + printf ("warning: could not remove temporary file: %s: %m\n", + temp_name_list->name); + } free (temp_name_list->name); - struct temp_name_list *next - = (struct temp_name_list *) temp_name_list->q.q_forw; + struct temp_name_list *next = temp_name_list->next; free (temp_name_list); temp_name_list = next; } @@ -116,9 +125,7 @@ support_print_temp_files (FILE *f) { struct temp_name_list *n; fprintf (f, "temp_files=(\n"); - for (n = temp_name_list; - n != NULL; - n = (struct temp_name_list *) n->q.q_forw) + for (n = temp_name_list; n != NULL; n = n->next) fprintf (f, " '%s'\n", n->name); fprintf (f, ")\n"); } diff --git a/support/test-driver.c b/support/test-driver.c index 482066d..47c387c 100644 --- a/support/test-driver.c +++ b/support/test-driver.c @@ -93,6 +93,10 @@ has this type: void CMDLINE_PROCESS (int); + + If the program also to process custom default short command line + argument (similar to getopt) it must define CMDLINE_OPTSTRING + with the expected options (for instance "vb"). */ #include @@ -151,6 +155,11 @@ main (int argc, char **argv) #ifdef CMDLINE_PROCESS test_config.cmdline_function = CMDLINE_PROCESS; #endif +#ifdef CMDLINE_OPTSTRING + test_config.optstring = "+" CMDLINE_OPTSTRING; +#else + test_config.optstring = "+"; +#endif return support_test_main (argc, argv, &test_config); } diff --git a/support/test-driver.h b/support/test-driver.h index af1971a..a8fe9c3 100644 --- a/support/test-driver.h +++ b/support/test-driver.h @@ -35,6 +35,7 @@ struct test_config int expected_status; /* Expected exit status. */ int expected_signal; /* If non-zero, expect termination by signal. */ char no_mallopt; /* Boolean flag to disable mallopt. */ + const char *optstring; /* Short command line options. */ }; enum diff --git a/support/tst-support-namespace.c b/support/tst-support-namespace.c index a50b074..dbe7cc0 100644 --- a/support/tst-support-namespace.c +++ b/support/tst-support-namespace.c @@ -16,18 +16,98 @@ License along with the GNU C Library; if not, see . */ +#include +#include #include +#include #include +#include +#include + +/* Check that the loopback interface provides multiple addresses which + can be used to run independent servers. */ +static void +test_localhost_bind (void) +{ + printf ("info: testing loopback interface with multiple addresses\n"); + + /* Create the two server addresses. */ + static const struct addrinfo hints = + { + .ai_family = AF_INET, + .ai_socktype = SOCK_DGRAM, + .ai_protocol = IPPROTO_UDP, + }; + struct addrinfo *ai[3]; + TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.1", "53", &hints, ai + 0) == 0); + TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.2", "53", &hints, ai + 1) == 0); + TEST_VERIFY_EXIT (getaddrinfo ("127.0.0.3", "53", &hints, ai + 2) == 0); + + /* Create the server scokets and bind them to these addresses. */ + int sockets[3]; + for (int i = 0; i < 3; ++i) + { + sockets[i] = xsocket + (ai[i]->ai_family, ai[i]->ai_socktype, ai[i]->ai_protocol); + xbind (sockets[i], ai[i]->ai_addr, ai[i]->ai_addrlen); + } + + /* Send two packets to each server. */ + int client = xsocket (AF_INET, SOCK_DGRAM, IPPROTO_UDP); + for (int i = 0; i < 3; ++i) + { + TEST_VERIFY (sendto (client, &i, sizeof (i), 0, + ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (i)); + int j = i + 256; + TEST_VERIFY (sendto (client, &j, sizeof (j), 0, + ai[i]->ai_addr, ai[i]->ai_addrlen) == sizeof (j)); + } + + /* Check that the packets can be received with the expected + contents. Note that the receive calls interleave differently, + which hopefully proves that the sockets are, indeed, + independent. */ + for (int i = 0; i < 3; ++i) + { + int buf; + TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf)); + TEST_VERIFY (buf == i); + } + for (int i = 0; i < 3; ++i) + { + int buf; + TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), 0) == sizeof (buf)); + TEST_VERIFY (buf == i + 256); + /* Check that there is no more data to receive. */ + TEST_VERIFY (recv (sockets[i], &buf, sizeof (buf), MSG_DONTWAIT) == -1); + TEST_VERIFY (errno == EWOULDBLOCK || errno == EAGAIN); + } + + /* Close all sockets and free the addresses. */ + for (int i = 0; i < 3; ++i) + { + freeaddrinfo (ai[i]); + xclose (sockets[i]); + } + xclose (client); +} + static int do_test (void) { - if (support_become_root ()) + bool root = support_become_root (); + if (root) printf ("info: acquired root-like privileges\n"); - if (support_enter_network_namespace ()) + bool netns = support_enter_network_namespace (); + if (netns) printf ("info: entered network namespace\n"); if (support_in_uts_namespace ()) printf ("info: also entered UTS namespace\n"); + + if (root && netns) + test_localhost_bind (); + return 0; } diff --git a/support/tst-support_capture_subprocess.c b/support/tst-support_capture_subprocess.c new file mode 100644 index 0000000..5672fba --- /dev/null +++ b/support/tst-support_capture_subprocess.c @@ -0,0 +1,188 @@ +/* Test capturing output from a subprocess. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Write one byte at *P to FD and advance *P. Do nothing if *P is + '\0'. */ +static void +transfer (const unsigned char **p, int fd) +{ + if (**p != '\0') + { + TEST_VERIFY (write (fd, *p, 1) == 1); + ++*p; + } +} + +/* Determine the order in which stdout and stderr are written. */ +enum write_mode { out_first, err_first, interleave, + write_mode_last = interleave }; + +/* Describe what to write in the subprocess. */ +struct test +{ + char *out; + char *err; + enum write_mode write_mode; + int signal; + int status; +}; + +/* For use with support_capture_subprocess. */ +static void +callback (void *closure) +{ + const struct test *test = closure; + bool mode_ok = false; + switch (test->write_mode) + { + case out_first: + TEST_VERIFY (fputs (test->out, stdout) >= 0); + TEST_VERIFY (fflush (stdout) == 0); + TEST_VERIFY (fputs (test->err, stderr) >= 0); + TEST_VERIFY (fflush (stderr) == 0); + mode_ok = true; + break; + case err_first: + TEST_VERIFY (fputs (test->err, stderr) >= 0); + TEST_VERIFY (fflush (stderr) == 0); + TEST_VERIFY (fputs (test->out, stdout) >= 0); + TEST_VERIFY (fflush (stdout) == 0); + mode_ok = true; + break; + case interleave: + { + const unsigned char *pout = (const unsigned char *) test->out; + const unsigned char *perr = (const unsigned char *) test->err; + do + { + transfer (&pout, STDOUT_FILENO); + transfer (&perr, STDERR_FILENO); + } + while (*pout != '\0' || *perr != '\0'); + } + mode_ok = true; + break; + } + TEST_VERIFY (mode_ok); + + if (test->signal != 0) + raise (test->signal); + exit (test->status); +} + +/* Create a heap-allocated random string of letters. */ +static char * +random_string (size_t length) +{ + char *result = xmalloc (length + 1); + for (size_t i = 0; i < length; ++i) + result[i] = 'a' + (rand () % 26); + result[length] = '\0'; + return result; +} + +/* Check that the specific stream from the captured subprocess matches + expectations. */ +static void +check_stream (const char *what, const struct xmemstream *stream, + const char *expected) +{ + if (strcmp (stream->buffer, expected) != 0) + { + support_record_failure (); + printf ("error: captured %s data incorrect\n" + " expected: %s\n" + " actual: %s\n", + what, expected, stream->buffer); + } + if (stream->length != strlen (expected)) + { + support_record_failure (); + printf ("error: captured %s data length incorrect\n" + " expected: %zu\n" + " actual: %zu\n", + what, strlen (expected), stream->length); + } +} + +static int +do_test (void) +{ + const int lengths[] = {0, 1, 17, 512, 20000, -1}; + + /* Test multiple combinations of support_capture_subprocess. + + length_idx_stdout: Index into the lengths array above, + controls how many bytes are written by the subprocess to + standard output. + length_idx_stderr: Same for standard error. + write_mode: How standard output and standard error writes are + ordered. + signal: Exit with no signal if zero, with SIGTERM if one. + status: Process exit status: 0 if zero, 3 if one. */ + for (int length_idx_stdout = 0; lengths[length_idx_stdout] >= 0; + ++length_idx_stdout) + for (int length_idx_stderr = 0; lengths[length_idx_stderr] >= 0; + ++length_idx_stderr) + for (int write_mode = 0; write_mode < write_mode_last; ++write_mode) + for (int signal = 0; signal < 2; ++signal) + for (int status = 0; status < 2; ++status) + { + struct test test = + { + .out = random_string (lengths[length_idx_stdout]), + .err = random_string (lengths[length_idx_stderr]), + .write_mode = write_mode, + .signal = signal * SIGTERM, /* 0 or SIGTERM. */ + .status = status * 3, /* 0 or 3. */ + }; + TEST_VERIFY (strlen (test.out) == lengths[length_idx_stdout]); + TEST_VERIFY (strlen (test.err) == lengths[length_idx_stderr]); + + struct support_capture_subprocess result + = support_capture_subprocess (callback, &test); + check_stream ("stdout", &result.out, test.out); + check_stream ("stderr", &result.err, test.err); + if (test.signal != 0) + { + TEST_VERIFY (WIFSIGNALED (result.status)); + TEST_VERIFY (WTERMSIG (result.status) == test.signal); + } + else + { + TEST_VERIFY (WIFEXITED (result.status)); + TEST_VERIFY (WEXITSTATUS (result.status) == test.status); + } + support_capture_subprocess_free (&result); + free (test.out); + free (test.err); + } + return 0; +} + +#include diff --git a/support/tst-support_format_dns_packet.c b/support/tst-support_format_dns_packet.c new file mode 100644 index 0000000..9c8589c --- /dev/null +++ b/support/tst-support_format_dns_packet.c @@ -0,0 +1,101 @@ +/* Tests for the support_format_dns_packet function. + Copyright (C) 2016-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +#include +#include +#include + +static void +check_packet (const void *buffer, size_t length, + const char *name, const char *expected) +{ + char *actual = support_format_dns_packet (buffer, length); + if (strcmp (actual, expected) != 0) + { + support_record_failure (); + printf ("error: formatted packet does not match: %s\n", name); + support_run_diff ("expected", expected, + "actual", actual); + } + free (actual); +} + +static void +test_aaaa_length (void) +{ + static const char packet[] = + /* Header: Response with two records. */ + "\x12\x34\x80\x00\x00\x01\x00\x02\x00\x00\x00\x00" + /* Question section. www.example/IN/AAAA. */ + "\x03www\x07""example\x00\x00\x1c\x00\x01" + /* Answer section. www.example AAAA [corrupted]. */ + "\xc0\x0c" + "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x10" + "\x20\x01\x0d\xb8\x05\x06\x07\x08" + "\x11\x12\x13\x14\x15\x16\x17\x18" + /* www.example AAAA [corrupted]. */ + "\xc0\x0c" + "\x00\x1c\x00\x01\x00\x00\x00\x00\x00\x11" + "\x01\x02\x03\x04\x05\x06\x07\x08" + "\x11\x12\x13\x14\x15\x16\x17\x18" "\xff"; + check_packet (packet, sizeof (packet) - 1, __func__, + "name: www.example\n" + "address: 2001:db8:506:708:1112:1314:1516:1718\n" + "error: AAAA record of size 17: www.example\n"); +} + +static void +test_multiple_cnames (void) +{ + static const char packet[] = + /* Header: Response with three records. */ + "\x12\x34\x80\x00\x00\x01\x00\x03\x00\x00\x00\x00" + /* Question section. www.example/IN/A. */ + "\x03www\x07""example\x00\x00\x01\x00\x01" + /* Answer section. www.example CNAME www1.example. */ + "\xc0\x0c" + "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" + "\x04www1\xc0\x10" + /* www1 CNAME www2. */ + "\x04www1\xc0\x10" + "\x00\x05\x00\x01\x00\x00\x00\x00\x00\x07" + "\x04www2\xc0\x10" + /* www2 A 192.0.2.1. */ + "\x04www2\xc0\x10" + "\x00\x01\x00\x01\x00\x00\x00\x00\x00\x04" + "\xc0\x00\x02\x01"; + check_packet (packet, sizeof (packet) - 1, __func__, + "name: www.example\n" + "name: www1.example\n" + "name: www2.example\n" + "address: 192.0.2.1\n"); +} + +static int +do_test (void) +{ + test_aaaa_length (); + test_multiple_cnames (); + return 0; +} + +#include diff --git a/support/tst-support_record_failure-2.sh b/support/tst-support_record_failure-2.sh index 1751377..2c9372c 100644 --- a/support/tst-support_record_failure-2.sh +++ b/support/tst-support_record_failure-2.sh @@ -37,7 +37,7 @@ run_test () { set -e echo " exit status: $status" if test "$output" != "$expected_output" ; then - echo "error: unexpected ouput: $output" + echo "error: unexpected output: $output" exit 1 fi if test "$status" -ne "$expected_status" ; then @@ -52,9 +52,9 @@ different_status () { run_test 1 "error: 1 test failures" $direct --status=1 run_test 2 "error: 1 test failures" $direct --status=2 run_test 1 "error: 1 test failures" $direct --status=77 - run_test 2 "error: tst-support_record_failure.c:108: not true: false + run_test 2 "error: tst-support_record_failure.c:109: not true: false error: 1 test failures" $direct --test-verify - run_test 2 "error: tst-support_record_failure.c:108: not true: false + run_test 2 "error: tst-support_record_failure.c:109: not true: false info: execution passed failed TEST_VERIFY error: 1 test failures" $direct --test-verify --verbose } @@ -62,8 +62,8 @@ error: 1 test failures" $direct --test-verify --verbose different_status different_status --direct -run_test 1 "error: tst-support_record_failure.c:115: not true: false +run_test 1 "error: tst-support_record_failure.c:116: not true: false error: 1 test failures" --test-verify-exit # --direct does not print the summary error message if exit is called. -run_test 1 "error: tst-support_record_failure.c:115: not true: false" \ +run_test 1 "error: tst-support_record_failure.c:116: not true: false" \ --direct --test-verify-exit diff --git a/support/tst-support_record_failure.c b/support/tst-support_record_failure.c index 62d8e1f..e739e73 100644 --- a/support/tst-support_record_failure.c +++ b/support/tst-support_record_failure.c @@ -25,6 +25,7 @@ #include #include #include +#include static int exit_status_with_failure = -1; static bool test_verify; diff --git a/support/xaccept4.c b/support/xaccept4.c new file mode 100644 index 0000000..67dd95e --- /dev/null +++ b/support/xaccept4.c @@ -0,0 +1,32 @@ +/* accept4 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include +#include +#include + +int +xaccept4 (int fd, struct sockaddr *sa, socklen_t *salen, int flags) +{ + int clientfd = accept4 (fd, sa, salen, flags); + if (clientfd < 0) + FAIL_EXIT1 ("accept4 (%d, 0x%x): %m", fd, flags); + return clientfd; +} diff --git a/support/xchroot.c b/support/xchroot.c new file mode 100644 index 0000000..abcc299 --- /dev/null +++ b/support/xchroot.c @@ -0,0 +1,28 @@ +/* chroot with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xchroot (const char *path) +{ + if (chroot (path) != 0) + FAIL_EXIT1 ("chroot (\"%s\"): %m", path); +} diff --git a/support/xclose.c b/support/xclose.c new file mode 100644 index 0000000..c931e08 --- /dev/null +++ b/support/xclose.c @@ -0,0 +1,28 @@ +/* close with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xclose (int fd) +{ + if (close (fd) < 0 && errno != EINTR) + FAIL_EXIT1 ("close of descriptor %d failed: %m", fd); +} diff --git a/support/xdup2.c b/support/xdup2.c new file mode 100644 index 0000000..dc08c94 --- /dev/null +++ b/support/xdup2.c @@ -0,0 +1,28 @@ +/* dup2 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +xdup2 (int from, int to) +{ + if (dup2 (from, to) < 0) + FAIL_EXIT1 ("dup2 (%d, %d): %m", from, to); +} diff --git a/support/xmkdir.c b/support/xmkdir.c new file mode 100644 index 0000000..ea17d49 --- /dev/null +++ b/support/xmkdir.c @@ -0,0 +1,28 @@ +/* mkdir with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xmkdir (const char *path, mode_t mode) +{ + if (mkdir (path, mode) != 0) + FAIL_EXIT1 ("mkdir (\"%s\", 0%o): %m", path, mode); +} diff --git a/support/xmprotect.c b/support/xmprotect.c new file mode 100644 index 0000000..9410251 --- /dev/null +++ b/support/xmprotect.c @@ -0,0 +1,28 @@ +/* mprotect with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +void +xmprotect (void *addr, size_t length, int prot) +{ + if (mprotect (addr, length, prot) != 0) + FAIL_EXIT1 ("mprotect (%p, %zu, 0x%x): %m", addr, length, prot); +} diff --git a/support/xopen.c b/support/xopen.c new file mode 100644 index 0000000..7f033a0 --- /dev/null +++ b/support/xopen.c @@ -0,0 +1,30 @@ +/* open64 with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +xopen (const char *path, int flags, mode_t mode) +{ + int ret = open64 (path, flags, mode); + if (ret < 0) + FAIL_EXIT1 ("open64 (\"%s\", 0x%x, 0%o): %m", path, flags, mode); + return ret; +} diff --git a/support/xpipe.c b/support/xpipe.c new file mode 100644 index 0000000..89a64a5 --- /dev/null +++ b/support/xpipe.c @@ -0,0 +1,28 @@ +/* pipe with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#include + +void +xpipe (int fds[2]) +{ + if (pipe (fds) < 0) + FAIL_EXIT1 ("pipe: %m"); +} diff --git a/support/xpthread_attr_setguardsize.c b/support/xpthread_attr_setguardsize.c new file mode 100644 index 0000000..35fed5d --- /dev/null +++ b/support/xpthread_attr_setguardsize.c @@ -0,0 +1,26 @@ +/* pthread_attr_setguardsize with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_attr_setguardsize (pthread_attr_t *attr, size_t guardsize) +{ + xpthread_check_return ("pthread_attr_setguardize", + pthread_attr_setguardsize (attr, guardsize)); +} diff --git a/support/xpthread_rwlock_init.c b/support/xpthread_rwlock_init.c new file mode 100644 index 0000000..824288c --- /dev/null +++ b/support/xpthread_rwlock_init.c @@ -0,0 +1,27 @@ +/* pthread_rwlock_init with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlock_init (pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr) +{ + xpthread_check_return ("pthread_rwlock_init", + pthread_rwlock_init (rwlock, attr)); +} diff --git a/support/xpthread_rwlock_rdlock.c b/support/xpthread_rwlock_rdlock.c new file mode 100644 index 0000000..96330a5 --- /dev/null +++ b/support/xpthread_rwlock_rdlock.c @@ -0,0 +1,26 @@ +/* pthread_rwlock_rdlock with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + xpthread_check_return ("pthread_rwlock_rdlock", + pthread_rwlock_rdlock (rwlock)); +} diff --git a/support/xpthread_rwlock_unlock.c b/support/xpthread_rwlock_unlock.c new file mode 100644 index 0000000..eaa136b --- /dev/null +++ b/support/xpthread_rwlock_unlock.c @@ -0,0 +1,26 @@ +/* pthread_rwlock_unlock with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + xpthread_check_return ("pthread_rwlock_unlock", + pthread_rwlock_unlock (rwlock)); +} diff --git a/support/xpthread_rwlock_wrlock.c b/support/xpthread_rwlock_wrlock.c new file mode 100644 index 0000000..8d25d5b --- /dev/null +++ b/support/xpthread_rwlock_wrlock.c @@ -0,0 +1,26 @@ +/* pthread_rwlock_wrlock with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + xpthread_check_return ("pthread_rwlock_wrlock", + pthread_rwlock_wrlock (rwlock)); +} diff --git a/support/xpthread_rwlockattr_init.c b/support/xpthread_rwlockattr_init.c new file mode 100644 index 0000000..48baf24 --- /dev/null +++ b/support/xpthread_rwlockattr_init.c @@ -0,0 +1,26 @@ +/* pthread_rwlockattr_init with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlockattr_init (pthread_rwlockattr_t *attr) +{ + xpthread_check_return ("pthread_rwlockattr_init", + pthread_rwlockattr_init (attr)); +} diff --git a/support/xpthread_rwlockattr_setkind_np.c b/support/xpthread_rwlockattr_setkind_np.c new file mode 100644 index 0000000..958aace --- /dev/null +++ b/support/xpthread_rwlockattr_setkind_np.c @@ -0,0 +1,27 @@ +/* pthread_rwlockattr_setkind_np with error checking. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +void +xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, + int pref) +{ + xpthread_check_return ("pthread_rwlockattr_setkind_np", + pthread_rwlockattr_setkind_np (attr, pref)); +} diff --git a/support/xsocket.h b/support/xsocket.h index 0dbf13a..d672494 100644 --- a/support/xsocket.h +++ b/support/xsocket.h @@ -30,6 +30,7 @@ void xconnect (int, const struct sockaddr *, socklen_t); void xbind (int, const struct sockaddr *, socklen_t); void xlisten (int, int); int xaccept (int, struct sockaddr *, socklen_t *); +int xaccept4 (int, struct sockaddr *, socklen_t *, int); void xsendto (int, const void *, size_t, int, const struct sockaddr *, socklen_t); size_t xrecvfrom (int, void *, size_t, int, struct sockaddr *, socklen_t *); diff --git a/support/xthread.h b/support/xthread.h index 6dd7e70..472763e 100644 --- a/support/xthread.h +++ b/support/xthread.h @@ -67,11 +67,21 @@ void xpthread_attr_setdetachstate (pthread_attr_t *attr, int detachstate); void xpthread_attr_setstacksize (pthread_attr_t *attr, size_t stacksize); +void xpthread_attr_setguardsize (pthread_attr_t *attr, + size_t guardsize); /* This function returns non-zero if pthread_barrier_wait returned PTHREAD_BARRIER_SERIAL_THREAD. */ int xpthread_barrier_wait (pthread_barrier_t *barrier); +void xpthread_rwlock_init (pthread_rwlock_t *rwlock, + const pthread_rwlockattr_t *attr); +void xpthread_rwlockattr_init (pthread_rwlockattr_t *attr); +void xpthread_rwlockattr_setkind_np (pthread_rwlockattr_t *attr, int pref); +void xpthread_rwlock_wrlock (pthread_rwlock_t *rwlock); +void xpthread_rwlock_rdlock (pthread_rwlock_t *rwlock); +void xpthread_rwlock_unlock (pthread_rwlock_t *rwlock); + __END_DECLS #endif /* SUPPORT_THREAD_H */ diff --git a/support/xunistd.h b/support/xunistd.h index a83b1f4..c947bfd 100644 --- a/support/xunistd.h +++ b/support/xunistd.h @@ -22,20 +22,33 @@ #ifndef SUPPORT_XUNISTD_H #define SUPPORT_XUNISTD_H -#include #include +#include +#include __BEGIN_DECLS +struct stat64; + pid_t xfork (void); pid_t xwaitpid (pid_t, int *status, int flags); +void xpipe (int[2]); +void xdup2 (int, int); +int xopen (const char *path, int flags, mode_t); +void xstat (const char *path, struct stat64 *); +void xmkdir (const char *path, mode_t); +void xchroot (const char *path); + +/* Close the file descriptor. Ignore EINTR errors, but terminate the + process on other errors. */ +void xclose (int); /* Write the buffer. Retry on short writes. */ void xwrite (int, const void *, size_t); /* Invoke mmap with a zero file offset. */ void *xmmap (void *addr, size_t length, int prot, int flags, int fd); - +void xmprotect (void *addr, size_t length, int prot); void xmunmap (void *addr, size_t length); __END_DECLS commit 4b3a995ad64bed54baf544281596a785d18789f6 Author: Carlos O'Donell Date: Mon Aug 28 15:04:39 2017 +0200 rwlock: Fix explicit hand-over (bug 21298) Without this fix, the rwlock can fail to execute the explicit hand-over in certain cases (e.g., empty critical sections that switch quickly between read and write phases). This can then lead to errors in how __wrphase_futex is accessed, which in turn can lead to deadlocks. (cherry picked from commit faf8c066df0d6bccb54bd74dd696eeb65e1b3bbc) diff --git a/ChangeLog b/ChangeLog index de780da..01298da 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2017-07-28 Torvald Riegel + Carlos O'Donell + + [BZ #21298] + * nptl/Makefile (tests): Add tst-rwlock20. + * nptl/pthread_rwlock_common.c (__pthread_rwlock_rdlock_full): Fix + explicit hand-over. + (__pthread_rwlock_wrlock_full): Likewise. + * nptl/tst-rwlock20.c: New file. + 2017-08-21 Florian Weimer [BZ #21972] diff --git a/NEWS b/NEWS index 6abe902..6963f33 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ The following bugs are resolved with this release: [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs [21242] assert: Suppress pedantic warning caused by statement expression [21289] Fix symbol redirect for fts_set + [21298] rwlock can deadlock on frequent reader/writer phase switching [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) [21972] assert macro requires operator== (int) for its argument type diff --git a/nptl/Makefile b/nptl/Makefile index 6d48c0c..0cc2873 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -241,7 +241,7 @@ tests = tst-typesizes \ tst-rwlock4 tst-rwlock5 tst-rwlock6 tst-rwlock7 tst-rwlock8 \ tst-rwlock9 tst-rwlock10 tst-rwlock11 tst-rwlock12 tst-rwlock13 \ tst-rwlock14 tst-rwlock15 tst-rwlock16 tst-rwlock17 tst-rwlock18 \ - tst-rwlock19 \ + tst-rwlock19 tst-rwlock20 \ tst-once1 tst-once2 tst-once3 tst-once4 tst-once5 \ tst-key1 tst-key2 tst-key3 tst-key4 \ tst-sem1 tst-sem2 tst-sem3 tst-sem4 tst-sem5 tst-sem6 tst-sem7 \ diff --git a/nptl/pthread_rwlock_common.c b/nptl/pthread_rwlock_common.c index 256508c..846687e 100644 --- a/nptl/pthread_rwlock_common.c +++ b/nptl/pthread_rwlock_common.c @@ -55,7 +55,6 @@ lock acquisition attempts, so that new incoming readers do not prolong a phase in which readers have acquired the lock. - The main components of the rwlock are a writer-only lock that allows only one of the concurrent writers to be the primary writer, and a single-writer-multiple-readers lock that decides between read phases, in @@ -70,15 +69,16 @@ --------------------------- #1 0 0 0 0 Lock is idle (and in a read phase). #2 0 0 >0 0 Readers have acquired the lock. - #3 0 1 0 0 Lock is not acquired; a writer is waiting for a write - phase to start or will try to start one. + #3 0 1 0 0 Lock is not acquired; a writer will try to start a + write phase. #4 0 1 >0 0 Readers have acquired the lock; a writer is waiting and explicit hand-over to the writer is required. #4a 0 1 >0 1 Same as #4 except that there are further readers waiting because the writer is to be preferred. #5 1 0 0 0 Lock is idle (and in a write phase). - #6 1 0 >0 0 Write phase; readers are waiting for a read phase to - start or will try to start one. + #6 1 0 >0 0 Write phase; readers will try to start a read phase + (requires explicit hand-over to all readers that + do not start the read phase). #7 1 1 0 0 Lock is acquired by a writer. #8 1 1 >0 0 Lock acquired by a writer and readers are waiting; explicit hand-over to the readers is required. @@ -375,9 +375,9 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, complexity. */ if (__glibc_likely ((r & PTHREAD_RWLOCK_WRPHASE) == 0)) return 0; - - /* If there is no primary writer but we are in a write phase, we can try - to install a read phase ourself. */ + /* Otherwise, if we were in a write phase (states #6 or #8), we must wait + for explicit hand-over of the read phase; the only exception is if we + can start a read phase if there is no primary writer currently. */ while (((r & PTHREAD_RWLOCK_WRPHASE) != 0) && ((r & PTHREAD_RWLOCK_WRLOCKED) == 0)) { @@ -390,15 +390,18 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, { /* We started the read phase, so we are also responsible for updating the write-phase futex. Relaxed MO is sufficient. - Note that there can be no other reader that we have to wake - because all other readers will see the read phase started by us - (or they will try to start it themselves); if a writer started - the read phase, we cannot have started it. Furthermore, we - cannot discard a PTHREAD_RWLOCK_FUTEX_USED flag because we will - overwrite the value set by the most recent writer (or the readers - before it in case of explicit hand-over) and we know that there - are no waiting readers. */ - atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 0); + We have to do the same steps as a writer would when handing + over the read phase to us because other readers cannot + distinguish between us and the writer; this includes + explicit hand-over and potentially having to wake other readers + (but we can pretend to do the setting and unsetting of WRLOCKED + atomically, and thus can skip this step). */ + if ((atomic_exchange_relaxed (&rwlock->__data.__wrphase_futex, 0) + & PTHREAD_RWLOCK_FUTEX_USED) != 0) + { + int private = __pthread_rwlock_get_private (rwlock); + futex_wake (&rwlock->__data.__wrphase_futex, INT_MAX, private); + } return 0; } else @@ -407,102 +410,98 @@ __pthread_rwlock_rdlock_full (pthread_rwlock_t *rwlock, } } - if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) + /* We were in a write phase but did not install the read phase. We cannot + distinguish between a writer and another reader starting the read phase, + so we must wait for explicit hand-over via __wrphase_futex. + However, __wrphase_futex might not have been set to 1 yet (either + because explicit hand-over to the writer is still ongoing, or because + the writer has started the write phase but has not yet updated + __wrphase_futex). The least recent value of __wrphase_futex we can + read from here is the modification of the last read phase (because + we synchronize with the last reader in this read phase through + __readers; see the use of acquire MO on the fetch_add above). + Therefore, if we observe a value of 0 for __wrphase_futex, we need + to subsequently check that __readers now indicates a read phase; we + need to use acquire MO for this so that if we observe a read phase, + we will also see the modification of __wrphase_futex by the previous + writer. We then need to load __wrphase_futex again and continue to + wait if it is not 0, so that we do not skip explicit hand-over. + Relaxed MO is sufficient for the load from __wrphase_futex because + we just use it as an indicator for when we can proceed; we use + __readers and the acquire MO accesses to it to eventually read from + the proper stores to __wrphase_futex. */ + unsigned int wpf; + bool ready = false; + for (;;) { - /* We are in a write phase, and there must be a primary writer because - of the previous loop. Block until the primary writer gives up the - write phase. This case requires explicit hand-over using - __wrphase_futex. - However, __wrphase_futex might not have been set to 1 yet (either - because explicit hand-over to the writer is still ongoing, or because - the writer has started the write phase but does not yet have updated - __wrphase_futex). The least recent value of __wrphase_futex we can - read from here is the modification of the last read phase (because - we synchronize with the last reader in this read phase through - __readers; see the use of acquire MO on the fetch_add above). - Therefore, if we observe a value of 0 for __wrphase_futex, we need - to subsequently check that __readers now indicates a read phase; we - need to use acquire MO for this so that if we observe a read phase, - we will also see the modification of __wrphase_futex by the previous - writer. We then need to load __wrphase_futex again and continue to - wait if it is not 0, so that we do not skip explicit hand-over. - Relaxed MO is sufficient for the load from __wrphase_futex because - we just use it as an indicator for when we can proceed; we use - __readers and the acquire MO accesses to it to eventually read from - the proper stores to __wrphase_futex. */ - unsigned int wpf; - bool ready = false; - for (;;) + while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) + | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) { - while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) - | PTHREAD_RWLOCK_FUTEX_USED) == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + int private = __pthread_rwlock_get_private (rwlock); + if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) + && !atomic_compare_exchange_weak_relaxed + (&rwlock->__data.__wrphase_futex, + &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)) + continue; + int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, + 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); + if (err == ETIMEDOUT) { - int private = __pthread_rwlock_get_private (rwlock); - if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) - && !atomic_compare_exchange_weak_relaxed - (&rwlock->__data.__wrphase_futex, - &wpf, wpf | PTHREAD_RWLOCK_FUTEX_USED)) - continue; - int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, - 1 | PTHREAD_RWLOCK_FUTEX_USED, abstime, private); - if (err == ETIMEDOUT) + /* If we timed out, we need to unregister. If no read phase + has been installed while we waited, we can just decrement + the number of readers. Otherwise, we just acquire the + lock, which is allowed because we give no precise timing + guarantees, and because the timeout is only required to + be in effect if we would have had to wait for other + threads (e.g., if futex_wait would time-out immediately + because the given absolute time is in the past). */ + r = atomic_load_relaxed (&rwlock->__data.__readers); + while ((r & PTHREAD_RWLOCK_WRPHASE) != 0) { - /* If we timed out, we need to unregister. If no read phase - has been installed while we waited, we can just decrement - the number of readers. Otherwise, we just acquire the - lock, which is allowed because we give no precise timing - guarantees, and because the timeout is only required to - be in effect if we would have had to wait for other - threads (e.g., if futex_wait would time-out immediately - because the given absolute time is in the past). */ - r = atomic_load_relaxed (&rwlock->__data.__readers); - while ((r & PTHREAD_RWLOCK_WRPHASE) != 0) - { - /* We don't need to make anything else visible to - others besides unregistering, so relaxed MO is - sufficient. */ - if (atomic_compare_exchange_weak_relaxed - (&rwlock->__data.__readers, &r, - r - (1 << PTHREAD_RWLOCK_READER_SHIFT))) - return ETIMEDOUT; - /* TODO Back-off. */ - } - /* Use the acquire MO fence to mirror the steps taken in the - non-timeout case. Note that the read can happen both - in the atomic_load above as well as in the failure case - of the CAS operation. */ - atomic_thread_fence_acquire (); - /* We still need to wait for explicit hand-over, but we must - not use futex_wait anymore because we would just time out - in this case and thus make the spin-waiting we need - unnecessarily expensive. */ - while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex) - | PTHREAD_RWLOCK_FUTEX_USED) - == (1 | PTHREAD_RWLOCK_FUTEX_USED)) - { - /* TODO Back-off? */ - } - ready = true; - break; + /* We don't need to make anything else visible to + others besides unregistering, so relaxed MO is + sufficient. */ + if (atomic_compare_exchange_weak_relaxed + (&rwlock->__data.__readers, &r, + r - (1 << PTHREAD_RWLOCK_READER_SHIFT))) + return ETIMEDOUT; + /* TODO Back-off. */ } - /* If we got interrupted (EINTR) or the futex word does not have the - expected value (EAGAIN), retry. */ + /* Use the acquire MO fence to mirror the steps taken in the + non-timeout case. Note that the read can happen both + in the atomic_load above as well as in the failure case + of the CAS operation. */ + atomic_thread_fence_acquire (); + /* We still need to wait for explicit hand-over, but we must + not use futex_wait anymore because we would just time out + in this case and thus make the spin-waiting we need + unnecessarily expensive. */ + while ((atomic_load_relaxed (&rwlock->__data.__wrphase_futex) + | PTHREAD_RWLOCK_FUTEX_USED) + == (1 | PTHREAD_RWLOCK_FUTEX_USED)) + { + /* TODO Back-off? */ + } + ready = true; + break; } - if (ready) - /* See below. */ - break; - /* We need acquire MO here so that we synchronize with the lock - release of the writer, and so that we observe a recent value of - __wrphase_futex (see below). */ - if ((atomic_load_acquire (&rwlock->__data.__readers) - & PTHREAD_RWLOCK_WRPHASE) == 0) - /* We are in a read phase now, so the least recent modification of - __wrphase_futex we can read from is the store by the writer - with value 1. Thus, only now we can assume that if we observe - a value of 0, explicit hand-over is finished. Retry the loop - above one more time. */ - ready = true; + /* If we got interrupted (EINTR) or the futex word does not have the + expected value (EAGAIN), retry. */ } + if (ready) + /* See below. */ + break; + /* We need acquire MO here so that we synchronize with the lock + release of the writer, and so that we observe a recent value of + __wrphase_futex (see below). */ + if ((atomic_load_acquire (&rwlock->__data.__readers) + & PTHREAD_RWLOCK_WRPHASE) == 0) + /* We are in a read phase now, so the least recent modification of + __wrphase_futex we can read from is the store by the writer + with value 1. Thus, only now we can assume that if we observe + a value of 0, explicit hand-over is finished. Retry the loop + above one more time. */ + ready = true; } return 0; @@ -741,10 +740,23 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, r = atomic_load_relaxed (&rwlock->__data.__readers); } /* Our snapshot of __readers is up-to-date at this point because we - either set WRLOCKED using a CAS or were handed over WRLOCKED from + either set WRLOCKED using a CAS (and update r accordingly below, + which was used as expected value for the CAS) or got WRLOCKED from another writer whose snapshot of __readers we inherit. */ + r |= PTHREAD_RWLOCK_WRLOCKED; } + /* We are the primary writer; enable blocking on __writers_futex. Relaxed + MO is sufficient for futex words; acquire MO on the previous + modifications of __readers ensures that this store happens after the + store of value 0 by the previous primary writer. */ + atomic_store_relaxed (&rwlock->__data.__writers_futex, + 1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0)); + + /* If we are in a write phase, we have acquired the lock. */ + if ((r & PTHREAD_RWLOCK_WRPHASE) != 0) + goto done; + /* If we are in a read phase and there are no readers, try to start a write phase. */ while (((r & PTHREAD_RWLOCK_WRPHASE) == 0) @@ -758,166 +770,156 @@ __pthread_rwlock_wrlock_full (pthread_rwlock_t *rwlock, &r, r | PTHREAD_RWLOCK_WRPHASE)) { /* We have started a write phase, so need to enable readers to wait. - See the similar case in__pthread_rwlock_rdlock_full. */ + See the similar case in __pthread_rwlock_rdlock_full. Unlike in + that similar case, we are the (only) primary writer and so do + not need to wake another writer. */ atomic_store_relaxed (&rwlock->__data.__wrphase_futex, 1); - /* Make sure we fall through to the end of the function. */ - r |= PTHREAD_RWLOCK_WRPHASE; - break; + + goto done; } /* TODO Back-off. */ } - /* We are the primary writer; enable blocking on __writers_futex. Relaxed - MO is sufficient for futex words; acquire MO on the previous - modifications of __readers ensures that this store happens after the - store of value 0 by the previous primary writer. */ - atomic_store_relaxed (&rwlock->__data.__writers_futex, - 1 | (may_share_futex_used_flag ? PTHREAD_RWLOCK_FUTEX_USED : 0)); - - if (__glibc_unlikely ((r & PTHREAD_RWLOCK_WRPHASE) == 0)) + /* We became the primary writer in a read phase and there were readers when + we did (because of the previous loop). Thus, we have to wait for + explicit hand-over from one of these readers. + We basically do the same steps as for the similar case in + __pthread_rwlock_rdlock_full, except that we additionally might try + to directly hand over to another writer and need to wake up + other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING). */ + unsigned int wpf; + bool ready = false; + for (;;) { - /* We are not in a read phase and there are readers (because of the - previous loop). Thus, we have to wait for explicit hand-over from - one of these readers. - We basically do the same steps as for the similar case in - __pthread_rwlock_rdlock_full, except that we additionally might try - to directly hand over to another writer and need to wake up - other writers or waiting readers (i.e., PTHREAD_RWLOCK_RWAITING). */ - unsigned int wpf; - bool ready = false; - for (;;) + while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) + | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED) { - while (((wpf = atomic_load_relaxed (&rwlock->__data.__wrphase_futex)) - | PTHREAD_RWLOCK_FUTEX_USED) == PTHREAD_RWLOCK_FUTEX_USED) + int private = __pthread_rwlock_get_private (rwlock); + if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) + && !atomic_compare_exchange_weak_relaxed + (&rwlock->__data.__wrphase_futex, &wpf, + PTHREAD_RWLOCK_FUTEX_USED)) + continue; + int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, + PTHREAD_RWLOCK_FUTEX_USED, abstime, private); + if (err == ETIMEDOUT) { - int private = __pthread_rwlock_get_private (rwlock); - if (((wpf & PTHREAD_RWLOCK_FUTEX_USED) == 0) - && !atomic_compare_exchange_weak_relaxed - (&rwlock->__data.__wrphase_futex, &wpf, - PTHREAD_RWLOCK_FUTEX_USED)) - continue; - int err = futex_abstimed_wait (&rwlock->__data.__wrphase_futex, - PTHREAD_RWLOCK_FUTEX_USED, abstime, private); - if (err == ETIMEDOUT) + if (rwlock->__data.__flags + != PTHREAD_RWLOCK_PREFER_READER_NP) { - if (rwlock->__data.__flags - != PTHREAD_RWLOCK_PREFER_READER_NP) - { - /* We try writer--writer hand-over. */ - unsigned int w = atomic_load_relaxed - (&rwlock->__data.__writers); - if (w != 0) - { - /* We are about to hand over WRLOCKED, so we must - release __writers_futex too; otherwise, we'd have - a pending store, which could at least prevent - other threads from waiting using the futex - because it could interleave with the stores - by subsequent writers. In turn, this means that - we have to clean up when we do not hand over - WRLOCKED. - Release MO so that another writer that gets - WRLOCKED from us can take over our view of - __readers. */ - unsigned int wf = atomic_exchange_relaxed - (&rwlock->__data.__writers_futex, 0); - while (w != 0) - { - if (atomic_compare_exchange_weak_release - (&rwlock->__data.__writers, &w, - w | PTHREAD_RWLOCK_WRHANDOVER)) - { - /* Wake other writers. */ - if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) - futex_wake - (&rwlock->__data.__writers_futex, 1, - private); - return ETIMEDOUT; - } - /* TODO Back-off. */ - } - /* We still own WRLOCKED and someone else might set - a write phase concurrently, so enable waiting - again. Make sure we don't loose the flag that - signals whether there are threads waiting on - this futex. */ - atomic_store_relaxed - (&rwlock->__data.__writers_futex, wf); - } - } - /* If we timed out and we are not in a write phase, we can - just stop being a primary writer. Otherwise, we just - acquire the lock. */ - r = atomic_load_relaxed (&rwlock->__data.__readers); - if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + /* We try writer--writer hand-over. */ + unsigned int w = atomic_load_relaxed + (&rwlock->__data.__writers); + if (w != 0) { - /* We are about to release WRLOCKED, so we must release - __writers_futex too; see the handling of - writer--writer hand-over above. */ + /* We are about to hand over WRLOCKED, so we must + release __writers_futex too; otherwise, we'd have + a pending store, which could at least prevent + other threads from waiting using the futex + because it could interleave with the stores + by subsequent writers. In turn, this means that + we have to clean up when we do not hand over + WRLOCKED. + Release MO so that another writer that gets + WRLOCKED from us can take over our view of + __readers. */ unsigned int wf = atomic_exchange_relaxed (&rwlock->__data.__writers_futex, 0); - while ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + while (w != 0) { - /* While we don't need to make anything from a - caller's critical section visible to other - threads, we need to ensure that our changes to - __writers_futex are properly ordered. - Therefore, use release MO to synchronize with - subsequent primary writers. Also wake up any - waiting readers as they are waiting because of - us. */ if (atomic_compare_exchange_weak_release - (&rwlock->__data.__readers, &r, - (r ^ PTHREAD_RWLOCK_WRLOCKED) - & ~(unsigned int) PTHREAD_RWLOCK_RWAITING)) + (&rwlock->__data.__writers, &w, + w | PTHREAD_RWLOCK_WRHANDOVER)) { /* Wake other writers. */ if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) futex_wake (&rwlock->__data.__writers_futex, - 1, private); - /* Wake waiting readers. */ - if ((r & PTHREAD_RWLOCK_RWAITING) != 0) - futex_wake (&rwlock->__data.__readers, - INT_MAX, private); + 1, private); return ETIMEDOUT; } + /* TODO Back-off. */ } - /* We still own WRLOCKED and someone else might set a - write phase concurrently, so enable waiting again. - Make sure we don't loose the flag that signals - whether there are threads waiting on this futex. */ - atomic_store_relaxed (&rwlock->__data.__writers_futex, - wf); + /* We still own WRLOCKED and someone else might set + a write phase concurrently, so enable waiting + again. Make sure we don't loose the flag that + signals whether there are threads waiting on + this futex. */ + atomic_store_relaxed + (&rwlock->__data.__writers_futex, wf); } - /* Use the acquire MO fence to mirror the steps taken in the - non-timeout case. Note that the read can happen both - in the atomic_load above as well as in the failure case - of the CAS operation. */ - atomic_thread_fence_acquire (); - /* We still need to wait for explicit hand-over, but we must - not use futex_wait anymore. */ - while ((atomic_load_relaxed - (&rwlock->__data.__wrphase_futex) - | PTHREAD_RWLOCK_FUTEX_USED) - == PTHREAD_RWLOCK_FUTEX_USED) + } + /* If we timed out and we are not in a write phase, we can + just stop being a primary writer. Otherwise, we just + acquire the lock. */ + r = atomic_load_relaxed (&rwlock->__data.__readers); + if ((r & PTHREAD_RWLOCK_WRPHASE) == 0) + { + /* We are about to release WRLOCKED, so we must release + __writers_futex too; see the handling of + writer--writer hand-over above. */ + unsigned int wf = atomic_exchange_relaxed + (&rwlock->__data.__writers_futex, 0); + while ((r & PTHREAD_RWLOCK_WRPHASE) == 0) { - /* TODO Back-off. */ + /* While we don't need to make anything from a + caller's critical section visible to other + threads, we need to ensure that our changes to + __writers_futex are properly ordered. + Therefore, use release MO to synchronize with + subsequent primary writers. Also wake up any + waiting readers as they are waiting because of + us. */ + if (atomic_compare_exchange_weak_release + (&rwlock->__data.__readers, &r, + (r ^ PTHREAD_RWLOCK_WRLOCKED) + & ~(unsigned int) PTHREAD_RWLOCK_RWAITING)) + { + /* Wake other writers. */ + if ((wf & PTHREAD_RWLOCK_FUTEX_USED) != 0) + futex_wake (&rwlock->__data.__writers_futex, + 1, private); + /* Wake waiting readers. */ + if ((r & PTHREAD_RWLOCK_RWAITING) != 0) + futex_wake (&rwlock->__data.__readers, + INT_MAX, private); + return ETIMEDOUT; + } } - ready = true; - break; + /* We still own WRLOCKED and someone else might set a + write phase concurrently, so enable waiting again. + Make sure we don't loose the flag that signals + whether there are threads waiting on this futex. */ + atomic_store_relaxed (&rwlock->__data.__writers_futex, wf); } - /* If we got interrupted (EINTR) or the futex word does not have - the expected value (EAGAIN), retry. */ + /* Use the acquire MO fence to mirror the steps taken in the + non-timeout case. Note that the read can happen both + in the atomic_load above as well as in the failure case + of the CAS operation. */ + atomic_thread_fence_acquire (); + /* We still need to wait for explicit hand-over, but we must + not use futex_wait anymore. */ + while ((atomic_load_relaxed + (&rwlock->__data.__wrphase_futex) + | PTHREAD_RWLOCK_FUTEX_USED) + == PTHREAD_RWLOCK_FUTEX_USED) + { + /* TODO Back-off. */ + } + ready = true; + break; } - /* See pthread_rwlock_rdlock_full. */ - if (ready) - break; - if ((atomic_load_acquire (&rwlock->__data.__readers) - & PTHREAD_RWLOCK_WRPHASE) != 0) - ready = true; + /* If we got interrupted (EINTR) or the futex word does not have + the expected value (EAGAIN), retry. */ } + /* See pthread_rwlock_rdlock_full. */ + if (ready) + break; + if ((atomic_load_acquire (&rwlock->__data.__readers) + & PTHREAD_RWLOCK_WRPHASE) != 0) + ready = true; } + done: atomic_store_relaxed (&rwlock->__data.__cur_writer, THREAD_GETMEM (THREAD_SELF, tid)); return 0; diff --git a/nptl/tst-rwlock20.c b/nptl/tst-rwlock20.c new file mode 100644 index 0000000..4aeea2b --- /dev/null +++ b/nptl/tst-rwlock20.c @@ -0,0 +1,116 @@ +/* Test program for a read-phase / write-phase explicit hand-over. + Copyright (C) 2017 Free Software Foundation, Inc. + + 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; see the file COPYING.LIB. If + not, see . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* We realy want to set threads to 2 to reproduce this issue. The goal + is to have one primary writer and a single reader, and to hit the + bug that happens in the interleaving of those two phase transitions. + However, on most hardware, adding a second writer seems to help the + interleaving happen slightly more often, say 20% of the time. On a + 16 core ppc64 machine this fails 100% of the time with an unpatched + glibc. On a 8 core x86_64 machine this fails ~93% of the time, but + it doesn't fail at all on a 4 core system, so having available + unloaded cores makes a big difference in reproducibility. On an 8 + core qemu/kvm guest the reproducer reliability drops to ~10%. */ +#define THREADS 3 + +#define KIND PTHREAD_RWLOCK_PREFER_READER_NP + +static pthread_rwlock_t lock; +static int done = 0; + +static void* +tf (void* arg) +{ + while (atomic_load_relaxed (&done) == 0) + { + int rcnt = 0; + int wcnt = 100; + if ((uintptr_t) arg == 0) + { + rcnt = 1; + wcnt = 1; + } + + do + { + if (wcnt) + { + xpthread_rwlock_wrlock (&lock); + xpthread_rwlock_unlock (&lock); + wcnt--; + } + if (rcnt) + { + xpthread_rwlock_rdlock (&lock); + xpthread_rwlock_unlock (&lock); + rcnt--; + } + } + while ((atomic_load_relaxed (&done) == 0) && (rcnt + wcnt > 0)); + + } + return NULL; +} + + + +static int +do_test (void) +{ + pthread_t thr[THREADS]; + int n; + pthread_rwlockattr_t attr; + + xpthread_rwlockattr_init (&attr); + xpthread_rwlockattr_setkind_np (&attr, KIND); + + xpthread_rwlock_init (&lock, &attr); + + /* Make standard error the same as standard output. */ + dup2 (1, 2); + + /* Make sure we see all message, even those on stdout. */ + setvbuf (stdout, NULL, _IONBF, 0); + + for (n = 0; n < THREADS; ++n) + thr[n] = xpthread_create (NULL, tf, (void *) (uintptr_t) n); + + struct timespec delay; + delay.tv_sec = 10; + delay.tv_nsec = 0; + nanosleep (&delay, NULL); + atomic_store_relaxed (&done, 1); + + /* Wait for all the threads. */ + for (n = 0; n < THREADS; ++n) + xpthread_join (thr[n]); + + return 0; +} + +#include commit bc5ace67fe9823757532e0273f6c1cdfda065433 Author: Carlos O'Donell Date: Sat Jul 29 00:02:03 2017 -0400 mutex: Fix robust mutex lock acquire (Bug 21778) 65810f0ef05e8c9e333f17a44e77808b163ca298 fixed a robust mutex bug but introduced BZ 21778: if the CAS used to try to acquire a lock fails, the expected value is not updated, which breaks other cases in the loce acquisition loop. The fix is to simply update the expected value with the value returned by the CAS, which ensures that behavior is as if the first case with the CAS never happened (if the CAS fails). This is a regression introduced in the last release. Tested on x86_64, i686, ppc64, ppc64le, s390x, aarch64, armv7hl. (cherry picked from commit 5920a4a624b1f4db310d1c44997b640e2a4653e5) diff --git a/ChangeLog b/ChangeLog index 01298da..13415f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2017-07-29 Torvald Riegel + Carlos O'Donell + + [BZ 21778] + * nptl/pthread_mutex_timedlock.c (__pthread_mutex_timedlock): Update + oldval if the CAS fails. + * nptl/pthread_mutex_lock.c (__pthread_mutex_lock_full): Likewise. + * nptl/tst-mutex7.c: Add comments explaining template test. + (ROBUST, DELAY_NSEC, ROUNDS, N): New. + (tf, do_test): Use them. + * nptl/tst-mutex7robust.c: New file. + * nptl/Makefile (tests): Add new test. + 2017-07-28 Torvald Riegel Carlos O'Donell diff --git a/NEWS b/NEWS index 6963f33..f705771 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ The following bugs are resolved with this release: [21298] rwlock can deadlock on frequent reader/writer phase switching [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) + [21778] Robust mutex may deadlock [21972] assert macro requires operator== (int) for its argument type Version 2.25 diff --git a/nptl/Makefile b/nptl/Makefile index 0cc2873..2406776 100644 --- a/nptl/Makefile +++ b/nptl/Makefile @@ -224,6 +224,7 @@ tests = tst-typesizes \ tst-attr1 tst-attr2 tst-attr3 tst-default-attr \ tst-mutex1 tst-mutex2 tst-mutex3 tst-mutex4 tst-mutex5 tst-mutex6 \ tst-mutex7 tst-mutex8 tst-mutex9 tst-mutex5a tst-mutex7a \ + tst-mutex7robust \ tst-mutexpi1 tst-mutexpi2 tst-mutexpi3 tst-mutexpi4 tst-mutexpi5 \ tst-mutexpi5a tst-mutexpi6 tst-mutexpi7 tst-mutexpi7a tst-mutexpi8 \ tst-mutexpi9 \ diff --git a/nptl/pthread_mutex_lock.c b/nptl/pthread_mutex_lock.c index dc9ca4c..4425927 100644 --- a/nptl/pthread_mutex_lock.c +++ b/nptl/pthread_mutex_lock.c @@ -197,11 +197,14 @@ __pthread_mutex_lock_full (pthread_mutex_t *mutex) { /* Try to acquire the lock through a CAS from 0 (not acquired) to our TID | assume_other_futex_waiters. */ - if (__glibc_likely ((oldval == 0) - && (atomic_compare_and_exchange_bool_acq - (&mutex->__data.__lock, - id | assume_other_futex_waiters, 0) == 0))) - break; + if (__glibc_likely (oldval == 0)) + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + id | assume_other_futex_waiters, 0); + if (__glibc_likely (oldval == 0)) + break; + } if ((oldval & FUTEX_OWNER_DIED) != 0) { diff --git a/nptl/pthread_mutex_timedlock.c b/nptl/pthread_mutex_timedlock.c index a4beb7b..dd88cc4 100644 --- a/nptl/pthread_mutex_timedlock.c +++ b/nptl/pthread_mutex_timedlock.c @@ -154,11 +154,14 @@ pthread_mutex_timedlock (pthread_mutex_t *mutex, { /* Try to acquire the lock through a CAS from 0 (not acquired) to our TID | assume_other_futex_waiters. */ - if (__glibc_likely ((oldval == 0) - && (atomic_compare_and_exchange_bool_acq - (&mutex->__data.__lock, - id | assume_other_futex_waiters, 0) == 0))) - break; + if (__glibc_likely (oldval == 0)) + { + oldval + = atomic_compare_and_exchange_val_acq (&mutex->__data.__lock, + id | assume_other_futex_waiters, 0); + if (__glibc_likely (oldval == 0)) + break; + } if ((oldval & FUTEX_OWNER_DIED) != 0) { diff --git a/nptl/tst-mutex7.c b/nptl/tst-mutex7.c index a11afdb..08fe251 100644 --- a/nptl/tst-mutex7.c +++ b/nptl/tst-mutex7.c @@ -22,25 +22,41 @@ #include #include - +/* This test is a template for other tests to use. Other tests define + the following macros to change the behaviour of the template test. + The test is very simple, it configures N threads given the parameters + below and then proceeds to go through mutex lock and unlock + operations in each thread as described before for the thread + function. */ #ifndef TYPE # define TYPE PTHREAD_MUTEX_DEFAULT #endif - +#ifndef ROBUST +# define ROBUST PTHREAD_MUTEX_STALLED +#endif +#ifndef DELAY_NSEC +# define DELAY_NSEC 11000 +#endif +#ifndef ROUNDS +# define ROUNDS 1000 +#endif +#ifndef N +# define N 100 +#endif static pthread_mutex_t lock; - -#define ROUNDS 1000 -#define N 100 - - +/* Each thread locks and the subsequently unlocks the lock, yielding + the smallest critical section possible. After the unlock the thread + waits DELAY_NSEC nanoseconds before doing the lock and unlock again. + Every thread does this ROUNDS times. The lock and unlock are + checked for errors. */ static void * tf (void *arg) { int nr = (long int) arg; int cnt; - struct timespec ts = { .tv_sec = 0, .tv_nsec = 11000 }; + struct timespec ts = { .tv_sec = 0, .tv_nsec = DELAY_NSEC }; for (cnt = 0; cnt < ROUNDS; ++cnt) { @@ -56,13 +72,16 @@ tf (void *arg) return (void *) 1l; } - nanosleep (&ts, NULL); + if ((ts.tv_sec > 0) || (ts.tv_nsec > 0)) + nanosleep (&ts, NULL); } return NULL; } - +/* Setup and run N threads, where each thread does as described + in the above thread function. The threads are given a minimal 1MiB + stack since they don't do anything between the lock and unlock. */ static int do_test (void) { @@ -80,6 +99,12 @@ do_test (void) exit (1); } + if (pthread_mutexattr_setrobust (&a, ROBUST) != 0) + { + puts ("mutexattr_setrobust failed"); + exit (1); + } + #ifdef ENABLE_PI if (pthread_mutexattr_setprotocol (&a, PTHREAD_PRIO_INHERIT) != 0) { diff --git a/nptl/tst-mutex7robust.c b/nptl/tst-mutex7robust.c new file mode 100644 index 0000000..8221a61 --- /dev/null +++ b/nptl/tst-mutex7robust.c @@ -0,0 +1,7 @@ +/* Bug 21778: Fix oversight in robust mutex lock acquisition. */ +#define TYPE PTHREAD_MUTEX_NORMAL +#define ROBUST PTHREAD_MUTEX_ROBUST +#define DELAY_NSEC 0 +#define ROUNDS 1000 +#define N 32 +#include "tst-mutex7.c" commit c71ddec7b314d4da5397508516983e0a9e831711 Author: H.J. Lu Date: Thu Aug 31 06:28:31 2017 -0700 Place $(elf-objpfx)sofini.os last [BZ #22051] Since sofini.os terminates .eh_frame section, it should be placed last. [BZ #22051] * Makerules (build-module-helper-objlist): Filter out $(elf-objpfx)sofini.os. (build-shlib-objlist): Append $(elf-objpfx)sofini.os if it is needed. (cherry picked from commit ecd0747df388f3925d4839740b0abcf43d0a9fb2) diff --git a/ChangeLog b/ChangeLog index 13415f9..c48bdb62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-08-31 H.J. Lu + + [BZ #22051] + * Makerules (build-module-helper-objlist): Filter out + $(elf-objpfx)sofini.os. + (build-shlib-objlist): Append $(elf-objpfx)sofini.os if it is + needed. + 2017-07-29 Torvald Riegel Carlos O'Donell diff --git a/Makerules b/Makerules index 7f0eef8..7403305 100644 --- a/Makerules +++ b/Makerules @@ -669,14 +669,17 @@ $(build-module-helper) -o $@ $(shlib-lds-flags) \ $(call after-link,$@) endef +# sofini.os must be placed last since it terminates .eh_frame section. build-module-helper-objlist = \ $(patsubst %_pic.a,$(whole-archive) %_pic.a $(no-whole-archive),\ $(filter-out %.lds $(map-file) $(+preinit) $(+postinit) \ + $(elf-objpfx)sofini.os \ $(link-libc-deps),$^)) build-module-objlist = $(build-module-helper-objlist) $(LDLIBS-$(@F:%.so=%).so) build-shlib-objlist = $(build-module-helper-objlist) \ - $(LDLIBS-$(@F:lib%.so=%).so) + $(LDLIBS-$(@F:lib%.so=%).so) \ + $(filter $(elf-objpfx)sofini.os,$^) # Don't try to use -lc when making libc.so itself. # Also omits crti.o and crtn.o, which we do not want commit e0252d3c64f2f4f7f0f551815d304d864d7f68cd Author: H.J. Lu Date: Thu Sep 7 13:56:58 2017 -0700 Use "static const char domain[] =" * resolv/tst-resolv-qtypes.c (domain): Changed to "const char domain[] =". (cherry picked from commit 78bfa877b36e8f33c99cbe9a16eb73f5a2adc0c8) diff --git a/ChangeLog b/ChangeLog index c48bdb62..62f3a35 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-09-07 H.J. Lu + + * resolv/tst-resolv-qtypes.c (domain): Changed to + "const char domain[] =". + 2017-08-31 H.J. Lu [BZ #22051] diff --git a/resolv/tst-resolv-qtypes.c b/resolv/tst-resolv-qtypes.c index dcb39e5..da3325f 100644 --- a/resolv/tst-resolv-qtypes.c +++ b/resolv/tst-resolv-qtypes.c @@ -50,7 +50,7 @@ response (const struct resolv_response_context *ctx, resolv_response_close_record (b); } -static const const char *domain = "www.example.com"; +static const char domain[] = "www.example.com"; static int wrap_res_query (int type, unsigned char *answer, int answer_length) commit 4e4cfd77617c190a7c8b3f83c41e1ad0771bd569 Author: H.J. Lu Date: Mon Sep 11 08:51:52 2017 -0700 string/stratcliff.c: Replace int with size_t [BZ #21982] Fix GCC 7 errors when string/stratcliff.c is compiled with -O3: stratcliff.c: In function ‘do_test’: cc1: error: assuming signed overflow does not occur when assuming that (X - c) <= X is always true [-Werror=strict-overflow] [BZ #21982] * string/stratcliff.c (do_test): Declare size, nchars, inner, middle and outer with size_t instead of int. Repleace %d and %Zd with %zu in printf. Update "MAX (0, nchars - 128)" and "MAX (outer, nchars - 64)" to support unsigned outer and nchars. Also exit loop when outer == 0. (cherry picked from commit 376b40a27a6783ea7f73ae577be320df66aeb36d) diff --git a/ChangeLog b/ChangeLog index 62f3a35..a48cd9c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2017-09-11 H.J. Lu + + [BZ #21982] + * string/stratcliff.c (do_test): Declare size, nchars, inner, + middle and outer with size_t instead of int. Repleace %d and + %Zd with %zu in printf. Update "MAX (0, nchars - 128)" and + "MAX (outer, nchars - 64)" to support unsigned outer and + nchars. Also exit loop when outer == 0. + 2017-09-07 H.J. Lu * resolv/tst-resolv-qtypes.c (domain): Changed to diff --git a/string/stratcliff.c b/string/stratcliff.c index e672644..2cd8686 100644 --- a/string/stratcliff.c +++ b/string/stratcliff.c @@ -58,8 +58,8 @@ static int do_test (void) { - int size = sysconf (_SC_PAGESIZE); - int nchars = size / sizeof (CHAR); + size_t size = sysconf (_SC_PAGESIZE); + size_t nchars = size / sizeof (CHAR); CHAR *adr; CHAR *dest; int result = 0; @@ -80,7 +80,17 @@ do_test (void) } else { - int inner, middle, outer; + size_t inner, middle, outer, nchars64, max128; + + if (nchars > 64) + nchars64 = nchars - 64; + else + nchars64 = 0; + + if (nchars > 128) + max128 = nchars - 128; + else + max128 = 0; mprotect (adr, size, PROT_NONE); mprotect (adr + 2 * nchars, size, PROT_NONE); @@ -93,59 +103,65 @@ do_test (void) MEMSET (adr, L('T'), nchars); /* strlen/wcslen test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + for (inner = MAX (outer, nchars64); inner < nchars; ++inner) { adr[inner] = L('\0'); if (STRLEN (&adr[outer]) != (size_t) (inner - outer)) { - printf ("%s flunked for outer = %d, inner = %d\n", + printf ("%s flunked for outer = %zu, inner = %zu\n", STRINGIFY (STRLEN), outer, inner); result = 1; } adr[inner] = L('T'); } + if (outer == 0) + break; } /* strnlen/wcsnlen test */ - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars; outer >= max128; --outer) { - for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + for (inner = MAX (outer, nchars64); inner < nchars; ++inner) { adr[inner] = L('\0'); if (STRNLEN (&adr[outer], inner - outer + 1) != (size_t) (inner - outer)) { - printf ("%s flunked for outer = %d, inner = %d\n", + printf ("%s flunked for outer = %zu, inner = %zu\n", STRINGIFY (STRNLEN), outer, inner); result = 1; } adr[inner] = L('T'); } + if (outer == 0) + break; } - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars; outer >= max128; --outer) { - for (inner = MAX (outer, nchars - 64); inner <= nchars; ++inner) + for (inner = MAX (outer, nchars64); inner <= nchars; ++inner) { if (STRNLEN (&adr[outer], inner - outer) != (size_t) (inner - outer)) { - printf ("%s flunked bounded for outer = %d, inner = %d\n", + printf ("%s flunked bounded for outer = %zu, inner = %zu\n", STRINGIFY (STRNLEN), outer, inner); result = 1; } } + if (outer == 0) + break; } /* strchr/wcschr test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + for (middle = MAX (outer, nchars64); middle < nchars; ++middle) { for (inner = middle; inner < nchars; ++inner) { @@ -158,8 +174,8 @@ do_test (void) || (inner != middle && (cp - &adr[outer]) != middle - outer)) { - printf ("%s flunked for outer = %d, middle = %d, " - "inner = %d\n", + printf ("%s flunked for outer = %zu, middle = %zu, " + "inner = %zu\n", STRINGIFY (STRCHR), outer, middle, inner); result = 1; } @@ -168,6 +184,8 @@ do_test (void) adr[middle] = L('T'); } } + if (outer == 0) + break; } /* Special test. */ @@ -180,9 +198,9 @@ do_test (void) } /* strrchr/wcsrchr test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + for (middle = MAX (outer, nchars64); middle < nchars; ++middle) { for (inner = middle; inner < nchars; ++inner) { @@ -195,8 +213,8 @@ do_test (void) || (inner != middle && (cp - &adr[outer]) != middle - outer)) { - printf ("%s flunked for outer = %d, middle = %d, " - "inner = %d\n", + printf ("%s flunked for outer = %zu, middle = %zu, " + "inner = %zu\n", STRINGIFY (STRRCHR), outer, middle, inner); result = 1; } @@ -205,12 +223,14 @@ do_test (void) adr[middle] = L('T'); } } + if (outer == 0) + break; } /* memchr test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + for (middle = MAX (outer, nchars64); middle < nchars; ++middle) { adr[middle] = L('V'); @@ -218,32 +238,36 @@ do_test (void) if (cp - &adr[outer] != middle - outer) { - printf ("%s flunked for outer = %d, middle = %d\n", + printf ("%s flunked for outer = %zu, middle = %zu\n", STRINGIFY (MEMCHR), outer, middle); result = 1; } adr[middle] = L('T'); } + if (outer == 0) + break; } - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars; outer >= max128; --outer) { CHAR *cp = MEMCHR (&adr[outer], L('V'), nchars - outer); if (cp != NULL) { - printf ("%s flunked for outer = %d\n", + printf ("%s flunked for outer = %zu\n", STRINGIFY (MEMCHR), outer); result = 1; } + if (outer == 0) + break; } /* These functions only exist for single-byte characters. */ #ifndef WCSTEST /* rawmemchr test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + for (middle = MAX (outer, nchars64); middle < nchars; ++middle) { adr[middle] = L('V'); @@ -251,19 +275,21 @@ do_test (void) if (cp - &adr[outer] != middle - outer) { - printf ("%s flunked for outer = %d, middle = %d\n", + printf ("%s flunked for outer = %zu, middle = %zu\n", STRINGIFY (rawmemchr), outer, middle); result = 1; } adr[middle] = L('T'); } + if (outer == 0) + break; } /* memrchr test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + for (middle = MAX (outer, nchars64); middle < nchars; ++middle) { adr[middle] = L('V'); @@ -271,44 +297,50 @@ do_test (void) if (cp - &adr[outer] != middle - outer) { - printf ("%s flunked for outer = %d, middle = %d\n", + printf ("%s flunked for outer = %zu, middle = %zu\n", STRINGIFY (memrchr), outer, middle); result = 1; } adr[middle] = L('T'); } + if (outer == 0) + break; } - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars; outer >= max128; --outer) { CHAR *cp = memrchr (&adr[outer], L('V'), nchars - outer); if (cp != NULL) { - printf ("%s flunked for outer = %d\n", + printf ("%s flunked for outer = %zu\n", STRINGIFY (memrchr), outer); result = 1; } + if (outer == 0) + break; } #endif /* strcpy/wcscpy test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + for (inner = MAX (outer, nchars64); inner < nchars; ++inner) { adr[inner] = L('\0'); if (STRCPY (dest, &adr[outer]) != dest || STRLEN (dest) != (size_t) (inner - outer)) { - printf ("%s flunked for outer = %d, inner = %d\n", + printf ("%s flunked for outer = %zu, inner = %zu\n", STRINGIFY (STRCPY), outer, inner); result = 1; } adr[inner] = L('T'); } + if (outer == 0) + break; } /* strcmp/wcscmp tests */ @@ -322,14 +354,14 @@ do_test (void) if (STRCMP (adr + middle, dest + nchars - outer) <= 0) { - printf ("%s 1 flunked for outer = %d, middle = %d\n", + printf ("%s 1 flunked for outer = %zu, middle = %zu\n", STRINGIFY (STRCMP), outer, middle); result = 1; } if (STRCMP (dest + nchars - outer, adr + middle) >= 0) { - printf ("%s 2 flunked for outer = %d, middle = %d\n", + printf ("%s 2 flunked for outer = %zu, middle = %zu\n", STRINGIFY (STRCMP), outer, middle); result = 1; } @@ -348,16 +380,16 @@ do_test (void) { if (STRNCMP (adr + middle, dest + nchars - outer, inner) != 0) { - printf ("%s 1 flunked for outer = %d, middle = %d, " - "inner = %d\n", + printf ("%s 1 flunked for outer = %zu, middle = %zu, " + "inner = %zu\n", STRINGIFY (STRNCMP), outer, middle, inner); result = 1; } if (STRNCMP (dest + nchars - outer, adr + middle, inner) != 0) { - printf ("%s 2 flunked for outer = %d, middle = %d, " - "inner = %d\n", + printf ("%s 2 flunked for outer = %zu, middle = %zu, " + "inner = %zu\n", STRINGIFY (STRNCMP), outer, middle, inner); result = 1; } @@ -365,14 +397,14 @@ do_test (void) if (STRNCMP (adr + middle, dest + nchars - outer, outer) >= 0) { - printf ("%s 1 flunked for outer = %d, middle = %d, full\n", + printf ("%s 1 flunked for outer = %zu, middle = %zu, full\n", STRINGIFY (STRNCMP), outer, middle); result = 1; } if (STRNCMP (dest + nchars - outer, adr + middle, outer) <= 0) { - printf ("%s 2 flunked for outer = %d, middle = %d, full\n", + printf ("%s 2 flunked for outer = %zu, middle = %zu, full\n", STRINGIFY (STRNCMP), outer, middle); result = 1; } @@ -380,7 +412,7 @@ do_test (void) /* strncpy/wcsncpy tests */ adr[nchars - 1] = L('T'); - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars; outer >= max128; --outer) { size_t len; @@ -389,17 +421,19 @@ do_test (void) if (STRNCPY (dest, &adr[outer], len) != dest || MEMCMP (dest, &adr[outer], len) != 0) { - printf ("outer %s flunked for outer = %d, len = %Zd\n", + printf ("outer %s flunked for outer = %zu, len = %zu\n", STRINGIFY (STRNCPY), outer, len); result = 1; } } + if (outer == 0) + break; } adr[nchars - 1] = L('\0'); - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + for (inner = MAX (outer, nchars64); inner < nchars; ++inner) { size_t len; @@ -413,8 +447,8 @@ do_test (void) || (inner - outer < len && STRLEN (dest) != (inner - outer))) { - printf ("%s flunked for outer = %d, inner = %d, " - "len = %Zd\n", + printf ("%s flunked for outer = %zu, inner = %zu, " + "len = %zu\n", STRINGIFY (STRNCPY), outer, inner, len); result = 1; } @@ -424,8 +458,8 @@ do_test (void) || (inner - outer < len && STRLEN (dest + 1) != (inner - outer))) { - printf ("%s+1 flunked for outer = %d, inner = %d, " - "len = %Zd\n", + printf ("%s+1 flunked for outer = %zu, inner = %zu, " + "len = %zu\n", STRINGIFY (STRNCPY), outer, inner, len); result = 1; } @@ -433,29 +467,33 @@ do_test (void) adr[inner] = L('T'); } + if (outer == 0) + break; } /* stpcpy/wcpcpy test */ - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (inner = MAX (outer, nchars - 64); inner < nchars; ++inner) + for (inner = MAX (outer, nchars64); inner < nchars; ++inner) { adr[inner] = L('\0'); if ((STPCPY (dest, &adr[outer]) - dest) != inner - outer) { - printf ("%s flunked for outer = %d, inner = %d\n", + printf ("%s flunked for outer = %zu, inner = %zu\n", STRINGIFY (STPCPY), outer, inner); result = 1; } adr[inner] = L('T'); } + if (outer == 0) + break; } /* stpncpy/wcpncpy test */ adr[nchars - 1] = L('T'); - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars; outer >= max128; --outer) { size_t len; @@ -464,17 +502,19 @@ do_test (void) if (STPNCPY (dest, &adr[outer], len) != dest + len || MEMCMP (dest, &adr[outer], len) != 0) { - printf ("outer %s flunked for outer = %d, len = %Zd\n", + printf ("outer %s flunked for outer = %zu, len = %zu\n", STRINGIFY (STPNCPY), outer, len); result = 1; } } + if (outer == 0) + break; } adr[nchars - 1] = L('\0'); - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) + for (outer = nchars - 1; outer >= max128; --outer) { - for (middle = MAX (outer, nchars - 64); middle < nchars; ++middle) + for (middle = MAX (outer, nchars64); middle < nchars; ++middle) { adr[middle] = L('\0'); @@ -483,8 +523,8 @@ do_test (void) if ((STPNCPY (dest, &adr[outer], inner) - dest) != MIN (inner, middle - outer)) { - printf ("%s flunked for outer = %d, middle = %d, " - "inner = %d\n", + printf ("%s flunked for outer = %zu, middle = %zu, " + "inner = %zu\n", STRINGIFY (STPNCPY), outer, middle, inner); result = 1; } @@ -492,66 +532,84 @@ do_test (void) adr[middle] = L('T'); } + if (outer == 0) + break; } /* memcpy/wmemcpy test */ - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) - for (inner = 0; inner < nchars - outer; ++inner) - if (MEMCPY (dest, &adr[outer], inner) != dest) - { - printf ("%s flunked for outer = %d, inner = %d\n", - STRINGIFY (MEMCPY), outer, inner); - result = 1; - } + for (outer = nchars; outer >= max128; --outer) + { + for (inner = 0; inner < nchars - outer; ++inner) + if (MEMCPY (dest, &adr[outer], inner) != dest) + { + printf ("%s flunked for outer = %zu, inner = %zu\n", + STRINGIFY (MEMCPY), outer, inner); + result = 1; + } + if (outer == 0) + break; + } /* mempcpy/wmempcpy test */ - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) - for (inner = 0; inner < nchars - outer; ++inner) - if (MEMPCPY (dest, &adr[outer], inner) != dest + inner) - { - printf ("%s flunked for outer = %d, inner = %d\n", - STRINGIFY (MEMPCPY), outer, inner); - result = 1; - } + for (outer = nchars; outer >= max128; --outer) + { + for (inner = 0; inner < nchars - outer; ++inner) + if (MEMPCPY (dest, &adr[outer], inner) != dest + inner) + { + printf ("%s flunked for outer = %zu, inner = %zu\n", + STRINGIFY (MEMPCPY), outer, inner); + result = 1; + } + if (outer == 0) + break; + } /* This function only exists for single-byte characters. */ #ifndef WCSTEST /* memccpy test */ memset (adr, '\0', nchars); - for (outer = nchars; outer >= MAX (0, nchars - 128); --outer) - for (inner = 0; inner < nchars - outer; ++inner) - if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL) - { - printf ("memccpy flunked full copy for outer = %d, inner = %d\n", - outer, inner); - result = 1; - } - for (outer = nchars - 1; outer >= MAX (0, nchars - 128); --outer) - for (middle = 0; middle < nchars - outer; ++middle) - { - memset (dest, L('\2'), middle + 1); - for (inner = 0; inner < middle; ++inner) + for (outer = nchars; outer >= max128; --outer) + { + for (inner = 0; inner < nchars - outer; ++inner) + if (memccpy (dest, &adr[outer], L('\1'), inner) != NULL) { - adr[outer + inner] = L('\1'); - - if (memccpy (dest, &adr[outer], '\1', middle + 128) - != dest + inner + 1) - { - printf ("\ -memccpy flunked partial copy for outer = %d, middle = %d, inner = %d\n", - outer, middle, inner); - result = 1; - } - else if (dest[inner + 1] != L('\2')) - { - printf ("\ -memccpy copied too much for outer = %d, middle = %d, inner = %d\n", - outer, middle, inner); - result = 1; - } - adr[outer + inner] = L('\0'); + printf ("memccpy flunked full copy for outer = %zu, inner = %zu\n", + outer, inner); + result = 1; } - } + if (outer == 0) + break; + } + for (outer = nchars - 1; outer >= max128; --outer) + { + for (middle = 0; middle < nchars - outer; ++middle) + { + memset (dest, L('\2'), middle + 1); + for (inner = 0; inner < middle; ++inner) + { + adr[outer + inner] = L('\1'); + + if (memccpy (dest, &adr[outer], '\1', middle + 128) + != dest + inner + 1) + { + printf ("\ + memccpy flunked partial copy for outer = %zu, middle = %zu, inner = %zu\n", + outer, middle, inner); + result = 1; + } + else if (dest[inner + 1] != L('\2')) + { + printf ("\ + memccpy copied too much for outer = %zu, middle = %zu, inner = %zu\n", + outer, middle, inner); + result = 1; + } + adr[outer + inner] = L('\0'); + } + } + if (outer == 0) + break; + } #endif } commit b64e0298661a084d8aab6756b08dbced515449d8 Author: H.J. Lu Date: Mon Sep 11 09:04:57 2017 -0700 Make copy of from GCC 7 [BZ #21573] from GCC 7 will include /usr/include/stdlib.h from "#include_next" (instead of stdlib/stdlib.h in the glibc source directory), and this turns up as a make dependency. Also make a copy of to prevent it from including /usr/include/stdlib.h. * configure.ac (find_cxx_header): Suppress compiler error message. * configure: Regenerated. [BZ #21573] * Makerules [$(c++-bits-std_abs-h) != ""] (before-compile): Add $(common-objpfx)bits/std_abs.h. [$(c++-bits-std_abs-h) != ""] ($(common-objpfx)bits/std_abs.h): New target. * config.make.in (c++-bits-std_abs-h): New. * configure.ac (find_cxx_header): Use "\,$1," with sed. (CXX_BITS_STD_ABS_H): New. (AC_SUBST(CXX_BITS_STD_ABS_H)): Likewise. * configure: Regenerated. (cherry picked from commit a65ea28d1833d3502c5070472e43bda04410e6b5 and commit c2528fef3b05bcffb1ac27c6c09cc3ff24b7f03f) diff --git a/ChangeLog b/ChangeLog index a48cd9c..b7e129e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,21 @@ 2017-09-11 H.J. Lu + Florian Weimer + + * configure.ac (find_cxx_header): Suppress compiler error message. + * configure: Regenerated. + + [BZ #21573] + * Makerules [$(c++-bits-std_abs-h) != ""] (before-compile): Add + $(common-objpfx)bits/std_abs.h. + [$(c++-bits-std_abs-h) != ""] ($(common-objpfx)bits/std_abs.h): + New target. + * config.make.in (c++-bits-std_abs-h): New. + * configure.ac (find_cxx_header): Use "\,$1," with sed. + (CXX_BITS_STD_ABS_H): New. + (AC_SUBST(CXX_BITS_STD_ABS_H)): Likewise. + * configure: Regenerated. + +2017-09-11 H.J. Lu [BZ #21982] * string/stratcliff.c (do_test): Declare size, nchars, inner, diff --git a/Makerules b/Makerules index 7403305..43343f0 100644 --- a/Makerules +++ b/Makerules @@ -127,6 +127,14 @@ $(common-objpfx)cstdlib: $(c++-cstdlib-header) $(common-objpfx)cmath: $(c++-cmath-header) $(INSTALL_DATA) $< $@T $(move-if-change) $@T $@ +ifneq (,$(c++-bits-std_abs-h)) +# Also make a copy of from GCC 7 to prevent it from +# including /usr/include/stdlib.h. +before-compile := $(common-objpfx)bits/std_abs.h $(before-compile) +$(common-objpfx)bits/std_abs.h: $(c++-bits-std_abs-h) + $(INSTALL_DATA) $< $@T + $(move-if-change) $@T $@ +endif endif before-compile := $(common-objpfx)libc-abis.h $(before-compile) diff --git a/config.make.in b/config.make.in index 5836b32..709527d 100644 --- a/config.make.in +++ b/config.make.in @@ -47,6 +47,7 @@ sysincludes = @SYSINCLUDES@ c++-sysincludes = @CXX_SYSINCLUDES@ c++-cstdlib-header = @CXX_CSTDLIB_HEADER@ c++-cmath-header = @CXX_CMATH_HEADER@ +c++-bits-std_abs-h = @CXX_BITS_STD_ABS_H@ all-warnings = @all_warnings@ enable-werror = @enable_werror@ diff --git a/configure b/configure index eecd0ac..ee637a7 100755 --- a/configure +++ b/configure @@ -634,6 +634,7 @@ BISON INSTALL_INFO PERL BASH_SHELL +CXX_BITS_STD_ABS_H CXX_CMATH_HEADER CXX_CSTDLIB_HEADER CXX_SYSINCLUDES @@ -5318,14 +5319,17 @@ fi # copy of those headers in Makerules. if test -n "$CXX"; then find_cxx_header () { - echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}" + echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \ + | sed -n "\,$1:,{s/:\$//;p}" } CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)" CXX_CMATH_HEADER="$(find_cxx_header cmath)" + CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)" fi + # Test if LD_LIBRARY_PATH contains the notation for the current directory # since this would lead to problems installing/building glibc. # LD_LIBRARY_PATH contains the current directory if one of the following diff --git a/configure.ac b/configure.ac index 4a77411..d288ff4 100644 --- a/configure.ac +++ b/configure.ac @@ -1176,13 +1176,16 @@ AC_SUBST(CXX_SYSINCLUDES) # copy of those headers in Makerules. if test -n "$CXX"; then find_cxx_header () { - echo "#include <$1>" | $CXX -M -MP -x c++ - | sed -n "/$1:/{s/:\$//;p}" + echo "#include <$1>" | $CXX -M -MP -x c++ - 2>/dev/null \ + | sed -n "\,$1:,{s/:\$//;p}" } CXX_CSTDLIB_HEADER="$(find_cxx_header cstdlib)" CXX_CMATH_HEADER="$(find_cxx_header cmath)" + CXX_BITS_STD_ABS_H="$(find_cxx_header bits/std_abs.h)" fi AC_SUBST(CXX_CSTDLIB_HEADER) AC_SUBST(CXX_CMATH_HEADER) +AC_SUBST(CXX_BITS_STD_ABS_H) # Test if LD_LIBRARY_PATH contains the notation for the current directory # since this would lead to problems installing/building glibc. commit ac93084c086ff06f815c405c9eb36a2b1f02da6a Author: Joseph Myers Date: Tue Aug 22 00:59:43 2017 +0000 Fix sparc32 bits/long-double.h (bug 21987). My refactoring of long double information commit 0acb8a2a855395c25b1feef2470f4d7ca4bed589 Author: Joseph Myers Date: Wed Dec 14 18:27:56 2016 +0000 Refactor long double information into bits/long-double.h. resulted in sparc32 configurations installing the ldbl-opt version of bits/long-double.h instead of the intended sysdeps/unix/sysv/linux/sparc version. For sparc32 by itself, this is not a problem, since the ldbl-opt version is correct for sparc32. However, both sparc32 and sparc64 are supposed to install sets of headers that work for both of them, so that a single sysroot, whichever order the libraries are built and installed in, works for both. The effect of having the wrong version installed is that you end up with a miscompiled sparc64 libstdc++ which fails glibc's configure tests for the C++ compiler. This patch moves the header from sysdeps/unix/sysv/linux/sparc to separate copies of the same file for sparc32 and sparc64, to ensure it comes before ldbl-opt in the sysdeps directory ordering. Tested with build-many-glibcs.py for sparc64-linux-gnu and sparcv9-linux-gnu. [BZ #21987] * sysdeps/unix/sysv/linux/sparc/bits/long-double.h: Remove file and copy to ... * sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h: ... here. * sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h: ... and here. (cherry picked from commit 80f91666fed71fa3dd5eb5618739147cc731bc89) diff --git a/ChangeLog b/ChangeLog index b7e129e..53e80f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2017-08-22 Joseph Myers + + [BZ #21987] + * sysdeps/unix/sysv/linux/sparc/bits/long-double.h: Remove file + and copy to ... + * sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h: + ... here. + * sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h: + ... and here. + 2017-09-11 H.J. Lu Florian Weimer diff --git a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/bits/long-double.h deleted file mode 100644 index 094e051..0000000 --- a/sysdeps/unix/sysv/linux/sparc/bits/long-double.h +++ /dev/null @@ -1,26 +0,0 @@ -/* Properties of long double type. SPARC version. - Copyright (C) 2016-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 published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with the GNU C Library; if not, see - . */ - -#include - -#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32 -# define __LONG_DOUBLE_MATH_OPTIONAL 1 -# ifndef __LONG_DOUBLE_128__ -# define __NO_LONG_DOUBLE_MATH 1 -# endif -#endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h new file mode 100644 index 0000000..094e051 --- /dev/null +++ b/sysdeps/unix/sysv/linux/sparc/sparc32/bits/long-double.h @@ -0,0 +1,26 @@ +/* Properties of long double type. SPARC version. + Copyright (C) 2016-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 published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32 +# define __LONG_DOUBLE_MATH_OPTIONAL 1 +# ifndef __LONG_DOUBLE_128__ +# define __NO_LONG_DOUBLE_MATH 1 +# endif +#endif diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h new file mode 100644 index 0000000..094e051 --- /dev/null +++ b/sysdeps/unix/sysv/linux/sparc/sparc64/bits/long-double.h @@ -0,0 +1,26 @@ +/* Properties of long double type. SPARC version. + Copyright (C) 2016-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 published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +#if !defined __NO_LONG_DOUBLE_MATH && __WORDSIZE == 32 +# define __LONG_DOUBLE_MATH_OPTIONAL 1 +# ifndef __LONG_DOUBLE_128__ +# define __NO_LONG_DOUBLE_MATH 1 +# endif +#endif commit 0279dcae8825f5835d636a68372f6b4e72eb27f3 Author: DJ Delorie Date: Fri Jul 14 21:46:42 2017 -0400 Fix BZ #21654 - grp-merge.c alignment * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer alignment not char alignment. (__merge_grp): Likewise. (cherry picked from commit 4fa8ae49aa169fb8d97882938e8bee3ed9ce5410) diff --git a/ChangeLog b/ChangeLog index 53e80f8..f4e2c5d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-07-14 DJ Delorie + + [BZ #21654] + * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer + alignment not char alignment. + (__merge_grp): Likewise. + 2017-08-22 Joseph Myers [BZ #21987] diff --git a/grp/grp-merge.c b/grp/grp-merge.c index 77c494d..6590e5d 100644 --- a/grp/grp-merge.c +++ b/grp/grp-merge.c @@ -85,6 +85,14 @@ __copy_grp (const struct group srcgrp, const size_t buflen, } members[i] = NULL; + /* Align for pointers. We can't simply align C because we need to + align destbuf[c]. */ + if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0) + { + uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1); + c += __alignof__(char **) - mis_align; + } + /* Copy the pointers from the members array into the buffer and assign them to the gr_mem member of destgrp. */ destgrp->gr_mem = (char **) &destbuf[c]; @@ -168,6 +176,14 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, /* Add the NULL-terminator. */ members[savedmemcount + memcount] = NULL; + /* Align for pointers. We can't simply align C because we need to + align savedbuf[c]. */ + if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0) + { + uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1); + c += __alignof__(char **) - mis_align; + } + /* Copy the member array back into the buffer after the member list and free the member array. */ savedgrp->gr_mem = (char **) &savedbuf[c]; commit 864ea5f6579edfee41f7d4a778807045b5aff66b Author: DJ Delorie Date: Sat Oct 7 13:28:16 2017 +0200 Fix cast-after-dereference Original code was dereferencing a char*, then casting the value to size_t. Should cast the pointer to size_t* then deference. (cherry picked from commit f8cef4d07d9641e27629bd3ce2d13f5d702fb251) diff --git a/ChangeLog b/ChangeLog index f4e2c5d..f7cdb10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-19 DJ Delorie + + [BZ #21654] + * grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference. + 2017-07-14 DJ Delorie [BZ #21654] diff --git a/NEWS b/NEWS index f705771..11b82d2 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ The following bugs are resolved with this release: [21298] rwlock can deadlock on frequent reader/writer phase switching [21386] Assertion in fork for distinct parent PID is incorrect [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) + [21654] nss: Fix invalid cast in group merging [21778] Robust mutex may deadlock [21972] assert macro requires operator== (int) for its argument type diff --git a/grp/grp-merge.c b/grp/grp-merge.c index 6590e5d..035e7a6 100644 --- a/grp/grp-merge.c +++ b/grp/grp-merge.c @@ -137,7 +137,7 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, /* Get the count of group members from the last sizeof (size_t) bytes in the mergegrp buffer. */ - savedmemcount = (size_t) *(savedend - sizeof (size_t)); + savedmemcount = *(size_t *) (savedend - sizeof (size_t)); /* Get the count of new members to add. */ for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++) commit 595f287ae092dd973f6d5fb748cbe31ef7d82b2d Author: Florian Weimer Date: Wed Oct 11 13:09:11 2017 +0200 Synchronize support/ infrastructure with master This commit updates the support/ subdirectory to commit 84d0e6f05212cabe786cdf00bf3ba5d166d077c0 on the master branch. diff --git a/support/Makefile b/support/Makefile index 2ace3fa..027a663 100644 --- a/support/Makefile +++ b/support/Makefile @@ -65,6 +65,7 @@ libsupport-routines = \ xchroot \ xclose \ xconnect \ + xdlfcn \ xdup2 \ xfclose \ xfopen \ diff --git a/support/namespace.h b/support/namespace.h index 859c2fd..9eddb1a 100644 --- a/support/namespace.h +++ b/support/namespace.h @@ -66,7 +66,9 @@ struct support_chroot_configuration { /* File contents. The files are not created if the field is NULL. */ - const char *resolv_conf; + const char *resolv_conf; /* /etc/resolv.conf. */ + const char *hosts; /* /etc/hosts. */ + const char *host_conf; /* /etc/host.conf. */ }; /* The result of the creation of a chroot. */ @@ -78,8 +80,11 @@ struct support_chroot /* Path to the chroot directory. */ char *path_chroot; - /* Path to the /etc/resolv.conf file. */ - char *path_resolv_conf; + /* Paths to files in the chroot. These are absolute and outside of + the chroot. */ + char *path_resolv_conf; /* /etc/resolv.conf. */ + char *path_hosts; /* /etc/hosts. */ + char *path_host_conf; /* /etc/host.conf. */ }; /* Create a chroot environment. The returned data should be freed diff --git a/support/support_chroot.c b/support/support_chroot.c index c0807b3..f3ef551 100644 --- a/support/support_chroot.c +++ b/support/support_chroot.c @@ -24,6 +24,23 @@ #include #include +/* If CONTENTS is not NULL, write it to the file at DIRECTORY/RELPATH, + and store the name in *ABSPATH. If CONTENTS is NULL, store NULL in + *ABSPATH. */ +static void +write_file (const char *directory, const char *relpath, const char *contents, + char **abspath) +{ + if (contents != NULL) + { + *abspath = xasprintf ("%s/%s", directory, relpath); + add_temp_file (*abspath); + support_write_file_string (*abspath, contents); + } + else + *abspath = NULL; +} + struct support_chroot * support_chroot_create (struct support_chroot_configuration conf) { @@ -39,15 +56,10 @@ support_chroot_create (struct support_chroot_configuration conf) xmkdir (path_etc, 0777); add_temp_file (path_etc); - if (conf.resolv_conf != NULL) - { - /* Create an empty resolv.conf file. */ - chroot->path_resolv_conf = xasprintf ("%s/resolv.conf", path_etc); - add_temp_file (chroot->path_resolv_conf); - support_write_file_string (chroot->path_resolv_conf, conf.resolv_conf); - } - else - chroot->path_resolv_conf = NULL; + write_file (path_etc, "resolv.conf", conf.resolv_conf, + &chroot->path_resolv_conf); + write_file (path_etc, "hosts", conf.hosts, &chroot->path_hosts); + write_file (path_etc, "host.conf", conf.host_conf, &chroot->path_host_conf); free (path_etc); @@ -67,5 +79,7 @@ support_chroot_free (struct support_chroot *chroot) { free (chroot->path_chroot); free (chroot->path_resolv_conf); + free (chroot->path_hosts); + free (chroot->path_host_conf); free (chroot); } diff --git a/support/support_format_hostent.c b/support/support_format_hostent.c index 5b5f260..88c85ec 100644 --- a/support/support_format_hostent.c +++ b/support/support_format_hostent.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -41,10 +42,15 @@ support_format_hostent (struct hostent *h) { if (h == NULL) { - char *value = support_format_herrno (h_errno); - char *result = xasprintf ("error: %s\n", value); - free (value); - return result; + if (h_errno == NETDB_INTERNAL) + return xasprintf ("error: NETDB_INTERNAL (errno %d, %m)\n", errno); + else + { + char *value = support_format_herrno (h_errno); + char *result = xasprintf ("error: %s\n", value); + free (value); + return result; + } } struct xmemstream mem; diff --git a/support/xdlfcn.c b/support/xdlfcn.c new file mode 100644 index 0000000..6e39799 --- /dev/null +++ b/support/xdlfcn.c @@ -0,0 +1,58 @@ +/* Support functionality for using dlopen/dlclose/dlsym. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include + +void * +xdlopen (const char *filename, int flags) +{ + void *dso = dlopen (filename, flags); + + if (dso == NULL) + FAIL_EXIT1 ("error: dlopen: %s\n", dlerror ()); + + /* Clear any errors. */ + dlerror (); + + return dso; +} + +void * +xdlsym (void *handle, const char *symbol) +{ + void *sym = dlsym (handle, symbol); + + if (sym == NULL) + FAIL_EXIT1 ("error: dlsym: %s\n", dlerror ()); + + /* Clear any errors. */ + dlerror (); + + return sym; +} + +void +xdlclose (void *handle) +{ + if (dlclose (handle) != 0) + FAIL_EXIT1 ("error: dlclose: %s\n", dlerror ()); + + /* Clear any errors. */ + dlerror (); +} diff --git a/support/xdlfcn.h b/support/xdlfcn.h new file mode 100644 index 0000000..9bdcb38 --- /dev/null +++ b/support/xdlfcn.h @@ -0,0 +1,34 @@ +/* Support functionality for using dlopen/dlclose/dlsym. + 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 + . */ + +#ifndef SUPPORT_DLOPEN_H +#define SUPPORT_DLOPEN_H + +#include + +__BEGIN_DECLS + +/* Each of these terminates process on failure with relevant error message. */ +void *xdlopen (const char *filename, int flags); +void *xdlsym (void *handle, const char *symbol); +void xdlclose (void *handle); + + +__END_DECLS + +#endif /* SUPPORT_DLOPEN_H */