3080 lines
104 KiB
Diff
3080 lines
104 KiB
Diff
diff --git a/ChangeLog b/ChangeLog
|
||
index f140ee67de..73546da9e9 100644
|
||
--- a/ChangeLog
|
||
+++ b/ChangeLog
|
||
@@ -1,3 +1,215 @@
|
||
+2017-06-14 Florian Weimer <fweimer@redhat.com>
|
||
+
|
||
+ * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard.
|
||
+ * sysdeps/i386/i686/multiarch/varshift.c: Likewise.
|
||
+
|
||
+2017-03-07 Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||
+
|
||
+ [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 <fweimer@redhat.com>
|
||
+
|
||
+ * 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 <fweimer@redhat.com>
|
||
+
|
||
+ * 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 <fweimer@redhat.com>
|
||
+
|
||
+ [BZ #21624]
|
||
+ CVE-2017-1000366
|
||
+ * elf/rtld.c (process_envvars): Ignore LD_LIBRARY_PATH for
|
||
+ __libc_enable_secure.
|
||
+
|
||
+2017-05-12 Florian Weimer <fweimer@redhat.com>
|
||
+
|
||
+ [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 <joseph@codesourcery.com>
|
||
+
|
||
+ * 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 <adhemerval.zanella@linaro.org>
|
||
+
|
||
+ [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 <hongjiu.lu@intel.com>
|
||
+
|
||
+ [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 <hongjiu.lu@intel.com>
|
||
+
|
||
+ * 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 <adhemerval.zanella@linaro.org>
|
||
+
|
||
+ * posix/globtest.sh: Add cleanup routine on trap 0.
|
||
+
|
||
+2017-04-07 H.J. Lu <hongjiu.lu@intel.com>
|
||
+
|
||
+ [BZ #21258]
|
||
+ * sysdeps/x86_64/dl-trampoline.S (_dl_runtime_resolve_opt):
|
||
+ Define only if _dl_runtime_resolve is defined to
|
||
+ _dl_runtime_resolve_sse_vex.
|
||
+ * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_opt):
|
||
+ Fallthrough to _dl_runtime_resolve_sse_vex.
|
||
+
|
||
+2017-04-03 Mike Frysinger <vapier@gentoo.org>
|
||
+
|
||
+ [BZ #21253]
|
||
+ * sysdeps/unix/sysv/linux/spawni.c (__spawnix): Increase argv_size
|
||
+ slack space by 32KiB.
|
||
+
|
||
+2017-04-03 Wladimir van der Laan <laanwj@gmail.com>
|
||
+
|
||
+ [BZ# 21338]
|
||
+ * malloc/malloc.c: Call do_set_arena_max for M_ARENA_MAX
|
||
+ instead of incorrect do_set_arena_test
|
||
+
|
||
+2017-03-31 Slava Barinov <v.barinov@samsung.com>
|
||
+
|
||
+ [BZ #21289]
|
||
+ * io/fts.h (fts_set): Replace __REDIRECT with __REDIRECT_NTH.
|
||
+
|
||
+2017-03-20 Mike Frysinger <vapier@gentoo.org>
|
||
+
|
||
+ [BZ #21275]
|
||
+ * sysdeps/unix/sysv/linux/spawni.c [__ia64__] (CLONE): Rename
|
||
+ __stack to __stackbase.
|
||
+ (STACK): Invert _STACK_GROWS_DOWN and _STACK_GROWS_UP order of
|
||
+ checks so we can include defined(__ia64__) first.
|
||
+
|
||
+2017-03-15 Mike Frysinger <vapier@gentoo.org>
|
||
+
|
||
+ * sysdeps/x86_64/mempcpy_chk.S (__mempcpy_chk): Check for SHARED
|
||
+ instead of PIC.
|
||
+
|
||
+2017-03-15 John David Anglin <danglin@gcc.gnu.org>
|
||
+
|
||
+ * sysdeps/hppa/dl-machine.h (DL_STACK_END): Define.
|
||
+ (RTLD_START): Don't record stack end address in _dl_start_user.
|
||
+
|
||
+2017-03-02 Florian Weimer <fweimer@redhat.com>
|
||
+
|
||
+ [BZ #21015]
|
||
+ * manual/install.texi (Configuring and compiling): Document
|
||
+ --enable-bind-now.
|
||
+ * Makeconfig [bind-now] (LDFLAGS-lib.so): Set.
|
||
+ (build-shlib-helper): Use $(LDFLAGS-lib.so).
|
||
+ (format.lds): Likewise.
|
||
+ [bind-now] (LDFLAGS-c.so): Remove.
|
||
+ * sysdeps/x86_64/localplt.data (libm.so): matherr relocation can
|
||
+ be R_X86_64_GLOB_DAT.
|
||
+ * sysdeps/unix/sysv/linux/i386/localplt.data (libm.so): matherr
|
||
+ relocation can be R_386_GLOB_DAT.
|
||
+ * sysdeps/unix/sysv/linux/alpha/localplt.data (libm.so): matherr
|
||
+ relocaiton can be R_ALPHA_GLOB_DAT.
|
||
+ * iconvdata/Makefile [bind-now] (LDFLAGS.so): Add -Wl,-z,now.
|
||
+
|
||
+2017-02-28 Florian Weimer <fweimer@redhat.com>
|
||
+
|
||
+ [BZ #20257]
|
||
+ * inet/Makefile (routines): Add deadline.
|
||
+ (tests-static): Add tst-deadline.
|
||
+ * inet/net-internal.h (struct deadline_current_time)
|
||
+ (__deadline_current_time, struct deadline, __deadline_is_infinite)
|
||
+ (__deadline_elapsed, __deadline_first, __deadline_from_timeval)
|
||
+ (__deadline_to_ms, __is_timeval_valid_timeout): Declare.
|
||
+ * inet/deadline.c: New file.
|
||
+ * inet/tst-deadline.c: Likewise.
|
||
+ * sunrpc/Makefile (tests): Add tst-udp-nonblocking,
|
||
+ tst-udp-timeout, tst-udp-garbage.
|
||
+ (tst-udp-nonblocking, tst-udp-timeout): Link against libc.so
|
||
+ explicitly.
|
||
+ (tst-udp-garbage): Likewise. Also link against thread library.
|
||
+ * sunrpc/clnt_udp.c (struct cu_data): Mention in comment that the
|
||
+ struct layout is part of the ABI.
|
||
+ (clntudp_call): Rework timeout handling.
|
||
+ * sunrpc/tst-udp-garbage.c: New file.
|
||
+ * sunrpc/tst-udp-nonblocking.c: Likewise.
|
||
+ * sunrpc/tst-udp-timeout.c: Likewise.
|
||
+
|
||
+2017-02-27 Florian Weimer <fweimer@redhat.com>
|
||
+
|
||
+ [BZ #21115]
|
||
+ * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later.
|
||
+ * sunrpc/Makefile (tests): Add tst-udp-error.
|
||
+ (tst-udp-error): Link against libc.so explicitly.
|
||
+ * sunrpc/tst-udp-error: New file.
|
||
+
|
||
+2017-02-08 Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||
+
|
||
+ [BZ #21109]
|
||
+ * elf/dl-tunable-types.h (tunable_callback_t): Accept
|
||
+ tunable_val_t as argument.
|
||
+ * elf/dl-tunables.c (__tunable_set_val): Add comment.
|
||
+ * malloc/arena.c (set_mallopt_check): Take tunable_val_t as
|
||
+ argument.
|
||
+ (DL_TUNABLE_CALLBACK_FNDECL): Likewise.
|
||
+
|
||
2017-02-05 Siddhesh Poyarekar <siddhesh@sourceware.org>
|
||
|
||
* version.h (RELEASE): Set to "stable"
|
||
diff --git a/INSTALL b/INSTALL
|
||
index 3b3fd121b2..e77cb2d4e2 100644
|
||
--- a/INSTALL
|
||
+++ b/INSTALL
|
||
@@ -146,6 +146,12 @@ will be used, and CFLAGS sets optimization options for the compiler.
|
||
of routines called directly from assembler are excluded from this
|
||
protection.
|
||
|
||
+'--enable-bind-now'
|
||
+ Disable lazy binding for installed shared objects. This provides
|
||
+ additional security hardening because it enables full RELRO and a
|
||
+ read-only global offset table (GOT), at the cost of slightly
|
||
+ increased program load times.
|
||
+
|
||
'--enable-pt_chown'
|
||
The file 'pt_chown' is a helper binary for 'grantpt' (*note
|
||
Pseudo-Terminals: Allocation.) that is installed setuid root to fix
|
||
diff --git a/Makeconfig b/Makeconfig
|
||
index 97a15b569e..1c815113b9 100644
|
||
--- a/Makeconfig
|
||
+++ b/Makeconfig
|
||
@@ -386,6 +386,13 @@ LDFLAGS.so += $(hashstyle-LDFLAGS)
|
||
LDFLAGS-rtld += $(hashstyle-LDFLAGS)
|
||
endif
|
||
|
||
+# If lazy relocations are disabled, add the -z now flag. Use
|
||
+# LDFLAGS-lib.so instead of LDFLAGS.so, to avoid adding the flag to
|
||
+# test modules.
|
||
+ifeq ($(bind-now),yes)
|
||
+LDFLAGS-lib.so += -Wl,-z,now
|
||
+endif
|
||
+
|
||
# Command to run after every final link (executable or shared object).
|
||
# This is invoked with $(call after-link,...), so it should operate on
|
||
# the file $1. This can be set to do some sort of post-processing on
|
||
diff --git a/Makerules b/Makerules
|
||
index e9194e54cf..7f0eef8096 100644
|
||
--- a/Makerules
|
||
+++ b/Makerules
|
||
@@ -588,7 +588,7 @@ $(LINK.o) -shared -static-libgcc -Wl,-O1 $(sysdep-LDFLAGS) \
|
||
$(extra-B-$(@F:lib%.so=%).so) -B$(csu-objpfx) \
|
||
$(extra-B-$(@F:lib%.so=%).so) $(load-map-file) \
|
||
-Wl,-soname=lib$(libprefix)$(@F:lib%.so=%).so$($(@F)-version) \
|
||
- $(LDFLAGS.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
|
||
+ $(LDFLAGS.so) $(LDFLAGS-lib.so) $(LDFLAGS-$(@F:lib%.so=%).so) \
|
||
-L$(subst :, -L,$(rpath-link)) -Wl,-rpath-link=$(rpath-link)
|
||
endef
|
||
|
||
@@ -686,10 +686,6 @@ LDFLAGS-c.so = -nostdlib -nostartfiles
|
||
LDLIBS-c.so += $(libc.so-gnulib)
|
||
# Give libc.so an entry point and make it directly runnable itself.
|
||
LDFLAGS-c.so += -e __libc_main
|
||
-# If lazy relocation is disabled add the -z now flag.
|
||
-ifeq ($(bind-now),yes)
|
||
-LDFLAGS-c.so += -Wl,-z,now
|
||
-endif
|
||
# Pre-link the objects of libc_pic.a so that we can locally resolve
|
||
# COMMON symbols before we link against ld.so. This is because ld.so
|
||
# contains some of libc_pic.a already, which will prevent the COMMONs
|
||
@@ -1104,7 +1100,8 @@ $(common-objpfx)format.lds: $(..)scripts/output-format.sed \
|
||
ifneq (unknown,$(output-format))
|
||
echo > $@.new 'OUTPUT_FORMAT($(output-format))'
|
||
else
|
||
- $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) $(LDFLAGS.so) \
|
||
+ $(LINK.o) -shared $(sysdep-LDFLAGS) $(rtld-LDFLAGS) \
|
||
+ $(LDFLAGS.so) $(LDFLAGS-lib.so) \
|
||
-x c /dev/null -o $@.so -Wl,--verbose -v 2>&1 \
|
||
| sed -n -f $< > $@.new
|
||
test -s $@.new
|
||
diff --git a/NEWS b/NEWS
|
||
index ec15dde761..7be238c404 100644
|
||
--- a/NEWS
|
||
+++ b/NEWS
|
||
@@ -5,6 +5,19 @@ See the end for copying conditions.
|
||
Please send GNU C library bug reports via <http://sourceware.org/bugzilla/>
|
||
using `glibc' in the "product" field.
|
||
|
||
+Version 2.25.1
|
||
+
|
||
+The following bugs are resolved with this release:
|
||
+
|
||
+ [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
|
||
+ [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)
|
||
+
|
||
Version 2.25
|
||
|
||
* The feature test macro __STDC_WANT_LIB_EXT2__, from ISO/IEC TR
|
||
diff --git a/elf/Makefile b/elf/Makefile
|
||
index 61abeb59ee..cc4aeb25b6 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/dl-tunable-types.h b/elf/dl-tunable-types.h
|
||
index a986f0b593..37a4e8021f 100644
|
||
--- a/elf/dl-tunable-types.h
|
||
+++ b/elf/dl-tunable-types.h
|
||
@@ -21,8 +21,6 @@
|
||
# define _TUNABLE_TYPES_H_
|
||
#include <stddef.h>
|
||
|
||
-typedef void (*tunable_callback_t) (void *);
|
||
-
|
||
typedef enum
|
||
{
|
||
TUNABLE_TYPE_INT_32,
|
||
@@ -43,6 +41,8 @@ typedef union
|
||
const char *strval;
|
||
} tunable_val_t;
|
||
|
||
+typedef void (*tunable_callback_t) (tunable_val_t *);
|
||
+
|
||
/* Security level for tunables. This decides what to do with individual
|
||
tunables for AT_SECURE binaries. */
|
||
typedef enum
|
||
diff --git a/elf/dl-tunables.c b/elf/dl-tunables.c
|
||
index a8d53d6a31..e42aa67003 100644
|
||
--- a/elf/dl-tunables.c
|
||
+++ b/elf/dl-tunables.c
|
||
@@ -455,6 +455,8 @@ __tunable_set_val (tunable_id_t id, void *valp, tunable_callback_t callback)
|
||
if (cur->strval == NULL)
|
||
return;
|
||
|
||
+ /* Caller does not need the value, just call the callback with our tunable
|
||
+ value. */
|
||
if (valp == NULL)
|
||
goto cb;
|
||
|
||
diff --git a/elf/rtld.c b/elf/rtld.c
|
||
index a036ece956..9362a21e73 100644
|
||
--- a/elf/rtld.c
|
||
+++ b/elf/rtld.c
|
||
@@ -99,14 +99,121 @@ 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. */
|
||
+/* 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
|
||
@@ -716,6 +823,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,
|
||
@@ -1238,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. */
|
||
@@ -1253,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
|
||
@@ -1264,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;
|
||
@@ -1277,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);
|
||
}
|
||
@@ -1381,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. */
|
||
@@ -1462,23 +1609,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);
|
||
@@ -1663,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 ();
|
||
@@ -2294,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. */
|
||
@@ -2360,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:
|
||
@@ -2404,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;
|
||
@@ -2418,7 +2549,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;
|
||
diff --git a/elf/tst-env-setuid.c b/elf/tst-env-setuid.c
|
||
index 6ec3fa5874..eec408eb5d 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/iconvdata/Makefile b/iconvdata/Makefile
|
||
index 04157b25c5..e4845871f5 100644
|
||
--- a/iconvdata/Makefile
|
||
+++ b/iconvdata/Makefile
|
||
@@ -63,6 +63,11 @@ modules := ISO8859-1 ISO8859-2 ISO8859-3 ISO8859-4 ISO8859-5 \
|
||
MAC-CENTRALEUROPE KOI8-RU ISO8859-9E \
|
||
CP770 CP771 CP772 CP773 CP774
|
||
|
||
+# If lazy binding is disabled, use BIND_NOW for the gconv modules.
|
||
+ifeq ($(bind-now),yes)
|
||
+LDFLAGS.so += -Wl,-z,now
|
||
+endif
|
||
+
|
||
modules.so := $(addsuffix .so, $(modules))
|
||
|
||
ifeq (yes,$(build-shared))
|
||
diff --git a/inet/Makefile b/inet/Makefile
|
||
index 010792af8f..6a7d3e0664 100644
|
||
--- a/inet/Makefile
|
||
+++ b/inet/Makefile
|
||
@@ -45,14 +45,18 @@ routines := htonl htons \
|
||
in6_addr getnameinfo if_index ifaddrs inet6_option \
|
||
getipv4sourcefilter setipv4sourcefilter \
|
||
getsourcefilter setsourcefilter inet6_opt inet6_rth \
|
||
- inet6_scopeid_pton
|
||
+ inet6_scopeid_pton deadline
|
||
|
||
aux := check_pf check_native ifreq
|
||
|
||
tests := htontest test_ifindex tst-ntoa tst-ether_aton tst-network \
|
||
tst-gethnm test-ifaddrs bug-if1 test-inet6_opt tst-ether_line \
|
||
tst-getni1 tst-getni2 tst-inet6_rth tst-checks tst-checks-posix \
|
||
- tst-sockaddr tst-inet6_scopeid_pton test-hnto-types
|
||
+ tst-sockaddr tst-inet6_scopeid_pton test-hnto-types tst-deadline
|
||
+
|
||
+# tst-deadline must be linked statically so that we can access
|
||
+# internal functions.
|
||
+tests-static += tst-deadline
|
||
|
||
include ../Rules
|
||
|
||
diff --git a/inet/deadline.c b/inet/deadline.c
|
||
new file mode 100644
|
||
index 0000000000..c1fa415a39
|
||
--- /dev/null
|
||
+++ b/inet/deadline.c
|
||
@@ -0,0 +1,122 @@
|
||
+/* Computing deadlines for timeouts.
|
||
+ Copyright (C) 2017 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <net-internal.h>
|
||
+
|
||
+#include <assert.h>
|
||
+#include <limits.h>
|
||
+#include <stdio.h>
|
||
+#include <stdint.h>
|
||
+#include <time.h>
|
||
+
|
||
+struct deadline_current_time internal_function
|
||
+__deadline_current_time (void)
|
||
+{
|
||
+ struct deadline_current_time result;
|
||
+ if (__clock_gettime (CLOCK_MONOTONIC, &result.current) != 0)
|
||
+ {
|
||
+ struct timeval current_tv;
|
||
+ if (__gettimeofday (¤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 087597ed99..2b2632c7ba 100644
|
||
--- a/inet/net-internal.h
|
||
+++ b/inet/net-internal.h
|
||
@@ -20,11 +20,100 @@
|
||
#define _NET_INTERNAL_H 1
|
||
|
||
#include <arpa/inet.h>
|
||
+#include <stdbool.h>
|
||
#include <stdint.h>
|
||
+#include <sys/time.h>
|
||
|
||
int __inet6_scopeid_pton (const struct in6_addr *address,
|
||
const char *scope, uint32_t *result)
|
||
internal_function attribute_hidden;
|
||
libc_hidden_proto (__inet6_scopeid_pton)
|
||
|
||
+
|
||
+/* Deadline handling for enforcing timeouts.
|
||
+
|
||
+ Code should call __deadline_current_time to obtain the current time
|
||
+ and cache it locally. The cache needs updating after every
|
||
+ long-running or potentially blocking operation. Deadlines relative
|
||
+ to the current time can be computed using __deadline_from_timeval.
|
||
+ The deadlines may have to be recomputed in response to certain
|
||
+ events (such as an incoming packet), but they are absolute (not
|
||
+ relative to the current time). A timeout suitable for use with the
|
||
+ poll function can be computed from such a deadline using
|
||
+ __deadline_to_ms.
|
||
+
|
||
+ The fields in the structs defined belowed should only be used
|
||
+ within the implementation. */
|
||
+
|
||
+/* Cache of the current time. Used to compute deadlines from relative
|
||
+ timeouts and vice versa. */
|
||
+struct deadline_current_time
|
||
+{
|
||
+ struct timespec current;
|
||
+};
|
||
+
|
||
+/* Return the current time. Terminates the process if the current
|
||
+ time is not available. */
|
||
+struct deadline_current_time __deadline_current_time (void)
|
||
+ internal_function attribute_hidden;
|
||
+
|
||
+/* Computed absolute deadline. */
|
||
+struct deadline
|
||
+{
|
||
+ struct timespec absolute;
|
||
+};
|
||
+
|
||
+
|
||
+/* For internal use only. */
|
||
+static inline bool
|
||
+__deadline_is_infinite (struct deadline deadline)
|
||
+{
|
||
+ return deadline.absolute.tv_nsec < 0;
|
||
+}
|
||
+
|
||
+/* Return true if the current time is at the deadline or past it. */
|
||
+static inline bool
|
||
+__deadline_elapsed (struct deadline_current_time current,
|
||
+ struct deadline deadline)
|
||
+{
|
||
+ return !__deadline_is_infinite (deadline)
|
||
+ && (current.current.tv_sec > deadline.absolute.tv_sec
|
||
+ || (current.current.tv_sec == deadline.absolute.tv_sec
|
||
+ && current.current.tv_nsec >= deadline.absolute.tv_nsec));
|
||
+}
|
||
+
|
||
+/* Return the deadline which occurs first. */
|
||
+static inline struct deadline
|
||
+__deadline_first (struct deadline left, struct deadline right)
|
||
+{
|
||
+ if (__deadline_is_infinite (right)
|
||
+ || left.absolute.tv_sec < right.absolute.tv_sec
|
||
+ || (left.absolute.tv_sec == right.absolute.tv_sec
|
||
+ && left.absolute.tv_nsec < right.absolute.tv_nsec))
|
||
+ return left;
|
||
+ else
|
||
+ return right;
|
||
+}
|
||
+
|
||
+/* Add TV to the current time and return it. Returns a special
|
||
+ infinite absolute deadline on overflow. */
|
||
+struct deadline __deadline_from_timeval (struct deadline_current_time,
|
||
+ struct timeval tv)
|
||
+ internal_function attribute_hidden;
|
||
+
|
||
+/* Compute the number of milliseconds until the specified deadline,
|
||
+ from the current time in the argument. The result is mainly for
|
||
+ use with poll. If the deadline has already passed, return 0. If
|
||
+ the result would overflow an int, return INT_MAX. */
|
||
+int __deadline_to_ms (struct deadline_current_time, struct deadline)
|
||
+ internal_function attribute_hidden;
|
||
+
|
||
+/* Return true if TV.tv_sec is non-negative and TV.tv_usec is in the
|
||
+ interval [0, 999999]. */
|
||
+static inline bool
|
||
+__is_timeval_valid_timeout (struct timeval tv)
|
||
+{
|
||
+ return tv.tv_sec >= 0 && tv.tv_usec >= 0 && tv.tv_usec < 1000 * 1000;
|
||
+}
|
||
+
|
||
#endif /* _NET_INTERNAL_H */
|
||
diff --git a/inet/tst-deadline.c b/inet/tst-deadline.c
|
||
new file mode 100644
|
||
index 0000000000..ed04345c35
|
||
--- /dev/null
|
||
+++ b/inet/tst-deadline.c
|
||
@@ -0,0 +1,188 @@
|
||
+/* Tests for computing deadlines for timeouts.
|
||
+ Copyright (C) 2017 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <inet/net-internal.h>
|
||
+#include <limits.h>
|
||
+#include <stdbool.h>
|
||
+#include <stdint.h>
|
||
+#include <support/check.h>
|
||
+
|
||
+/* Find the maximum value which can be represented in a time_t. */
|
||
+static time_t
|
||
+time_t_max (void)
|
||
+{
|
||
+ _Static_assert (0 > (time_t) -1, "time_t is signed");
|
||
+ uintmax_t current = 1;
|
||
+ while (true)
|
||
+ {
|
||
+ uintmax_t next = current * 2;
|
||
+ /* This cannot happen because time_t is signed. */
|
||
+ TEST_VERIFY_EXIT (next > current);
|
||
+ ++next;
|
||
+ if ((time_t) next < 0 || next != (uintmax_t) (time_t) next)
|
||
+ /* Value cannot be represented in time_t. Return the previous
|
||
+ value. */
|
||
+ return current;
|
||
+ current = next;
|
||
+ }
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ {
|
||
+ struct deadline_current_time current_time = __deadline_current_time ();
|
||
+ TEST_VERIFY (current_time.current.tv_sec >= 0);
|
||
+ current_time = __deadline_current_time ();
|
||
+ /* Due to CLOCK_MONOTONIC, either seconds or nanoseconds are
|
||
+ greater than zero. This is also true for the gettimeofday
|
||
+ fallback. */
|
||
+ TEST_VERIFY (current_time.current.tv_sec >= 0);
|
||
+ TEST_VERIFY (current_time.current.tv_sec > 0
|
||
+ || current_time.current.tv_nsec > 0);
|
||
+ }
|
||
+
|
||
+ /* Check basic computations of deadlines. */
|
||
+ struct deadline_current_time current_time = { { 1, 123456789 } };
|
||
+ struct deadline deadline = __deadline_from_timeval
|
||
+ (current_time, (struct timeval) { 0, 1 });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 123457789);
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1);
|
||
+
|
||
+ deadline = __deadline_from_timeval
|
||
+ (current_time, ((struct timeval) { 0, 2 }));
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 123458789);
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1);
|
||
+
|
||
+ deadline = __deadline_from_timeval
|
||
+ (current_time, ((struct timeval) { 1, 0 }));
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 2);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 123456789);
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
|
||
+
|
||
+ /* Check if timeouts are correctly rounded up to the next
|
||
+ millisecond. */
|
||
+ for (int i = 0; i < 999999; ++i)
|
||
+ {
|
||
+ ++current_time.current.tv_nsec;
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
|
||
+ }
|
||
+
|
||
+ /* A full millisecond has elapsed, so the time to the deadline is
|
||
+ now less than 1000. */
|
||
+ ++current_time.current.tv_nsec;
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999);
|
||
+
|
||
+ /* Check __deadline_to_ms carry-over. */
|
||
+ current_time = (struct deadline_current_time) { { 9, 123456789 } };
|
||
+ deadline = (struct deadline) { { 10, 122456789 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 999);
|
||
+ deadline = (struct deadline) { { 10, 122456790 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
|
||
+ deadline = (struct deadline) { { 10, 123456788 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
|
||
+ deadline = (struct deadline) { { 10, 123456789 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 1000);
|
||
+
|
||
+ /* Check __deadline_to_ms overflow. */
|
||
+ deadline = (struct deadline) { { INT_MAX - 1, 1 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == INT_MAX);
|
||
+
|
||
+ /* Check __deadline_to_ms for elapsed deadlines. */
|
||
+ current_time = (struct deadline_current_time) { { 9, 123456789 } };
|
||
+ deadline.absolute = current_time.current;
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
|
||
+ current_time = (struct deadline_current_time) { { 9, 123456790 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
|
||
+ current_time = (struct deadline_current_time) { { 10, 0 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
|
||
+ current_time = (struct deadline_current_time) { { 10, 123456788 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
|
||
+ current_time = (struct deadline_current_time) { { 10, 123456789 } };
|
||
+ TEST_VERIFY (__deadline_to_ms (current_time, deadline) == 0);
|
||
+
|
||
+ /* Check carry-over in __deadline_from_timeval. */
|
||
+ current_time = (struct deadline_current_time) { { 9, 998000001 } };
|
||
+ for (int i = 0; i < 2000; ++i)
|
||
+ {
|
||
+ deadline = __deadline_from_timeval
|
||
+ (current_time, (struct timeval) { 1, i });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 10);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 998000001 + i * 1000);
|
||
+ }
|
||
+ for (int i = 2000; i < 3000; ++i)
|
||
+ {
|
||
+ deadline = __deadline_from_timeval
|
||
+ (current_time, (struct timeval) { 2, i });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 12);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 1 + (i - 2000) * 1000);
|
||
+ }
|
||
+
|
||
+ /* Check infinite deadlines. */
|
||
+ deadline = __deadline_from_timeval
|
||
+ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1000 } },
|
||
+ (struct timeval) { time_t_max (), 1 });
|
||
+ TEST_VERIFY (__deadline_is_infinite (deadline));
|
||
+ deadline = __deadline_from_timeval
|
||
+ ((struct deadline_current_time) { { 0, 1000 * 1000 * 1000 - 1001 } },
|
||
+ (struct timeval) { time_t_max (), 1 });
|
||
+ TEST_VERIFY (!__deadline_is_infinite (deadline));
|
||
+ deadline = __deadline_from_timeval
|
||
+ ((struct deadline_current_time)
|
||
+ { { time_t_max (), 1000 * 1000 * 1000 - 1000 } },
|
||
+ (struct timeval) { 0, 1 });
|
||
+ TEST_VERIFY (__deadline_is_infinite (deadline));
|
||
+ deadline = __deadline_from_timeval
|
||
+ ((struct deadline_current_time)
|
||
+ { { time_t_max () / 2 + 1, 0 } },
|
||
+ (struct timeval) { time_t_max () / 2 + 1, 0 });
|
||
+ TEST_VERIFY (__deadline_is_infinite (deadline));
|
||
+
|
||
+ /* Check __deadline_first behavior. */
|
||
+ deadline = __deadline_first
|
||
+ ((struct deadline) { { 1, 2 } },
|
||
+ (struct deadline) { { 1, 3 } });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
|
||
+ deadline = __deadline_first
|
||
+ ((struct deadline) { { 1, 3 } },
|
||
+ (struct deadline) { { 1, 2 } });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
|
||
+ deadline = __deadline_first
|
||
+ ((struct deadline) { { 1, 2 } },
|
||
+ (struct deadline) { { 2, 1 } });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
|
||
+ deadline = __deadline_first
|
||
+ ((struct deadline) { { 1, 2 } },
|
||
+ (struct deadline) { { 2, 4 } });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
|
||
+ deadline = __deadline_first
|
||
+ ((struct deadline) { { 2, 4 } },
|
||
+ (struct deadline) { { 1, 2 } });
|
||
+ TEST_VERIFY (deadline.absolute.tv_sec == 1);
|
||
+ TEST_VERIFY (deadline.absolute.tv_nsec == 2);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/io/fts.h b/io/fts.h
|
||
index b9cff534e9..ab15567001 100644
|
||
--- a/io/fts.h
|
||
+++ b/io/fts.h
|
||
@@ -193,7 +193,7 @@ FTS *__REDIRECT (fts_open, (char * const *, int,
|
||
int (*)(const FTSENT **, const FTSENT **)),
|
||
fts64_open);
|
||
FTSENT *__REDIRECT (fts_read, (FTS *), fts64_read);
|
||
-int __REDIRECT (fts_set, (FTS *, FTSENT *, int), fts64_set) __THROW;
|
||
+int __REDIRECT_NTH (fts_set, (FTS *, FTSENT *, int), fts64_set);
|
||
# else
|
||
# define fts_children fts64_children
|
||
# define fts_close fts64_close
|
||
diff --git a/localedata/ChangeLog b/localedata/ChangeLog
|
||
index 0cdb097ab6..127c1cfb35 100644
|
||
--- a/localedata/ChangeLog
|
||
+++ b/localedata/ChangeLog
|
||
@@ -1,3 +1,11 @@
|
||
+2017-06-11 Santhosh Thottingal <santhosh.thottingal@gmail.com>
|
||
+
|
||
+ [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 <joseph@codesourcery.com>
|
||
|
||
* All files with FSF copyright notices: Update copyright dates
|
||
diff --git a/localedata/locales/iso14651_t1_common b/localedata/locales/iso14651_t1_common
|
||
index eef75ba65e..0e64f26a12 100644
|
||
--- a/localedata/locales/iso14651_t1_common
|
||
+++ b/localedata/locales/iso14651_t1_common
|
||
@@ -1042,9 +1042,9 @@ collating-element <ml-bh> from "<U0D2D><U0D4D>"
|
||
collating-element <ml-m> from "<U0D2E><U0D4D>"
|
||
collating-element <ml-y> from "<U0D2F><U0D4D>"
|
||
collating-element <ml-v> from "<U0D35><U0D4D>"
|
||
-collating-element <ml-s> from "<U0D38><U0D4D>"
|
||
collating-element <ml-ss> from "<U0D36><U0D4D>"
|
||
collating-element <ml-sh> from "<U0D37><U0D4D>"
|
||
+collating-element <ml-s> from "<U0D38><U0D4D>"
|
||
collating-element <ml-h> from "<U0D39><U0D4D>"
|
||
collating-element <ml-zh> from "<U0D34><U0D4D>"
|
||
collating-element <ml-rr> from "<U0D31><U0D4D>"
|
||
@@ -1103,8 +1103,8 @@ collating-symbol <ml-rra>
|
||
collating-symbol <ml-la>
|
||
collating-symbol <ml-lla>
|
||
collating-symbol <ml-va>
|
||
-collating-symbol <ml-sha>
|
||
collating-symbol <ml-ssa>
|
||
+collating-symbol <ml-sha>
|
||
collating-symbol <ml-sa>
|
||
collating-symbol <ml-ha>
|
||
collating-symbol <ml-avagrah>
|
||
@@ -1126,6 +1126,12 @@ collating-symbol <mlvs-o>
|
||
collating-symbol <mlvs-au>
|
||
collating-symbol <ml-visarga>
|
||
collating-symbol <ml-virama>
|
||
+collating-symbol <ml-atomic-chillu-k>
|
||
+collating-symbol <ml-atomic-chillu-n>
|
||
+collating-symbol <ml-atomic-chillu-nn>
|
||
+collating-symbol <ml-atomic-chillu-l>
|
||
+collating-symbol <ml-atomic-chillu-ll>
|
||
+collating-symbol <ml-atomic-chillu-r>
|
||
#
|
||
# <BENGALI>
|
||
#
|
||
@@ -4552,6 +4558,12 @@ collating-symbol <TIB-subA>
|
||
<mlvs-o>
|
||
<mlvs-au>
|
||
<ml-visarga>
|
||
+<ml-atomic-chillu-k>
|
||
+<ml-atomic-chillu-n>
|
||
+<ml-atomic-chillu-nn>
|
||
+<ml-atomic-chillu-l>
|
||
+<ml-atomic-chillu-ll>
|
||
+<ml-atomic-chillu-r>
|
||
#
|
||
# <BENGALI>
|
||
#
|
||
@@ -7252,6 +7264,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||
<U0D13> <mlvw-o>;<BAS>;<MIN>;IGNORE
|
||
<U0D14> <mlvw-au>;<BAS>;<MIN>;IGNORE
|
||
<ml-chillu-k> "<ml-ka><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
+<U0D7F> "<ml-ka><ml-virama>";<ml-atomic-chillu-k>;<MIN>;IGNORE
|
||
<U0D15> "<ml-ka><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-kh> "<ml-kha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D16> "<ml-kha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
@@ -7280,6 +7293,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||
<ml-dh> "<ml-dha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D22> "<ml-dha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-chillu-nn> "<ml-nna><ml-virama>";<BAS>;<MIN>;IGNORE # ണ് = ണ + ് + zwj
|
||
+<U0D7A> "<ml-nna><ml-virama>";<ml-atomic-chillu-nn>;<MIN>;IGNORE
|
||
<U0D23> "<ml-nna><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ണ = ണ + ് + അ
|
||
<ml-th> "<ml-tha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D24> "<ml-tha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
@@ -7290,6 +7304,7 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||
<ml-ddh> "<ml-ddha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D27> "<ml-ddha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-chillu-n> "<ml-na><ml-virama>";<BAS>;<MIN>;IGNORE # ന്= ന + ് + zwj
|
||
+<U0D7B> "<ml-na><ml-virama>";<ml-atomic-chillu-n>;<MIN>;IGNORE
|
||
<U0D28> "<ml-na><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE #ന = ന + ് + അ
|
||
<ml-p> "<ml-pa><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D2A> "<ml-pa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
@@ -7305,20 +7320,23 @@ order_start <MALAYALAM>;forward;forward;forward;forward,position
|
||
<ml-y> "<ml-ya><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D2F> "<ml-ya><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-chillu-r> "<ml-ra><ml-virama>";<BAS>;<MIN>;IGNORE # ര = ര + ് + zwj
|
||
+<U0D7C> "<ml-ra><ml-virama>";<ml-atomic-chillu-r>;<MIN>;IGNORE
|
||
<U0D30> "<ml-ra><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ര = ര + ് + അ
|
||
<ml-chillu-l> <ml-la>;<BAS>;<MIN>;IGNORE # ല് = ല + ് + zwj
|
||
+<U0D7D> "<ml-la><ml-virama>";<ml-atomic-chillu-l>;<MIN>;IGNORE
|
||
<U0D32> "<ml-la><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ല = ല + ് + അ
|
||
<ml-v> "<ml-va><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D35> "<ml-va><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-ss> "<ml-ssa><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
-<U0D37> "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
+<U0D36> "<ml-ssa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-sh> "<ml-sha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
-<U0D36> "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
+<U0D37> "<ml-sha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-s> "<ml-sa><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D38> "<ml-sa><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-h> "<ml-ha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D39> "<ml-ha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
<ml-chillu-ll> "<ml-lla><ml-virama>";<BAS>;<MIN>;IGNORE # ള് = ള + ് + zwj
|
||
+<U0D7E> "<ml-lla><ml-virama>";<ml-atomic-chillu-ll>;<MIN>;IGNORE
|
||
<U0D33> "<ml-lla><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE # ള = ള + ് + അ
|
||
<ml-zh> "<ml-zha><ml-virama>";<BAS>;<MIN>;IGNORE
|
||
<U0D34> "<ml-zha><ml-virama><mlvw-shorta>";<BAS>;<MIN>;IGNORE
|
||
diff --git a/malloc/arena.c b/malloc/arena.c
|
||
index b91d7d6b16..d49e4a21c8 100644
|
||
--- a/malloc/arena.c
|
||
+++ b/malloc/arena.c
|
||
@@ -212,9 +212,9 @@ __malloc_fork_unlock_child (void)
|
||
#if HAVE_TUNABLES
|
||
static inline int do_set_mallopt_check (int32_t value);
|
||
void
|
||
-DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp)
|
||
+DL_TUNABLE_CALLBACK (set_mallopt_check) (tunable_val_t *valp)
|
||
{
|
||
- int32_t value = *(int32_t *) valp;
|
||
+ int32_t value = (int32_t) valp->numval;
|
||
do_set_mallopt_check (value);
|
||
if (check_action != 0)
|
||
__malloc_check_init ();
|
||
@@ -223,9 +223,9 @@ DL_TUNABLE_CALLBACK (set_mallopt_check) (void *valp)
|
||
# define DL_TUNABLE_CALLBACK_FNDECL(__name, __type) \
|
||
static inline int do_ ## __name (__type value); \
|
||
void \
|
||
-DL_TUNABLE_CALLBACK (__name) (void *valp) \
|
||
+DL_TUNABLE_CALLBACK (__name) (tunable_val_t *valp) \
|
||
{ \
|
||
- __type value = *(__type *) valp; \
|
||
+ __type value = (__type) (valp)->numval; \
|
||
do_ ## __name (value); \
|
||
}
|
||
|
||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||
index 4885793905..4e076638b0 100644
|
||
--- a/malloc/malloc.c
|
||
+++ b/malloc/malloc.c
|
||
@@ -4902,7 +4902,7 @@ __libc_mallopt (int param_number, int value)
|
||
|
||
case M_ARENA_MAX:
|
||
if (value > 0)
|
||
- do_set_arena_test (value);
|
||
+ do_set_arena_max (value);
|
||
break;
|
||
}
|
||
__libc_lock_unlock (av->mutex);
|
||
diff --git a/manual/install.texi b/manual/install.texi
|
||
index 266add8ba9..3398cfab02 100644
|
||
--- a/manual/install.texi
|
||
+++ b/manual/install.texi
|
||
@@ -175,6 +175,12 @@ options to detect stack overruns. Only the dynamic linker and a small
|
||
number of routines called directly from assembler are excluded from this
|
||
protection.
|
||
|
||
+@item --enable-bind-now
|
||
+Disable lazy binding for installed shared objects. This provides
|
||
+additional security hardening because it enables full RELRO and a
|
||
+read-only global offset table (GOT), at the cost of slightly increased
|
||
+program load times.
|
||
+
|
||
@pindex pt_chown
|
||
@findex grantpt
|
||
@item --enable-pt_chown
|
||
diff --git a/posix/globtest.sh b/posix/globtest.sh
|
||
index f9cc80b4b5..73f7ae31cc 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
|
||
|
||
diff --git a/string/test-memchr.c b/string/test-memchr.c
|
||
index d62889ff8f..6431605c7e 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/sunrpc/Makefile b/sunrpc/Makefile
|
||
index 0c1e6124ff..7e5d2955a0 100644
|
||
--- a/sunrpc/Makefile
|
||
+++ b/sunrpc/Makefile
|
||
@@ -93,11 +93,12 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \
|
||
extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs))
|
||
others += rpcgen
|
||
|
||
-tests = tst-xdrmem tst-xdrmem2 test-rpcent
|
||
+tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error tst-udp-timeout \
|
||
+ tst-udp-nonblocking
|
||
xtests := tst-getmyaddr
|
||
|
||
ifeq ($(have-thread-library),yes)
|
||
-xtests += thrsvc
|
||
+xtests += thrsvc tst-udp-garbage
|
||
endif
|
||
|
||
ifeq ($(run-built-tests),yes)
|
||
@@ -155,6 +156,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS)
|
||
$(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so
|
||
$(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so
|
||
$(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so
|
||
+$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so
|
||
|
||
$(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs))
|
||
|
||
@@ -234,3 +236,8 @@ $(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen
|
||
$(built-program-cmd) -c $< -o $@; \
|
||
$(evaluate-test)
|
||
endif
|
||
+
|
||
+$(objpfx)tst-udp-timeout: $(common-objpfx)linkobj/libc.so
|
||
+$(objpfx)tst-udp-nonblocking: $(common-objpfx)linkobj/libc.so
|
||
+$(objpfx)tst-udp-garbage: \
|
||
+ $(common-objpfx)linkobj/libc.so $(shared-thread-library)
|
||
diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c
|
||
index 4d9acb1e6a..6ce16eb298 100644
|
||
--- a/sunrpc/clnt_udp.c
|
||
+++ b/sunrpc/clnt_udp.c
|
||
@@ -55,6 +55,7 @@
|
||
#endif
|
||
|
||
#include <kernel-features.h>
|
||
+#include <inet/net-internal.h>
|
||
|
||
extern u_long _create_xid (void);
|
||
|
||
@@ -80,7 +81,9 @@ static const struct clnt_ops udp_ops =
|
||
};
|
||
|
||
/*
|
||
- * Private data kept per client handle
|
||
+ * Private data kept per client handle. This private struct is
|
||
+ * unfortunately part of the ABI; ypbind contains a copy of it and
|
||
+ * accesses it through CLIENT::cl_private field.
|
||
*/
|
||
struct cu_data
|
||
{
|
||
@@ -278,28 +281,38 @@ clntudp_call (/* client handle */
|
||
int inlen;
|
||
socklen_t fromlen;
|
||
struct pollfd fd;
|
||
- int milliseconds = (cu->cu_wait.tv_sec * 1000) +
|
||
- (cu->cu_wait.tv_usec / 1000);
|
||
struct sockaddr_in from;
|
||
struct rpc_msg reply_msg;
|
||
XDR reply_xdrs;
|
||
- struct timeval time_waited;
|
||
bool_t ok;
|
||
int nrefreshes = 2; /* number of times to refresh cred */
|
||
- struct timeval timeout;
|
||
int anyup; /* any network interface up */
|
||
|
||
- if (cu->cu_total.tv_usec == -1)
|
||
- {
|
||
- timeout = utimeout; /* use supplied timeout */
|
||
- }
|
||
- else
|
||
+ struct deadline_current_time current_time = __deadline_current_time ();
|
||
+ struct deadline total_deadline; /* Determined once by overall timeout. */
|
||
+ struct deadline response_deadline; /* Determined anew for each query. */
|
||
+
|
||
+ /* Choose the timeout value. For non-sending usage (xargs == NULL),
|
||
+ the total deadline does not matter, only cu->cu_wait is used
|
||
+ below. */
|
||
+ if (xargs != NULL)
|
||
{
|
||
- timeout = cu->cu_total; /* use default timeout */
|
||
+ struct timeval tv;
|
||
+ if (cu->cu_total.tv_usec == -1)
|
||
+ /* Use supplied timeout. */
|
||
+ tv = utimeout;
|
||
+ else
|
||
+ /* Use default timeout. */
|
||
+ tv = cu->cu_total;
|
||
+ if (!__is_timeval_valid_timeout (tv))
|
||
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
||
+ total_deadline = __deadline_from_timeval (current_time, tv);
|
||
}
|
||
|
||
- time_waited.tv_sec = 0;
|
||
- time_waited.tv_usec = 0;
|
||
+ /* Guard against bad timeout specification. */
|
||
+ if (!__is_timeval_valid_timeout (cu->cu_wait))
|
||
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
||
+
|
||
call_again:
|
||
xdrs = &(cu->cu_outxdrs);
|
||
if (xargs == NULL)
|
||
@@ -325,27 +338,46 @@ send_again:
|
||
return (cu->cu_error.re_status = RPC_CANTSEND);
|
||
}
|
||
|
||
- /*
|
||
- * Hack to provide rpc-based message passing
|
||
- */
|
||
- if (timeout.tv_sec == 0 && timeout.tv_usec == 0)
|
||
- {
|
||
- return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
||
- }
|
||
+ /* sendto may have blocked, so recompute the current time. */
|
||
+ current_time = __deadline_current_time ();
|
||
get_reply:
|
||
- /*
|
||
- * sub-optimal code appears here because we have
|
||
- * some clock time to spare while the packets are in flight.
|
||
- * (We assume that this is actually only executed once.)
|
||
- */
|
||
+ response_deadline = __deadline_from_timeval (current_time, cu->cu_wait);
|
||
+
|
||
reply_msg.acpted_rply.ar_verf = _null_auth;
|
||
reply_msg.acpted_rply.ar_results.where = resultsp;
|
||
reply_msg.acpted_rply.ar_results.proc = xresults;
|
||
fd.fd = cu->cu_sock;
|
||
fd.events = POLLIN;
|
||
anyup = 0;
|
||
+
|
||
+ /* Per-response retry loop. current_time must be up-to-date at the
|
||
+ top of the loop. */
|
||
for (;;)
|
||
{
|
||
+ int milliseconds;
|
||
+ if (xargs != NULL)
|
||
+ {
|
||
+ if (__deadline_elapsed (current_time, total_deadline))
|
||
+ /* Overall timeout expired. */
|
||
+ return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
||
+ milliseconds = __deadline_to_ms
|
||
+ (current_time, __deadline_first (total_deadline,
|
||
+ response_deadline));
|
||
+ if (milliseconds == 0)
|
||
+ /* Per-query timeout expired. */
|
||
+ goto send_again;
|
||
+ }
|
||
+ else
|
||
+ {
|
||
+ /* xatgs == NULL. Collect a response without sending a
|
||
+ query. In this mode, we need to ignore the total
|
||
+ deadline. */
|
||
+ milliseconds = __deadline_to_ms (current_time, response_deadline);
|
||
+ if (milliseconds == 0)
|
||
+ /* Cannot send again, so bail out. */
|
||
+ return (cu->cu_error.re_status = RPC_CANTSEND);
|
||
+ }
|
||
+
|
||
switch (__poll (&fd, 1, milliseconds))
|
||
{
|
||
|
||
@@ -356,27 +388,10 @@ send_again:
|
||
if (!anyup)
|
||
return (cu->cu_error.re_status = RPC_CANTRECV);
|
||
}
|
||
-
|
||
- time_waited.tv_sec += cu->cu_wait.tv_sec;
|
||
- time_waited.tv_usec += cu->cu_wait.tv_usec;
|
||
- while (time_waited.tv_usec >= 1000000)
|
||
- {
|
||
- time_waited.tv_sec++;
|
||
- time_waited.tv_usec -= 1000000;
|
||
- }
|
||
- if ((time_waited.tv_sec < timeout.tv_sec) ||
|
||
- ((time_waited.tv_sec == timeout.tv_sec) &&
|
||
- (time_waited.tv_usec < timeout.tv_usec)))
|
||
- goto send_again;
|
||
- return (cu->cu_error.re_status = RPC_TIMEDOUT);
|
||
-
|
||
- /*
|
||
- * buggy in other cases because time_waited is not being
|
||
- * updated.
|
||
- */
|
||
+ goto next_response;
|
||
case -1:
|
||
if (errno == EINTR)
|
||
- continue;
|
||
+ goto next_response;
|
||
cu->cu_error.re_errno = errno;
|
||
return (cu->cu_error.re_status = RPC_CANTRECV);
|
||
}
|
||
@@ -421,9 +436,9 @@ send_again:
|
||
cmsg = CMSG_NXTHDR (&msg, cmsg))
|
||
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
|
||
{
|
||
- free (cbuf);
|
||
e = (struct sock_extended_err *) CMSG_DATA(cmsg);
|
||
cu->cu_error.re_errno = e->ee_errno;
|
||
+ free (cbuf);
|
||
return (cu->cu_error.re_status = RPC_CANTRECV);
|
||
}
|
||
free (cbuf);
|
||
@@ -440,20 +455,22 @@ send_again:
|
||
if (inlen < 0)
|
||
{
|
||
if (errno == EWOULDBLOCK)
|
||
- continue;
|
||
+ goto next_response;
|
||
cu->cu_error.re_errno = errno;
|
||
return (cu->cu_error.re_status = RPC_CANTRECV);
|
||
}
|
||
- if (inlen < 4)
|
||
- continue;
|
||
-
|
||
- /* see if reply transaction id matches sent id.
|
||
- Don't do this if we only wait for a replay */
|
||
- if (xargs != NULL
|
||
- && memcmp (cu->cu_inbuf, cu->cu_outbuf, sizeof (u_int32_t)) != 0)
|
||
- continue;
|
||
- /* we now assume we have the proper reply */
|
||
- break;
|
||
+ /* Accept the response if the packet is sufficiently long and
|
||
+ the transaction ID matches the query (if available). */
|
||
+ if (inlen >= 4
|
||
+ && (xargs == NULL
|
||
+ || memcmp (cu->cu_inbuf, cu->cu_outbuf,
|
||
+ sizeof (u_int32_t)) == 0))
|
||
+ break;
|
||
+
|
||
+ next_response:
|
||
+ /* Update the current time because poll and recvmsg waited for
|
||
+ an unknown time. */
|
||
+ current_time = __deadline_current_time ();
|
||
}
|
||
|
||
/*
|
||
diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c
|
||
new file mode 100644
|
||
index 0000000000..1efc02f5c6
|
||
--- /dev/null
|
||
+++ b/sunrpc/tst-udp-error.c
|
||
@@ -0,0 +1,62 @@
|
||
+/* Check for use-after-free in clntudp_call (bug 21115).
|
||
+ Copyright (C) 2017 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <netinet/in.h>
|
||
+#include <rpc/clnt.h>
|
||
+#include <rpc/svc.h>
|
||
+#include <support/check.h>
|
||
+#include <support/namespace.h>
|
||
+#include <support/xsocket.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ support_become_root ();
|
||
+ support_enter_network_namespace ();
|
||
+
|
||
+ /* Obtain a likely-unused port number. */
|
||
+ struct sockaddr_in sin =
|
||
+ {
|
||
+ .sin_family = AF_INET,
|
||
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
|
||
+ };
|
||
+ {
|
||
+ int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||
+ xbind (fd, (struct sockaddr *) &sin, sizeof (sin));
|
||
+ socklen_t sinlen = sizeof (sin);
|
||
+ xgetsockname (fd, (struct sockaddr *) &sin, &sinlen);
|
||
+ /* Close the socket, so that we will receive an error below. */
|
||
+ close (fd);
|
||
+ }
|
||
+
|
||
+ int sock = RPC_ANYSOCK;
|
||
+ CLIENT *clnt = clntudp_create
|
||
+ (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock);
|
||
+ TEST_VERIFY_EXIT (clnt != NULL);
|
||
+ TEST_VERIFY (clnt_call (clnt, 3,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ ((struct timeval) { 3, 0 }))
|
||
+ == RPC_CANTRECV);
|
||
+ clnt_destroy (clnt);
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/sunrpc/tst-udp-garbage.c b/sunrpc/tst-udp-garbage.c
|
||
new file mode 100644
|
||
index 0000000000..4abda93f08
|
||
--- /dev/null
|
||
+++ b/sunrpc/tst-udp-garbage.c
|
||
@@ -0,0 +1,104 @@
|
||
+/* Test that garbage packets do not affect timeout handling.
|
||
+ Copyright (C) 2017 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <netinet/in.h>
|
||
+#include <rpc/clnt.h>
|
||
+#include <rpc/svc.h>
|
||
+#include <stdbool.h>
|
||
+#include <support/check.h>
|
||
+#include <support/namespace.h>
|
||
+#include <support/xsocket.h>
|
||
+#include <support/xthread.h>
|
||
+#include <sys/socket.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+/* Descriptor for the server UDP socket. */
|
||
+static int server_fd;
|
||
+
|
||
+static void *
|
||
+garbage_sender_thread (void *unused)
|
||
+{
|
||
+ while (true)
|
||
+ {
|
||
+ struct sockaddr_storage sa;
|
||
+ socklen_t salen = sizeof (sa);
|
||
+ char buf[1];
|
||
+ if (recvfrom (server_fd, buf, sizeof (buf), 0,
|
||
+ (struct sockaddr *) &sa, &salen) < 0)
|
||
+ FAIL_EXIT1 ("recvfrom: %m");
|
||
+
|
||
+ /* Send garbage packets indefinitely. */
|
||
+ buf[0] = 0;
|
||
+ while (true)
|
||
+ {
|
||
+ /* sendto can fail if the client closed the socket. */
|
||
+ if (sendto (server_fd, buf, sizeof (buf), 0,
|
||
+ (struct sockaddr *) &sa, salen) < 0)
|
||
+ break;
|
||
+
|
||
+ /* Wait a bit, to avoid burning too many CPU cycles in a
|
||
+ tight loop. The wait period must be much shorter than
|
||
+ the client timeouts configured below. */
|
||
+ usleep (50 * 1000);
|
||
+ }
|
||
+ }
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ support_become_root ();
|
||
+ support_enter_network_namespace ();
|
||
+
|
||
+ server_fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_UDP);
|
||
+ struct sockaddr_in server_address =
|
||
+ {
|
||
+ .sin_family = AF_INET,
|
||
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
|
||
+ };
|
||
+ xbind (server_fd,
|
||
+ (struct sockaddr *) &server_address, sizeof (server_address));
|
||
+ {
|
||
+ socklen_t sinlen = sizeof (server_address);
|
||
+ xgetsockname (server_fd, (struct sockaddr *) &server_address, &sinlen);
|
||
+ TEST_VERIFY (sizeof (server_address) == sinlen);
|
||
+ }
|
||
+
|
||
+ /* Garbage packet source. */
|
||
+ xpthread_detach (xpthread_create (NULL, garbage_sender_thread, NULL));
|
||
+
|
||
+ /* Test client. Use an arbitrary timeout of one second, which is
|
||
+ much longer than the garbage packet interval, but still
|
||
+ reasonably short, so that the test completes quickly. */
|
||
+ int client_fd = RPC_ANYSOCK;
|
||
+ CLIENT *clnt = clntudp_create (&server_address,
|
||
+ 1, 2, /* Arbitrary RPC endpoint numbers. */
|
||
+ (struct timeval) { 1, 0 },
|
||
+ &client_fd);
|
||
+ if (clnt == NULL)
|
||
+ FAIL_EXIT1 ("clntudp_create: %m");
|
||
+
|
||
+ TEST_VERIFY (clnt_call (clnt, 3, /* Arbitrary RPC procedure number. */
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ ((struct timeval) { 1, 0 })));
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/sunrpc/tst-udp-nonblocking.c b/sunrpc/tst-udp-nonblocking.c
|
||
new file mode 100644
|
||
index 0000000000..1d6a7f4b56
|
||
--- /dev/null
|
||
+++ b/sunrpc/tst-udp-nonblocking.c
|
||
@@ -0,0 +1,333 @@
|
||
+/* Test non-blocking use of the UDP client.
|
||
+ Copyright (C) 2017 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <netinet/in.h>
|
||
+#include <rpc/clnt.h>
|
||
+#include <rpc/svc.h>
|
||
+#include <stdbool.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/namespace.h>
|
||
+#include <support/test-driver.h>
|
||
+#include <support/xsocket.h>
|
||
+#include <support/xunistd.h>
|
||
+#include <sys/socket.h>
|
||
+#include <time.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+/* Test data serialization and deserialization. */
|
||
+
|
||
+struct test_query
|
||
+{
|
||
+ uint32_t a;
|
||
+ uint32_t b;
|
||
+ uint32_t timeout_ms;
|
||
+};
|
||
+
|
||
+static bool_t
|
||
+xdr_test_query (XDR *xdrs, void *data, ...)
|
||
+{
|
||
+ struct test_query *p = data;
|
||
+ return xdr_uint32_t (xdrs, &p->a)
|
||
+ && xdr_uint32_t (xdrs, &p->b)
|
||
+ && xdr_uint32_t (xdrs, &p->timeout_ms);
|
||
+}
|
||
+
|
||
+struct test_response
|
||
+{
|
||
+ uint32_t server_id;
|
||
+ uint32_t seq;
|
||
+ uint32_t sum;
|
||
+};
|
||
+
|
||
+static bool_t
|
||
+xdr_test_response (XDR *xdrs, void *data, ...)
|
||
+{
|
||
+ struct test_response *p = data;
|
||
+ return xdr_uint32_t (xdrs, &p->server_id)
|
||
+ && xdr_uint32_t (xdrs, &p->seq)
|
||
+ && xdr_uint32_t (xdrs, &p->sum);
|
||
+}
|
||
+
|
||
+/* Implementation of the test server. */
|
||
+
|
||
+enum
|
||
+ {
|
||
+ /* Number of test servers to run. */
|
||
+ SERVER_COUNT = 3,
|
||
+
|
||
+ /* RPC parameters, chosen at random. */
|
||
+ PROGNUM = 8242,
|
||
+ VERSNUM = 19654,
|
||
+
|
||
+ /* Main RPC operation. */
|
||
+ PROC_ADD = 1,
|
||
+
|
||
+ /* Request process termination. */
|
||
+ PROC_EXIT,
|
||
+
|
||
+ /* Special exit status to mark successful processing. */
|
||
+ EXIT_MARKER = 55,
|
||
+ };
|
||
+
|
||
+/* Set by the parent process to tell test servers apart. */
|
||
+static int server_id;
|
||
+
|
||
+/* Implementation of the test server. */
|
||
+static void
|
||
+server_dispatch (struct svc_req *request, SVCXPRT *transport)
|
||
+{
|
||
+ /* Query sequence number. */
|
||
+ static uint32_t seq = 0;
|
||
+ ++seq;
|
||
+ static bool proc_add_seen;
|
||
+
|
||
+ if (test_verbose)
|
||
+ printf ("info: server_dispatch server_id=%d seq=%u rq_proc=%lu\n",
|
||
+ server_id, seq, request->rq_proc);
|
||
+
|
||
+ switch (request->rq_proc)
|
||
+ {
|
||
+ case PROC_ADD:
|
||
+ {
|
||
+ struct test_query query;
|
||
+ memset (&query, 0xc0, sizeof (query));
|
||
+ TEST_VERIFY_EXIT
|
||
+ (svc_getargs (transport, xdr_test_query,
|
||
+ (void *) &query));
|
||
+
|
||
+ if (test_verbose)
|
||
+ printf (" a=%u b=%u timeout_ms=%u\n",
|
||
+ query.a, query.b, query.timeout_ms);
|
||
+
|
||
+ usleep (query.timeout_ms * 1000);
|
||
+
|
||
+ struct test_response response =
|
||
+ {
|
||
+ .server_id = server_id,
|
||
+ .seq = seq,
|
||
+ .sum = query.a + query.b,
|
||
+ };
|
||
+ TEST_VERIFY (svc_sendreply (transport, xdr_test_response,
|
||
+ (void *) &response));
|
||
+ if (test_verbose)
|
||
+ printf (" server id %d response seq=%u sent\n", server_id, seq);
|
||
+ proc_add_seen = true;
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case PROC_EXIT:
|
||
+ TEST_VERIFY (proc_add_seen);
|
||
+ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
|
||
+ _exit (EXIT_MARKER);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Return the number seconds since an arbitrary point in time. */
|
||
+static double
|
||
+get_ticks (void)
|
||
+{
|
||
+ {
|
||
+ struct timespec ts;
|
||
+ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
|
||
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
|
||
+ }
|
||
+ {
|
||
+ struct timeval tv;
|
||
+ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0);
|
||
+ return tv.tv_sec + tv.tv_usec * 1e-6;
|
||
+ }
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ support_become_root ();
|
||
+ support_enter_network_namespace ();
|
||
+
|
||
+ /* Information about the test servers. */
|
||
+ struct
|
||
+ {
|
||
+ SVCXPRT *transport;
|
||
+ struct sockaddr_in address;
|
||
+ pid_t pid;
|
||
+ uint32_t xid;
|
||
+ } servers[SERVER_COUNT];
|
||
+
|
||
+ /* Spawn the test servers. */
|
||
+ for (int i = 0; i < SERVER_COUNT; ++i)
|
||
+ {
|
||
+ servers[i].transport = svcudp_create (RPC_ANYSOCK);
|
||
+ TEST_VERIFY_EXIT (servers[i].transport != NULL);
|
||
+ servers[i].address = (struct sockaddr_in)
|
||
+ {
|
||
+ .sin_family = AF_INET,
|
||
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
|
||
+ .sin_port = htons (servers[i].transport->xp_port),
|
||
+ };
|
||
+ servers[i].xid = 0xabcd0101 + i;
|
||
+ if (test_verbose)
|
||
+ printf ("info: setting up server %d xid=%x on port %d\n",
|
||
+ i, servers[i].xid, servers[i].transport->xp_port);
|
||
+
|
||
+ server_id = i;
|
||
+ servers[i].pid = xfork ();
|
||
+ if (servers[i].pid == 0)
|
||
+ {
|
||
+ TEST_VERIFY (svc_register (servers[i].transport,
|
||
+ PROGNUM, VERSNUM, server_dispatch, 0));
|
||
+ svc_run ();
|
||
+ FAIL_EXIT1 ("supposed to be unreachable");
|
||
+ }
|
||
+ /* We need to close the socket so that we do not accidentally
|
||
+ consume the request. */
|
||
+ TEST_VERIFY (close (servers[i].transport->xp_sock) == 0);
|
||
+ }
|
||
+
|
||
+
|
||
+ /* The following code mirrors what ypbind does. */
|
||
+
|
||
+ /* Copied from clnt_udp.c (like ypbind). */
|
||
+ struct cu_data
|
||
+ {
|
||
+ int cu_sock;
|
||
+ bool_t cu_closeit;
|
||
+ struct sockaddr_in cu_raddr;
|
||
+ int cu_rlen;
|
||
+ struct timeval cu_wait;
|
||
+ struct timeval cu_total;
|
||
+ struct rpc_err cu_error;
|
||
+ XDR cu_outxdrs;
|
||
+ u_int cu_xdrpos;
|
||
+ u_int cu_sendsz;
|
||
+ char *cu_outbuf;
|
||
+ u_int cu_recvsz;
|
||
+ char cu_inbuf[1];
|
||
+ };
|
||
+
|
||
+ int client_socket = xsocket (AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
|
||
+ CLIENT *clnt = clntudp_create (&servers[0].address, PROGNUM, VERSNUM,
|
||
+ /* 5 seconds per-response timeout. */
|
||
+ ((struct timeval) { 5, 0 }),
|
||
+ &client_socket);
|
||
+ TEST_VERIFY (clnt != NULL);
|
||
+ clnt->cl_auth = authunix_create_default ();
|
||
+ {
|
||
+ struct timeval zero = { 0, 0 };
|
||
+ TEST_VERIFY (clnt_control (clnt, CLSET_TIMEOUT, (void *) &zero));
|
||
+ }
|
||
+
|
||
+ /* Poke at internal data structures (like ypbind). */
|
||
+ struct cu_data *cu = (struct cu_data *) clnt->cl_private;
|
||
+
|
||
+ /* Send a ping to each server. */
|
||
+ double before_pings = get_ticks ();
|
||
+ for (int i = 0; i < SERVER_COUNT; ++i)
|
||
+ {
|
||
+ if (test_verbose)
|
||
+ printf ("info: sending server %d ping\n", i);
|
||
+ /* Reset the xid because it is changed by each invocation of
|
||
+ clnt_call. Subtract one to compensate for the xid update
|
||
+ during the call. */
|
||
+ *((u_int32_t *) (cu->cu_outbuf)) = servers[i].xid - 1;
|
||
+ cu->cu_raddr = servers[i].address;
|
||
+
|
||
+ struct test_query query = { .a = 100, .b = i + 1 };
|
||
+ if (i == 1)
|
||
+ /* Shorter timeout to prefer this server. These timeouts must
|
||
+ be much shorter than the 5-second per-response timeout
|
||
+ configured with clntudp_create. */
|
||
+ query.timeout_ms = 700;
|
||
+ else
|
||
+ query.timeout_ms = 1400;
|
||
+ struct test_response response = { 0 };
|
||
+ /* NB: Do not check the return value. The server reply will
|
||
+ prove that the call worked. */
|
||
+ double before_one_ping = get_ticks ();
|
||
+ clnt_call (clnt, PROC_ADD,
|
||
+ xdr_test_query, (void *) &query,
|
||
+ xdr_test_response, (void *) &response,
|
||
+ ((struct timeval) { 0, 0 }));
|
||
+ double after_one_ping = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: non-blocking send took %f seconds\n",
|
||
+ after_one_ping - before_one_ping);
|
||
+ /* clnt_call should return immediately. Accept some delay in
|
||
+ case the process is descheduled. */
|
||
+ TEST_VERIFY (after_one_ping - before_one_ping < 0.3);
|
||
+ }
|
||
+
|
||
+ /* Collect the non-blocking response. */
|
||
+ if (test_verbose)
|
||
+ printf ("info: collecting response\n");
|
||
+ struct test_response response = { 0 };
|
||
+ TEST_VERIFY
|
||
+ (clnt_call (clnt, PROC_ADD, NULL, NULL,
|
||
+ xdr_test_response, (void *) &response,
|
||
+ ((struct timeval) { 0, 0 })) == RPC_SUCCESS);
|
||
+ double after_pings = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: send/receive took %f seconds\n",
|
||
+ after_pings - before_pings);
|
||
+ /* Expected timeout is 0.7 seconds. */
|
||
+ TEST_VERIFY (0.7 <= after_pings - before_pings);
|
||
+ TEST_VERIFY (after_pings - before_pings < 1.2);
|
||
+
|
||
+ uint32_t xid;
|
||
+ memcpy (&xid, &cu->cu_inbuf, sizeof (xid));
|
||
+ if (test_verbose)
|
||
+ printf ("info: non-blocking response: xid=%x server_id=%u seq=%u sum=%u\n",
|
||
+ xid, response.server_id, response.seq, response.sum);
|
||
+ /* Check that the reply from the preferred server was used. */
|
||
+ TEST_VERIFY (servers[1].xid == xid);
|
||
+ TEST_VERIFY (response.server_id == 1);
|
||
+ TEST_VERIFY (response.seq == 1);
|
||
+ TEST_VERIFY (response.sum == 102);
|
||
+
|
||
+ auth_destroy (clnt->cl_auth);
|
||
+ clnt_destroy (clnt);
|
||
+
|
||
+ for (int i = 0; i < SERVER_COUNT; ++i)
|
||
+ {
|
||
+ if (test_verbose)
|
||
+ printf ("info: requesting server %d termination\n", i);
|
||
+ client_socket = RPC_ANYSOCK;
|
||
+ clnt = clntudp_create (&servers[i].address, PROGNUM, VERSNUM,
|
||
+ ((struct timeval) { 5, 0 }),
|
||
+ &client_socket);
|
||
+ TEST_VERIFY_EXIT (clnt != NULL);
|
||
+ TEST_VERIFY (clnt_call (clnt, PROC_EXIT,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ ((struct timeval) { 3, 0 })) == RPC_SUCCESS);
|
||
+ clnt_destroy (clnt);
|
||
+
|
||
+ int status;
|
||
+ xwaitpid (servers[i].pid, &status, 0);
|
||
+ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER);
|
||
+ }
|
||
+
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+#include <support/test-driver.c>
|
||
diff --git a/sunrpc/tst-udp-timeout.c b/sunrpc/tst-udp-timeout.c
|
||
new file mode 100644
|
||
index 0000000000..db9943a03e
|
||
--- /dev/null
|
||
+++ b/sunrpc/tst-udp-timeout.c
|
||
@@ -0,0 +1,402 @@
|
||
+/* Test timeout handling in the UDP client.
|
||
+ Copyright (C) 2017 Free Software Foundation, Inc.
|
||
+ This file is part of the GNU C Library.
|
||
+
|
||
+ The GNU C Library is free software; you can redistribute it and/or
|
||
+ modify it under the terms of the GNU Lesser General Public
|
||
+ License as published by the Free Software Foundation; either
|
||
+ version 2.1 of the License, or (at your option) any later version.
|
||
+
|
||
+ The GNU C Library is distributed in the hope that it will be useful,
|
||
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
+ Lesser General Public License for more details.
|
||
+
|
||
+ You should have received a copy of the GNU Lesser General Public
|
||
+ License along with the GNU C Library; if not, see
|
||
+ <http://www.gnu.org/licenses/>. */
|
||
+
|
||
+#include <netinet/in.h>
|
||
+#include <rpc/clnt.h>
|
||
+#include <rpc/svc.h>
|
||
+#include <stdbool.h>
|
||
+#include <string.h>
|
||
+#include <support/check.h>
|
||
+#include <support/namespace.h>
|
||
+#include <support/test-driver.h>
|
||
+#include <support/xsocket.h>
|
||
+#include <support/xunistd.h>
|
||
+#include <sys/socket.h>
|
||
+#include <time.h>
|
||
+#include <unistd.h>
|
||
+
|
||
+/* Test data serialization and deserialization. */
|
||
+
|
||
+struct test_query
|
||
+{
|
||
+ uint32_t a;
|
||
+ uint32_t b;
|
||
+ uint32_t timeout_ms;
|
||
+ uint32_t wait_for_seq;
|
||
+ uint32_t garbage_packets;
|
||
+};
|
||
+
|
||
+static bool_t
|
||
+xdr_test_query (XDR *xdrs, void *data, ...)
|
||
+{
|
||
+ struct test_query *p = data;
|
||
+ return xdr_uint32_t (xdrs, &p->a)
|
||
+ && xdr_uint32_t (xdrs, &p->b)
|
||
+ && xdr_uint32_t (xdrs, &p->timeout_ms)
|
||
+ && xdr_uint32_t (xdrs, &p->wait_for_seq)
|
||
+ && xdr_uint32_t (xdrs, &p->garbage_packets);
|
||
+}
|
||
+
|
||
+struct test_response
|
||
+{
|
||
+ uint32_t seq;
|
||
+ uint32_t sum;
|
||
+};
|
||
+
|
||
+static bool_t
|
||
+xdr_test_response (XDR *xdrs, void *data, ...)
|
||
+{
|
||
+ struct test_response *p = data;
|
||
+ return xdr_uint32_t (xdrs, &p->seq)
|
||
+ && xdr_uint32_t (xdrs, &p->sum);
|
||
+}
|
||
+
|
||
+/* Implementation of the test server. */
|
||
+
|
||
+enum
|
||
+ {
|
||
+ /* RPC parameters, chosen at random. */
|
||
+ PROGNUM = 15717,
|
||
+ VERSNUM = 13689,
|
||
+
|
||
+ /* Main RPC operation. */
|
||
+ PROC_ADD = 1,
|
||
+
|
||
+ /* Reset the sequence number. */
|
||
+ PROC_RESET_SEQ,
|
||
+
|
||
+ /* Request process termination. */
|
||
+ PROC_EXIT,
|
||
+
|
||
+ /* Special exit status to mark successful processing. */
|
||
+ EXIT_MARKER = 55,
|
||
+ };
|
||
+
|
||
+static void
|
||
+server_dispatch (struct svc_req *request, SVCXPRT *transport)
|
||
+{
|
||
+ /* Query sequence number. */
|
||
+ static uint32_t seq = 0;
|
||
+ ++seq;
|
||
+
|
||
+ if (test_verbose)
|
||
+ printf ("info: server_dispatch seq=%u rq_proc=%lu\n",
|
||
+ seq, request->rq_proc);
|
||
+
|
||
+ switch (request->rq_proc)
|
||
+ {
|
||
+ case PROC_ADD:
|
||
+ {
|
||
+ struct test_query query;
|
||
+ memset (&query, 0xc0, sizeof (query));
|
||
+ TEST_VERIFY_EXIT
|
||
+ (svc_getargs (transport, xdr_test_query,
|
||
+ (void *) &query));
|
||
+
|
||
+ if (test_verbose)
|
||
+ printf (" a=%u b=%u timeout_ms=%u wait_for_seq=%u"
|
||
+ " garbage_packets=%u\n",
|
||
+ query.a, query.b, query.timeout_ms, query.wait_for_seq,
|
||
+ query.garbage_packets);
|
||
+
|
||
+ if (seq < query.wait_for_seq)
|
||
+ {
|
||
+ /* No response at this point. */
|
||
+ if (test_verbose)
|
||
+ printf (" skipped response\n");
|
||
+ break;
|
||
+ }
|
||
+
|
||
+ if (query.garbage_packets > 0)
|
||
+ {
|
||
+ int per_packet_timeout;
|
||
+ if (query.timeout_ms > 0)
|
||
+ per_packet_timeout
|
||
+ = query.timeout_ms * 1000 / query.garbage_packets;
|
||
+ else
|
||
+ per_packet_timeout = 0;
|
||
+
|
||
+ char buf[20];
|
||
+ memset (&buf, 0xc0, sizeof (buf));
|
||
+ for (int i = 0; i < query.garbage_packets; ++i)
|
||
+ {
|
||
+ /* 13 is relatively prime to 20 = sizeof (buf) + 1, so
|
||
+ the len variable will cover the entire interval
|
||
+ [0, 20] if query.garbage_packets is sufficiently
|
||
+ large. */
|
||
+ size_t len = (i * 13 + 1) % (sizeof (buf) + 1);
|
||
+ TEST_VERIFY (sendto (transport->xp_sock,
|
||
+ buf, len, MSG_NOSIGNAL,
|
||
+ (struct sockaddr *) &transport->xp_raddr,
|
||
+ transport->xp_addrlen) == len);
|
||
+ if (per_packet_timeout > 0)
|
||
+ usleep (per_packet_timeout);
|
||
+ }
|
||
+ }
|
||
+ else if (query.timeout_ms > 0)
|
||
+ usleep (query.timeout_ms * 1000);
|
||
+
|
||
+ struct test_response response =
|
||
+ {
|
||
+ .seq = seq,
|
||
+ .sum = query.a + query.b,
|
||
+ };
|
||
+ TEST_VERIFY (svc_sendreply (transport, xdr_test_response,
|
||
+ (void *) &response));
|
||
+ }
|
||
+ break;
|
||
+
|
||
+ case PROC_RESET_SEQ:
|
||
+ seq = 0;
|
||
+ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
|
||
+ break;
|
||
+
|
||
+ case PROC_EXIT:
|
||
+ TEST_VERIFY (svc_sendreply (transport, (xdrproc_t) xdr_void, NULL));
|
||
+ _exit (EXIT_MARKER);
|
||
+ break;
|
||
+
|
||
+ default:
|
||
+ FAIL_EXIT1 ("invalid rq_proc value: %lu", request->rq_proc);
|
||
+ break;
|
||
+ }
|
||
+}
|
||
+
|
||
+/* Implementation of the test client. */
|
||
+
|
||
+static struct test_response
|
||
+test_call (CLIENT *clnt, int proc, struct test_query query,
|
||
+ struct timeval timeout)
|
||
+{
|
||
+ if (test_verbose)
|
||
+ printf ("info: test_call proc=%d timeout=%lu.%06lu\n",
|
||
+ proc, (unsigned long) timeout.tv_sec,
|
||
+ (unsigned long) timeout.tv_usec);
|
||
+ struct test_response response;
|
||
+ TEST_VERIFY_EXIT (clnt_call (clnt, proc,
|
||
+ xdr_test_query, (void *) &query,
|
||
+ xdr_test_response, (void *) &response,
|
||
+ timeout)
|
||
+ == RPC_SUCCESS);
|
||
+ return response;
|
||
+}
|
||
+
|
||
+static void
|
||
+test_call_timeout (CLIENT *clnt, int proc, struct test_query query,
|
||
+ struct timeval timeout)
|
||
+{
|
||
+ struct test_response response;
|
||
+ TEST_VERIFY (clnt_call (clnt, proc,
|
||
+ xdr_test_query, (void *) &query,
|
||
+ xdr_test_response, (void *) &response,
|
||
+ timeout)
|
||
+ == RPC_TIMEDOUT);
|
||
+}
|
||
+
|
||
+/* Complete one regular RPC call to drain the server socket
|
||
+ buffer. Resets the sequence number. */
|
||
+static void
|
||
+test_call_flush (CLIENT *clnt)
|
||
+{
|
||
+ /* This needs a longer timeout to flush out all pending requests.
|
||
+ The choice of 5 seconds is larger than the per-response timeouts
|
||
+ requested via the timeout_ms field. */
|
||
+ if (test_verbose)
|
||
+ printf ("info: flushing pending queries\n");
|
||
+ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_RESET_SEQ,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ ((struct timeval) { 5, 0 }))
|
||
+ == RPC_SUCCESS);
|
||
+}
|
||
+
|
||
+/* Return the number seconds since an arbitrary point in time. */
|
||
+static double
|
||
+get_ticks (void)
|
||
+{
|
||
+ {
|
||
+ struct timespec ts;
|
||
+ if (clock_gettime (CLOCK_MONOTONIC, &ts) == 0)
|
||
+ return ts.tv_sec + ts.tv_nsec * 1e-9;
|
||
+ }
|
||
+ {
|
||
+ struct timeval tv;
|
||
+ TEST_VERIFY_EXIT (gettimeofday (&tv, NULL) == 0);
|
||
+ return tv.tv_sec + tv.tv_usec * 1e-6;
|
||
+ }
|
||
+}
|
||
+
|
||
+static void
|
||
+test_udp_server (int port)
|
||
+{
|
||
+ struct sockaddr_in sin =
|
||
+ {
|
||
+ .sin_family = AF_INET,
|
||
+ .sin_addr.s_addr = htonl (INADDR_LOOPBACK),
|
||
+ .sin_port = htons (port)
|
||
+ };
|
||
+ int sock = RPC_ANYSOCK;
|
||
+
|
||
+ /* The client uses a 1.5 second timeout for retries. The timeouts
|
||
+ are arbitrary, but chosen so that there is a substantial gap
|
||
+ between them, but the total time spent waiting is not too
|
||
+ large. */
|
||
+ CLIENT *clnt = clntudp_create (&sin, PROGNUM, VERSNUM,
|
||
+ (struct timeval) { 1, 500 * 1000 },
|
||
+ &sock);
|
||
+ TEST_VERIFY_EXIT (clnt != NULL);
|
||
+
|
||
+ /* Basic call/response test. */
|
||
+ struct test_response response = test_call
|
||
+ (clnt, PROC_ADD,
|
||
+ (struct test_query) { .a = 17, .b = 4 },
|
||
+ (struct timeval) { 3, 0 });
|
||
+ TEST_VERIFY (response.sum == 21);
|
||
+ TEST_VERIFY (response.seq == 1);
|
||
+
|
||
+ /* Check that garbage packets do not interfere with timeout
|
||
+ processing. */
|
||
+ double before = get_ticks ();
|
||
+ response = test_call
|
||
+ (clnt, PROC_ADD,
|
||
+ (struct test_query) {
|
||
+ .a = 19, .b = 4, .timeout_ms = 500, .garbage_packets = 21,
|
||
+ },
|
||
+ (struct timeval) { 3, 0 });
|
||
+ TEST_VERIFY (response.sum == 23);
|
||
+ TEST_VERIFY (response.seq == 2);
|
||
+ double after = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: 21 garbage packets took %f seconds\n", after - before);
|
||
+ /* Expected timeout is 0.5 seconds. Add some slack in case process
|
||
+ scheduling delays processing the query or response, but do not
|
||
+ accept a retry (which would happen at 1.5 seconds). */
|
||
+ TEST_VERIFY (0.5 <= after - before);
|
||
+ TEST_VERIFY (after - before < 1.2);
|
||
+ test_call_flush (clnt);
|
||
+
|
||
+ /* Check that missing a response introduces a 1.5 second timeout, as
|
||
+ requested when calling clntudp_create. */
|
||
+ before = get_ticks ();
|
||
+ response = test_call
|
||
+ (clnt, PROC_ADD,
|
||
+ (struct test_query) { .a = 170, .b = 40, .wait_for_seq = 2 },
|
||
+ (struct timeval) { 3, 0 });
|
||
+ TEST_VERIFY (response.sum == 210);
|
||
+ TEST_VERIFY (response.seq == 2);
|
||
+ after = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: skipping one response took %f seconds\n",
|
||
+ after - before);
|
||
+ /* Expected timeout is 1.5 seconds. Do not accept a second retry
|
||
+ (which would happen at 3 seconds). */
|
||
+ TEST_VERIFY (1.5 <= after - before);
|
||
+ TEST_VERIFY (after - before < 2.9);
|
||
+ test_call_flush (clnt);
|
||
+
|
||
+ /* Check that the overall timeout wins against the per-query
|
||
+ timeout. */
|
||
+ before = get_ticks ();
|
||
+ test_call_timeout
|
||
+ (clnt, PROC_ADD,
|
||
+ (struct test_query) { .a = 170, .b = 41, .wait_for_seq = 2 },
|
||
+ (struct timeval) { 0, 750 * 1000 });
|
||
+ after = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: 0.75 second timeout took %f seconds\n",
|
||
+ after - before);
|
||
+ TEST_VERIFY (0.75 <= after - before);
|
||
+ TEST_VERIFY (after - before < 1.4);
|
||
+ test_call_flush (clnt);
|
||
+
|
||
+ for (int with_garbage = 0; with_garbage < 2; ++with_garbage)
|
||
+ {
|
||
+ /* Check that no response at all causes the client to bail out. */
|
||
+ before = get_ticks ();
|
||
+ test_call_timeout
|
||
+ (clnt, PROC_ADD,
|
||
+ (struct test_query) {
|
||
+ .a = 170, .b = 40, .timeout_ms = 1200,
|
||
+ .garbage_packets = with_garbage * 21
|
||
+ },
|
||
+ (struct timeval) { 0, 750 * 1000 });
|
||
+ after = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: test_udp_server: 0.75 second timeout took %f seconds"
|
||
+ " (garbage %d)\n",
|
||
+ after - before, with_garbage);
|
||
+ TEST_VERIFY (0.75 <= after - before);
|
||
+ TEST_VERIFY (after - before < 1.4);
|
||
+ test_call_flush (clnt);
|
||
+
|
||
+ /* As above, but check the total timeout. */
|
||
+ before = get_ticks ();
|
||
+ test_call_timeout
|
||
+ (clnt, PROC_ADD,
|
||
+ (struct test_query) {
|
||
+ .a = 170, .b = 40, .timeout_ms = 3000,
|
||
+ .garbage_packets = with_garbage * 30
|
||
+ },
|
||
+ (struct timeval) { 2, 300 * 1000 });
|
||
+ after = get_ticks ();
|
||
+ if (test_verbose)
|
||
+ printf ("info: test_udp_server: 2.3 second timeout took %f seconds"
|
||
+ " (garbage %d)\n",
|
||
+ after - before, with_garbage);
|
||
+ TEST_VERIFY (2.3 <= after - before);
|
||
+ TEST_VERIFY (after - before < 3.0);
|
||
+ test_call_flush (clnt);
|
||
+ }
|
||
+
|
||
+ TEST_VERIFY_EXIT (clnt_call (clnt, PROC_EXIT,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ (xdrproc_t) xdr_void, NULL,
|
||
+ ((struct timeval) { 5, 0 }))
|
||
+ == RPC_SUCCESS);
|
||
+ clnt_destroy (clnt);
|
||
+}
|
||
+
|
||
+static int
|
||
+do_test (void)
|
||
+{
|
||
+ support_become_root ();
|
||
+ support_enter_network_namespace ();
|
||
+
|
||
+ SVCXPRT *transport = svcudp_create (RPC_ANYSOCK);
|
||
+ TEST_VERIFY_EXIT (transport != NULL);
|
||
+ TEST_VERIFY (svc_register (transport, PROGNUM, VERSNUM, server_dispatch, 0));
|
||
+
|
||
+ pid_t pid = xfork ();
|
||
+ if (pid == 0)
|
||
+ {
|
||
+ svc_run ();
|
||
+ FAIL_EXIT1 ("supposed to be unreachable");
|
||
+ }
|
||
+ test_udp_server (transport->xp_port);
|
||
+
|
||
+ int status;
|
||
+ xwaitpid (pid, &status, 0);
|
||
+ TEST_VERIFY (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_MARKER);
|
||
+
|
||
+ SVC_DESTROY (transport);
|
||
+ return 0;
|
||
+}
|
||
+
|
||
+/* The minimum run time is around 17 seconds. */
|
||
+#define TIMEOUT 25
|
||
+#include <support/test-driver.c>
|
||
diff --git a/sysdeps/generic/unsecvars.h b/sysdeps/generic/unsecvars.h
|
||
index a74083786e..5ea8a4a259 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" \
|
||
diff --git a/sysdeps/hppa/dl-machine.h b/sysdeps/hppa/dl-machine.h
|
||
index 339c7bb771..787b95f502 100644
|
||
--- a/sysdeps/hppa/dl-machine.h
|
||
+++ b/sysdeps/hppa/dl-machine.h
|
||
@@ -302,6 +302,10 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile)
|
||
#define ARCH_LA_PLTENTER hppa_gnu_pltenter
|
||
#define ARCH_LA_PLTEXIT hppa_gnu_pltexit
|
||
|
||
+/* Adjust DL_STACK_END to get value we want in __libc_stack_end. */
|
||
+#define DL_STACK_END(cookie) \
|
||
+ ((void *) (((long) (cookie)) + 0x160))
|
||
+
|
||
/* Initial entry point code for the dynamic linker.
|
||
The C function `_dl_start' is the real entry point;
|
||
its return value is the user program's entry point. */
|
||
@@ -401,11 +405,6 @@ asm ( \
|
||
/* Save the entry point in %r3. */ \
|
||
" copy %ret0,%r3\n" \
|
||
\
|
||
- /* Remember the lowest stack address. */ \
|
||
-" addil LT'__libc_stack_end,%r19\n" \
|
||
-" ldw RT'__libc_stack_end(%r1),%r20\n" \
|
||
-" stw %sp,0(%r20)\n" \
|
||
- \
|
||
/* See if we were called as a command with the executable file \
|
||
name as an extra leading argument. */ \
|
||
" addil LT'_dl_skip_args,%r19\n" \
|
||
diff --git a/sysdeps/i386/i686/multiarch/memchr-sse2.S b/sysdeps/i386/i686/multiarch/memchr-sse2.S
|
||
index 910679cfc0..e41f324a77 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
|
||
diff --git a/sysdeps/i386/i686/multiarch/strcspn-c.c b/sysdeps/i386/i686/multiarch/strcspn-c.c
|
||
index 6d61e190a8..ec230fb383 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 <sysdeps/x86_64/multiarch/strcspn-c.c>
|
||
+#if IS_IN (libc)
|
||
+# define __strcspn_sse2 __strcspn_ia32
|
||
+# include <sysdeps/x86_64/multiarch/strcspn-c.c>
|
||
+#endif
|
||
diff --git a/sysdeps/i386/i686/multiarch/varshift.c b/sysdeps/i386/i686/multiarch/varshift.c
|
||
index 7760b966e2..6742a35d41 100644
|
||
--- a/sysdeps/i386/i686/multiarch/varshift.c
|
||
+++ b/sysdeps/i386/i686/multiarch/varshift.c
|
||
@@ -1 +1,3 @@
|
||
-#include <sysdeps/x86_64/multiarch/varshift.c>
|
||
+#if IS_IN (libc)
|
||
+# include <sysdeps/x86_64/multiarch/varshift.c>
|
||
+#endif
|
||
diff --git a/sysdeps/nptl/fork.c b/sysdeps/nptl/fork.c
|
||
index db6d721fce..4bb87e2331 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)
|
||
{
|
||
diff --git a/sysdeps/unix/sysv/linux/alpha/localplt.data b/sysdeps/unix/sysv/linux/alpha/localplt.data
|
||
index cca17f1e34..1f0e3b494e 100644
|
||
--- a/sysdeps/unix/sysv/linux/alpha/localplt.data
|
||
+++ b/sysdeps/unix/sysv/linux/alpha/localplt.data
|
||
@@ -20,7 +20,7 @@ libc.so: free + RELA R_ALPHA_GLOB_DAT
|
||
libc.so: malloc + RELA R_ALPHA_GLOB_DAT
|
||
libc.so: memalign + RELA R_ALPHA_GLOB_DAT
|
||
libc.so: realloc + RELA R_ALPHA_GLOB_DAT
|
||
-libm.so: matherr
|
||
+libm.so: matherr + RELA R_ALPHA_GLOB_DAT
|
||
# We used to offer inline functions that used this, so it must be exported.
|
||
# Ought to reorg things such that carg isn't thus forced to use a plt.
|
||
libm.so: __atan2
|
||
diff --git a/sysdeps/unix/sysv/linux/i386/localplt.data b/sysdeps/unix/sysv/linux/i386/localplt.data
|
||
index 2c2584956d..8ea4333846 100644
|
||
--- a/sysdeps/unix/sysv/linux/i386/localplt.data
|
||
+++ b/sysdeps/unix/sysv/linux/i386/localplt.data
|
||
@@ -6,7 +6,7 @@ libc.so: free + REL R_386_GLOB_DAT
|
||
libc.so: malloc + REL R_386_GLOB_DAT
|
||
libc.so: memalign + REL R_386_GLOB_DAT
|
||
libc.so: realloc + REL R_386_GLOB_DAT
|
||
-libm.so: matherr
|
||
+libm.so: matherr + REL R_386_GLOB_DAT
|
||
# The main malloc is interposed into the dynamic linker, for
|
||
# allocations after the initial link (when dlopen is used).
|
||
ld.so: malloc + REL R_386_GLOB_DAT
|
||
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
|
||
index 2daf0c5ef0..29d8f25ab5 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
|
||
|
||
|
||
@@ -318,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);
|
||
diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c
|
||
index 1c714a4017..9afd74c42e 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,16 @@ 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. 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. */
|
||
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 95f0fcff87..a409db67d8 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. */
|
||
|
||
@@ -62,6 +63,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)
|
||
@@ -111,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)
|
||
@@ -236,6 +243,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 +266,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
|
||
@@ -283,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/fpu/test-math-vector-sincos.h b/sysdeps/x86/fpu/test-math-vector-sincos.h
|
||
index 5043b32563..95282a3ac7 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
|
||
<http://www.gnu.org/licenses/>. */
|
||
|
||
-#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); \
|
||
diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S
|
||
index 33d7fcf7d0..c14c61aa58 100644
|
||
--- a/sysdeps/x86_64/dl-trampoline.S
|
||
+++ b/sysdeps/x86_64/dl-trampoline.S
|
||
@@ -87,11 +87,9 @@
|
||
#endif
|
||
#define VEC(i) zmm##i
|
||
#define _dl_runtime_resolve _dl_runtime_resolve_avx512
|
||
-#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt
|
||
#define _dl_runtime_profile _dl_runtime_profile_avx512
|
||
#include "dl-trampoline.h"
|
||
#undef _dl_runtime_resolve
|
||
-#undef _dl_runtime_resolve_opt
|
||
#undef _dl_runtime_profile
|
||
#undef VEC
|
||
#undef VMOV
|
||
@@ -145,4 +143,5 @@
|
||
# define VMOV vmovdqu
|
||
#endif
|
||
#define _dl_runtime_resolve _dl_runtime_resolve_sse_vex
|
||
+#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt
|
||
#include "dl-trampoline.h"
|
||
diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h
|
||
index b27fa06974..8db24c16ac 100644
|
||
--- a/sysdeps/x86_64/dl-trampoline.h
|
||
+++ b/sysdeps/x86_64/dl-trampoline.h
|
||
@@ -129,19 +129,20 @@ _dl_runtime_resolve_opt:
|
||
# YMM state isn't in use.
|
||
PRESERVE_BND_REGS_PREFIX
|
||
jz _dl_runtime_resolve_sse_vex
|
||
-# elif VEC_SIZE == 64
|
||
+# elif VEC_SIZE == 16
|
||
# For ZMM registers, check if YMM state and ZMM state are in
|
||
# use.
|
||
andl $(bit_YMM_state | bit_ZMM0_15_state), %r11d
|
||
cmpl $bit_YMM_state, %r11d
|
||
- # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
|
||
- # neither YMM state nor ZMM state are in use.
|
||
+ # Preserve %zmm0 - %zmm7 registers if ZMM state is in use.
|
||
PRESERVE_BND_REGS_PREFIX
|
||
- jl _dl_runtime_resolve_sse_vex
|
||
+ jg _dl_runtime_resolve_avx512
|
||
# Preserve %ymm0 - %ymm7 registers with the zero upper 256 bits if
|
||
# ZMM state isn't in use.
|
||
PRESERVE_BND_REGS_PREFIX
|
||
je _dl_runtime_resolve_avx
|
||
+ # Preserve %xmm0 - %xmm7 registers with the zero upper 384 bits if
|
||
+ # neither YMM state nor ZMM state are in use.
|
||
# else
|
||
# error Unsupported VEC_SIZE!
|
||
# endif
|
||
diff --git a/sysdeps/x86_64/localplt.data b/sysdeps/x86_64/localplt.data
|
||
index 014a9f4554..a1840cff31 100644
|
||
--- a/sysdeps/x86_64/localplt.data
|
||
+++ b/sysdeps/x86_64/localplt.data
|
||
@@ -8,7 +8,7 @@ libc.so: free + RELA R_X86_64_GLOB_DAT
|
||
libc.so: malloc + RELA R_X86_64_GLOB_DAT
|
||
libc.so: memalign + RELA R_X86_64_GLOB_DAT
|
||
libc.so: realloc + RELA R_X86_64_GLOB_DAT
|
||
-libm.so: matherr
|
||
+libm.so: matherr + RELA R_X86_64_GLOB_DAT
|
||
# The main malloc is interposed into the dynamic linker, for
|
||
# allocations after the initial link (when dlopen is used).
|
||
ld.so: malloc + RELA R_X86_64_GLOB_DAT
|
||
diff --git a/sysdeps/x86_64/mempcpy_chk.S b/sysdeps/x86_64/mempcpy_chk.S
|
||
index f8a9260e6e..f912291576 100644
|
||
--- a/sysdeps/x86_64/mempcpy_chk.S
|
||
+++ b/sysdeps/x86_64/mempcpy_chk.S
|
||
@@ -19,7 +19,7 @@
|
||
#include <sysdep.h>
|
||
#include "asm-syntax.h"
|
||
|
||
-#ifndef PIC
|
||
+#ifndef SHARED
|
||
/* For libc.so this is defined in memcpy.S.
|
||
For libc.a, this is a separate source to avoid
|
||
mempcpy bringing in __chk_fail and all routines
|
||
diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S
|
||
index 1f83ee3e84..af2770397c 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 54923420f1..8737fb9755 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 2021bfc30c..8c534e83e0 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 8a252adcae..7870dd0247 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 79c840d075..b8b2b28094 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 6927962e81..072b22c49f 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 c958b2f49f..9d33118cf8 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 79eaa37bb6..7e08311cdf 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
|