From 8c04a738135e6267f21927588ae21b2eb48ca9da Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 6 Jul 2017 04:43:06 -0700 Subject: x86-64: Align the stack in __tls_get_addr [BZ #21609] This change forces realignment of the stack pointer in __tls_get_addr, so that binaries compiled by GCCs older than GCC 4.9: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58066 continue to work even if vector instructions are used in glibc which require the ABI stack realignment. __tls_get_addr_slow is added to handle the slow paths in the default implementation of__tls_get_addr in elf/dl-tls.c. The new __tls_get_addr calls __tls_get_addr_slow after realigning the stack. Internal calls within ld.so go directly to the default implementation of __tls_get_addr because they do not need stack realignment. [BZ #21609] * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr. (gen-as-const-headers): Add rtld-offsets.sym. * sysdeps/x86_64/dl-tls.c: New file. * sysdeps/x86_64/rtld-offsets.sym: Likwise. * sysdeps/x86_64/tls_get_addr.S: Likewise. * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards. * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New. (TI_OFFSET_OFFSET): Likwise. (cherry picked from commit 031e519c95c069abe4e4c7c59e2b4b67efccdee5) --- ChangeLog | 13 +++++++++ NEWS | 1 + sysdeps/x86_64/Makefile | 4 +-- sysdeps/x86_64/dl-tls.c | 53 +++++++++++++++++++++++++++++++++++ sysdeps/x86_64/dl-tls.h | 5 ++++ sysdeps/x86_64/rtld-offsets.sym | 6 ++++ sysdeps/x86_64/tls_get_addr.S | 61 +++++++++++++++++++++++++++++++++++++++++ sysdeps/x86_64/tlsdesc.sym | 3 ++ 8 files changed, 144 insertions(+), 2 deletions(-) create mode 100644 sysdeps/x86_64/dl-tls.c create mode 100644 sysdeps/x86_64/rtld-offsets.sym create mode 100644 sysdeps/x86_64/tls_get_addr.S diff --git a/ChangeLog b/ChangeLog index cd6b5a92e9..12067b9ea2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2017-07-06 Florian Weimer + H.J. Lu + + [BZ #21609] + * sysdeps/x86_64/Makefile (sysdep-dl-routines): Add tls_get_addr. + (gen-as-const-headers): Add rtld-offsets.sym. + * sysdeps/x86_64/dl-tls.c: New file. + * sysdeps/x86_64/rtld-offsets.sym: Likwise. + * sysdeps/x86_64/tls_get_addr.S: Likewise. + * sysdeps/x86_64/dl-tls.h: Add multiple inclusion guards. + * sysdeps/x86_64/tlsdesc.sym (TI_MODULE_OFFSET): New. + (TI_OFFSET_OFFSET): Likwise. + 2017-06-14 Florian Weimer * sysdeps/i386/i686/multiarch/strcspn-c.c: Add IS_IN (libc) guard. diff --git a/NEWS b/NEWS index c4c082b415..f60077bee5 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ The following bugs are resolved with this release: [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 + [21609] x86-64: Align the stack in __tls_get_addr [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) Version 2.24 diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile index 6d99284cd0..bd4f6ce417 100644 --- a/sysdeps/x86_64/Makefile +++ b/sysdeps/x86_64/Makefile @@ -27,7 +27,7 @@ ifeq ($(subdir),elf) CFLAGS-.os += $(if $(filter $(@F),$(patsubst %,%.os,$(all-rtld-routines))),\ -mno-mmx) -sysdep-dl-routines += tlsdesc dl-tlsdesc +sysdep-dl-routines += tlsdesc dl-tlsdesc tls_get_addr tests += ifuncmain8 modules-names += ifuncmod8 @@ -105,5 +105,5 @@ endif endif ifeq ($(subdir),csu) -gen-as-const-headers += tlsdesc.sym +gen-as-const-headers += tlsdesc.sym rtld-offsets.sym endif diff --git a/sysdeps/x86_64/dl-tls.c b/sysdeps/x86_64/dl-tls.c new file mode 100644 index 0000000000..3584805c8e --- /dev/null +++ b/sysdeps/x86_64/dl-tls.c @@ -0,0 +1,53 @@ +/* Thread-local storage handling in the ELF dynamic linker. x86-64 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef SHARED +/* Work around GCC PR58066, due to which __tls_get_addr may be called + with an unaligned stack. The compat implementation is in + tls_get_addr-compat.S. */ + +# include + +/* Define __tls_get_addr within elf/dl-tls.c under a different + name. */ +extern __typeof__ (__tls_get_addr) ___tls_get_addr; + +# define __tls_get_addr ___tls_get_addr +# include +# undef __tls_get_addr + +hidden_ver (___tls_get_addr, __tls_get_addr) + +/* Only handle slow paths for __tls_get_addr. */ +attribute_hidden +void * +__tls_get_addr_slow (GET_ADDR_ARGS) +{ + dtv_t *dtv = THREAD_DTV (); + + if (__glibc_unlikely (dtv[0].counter != GL(dl_tls_generation))) + return update_get_addr (GET_ADDR_PARAM); + + return tls_get_addr_tail (GET_ADDR_PARAM, dtv, NULL); +} +#else + +/* No compatibility symbol needed. */ +# include + +#endif diff --git a/sysdeps/x86_64/dl-tls.h b/sysdeps/x86_64/dl-tls.h index cf6c107f54..fa5bf6cd93 100644 --- a/sysdeps/x86_64/dl-tls.h +++ b/sysdeps/x86_64/dl-tls.h @@ -16,6 +16,9 @@ License along with the GNU C Library; if not, see . */ +#ifndef _X86_64_DL_TLS_H +#define _X86_64_DL_TLS_H + #include /* Type used for the representation of TLS information in the GOT. */ @@ -27,3 +30,5 @@ typedef struct dl_tls_index extern void *__tls_get_addr (tls_index *ti); + +#endif /* _X86_64_DL_TLS_H */ diff --git a/sysdeps/x86_64/rtld-offsets.sym b/sysdeps/x86_64/rtld-offsets.sym new file mode 100644 index 0000000000..fd41b51521 --- /dev/null +++ b/sysdeps/x86_64/rtld-offsets.sym @@ -0,0 +1,6 @@ +#define SHARED +#include + +-- + +GL_TLS_GENERATION_OFFSET offsetof (struct rtld_global, _dl_tls_generation) diff --git a/sysdeps/x86_64/tls_get_addr.S b/sysdeps/x86_64/tls_get_addr.S new file mode 100644 index 0000000000..9d38fb3be5 --- /dev/null +++ b/sysdeps/x86_64/tls_get_addr.S @@ -0,0 +1,61 @@ +/* Stack-aligning implementation of __tls_get_addr. x86-64 version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifdef SHARED + +# include +# include "tlsdesc.h" +# include "rtld-offsets.h" + +/* See __tls_get_addr and __tls_get_addr_slow in dl-tls.c. This function + call __tls_get_addr_slow on both slow paths. It realigns the stack + before the call to work around GCC PR58066. */ + +ENTRY (__tls_get_addr) + mov %fs:DTV_OFFSET, %RDX_LP + mov GL_TLS_GENERATION_OFFSET+_rtld_local(%rip), %RAX_LP + /* GL(dl_tls_generation) == dtv[0].counter */ + cmp %RAX_LP, (%rdx) + jne 1f + mov TI_MODULE_OFFSET(%rdi), %RAX_LP + /* dtv[ti->ti_module] */ +# ifdef __LP64__ + salq $4, %rax + movq (%rdx,%rax), %rax +# else + movl (%rdx,%rax, 8), %eax +# endif + cmp $-1, %RAX_LP + je 1f + add TI_OFFSET_OFFSET(%rdi), %RAX_LP + ret +1: + /* On the slow path, align the stack. */ + pushq %rbp + cfi_def_cfa_offset (16) + cfi_offset (%rbp, -16) + mov %RSP_LP, %RBP_LP + cfi_def_cfa_register (%rbp) + and $-16, %RSP_LP + call __tls_get_addr_slow + mov %RBP_LP, %RSP_LP + popq %rbp + cfi_def_cfa (%rsp, 8) + ret +END (__tls_get_addr) +#endif /* SHARED */ diff --git a/sysdeps/x86_64/tlsdesc.sym b/sysdeps/x86_64/tlsdesc.sym index 33854975d0..fc897ab4b5 100644 --- a/sysdeps/x86_64/tlsdesc.sym +++ b/sysdeps/x86_64/tlsdesc.sym @@ -15,3 +15,6 @@ TLSDESC_ARG offsetof(struct tlsdesc, arg) TLSDESC_GEN_COUNT offsetof(struct tlsdesc_dynamic_arg, gen_count) TLSDESC_MODID offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_module) TLSDESC_MODOFF offsetof(struct tlsdesc_dynamic_arg, tlsinfo.ti_offset) + +TI_MODULE_OFFSET offsetof(tls_index, ti_module) +TI_OFFSET_OFFSET offsetof(tls_index, ti_offset) -- cgit v1.2.3 From 605e6f9f4a4bf39416ac16fad1f41b5a93a0774d Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Mon, 5 Sep 2016 22:53:22 +0200 Subject: conform tests: call perl with '-I.' Historically perl includes the current directory in the module search path. Over the time this has been considered as a security issue and the recent vulnerabilities [1] made people to reconsider this behaviour. It is almost sure that this will be removed in the future [2], possibly for the 5.26 release, although this is not yet firmly decided. Debian has decided to backport the patches [3], so the perl binary in unstable do not have '.' in @INC anymore. This behaviour is used in the conform perl scripts to include the GlibcConform module. This patch fixes that by calling perl with '-I.'. This is not a security issue in this case as make ensures that the current directory is $(srcdir)/conform/ when the scripts are called. Passing the full path would do exactly the same. [1] CVE-2016-1238 CVE-2016-6185 [2] https://rt.perl.org/Public/Bug/Display.html?id=127810 [3] https://lists.debian.org/debian-devel-announce/2016/08/msg00013.html Changelog: * conform/Makefile (conformtest-header-tests): Pass -I. to $(PERL). (linknamespace-symlists-tests): Likewise. (linknamespace-header-tests): Likewise. (cherry picked from commit 6d5336211d2e823d4d431a01e62a80d9be4cbc9d) --- ChangeLog | 6 ++++++ conform/Makefile | 6 +++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 12067b9ea2..f58debbfc9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-09-05 Aurelien Jarno + + * conform/Makefile (conformtest-header-tests): Pass -I. to $(PERL). + (linknamespace-symlists-tests): Likewise. + (linknamespace-header-tests): Likewise. + 2017-07-06 Florian Weimer H.J. Lu diff --git a/conform/Makefile b/conform/Makefile index 762aac98fc..7883624c81 100644 --- a/conform/Makefile +++ b/conform/Makefile @@ -196,13 +196,13 @@ $(conformtest-header-tests): $(objpfx)%/conform.out: \ conformtest.pl $(conformtest-headers-data) (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ mkdir -p $(@D)/scratch; \ - $(PERL) conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \ + $(PERL) -I. conformtest.pl --tmpdir=$(@D)/scratch --cc='$(CC)' \ --flags='$(conformtest-cc-flags)' --standard=$$std \ --headers=$$hdr > $@); \ $(evaluate-test) $(linknamespace-symlists-tests): $(objpfx)symlist-%: list-header-symbols.pl - $(PERL) -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ + $(PERL) -I. -w $< --tmpdir=$(objpfx) --cc='$(CC)' \ --flags='$(conformtest-cc-flags)' --standard=$* \ --headers="$(strip $(conformtest-headers-$*))" \ > $@ 2> $@.err; \ @@ -233,7 +233,7 @@ $(linknamespace-header-tests): $(objpfx)%/linknamespace.out: \ $(linknamespace-symlist-stdlibs-tests) (set -e; std_hdr=$*; std=$${std_hdr%%/*}; hdr=$${std_hdr#*/}; \ mkdir -p $(@D)/scratch; \ - $(PERL) -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \ + $(PERL) -I. -w $< --tmpdir=$(@D)/scratch --cc='$(CC)' \ --flags='$(conformtest-cc-flags)' --standard=$$std \ --stdsyms=$(objpfx)symlist-$$std --header=$$hdr \ --libsyms=$(objpfx)symlist-stdlibs-$$std \ -- cgit v1.2.3 From cc392d6339e4172aa0cb5bdb2f006b4db5d7b831 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Wed, 12 Jul 2017 17:41:04 +0100 Subject: [AArch64] Use hidden __GI__dl_argv in rtld startup code We rely on the symbol being locally defined so using extern symbol is not correct and the linker may complain about the relocations. --- ChangeLog | 5 +++++ sysdeps/aarch64/dl-machine.h | 4 ++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index f58debbfc9..2f8f9c606b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-12 Szabolcs Nagy + + * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the + hidden __GI__dl_argv symbol. + 2016-09-05 Aurelien Jarno * conform/Makefile (conformtest-header-tests): Pass -I. to $(PERL). diff --git a/sysdeps/aarch64/dl-machine.h b/sysdeps/aarch64/dl-machine.h index 282805e396..e86d8b5b63 100644 --- a/sysdeps/aarch64/dl-machine.h +++ b/sysdeps/aarch64/dl-machine.h @@ -172,8 +172,8 @@ _dl_start_user: \n\ cmp x0, #0 \n\ bne 1b \n\ // Update _dl_argv \n\ - adrp x3, _dl_argv \n\ - str x2, [x3, #:lo12:_dl_argv] \n\ + adrp x3, __GI__dl_argv \n\ + str x2, [x3, #:lo12:__GI__dl_argv] \n\ .L_done_stack_adjust: \n\ // compute envp \n\ add x3, x2, x1, lsl #3 \n\ -- cgit v1.2.3 From fd5fade3054e4e5356154ea24e65d7ed816f5a1d Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Wed, 26 Jul 2017 10:08:46 -0700 Subject: Avoid .symver on common symbols [BZ #21666] The .symver directive on common symbol just creates a new common symbol, not an alias and the newer assembler with the bug fix for https://sourceware.org/bugzilla/show_bug.cgi?id=21661 will issue an error. Before the fix, we got $ readelf -sW libc.so | grep "loc[12s]" 5109: 00000000003a0608 8 OBJECT LOCAL DEFAULT 36 loc1 5188: 00000000003a0610 8 OBJECT LOCAL DEFAULT 36 loc2 5455: 00000000003a0618 8 OBJECT LOCAL DEFAULT 36 locs 6575: 00000000003a05f0 8 OBJECT GLOBAL DEFAULT 36 locs@GLIBC_2.2.5 7156: 00000000003a05f8 8 OBJECT GLOBAL DEFAULT 36 loc1@GLIBC_2.2.5 7312: 00000000003a0600 8 OBJECT GLOBAL DEFAULT 36 loc2@GLIBC_2.2.5 in libc.so. The versioned loc1, loc2 and locs have the wrong addresses. After the fix, we got $ readelf -sW libc.so | grep "loc[12s]" 6570: 000000000039e3b8 8 OBJECT GLOBAL DEFAULT 34 locs@GLIBC_2.2.5 7151: 000000000039e3c8 8 OBJECT GLOBAL DEFAULT 34 loc1@GLIBC_2.2.5 7307: 000000000039e3c0 8 OBJECT GLOBAL DEFAULT 34 loc2@GLIBC_2.2.5 [BZ #21666] * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); (loc2): Likewise. (locs): Likewise. (cherry picked from commit 388b4f1a02f3a801965028bbfcd48d905638b797) --- ChangeLog | 7 +++++++ misc/regexp.c | 9 +++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2f8f9c606b..178ffca243 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-07-26 H.J. Lu + + [BZ #21666] + * misc/regexp.c (loc1): Add __attribute__ ((nocommon)); + (loc2): Likewise. + (locs): Likewise. + 2017-07-12 Szabolcs Nagy * sysdeps/aarch64/dl-machine.h (RTLD_START_1): Change _dl_argv to the diff --git a/misc/regexp.c b/misc/regexp.c index 3b3668272f..b2a2c6e636 100644 --- a/misc/regexp.c +++ b/misc/regexp.c @@ -29,14 +29,15 @@ #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_23) -/* Define the variables used for the interface. */ -char *loc1; -char *loc2; +/* Define the variables used for the interface. Avoid .symver on common + symbol, which just creates a new common symbol, not an alias. */ +char *loc1 __attribute__ ((nocommon)); +char *loc2 __attribute__ ((nocommon)); compat_symbol (libc, loc1, loc1, GLIBC_2_0); compat_symbol (libc, loc2, loc2, GLIBC_2_0); /* Although we do not support the use we define this variable as well. */ -char *locs; +char *locs __attribute__ ((nocommon)); compat_symbol (libc, locs, locs, GLIBC_2_0); -- cgit v1.2.3 From 6aacb5befa4992dcbd6df17e914dd802fba8a1ea Mon Sep 17 00:00:00 2001 From: James Clarke Date: Tue, 24 Jan 2017 09:20:06 -0200 Subject: Bug 21053: sh: Reduce namespace pollution from sys/ucontext.h The problem is basically that sys/ucontext.h is defining R0..R15 which happens to conflict with some packages like Firefox when trying to build on SH. The very same problem existed on arm back then [1] and it was fixed by renaming R0..R15 to REG_R0..REG_R15. This patch imploy a similar strategy for SH. Checked on sh4-linux-gnu with run-built-tests=no and I also got reports that it fixes Firefox build on Debian sh4. * sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym: Use new REG_R* constants instead of the old R* ones. * sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym: Likewise. * sysdeps/unix/sysv/linux/sh/sys/ucontext.h (NGPREG): Rename... (NGREG): ... to this, to fit in with other architectures. (gpregset_t): Use new NGREG macro. [__USE_GNU]: Remove condition; all architectures other than tile are unconditional. (R*): Rename to REG_R*. (cherry picked from commit 3e1b518550634792de13332edaab0ad722322c2b) --- ChangeLog | 12 +++++ sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym | 32 ++++++------ sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym | 32 ++++++------ sysdeps/unix/sysv/linux/sh/sys/ucontext.h | 70 +++++++++++++-------------- 4 files changed, 78 insertions(+), 68 deletions(-) diff --git a/ChangeLog b/ChangeLog index 178ffca243..e2d55512c4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2017-01-24 James Clarke + + * sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym: Use new REG_R* + constants instead of the old R* ones. + * sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym: Likewise. + * sysdeps/unix/sysv/linux/sh/sys/ucontext.h (NGPREG): Rename... + (NGREG): ... to this, to fit in with other architectures. + (gpregset_t): Use new NGREG macro. + [__USE_GNU]: Remove condition; all architectures other than tile + are unconditional. + (R*): Rename to REG_R*. + 2017-07-26 H.J. Lu [BZ #21666] diff --git a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym index 17397c5511..25f914a93b 100644 --- a/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym @@ -13,22 +13,22 @@ SIG_SETMASK oLINK ucontext (uc_link) oSS_SP ucontext (uc_stack.ss_sp) oSS_SIZE ucontext (uc_stack.ss_size) -oR0 mcontext (gregs[R0]) -oR1 mcontext (gregs[R1]) -oR2 mcontext (gregs[R2]) -oR3 mcontext (gregs[R3]) -oR4 mcontext (gregs[R4]) -oR5 mcontext (gregs[R5]) -oR6 mcontext (gregs[R6]) -oR7 mcontext (gregs[R7]) -oR8 mcontext (gregs[R8]) -oR9 mcontext (gregs[R9]) -oR10 mcontext (gregs[R10]) -oR11 mcontext (gregs[R11]) -oR12 mcontext (gregs[R12]) -oR13 mcontext (gregs[R13]) -oR14 mcontext (gregs[R14]) -oR15 mcontext (gregs[R15]) +oR0 mcontext (gregs[REG_R0]) +oR1 mcontext (gregs[REG_R1]) +oR2 mcontext (gregs[REG_R2]) +oR3 mcontext (gregs[REG_R3]) +oR4 mcontext (gregs[REG_R4]) +oR5 mcontext (gregs[REG_R5]) +oR6 mcontext (gregs[REG_R6]) +oR7 mcontext (gregs[REG_R7]) +oR8 mcontext (gregs[REG_R8]) +oR9 mcontext (gregs[REG_R9]) +oR10 mcontext (gregs[REG_R10]) +oR11 mcontext (gregs[REG_R11]) +oR12 mcontext (gregs[REG_R12]) +oR13 mcontext (gregs[REG_R13]) +oR14 mcontext (gregs[REG_R14]) +oR15 mcontext (gregs[REG_R15]) oPC mcontext (pc) oPR mcontext (pr) oSR mcontext (sr) diff --git a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym index 65633fbcf4..130f60cd96 100644 --- a/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym +++ b/sysdeps/unix/sysv/linux/sh/sh4/ucontext_i.sym @@ -13,22 +13,22 @@ SIG_SETMASK oLINK ucontext (uc_link) oSS_SP ucontext (uc_stack.ss_sp) oSS_SIZE ucontext (uc_stack.ss_size) -oR0 mcontext (gregs[R0]) -oR1 mcontext (gregs[R1]) -oR2 mcontext (gregs[R2]) -oR3 mcontext (gregs[R3]) -oR4 mcontext (gregs[R4]) -oR5 mcontext (gregs[R5]) -oR6 mcontext (gregs[R6]) -oR7 mcontext (gregs[R7]) -oR8 mcontext (gregs[R8]) -oR9 mcontext (gregs[R9]) -oR10 mcontext (gregs[R10]) -oR11 mcontext (gregs[R11]) -oR12 mcontext (gregs[R12]) -oR13 mcontext (gregs[R13]) -oR14 mcontext (gregs[R14]) -oR15 mcontext (gregs[R15]) +oR0 mcontext (gregs[REG_R0]) +oR1 mcontext (gregs[REG_R1]) +oR2 mcontext (gregs[REG_R2]) +oR3 mcontext (gregs[REG_R3]) +oR4 mcontext (gregs[REG_R4]) +oR5 mcontext (gregs[REG_R5]) +oR6 mcontext (gregs[REG_R6]) +oR7 mcontext (gregs[REG_R7]) +oR8 mcontext (gregs[REG_R8]) +oR9 mcontext (gregs[REG_R9]) +oR10 mcontext (gregs[REG_R10]) +oR11 mcontext (gregs[REG_R11]) +oR12 mcontext (gregs[REG_R12]) +oR13 mcontext (gregs[REG_R13]) +oR14 mcontext (gregs[REG_R14]) +oR15 mcontext (gregs[REG_R15]) oPC mcontext (pc) oPR mcontext (pr) oSR mcontext (sr) diff --git a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h index ab9a7e66bf..037fbb73e8 100644 --- a/sysdeps/unix/sysv/linux/sh/sys/ucontext.h +++ b/sysdeps/unix/sysv/linux/sh/sys/ucontext.h @@ -31,49 +31,47 @@ typedef int greg_t; /* Number of general registers. */ -#define NGPREG 16 +#define NGREG 16 /* Container for all general registers. */ -typedef greg_t gregset_t[NGPREG]; +typedef greg_t gregset_t[NGREG]; -#ifdef __USE_GNU /* Number of each register is the `gregset_t' array. */ enum { - R0 = 0, -#define R0 R0 - R1 = 1, -#define R1 R1 - R2 = 2, -#define R2 R2 - R3 = 3, -#define R3 R3 - R4 = 4, -#define R4 R4 - R5 = 5, -#define R5 R5 - R6 = 6, -#define R6 R6 - R7 = 7, -#define R7 R7 - R8 = 8, -#define R8 R8 - R9 = 9, -#define R9 R9 - R10 = 10, -#define R10 R10 - R11 = 11, -#define R11 R11 - R12 = 12, -#define R12 R12 - R13 = 13, -#define R13 R13 - R14 = 14, -#define R14 R14 - R15 = 15, -#define R15 R15 + REG_R0 = 0, +#define REG_R0 REG_R0 + REG_R1 = 1, +#define REG_R1 REG_R1 + REG_R2 = 2, +#define REG_R2 REG_R2 + REG_R3 = 3, +#define REG_R3 REG_R3 + REG_R4 = 4, +#define REG_R4 REG_R4 + REG_R5 = 5, +#define REG_R5 REG_R5 + REG_R6 = 6, +#define REG_R6 REG_R6 + REG_R7 = 7, +#define REG_R7 REG_R7 + REG_R8 = 8, +#define REG_R8 REG_R8 + REG_R9 = 9, +#define REG_R9 REG_R9 + REG_R10 = 10, +#define REG_R10 REG_R10 + REG_R11 = 11, +#define REG_R11 REG_R11 + REG_R12 = 12, +#define REG_R12 REG_R12 + REG_R13 = 13, +#define REG_R13 REG_R13 + REG_R14 = 14, +#define REG_R14 REG_R14 + REG_R15 = 15, +#define REG_R15 REG_R15 }; -#endif #if (defined(__SH4__) || defined(__SH4A__)) typedef int freg_t; -- cgit v1.2.3 From 36f173ab3709b4a920a833b9af67f30bcba1ea01 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Mon, 27 Feb 2017 19:05:13 +0100 Subject: sunrpc: Avoid use-after-free read access in clntudp_call [BZ #21115] After commit bc779a1a5b3035133024b21e2f339fe4219fb11c (CVE-2016-4429: sunrpc: Do not use alloca in clntudp_call [BZ #20112]), ancillary data is stored on the heap, but it is accessed after it has been freed. The test case must be run under a heap debugger such as valgrind to observe the invalid access. A malloc implementation which immediately calls munmap on free would catch this bug as well. (cherry picked from commit d42eed4a044e5e10dfb885cf9891c2518a72a491) --- ChangeLog | 8 +++++++ sunrpc/Makefile | 3 ++- sunrpc/clnt_udp.c | 2 +- sunrpc/tst-udp-error.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 sunrpc/tst-udp-error.c diff --git a/ChangeLog b/ChangeLog index e2d55512c4..4f4252c4cf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-02-27 Florian Weimer + + [BZ #21115] + * sunrpc/clnt_udp.c (clntudp_call): Free ancillary data later. + * sunrpc/Makefile (tests): Add tst-udp-error. + (tst-udp-error): Link against libc.so explicitly. + * sunrpc/tst-udp-error: New file. + 2017-01-24 James Clarke * sysdeps/unix/sysv/linux/sh/sh3/ucontext_i.sym: Use new REG_R* diff --git a/sunrpc/Makefile b/sunrpc/Makefile index 789ef423e5..4373fffdec 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -96,7 +96,7 @@ rpcgen-objs = rpc_main.o rpc_hout.o rpc_cout.o rpc_parse.o \ extra-objs = $(rpcgen-objs) $(addprefix cross-,$(rpcgen-objs)) others += rpcgen -tests = tst-xdrmem tst-xdrmem2 test-rpcent +tests = tst-xdrmem tst-xdrmem2 test-rpcent tst-udp-error xtests := tst-getmyaddr ifeq ($(have-thread-library),yes) @@ -153,6 +153,7 @@ BUILD_CPPFLAGS += $(sunrpc-CPPFLAGS) $(objpfx)tst-getmyaddr: $(common-objpfx)linkobj/libc.so $(objpfx)tst-xdrmem: $(common-objpfx)linkobj/libc.so $(objpfx)tst-xdrmem2: $(common-objpfx)linkobj/libc.so +$(objpfx)tst-udp-error: $(common-objpfx)linkobj/libc.so $(objpfx)rpcgen: $(addprefix $(objpfx),$(rpcgen-objs)) diff --git a/sunrpc/clnt_udp.c b/sunrpc/clnt_udp.c index 4d9acb1e6a..1de25cb771 100644 --- a/sunrpc/clnt_udp.c +++ b/sunrpc/clnt_udp.c @@ -421,9 +421,9 @@ send_again: cmsg = CMSG_NXTHDR (&msg, cmsg)) if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { - free (cbuf); e = (struct sock_extended_err *) CMSG_DATA(cmsg); cu->cu_error.re_errno = e->ee_errno; + free (cbuf); return (cu->cu_error.re_status = RPC_CANTRECV); } free (cbuf); diff --git a/sunrpc/tst-udp-error.c b/sunrpc/tst-udp-error.c new file mode 100644 index 0000000000..1efc02f5c6 --- /dev/null +++ b/sunrpc/tst-udp-error.c @@ -0,0 +1,62 @@ +/* Check for use-after-free in clntudp_call (bug 21115). + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include + +static int +do_test (void) +{ + support_become_root (); + support_enter_network_namespace (); + + /* Obtain a likely-unused port number. */ + struct sockaddr_in sin = + { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl (INADDR_LOOPBACK), + }; + { + int fd = xsocket (AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0); + xbind (fd, (struct sockaddr *) &sin, sizeof (sin)); + socklen_t sinlen = sizeof (sin); + xgetsockname (fd, (struct sockaddr *) &sin, &sinlen); + /* Close the socket, so that we will receive an error below. */ + close (fd); + } + + int sock = RPC_ANYSOCK; + CLIENT *clnt = clntudp_create + (&sin, 1, 2, (struct timeval) { 1, 0 }, &sock); + TEST_VERIFY_EXIT (clnt != NULL); + TEST_VERIFY (clnt_call (clnt, 3, + (xdrproc_t) xdr_void, NULL, + (xdrproc_t) xdr_void, NULL, + ((struct timeval) { 3, 0 })) + == RPC_CANTRECV); + clnt_destroy (clnt); + + return 0; +} + +#include -- cgit v1.2.3 From d5a4092c367955ac0203ee603fdec625f6c924f9 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sun, 6 Aug 2017 10:44:30 -0700 Subject: x86-64: Use _dl_runtime_resolve_opt only with AVX512F [BZ #21871] On AVX machines with XGETBV (ECX == 1) like Skylake processors, (gdb) disass _dl_runtime_resolve_avx_opt Dump of assembler code for function _dl_runtime_resolve_avx_opt: 0x0000000000015890 <+0>: push %rax 0x0000000000015891 <+1>: push %rcx 0x0000000000015892 <+2>: push %rdx 0x0000000000015893 <+3>: mov $0x1,%ecx 0x0000000000015898 <+8>: xgetbv 0x000000000001589b <+11>: mov %eax,%r11d 0x000000000001589e <+14>: pop %rdx 0x000000000001589f <+15>: pop %rcx 0x00000000000158a0 <+16>: pop %rax 0x00000000000158a1 <+17>: and $0x4,%r11d 0x00000000000158a5 <+21>: bnd je 0x16200 <_dl_runtime_resolve_sse_vex> End of assembler dump. is slower than: (gdb) disass _dl_runtime_resolve_avx_slow Dump of assembler code for function _dl_runtime_resolve_avx_slow: 0x0000000000015850 <+0>: vorpd %ymm0,%ymm1,%ymm8 0x0000000000015854 <+4>: vorpd %ymm2,%ymm3,%ymm9 0x0000000000015858 <+8>: vorpd %ymm4,%ymm5,%ymm10 0x000000000001585c <+12>: vorpd %ymm6,%ymm7,%ymm11 0x0000000000015860 <+16>: vorpd %ymm8,%ymm9,%ymm9 0x0000000000015865 <+21>: vorpd %ymm10,%ymm11,%ymm10 0x000000000001586a <+26>: vpcmpeqd %xmm8,%xmm8,%xmm8 0x000000000001586f <+31>: vorpd %ymm9,%ymm10,%ymm10 0x0000000000015874 <+36>: vptest %ymm10,%ymm8 0x0000000000015879 <+41>: bnd jae 0x158b0 <_dl_runtime_resolve_avx> 0x000000000001587c <+44>: vzeroupper 0x000000000001587f <+47>: bnd jmpq 0x16200 <_dl_runtime_resolve_sse_vex> End of assembler dump. (gdb) since xgetbv takes much more cycles than single cycle operations like vpord/vvpcmpeq/ptest. _dl_runtime_resolve_opt should be used only with AVX512 where AVX512 instructions lead to lower CPU frequency on Skylake server. [BZ #21871] * sysdeps/x86/cpu-features.c (init_cpu_features): Set bit_arch_Use_dl_runtime_resolve_opt only with AVX512F. (cherry picked from commit d2cf37c0a2a375cf2fde69f1afbcc49e45368fc4) --- ChangeLog | 6 ++++++ sysdeps/x86/cpu-features.c | 7 +++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 4f4252c4cf..ecc0da0b02 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-08-06 H.J. Lu + + [BZ #21871] + * sysdeps/x86/cpu-features.c (init_cpu_features): Set + bit_arch_Use_dl_runtime_resolve_opt only with AVX512F. + 2017-02-27 Florian Weimer [BZ #21115] diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index d1ee922290..508ad2ae7b 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -215,10 +215,13 @@ init_cpu_features (struct cpu_features *cpu_features) |= bit_arch_Prefer_No_AVX512; /* To avoid SSE transition penalty, use _dl_runtime_resolve_slow. - If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. */ + If XGETBV suports ECX == 1, use _dl_runtime_resolve_opt. + Use _dl_runtime_resolve_opt only with AVX512F since it is + slower than _dl_runtime_resolve_slow with AVX. */ cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] |= bit_arch_Use_dl_runtime_resolve_slow; - if (cpu_features->max_cpuid >= 0xd) + if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) + && cpu_features->max_cpuid >= 0xd) { unsigned int eax; -- cgit v1.2.3 From caa97d7a46db35a5ddb7bc53e56a866bc180c3b0 Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Fri, 14 Jul 2017 21:46:42 -0400 Subject: Fix BZ #21654 - grp-merge.c alignment * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer alignment not char alignment. (__merge_grp): Likewise. (cherry picked from commit 4fa8ae49aa169fb8d97882938e8bee3ed9ce5410) --- ChangeLog | 7 +++++++ grp/grp-merge.c | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/ChangeLog b/ChangeLog index ecc0da0b02..fe5103f03e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-07-14 DJ Delorie + + [BZ #21654] + * grp/grp_merge.c (__copy_grp): Align char** to minimum pointer + alignment not char alignment. + (__merge_grp): Likewise. + 2017-08-06 H.J. Lu [BZ #21871] diff --git a/grp/grp-merge.c b/grp/grp-merge.c index 0a1eb38d2c..50573b8986 100644 --- a/grp/grp-merge.c +++ b/grp/grp-merge.c @@ -85,6 +85,14 @@ __copy_grp (const struct group srcgrp, const size_t buflen, } members[i] = NULL; + /* Align for pointers. We can't simply align C because we need to + align destbuf[c]. */ + if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0) + { + uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1); + c += __alignof__(char **) - mis_align; + } + /* Copy the pointers from the members array into the buffer and assign them to the gr_mem member of destgrp. */ destgrp->gr_mem = (char **) &destbuf[c]; @@ -168,6 +176,14 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, /* Add the NULL-terminator. */ members[savedmemcount + memcount] = NULL; + /* Align for pointers. We can't simply align C because we need to + align savedbuf[c]. */ + if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0) + { + uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1); + c += __alignof__(char **) - mis_align; + } + /* Copy the member array back into the buffer after the member list and free the member array. */ savedgrp->gr_mem = (char **) &savedbuf[c]; -- cgit v1.2.3 From b70f43dcef0ca638d2d550ead8007f7c9bb7e4bb Mon Sep 17 00:00:00 2001 From: DJ Delorie Date: Sat, 7 Oct 2017 13:32:00 +0200 Subject: Fix cast-after-dereference Original code was dereferencing a char*, then casting the value to size_t. Should cast the pointer to size_t* then deference. (cherry picked from commit f8cef4d07d9641e27629bd3ce2d13f5d702fb251) --- ChangeLog | 5 +++++ NEWS | 1 + grp/grp-merge.c | 2 +- 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index fe5103f03e..80cb667dd2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-07-19 DJ Delorie + + [BZ #21654] + * grp/grp-merge.c (libc_hidden_def): Fix cast-after-dereference. + 2017-07-14 DJ Delorie [BZ #21654] diff --git a/NEWS b/NEWS index f60077bee5..f03910105a 100644 --- a/NEWS +++ b/NEWS @@ -28,6 +28,7 @@ The following bugs are resolved with this release: [21386] Assertion in fork for distinct parent PID is incorrect [21609] x86-64: Align the stack in __tls_get_addr [21624] Unsafe alloca allows local attackers to alias stack and heap (CVE-2017-1000366) + [21654] nss: Fix invalid cast in group merging Version 2.24 diff --git a/grp/grp-merge.c b/grp/grp-merge.c index 50573b8986..5f79755798 100644 --- a/grp/grp-merge.c +++ b/grp/grp-merge.c @@ -137,7 +137,7 @@ __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend, /* Get the count of group members from the last sizeof (size_t) bytes in the mergegrp buffer. */ - savedmemcount = (size_t) *(savedend - sizeof (size_t)); + savedmemcount = *(size_t *) (savedend - sizeof (size_t)); /* Get the count of new members to add. */ for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++) -- cgit v1.2.3 From b3c498b834c112c10831dced77c9409cb79f339e Mon Sep 17 00:00:00 2001 From: steve ellcey-CA Eng-Software Date: Fri, 14 Oct 2016 12:53:27 -0700 Subject: Fix warnings from latest GCC. * sysdeps/ieee754/dbl-64/e_pow.c (checkint) Make conditions explicitly boolean. (cherry picked from commit e223d1fe72e820d96f43831412ab267a1ace04d0) --- ChangeLog | 5 +++++ sysdeps/ieee754/dbl-64/e_pow.c | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 80cb667dd2..30dbdf1fd9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2016-10-14 Steve Ellcey + + * sysdeps/ieee754/dbl-64/e_pow.c (checkint) Make conditions explicitly + boolean. + 2017-07-19 DJ Delorie [BZ #21654] diff --git a/sysdeps/ieee754/dbl-64/e_pow.c b/sysdeps/ieee754/dbl-64/e_pow.c index 663fa392c2..bd758b5979 100644 --- a/sysdeps/ieee754/dbl-64/e_pow.c +++ b/sysdeps/ieee754/dbl-64/e_pow.c @@ -466,15 +466,15 @@ checkint (double x) return (n & 1) ? -1 : 1; /* odd or even */ if (k > 20) { - if (n << (k - 20)) + if (n << (k - 20) != 0) return 0; /* if not integer */ - return (n << (k - 21)) ? -1 : 1; + return (n << (k - 21) != 0) ? -1 : 1; } if (n) return 0; /*if not integer */ if (k == 20) return (m & 1) ? -1 : 1; - if (m << (k + 12)) + if (m << (k + 12) != 0) return 0; - return (m << (k + 11)) ? -1 : 1; + return (m << (k + 11) != 0) ? -1 : 1; } -- cgit v1.2.3 From 7fca94796b67a8ca3730da255e64ee95a818f231 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Sat, 7 Oct 2017 13:42:41 +0200 Subject: Fix rpcgen buffer overrun (bug 20790). Building with GCC 7 produces an error building rpcgen: rpc_parse.c: In function 'get_prog_declaration': rpc_parse.c:543:25: error: may write a terminating nul past the end of the destination [-Werror=format-length=] sprintf (name, "%s%d", ARGNAME, num); /* default name of argument */ ~~~~^ rpc_parse.c:543:5: note: format output between 5 and 14 bytes into a destination of size 10 sprintf (name, "%s%d", ARGNAME, num); /* default name of argument */ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ That buffer overrun is for the case where the .x file declares a program with a million arguments. The strcpy two lines above can generate a buffer overrun much more simply for a long argument name. The limit on length of line read by rpcgen (MAXLINESIZE == 1024) provides a bound on the buffer size needed, so this patch just changes the buffer size to MAXLINESIZE to avoid both possible buffer overruns. A testcase is added that rpcgen does not crash with a 500-character argument name, where it previously crashed. It would not at all surprise me if there are many other ways of crashing rpcgen with either valid or invalid input; fuzz testing would likely find various such bugs, though I don't think they are that important to fix (rpcgen is not that likely to be used with untrusted .x files as input). (As well as fuzz-findable bugs there are probably also issues when various int variables get overflowed on very large input.) The test infrastructure for rpcgen-not-crashing tests would need extending if tests are to be added for cases where rpcgen should produce an error, as opposed to cases where it should succeed. Tested for x86_64 and x86. [BZ #20790] * sunrpc/rpc_parse.c (get_prog_declaration): Increase buffer size to MAXLINESIZE. * sunrpc/bug20790.x: New file. * sunrpc/Makefile [$(run-built-tests) = yes] (rpcgen-tests): New variable. [$(run-built-tests) = yes] (tests-special): Add $(rpcgen-tests). [$(run-built-tests) = yes] ($(rpcgen-tests)): New rule. (cherry picked from commit 5874510faaf3cbd0bb112aaacab9f225002beed1) --- ChangeLog | 11 +++++++++++ NEWS | 1 + sunrpc/Makefile | 11 +++++++++++ sunrpc/bug20790.x | 1 + sunrpc/rpc_parse.c | 2 +- 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 sunrpc/bug20790.x diff --git a/ChangeLog b/ChangeLog index 30dbdf1fd9..e593c33b0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2016-11-08 Joseph Myers + + [BZ #20790] + * sunrpc/rpc_parse.c (get_prog_declaration): Increase buffer size + to MAXLINESIZE. + * sunrpc/bug20790.x: New file. + * sunrpc/Makefile [$(run-built-tests) = yes] (rpcgen-tests): New + variable. + [$(run-built-tests) = yes] (tests-special): Add $(rpcgen-tests). + [$(run-built-tests) = yes] ($(rpcgen-tests)): New rule. + 2016-10-14 Steve Ellcey * sysdeps/ieee754/dbl-64/e_pow.c (checkint) Make conditions explicitly diff --git a/NEWS b/NEWS index f03910105a..e2935c063d 100644 --- a/NEWS +++ b/NEWS @@ -23,6 +23,7 @@ Security related changes: The following bugs are resolved with this release: + [20790] Fix rpcgen buffer overrun [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 diff --git a/sunrpc/Makefile b/sunrpc/Makefile index 4373fffdec..1e91905011 100644 --- a/sunrpc/Makefile +++ b/sunrpc/Makefile @@ -103,6 +103,11 @@ ifeq ($(have-thread-library),yes) xtests += thrsvc endif +ifeq ($(run-built-tests),yes) +rpcgen-tests := $(objpfx)bug20790.out +tests-special += $(rpcgen-tests) +endif + headers += $(rpcsvc:%.x=rpcsvc/%.h) extra-libs := librpcsvc extra-libs-others := librpcsvc # Make it in `others' pass, not `lib' pass. @@ -226,3 +231,9 @@ endif endif $(objpfx)thrsvc: $(common-objpfx)linkobj/libc.so $(shared-thread-library) + +ifeq ($(run-built-tests),yes) +$(rpcgen-tests): $(objpfx)%.out: %.x $(objpfx)rpcgen + $(built-program-cmd) -c $< -o $@; \ + $(evaluate-test) +endif diff --git a/sunrpc/bug20790.x b/sunrpc/bug20790.x new file mode 100644 index 0000000000..a00c9b3830 --- /dev/null +++ b/sunrpc/bug20790.x @@ -0,0 +1 @@ +program TPROG { version TVERS { int FUNC(int aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = 1; } = 1; } = 1; diff --git a/sunrpc/rpc_parse.c b/sunrpc/rpc_parse.c index 1a1df6d8c2..505a6554cf 100644 --- a/sunrpc/rpc_parse.c +++ b/sunrpc/rpc_parse.c @@ -521,7 +521,7 @@ static void get_prog_declaration (declaration * dec, defkind dkind, int num /* arg number */ ) { token tok; - char name[10]; /* argument name */ + char name[MAXLINESIZE]; /* argument name */ if (dkind == DEF_PROGRAM) { -- cgit v1.2.3 From 79c6f51428a9ec977e611e609a8be6aebcb00006 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Sat, 7 Oct 2017 13:44:49 +0200 Subject: Fix nss_nisplus build with mainline GCC (bug 20978). glibc build with current mainline GCC fails because nis/nss_nisplus/nisplus-alias.c contains code if (name != NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; } char buf[strlen (name) + 9 + tablename_len]; producing an error about strlen being called on a pointer that is always NULL (and a subsequent use of that pointer with a %s format in snprintf). As Andreas noted, the bogus conditional comes from a 1997 change: - if (name == NULL || strlen(name) > 8) - return NSS_STATUS_NOTFOUND; - else + if (name != NULL || strlen(name) <= 8) So the intention is clearly to return an error for NULL name. This patch duly inverts the sense of the conditional. It fixes the build with GCC mainline, and passes usual glibc testsuite testing for x86_64. However, I have not tried any actual substantive nisplus testing, do not have an environment for such testing, and do not know whether it is possible that strlen (name) or tablename_len might be large so that the VLA for buf is actually a security issue. However, if it is a security issue, there are plenty of other similar instances in the nisplus code (that haven't been hidden by a bogus comparison with NULL) - and nis_table.c:__create_ib_request uses strdupa on the string passed to nis_list, so a local fix in the caller wouldn't suffice anyway (see bug 20987). (Calls to strdupa and other such macros that use alloca must be considered equally questionable regarding stack overflow issues as direct calls to alloca and VLA declarations.) [BZ #20978] * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_getaliasbyname_r): Compare name == NULL, not name != NULL. (cherry picked from commit f88759ea9bd3c8d8fef28f123ba9767cb0e421a3) --- ChangeLog | 6 ++++++ NEWS | 1 + nis/nss_nisplus/nisplus-alias.c | 2 +- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e593c33b0c..79e3eb2e53 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2016-12-21 Joseph Myers + + [BZ #20978] + * nis/nss_nisplus/nisplus-alias.c (_nss_nisplus_getaliasbyname_r): + Compare name == NULL, not name != NULL. + 2016-11-08 Joseph Myers [BZ #20790] diff --git a/NEWS b/NEWS index e2935c063d..4831542023 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,7 @@ Security related changes: The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun + [20978] Fix strlen on null pointer in nss_nisplus [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 diff --git a/nis/nss_nisplus/nisplus-alias.c b/nis/nss_nisplus/nisplus-alias.c index 7f698b4e6d..cb5acce01d 100644 --- a/nis/nss_nisplus/nisplus-alias.c +++ b/nis/nss_nisplus/nisplus-alias.c @@ -291,7 +291,7 @@ _nss_nisplus_getaliasbyname_r (const char *name, struct aliasent *alias, return status; } - if (name != NULL) + if (name == NULL) { *errnop = EINVAL; return NSS_STATUS_UNAVAIL; -- cgit v1.2.3 From 37f4c94e1f0ae24b03d49839cd39c03076bd5c5b Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 19 Oct 2017 08:50:07 -0700 Subject: X86-64: Correct CFA in _dl_runtime_resolve When stack is re-aligned in _dl_runtime_resolve, there is no need to adjust CFA when allocating register save area on stack. * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't adjust CFA when allocating register save area on re-aligned stack. (cherry picked from commit 0ac8ee53e8efbfd6e1c37094b4653f5c2dad65b5) --- ChangeLog | 6 ++++++ sysdeps/x86_64/dl-trampoline.h | 2 ++ 2 files changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 79e3eb2e53..e61f956ef6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-10-19 H.J. Lu + + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't + adjust CFA when allocating register save area on re-aligned + stack. + 2016-12-21 Joseph Myers [BZ #20978] diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h index 32ad3af202..d21c5a987a 100644 --- a/sysdeps/x86_64/dl-trampoline.h +++ b/sysdeps/x86_64/dl-trampoline.h @@ -169,7 +169,9 @@ _dl_runtime_resolve: and $-VEC_SIZE, %RSP_LP #endif sub $REGISTER_SAVE_AREA, %RSP_LP +#if !DL_RUNTIME_RESOLVE_REALIGN_STACK cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) +#endif # Preserve registers otherwise clobbered. movq %rax, REGISTER_SAVE_RAX(%rsp) movq %rcx, REGISTER_SAVE_RCX(%rsp) -- cgit v1.2.3 From 5084717ffa05d15e98bc98a2c8b710ee57c4d133 Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Thu, 19 Oct 2017 08:52:50 -0700 Subject: x86-64: Verify that _dl_runtime_resolve preserves vector registers On x86-64, _dl_runtime_resolve must preserve the first 8 vector registers. Add 3 _dl_runtime_resolve tests to verify that SSE, AVX and AVX512 registers are preserved. * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and tst-avx512. (test-extras): Add tst-avx-aux and tst-avx512-aux. (extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o. (modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod. ($(objpfx)tst-sse): New rule. ($(objpfx)tst-avx): Likewise. ($(objpfx)tst-avx512): Likewise. (CFLAGS-tst-avx-aux.c): New. (CFLAGS-tst-avxmod.c): Likewise. (CFLAGS-tst-avx512-aux.c): Likewise. (CFLAGS-tst-avx512mod.c): Likewise. * sysdeps/x86_64/tst-avx-aux.c: New file. * sysdeps/x86_64/tst-avx.c: Likewise. * sysdeps/x86_64/tst-avx512-aux.c: Likewise. * sysdeps/x86_64/tst-avx512.c: Likewise. * sysdeps/x86_64/tst-avx512mod.c: Likewise. * sysdeps/x86_64/tst-avxmod.c: Likewise. * sysdeps/x86_64/tst-sse.c: Likewise. * sysdeps/x86_64/tst-ssemod.c: Likewise. (cherry picked from commit 3403a17fea8ccef7dc5f99553a13231acf838744) --- ChangeLog | 23 +++++++++++++++++ sysdeps/x86_64/Makefile | 20 ++++++++++++--- sysdeps/x86_64/tst-avx-aux.c | 47 +++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-avx.c | 49 +++++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-avx512-aux.c | 48 ++++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-avx512.c | 57 +++++++++++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-avx512mod.c | 48 ++++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-avxmod.c | 48 ++++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-sse.c | 46 +++++++++++++++++++++++++++++++++ sysdeps/x86_64/tst-ssemod.c | 46 +++++++++++++++++++++++++++++++++ 10 files changed, 428 insertions(+), 4 deletions(-) create mode 100644 sysdeps/x86_64/tst-avx-aux.c create mode 100644 sysdeps/x86_64/tst-avx.c create mode 100644 sysdeps/x86_64/tst-avx512-aux.c create mode 100644 sysdeps/x86_64/tst-avx512.c create mode 100644 sysdeps/x86_64/tst-avx512mod.c create mode 100644 sysdeps/x86_64/tst-avxmod.c create mode 100644 sysdeps/x86_64/tst-sse.c create mode 100644 sysdeps/x86_64/tst-ssemod.c diff --git a/ChangeLog b/ChangeLog index e61f956ef6..84189ec762 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2017-10-19 H.J. Lu + + * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and + tst-avx512. + (test-extras): Add tst-avx-aux and tst-avx512-aux. + (extra-test-objs): Add tst-avx-aux.o and tst-avx512-aux.o. + (modules-names): Add tst-ssemod, tst-avxmod and tst-avx512mod. + ($(objpfx)tst-sse): New rule. + ($(objpfx)tst-avx): Likewise. + ($(objpfx)tst-avx512): Likewise. + (CFLAGS-tst-avx-aux.c): New. + (CFLAGS-tst-avxmod.c): Likewise. + (CFLAGS-tst-avx512-aux.c): Likewise. + (CFLAGS-tst-avx512mod.c): Likewise. + * sysdeps/x86_64/tst-avx-aux.c: New file. + * sysdeps/x86_64/tst-avx.c: Likewise. + * sysdeps/x86_64/tst-avx512-aux.c: Likewise. + * sysdeps/x86_64/tst-avx512.c: Likewise. + * sysdeps/x86_64/tst-avx512mod.c: Likewise. + * sysdeps/x86_64/tst-avxmod.c: Likewise. + * sysdeps/x86_64/tst-sse.c: Likewise. + * sysdeps/x86_64/tst-ssemod.c: Likewise. + 2017-10-19 H.J. Lu * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve): Don't diff --git a/sysdeps/x86_64/Makefile b/sysdeps/x86_64/Makefile index bd4f6ce417..cc990a9685 100644 --- a/sysdeps/x86_64/Makefile +++ b/sysdeps/x86_64/Makefile @@ -49,9 +49,12 @@ extra-test-objs += tst-quadmod1pie.o tst-quadmod2pie.o $(objpfx)tst-quad1pie: $(objpfx)tst-quadmod1pie.o $(objpfx)tst-quad2pie: $(objpfx)tst-quadmod2pie.o -tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 tst-audit10 -test-extras += tst-audit4-aux tst-audit10-aux -extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o +tests += tst-audit3 tst-audit4 tst-audit5 tst-audit6 tst-audit7 \ + tst-audit10 tst-sse tst-avx tst-avx512 +test-extras += tst-audit4-aux tst-audit10-aux \ + tst-avx-aux tst-avx512-aux +extra-test-objs += tst-audit4-aux.o tst-audit10-aux.o \ + tst-avx-aux.o tst-avx512-aux.o tests += tst-split-dynreloc LDFLAGS-tst-split-dynreloc = -Wl,-T,$(..)sysdeps/x86_64/tst-split-dynreloc.lds @@ -62,7 +65,8 @@ modules-names += tst-auditmod3a tst-auditmod3b \ tst-auditmod5a tst-auditmod5b \ tst-auditmod6a tst-auditmod6b tst-auditmod6c \ tst-auditmod7a tst-auditmod7b \ - tst-auditmod10a tst-auditmod10b + tst-auditmod10a tst-auditmod10b \ + tst-ssemod tst-avxmod tst-avx512mod $(objpfx)tst-audit3: $(objpfx)tst-auditmod3a.so $(objpfx)tst-audit3.out: $(objpfx)tst-auditmod3b.so @@ -89,6 +93,10 @@ $(objpfx)tst-audit10: $(objpfx)tst-audit10-aux.o $(objpfx)tst-auditmod10a.so $(objpfx)tst-audit10.out: $(objpfx)tst-auditmod10b.so tst-audit10-ENV = LD_AUDIT=$(objpfx)tst-auditmod10b.so +$(objpfx)tst-sse: $(objpfx)tst-ssemod.so +$(objpfx)tst-avx: $(objpfx)tst-avx-aux.o $(objpfx)tst-avxmod.so +$(objpfx)tst-avx512: $(objpfx)tst-avx512-aux.o $(objpfx)tst-avx512mod.so + AVX-CFLAGS=-mavx -mno-vzeroupper CFLAGS-tst-audit4-aux.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod4a.c += $(AVX-CFLAGS) @@ -96,11 +104,15 @@ CFLAGS-tst-auditmod4b.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod6b.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod6c.c += $(AVX-CFLAGS) CFLAGS-tst-auditmod7b.c += $(AVX-CFLAGS) +CFLAGS-tst-avx-aux.c += $(AVX-CFLAGS) +CFLAGS-tst-avxmod.c += $(AVX-CFLAGS) ifeq (yes,$(config-cflags-avx512)) AVX512-CFLAGS = -mavx512f CFLAGS-tst-audit10-aux.c += $(AVX512-CFLAGS) CFLAGS-tst-auditmod10a.c += $(AVX512-CFLAGS) CFLAGS-tst-auditmod10b.c += $(AVX512-CFLAGS) +CFLAGS-tst-avx512-aux.c += $(AVX512-CFLAGS) +CFLAGS-tst-avx512mod.c += $(AVX512-CFLAGS) endif endif diff --git a/sysdeps/x86_64/tst-avx-aux.c b/sysdeps/x86_64/tst-avx-aux.c new file mode 100644 index 0000000000..e3807de7bb --- /dev/null +++ b/sysdeps/x86_64/tst-avx-aux.c @@ -0,0 +1,47 @@ +/* Test case for preserved AVX registers in dynamic linker, -mavx part. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +tst_avx_aux (void) +{ +#ifdef __AVX__ + extern __m256i avx_test (__m256i, __m256i, __m256i, __m256i, + __m256i, __m256i, __m256i, __m256i); + + __m256i ymm0 = _mm256_set1_epi32 (0); + __m256i ymm1 = _mm256_set1_epi32 (1); + __m256i ymm2 = _mm256_set1_epi32 (2); + __m256i ymm3 = _mm256_set1_epi32 (3); + __m256i ymm4 = _mm256_set1_epi32 (4); + __m256i ymm5 = _mm256_set1_epi32 (5); + __m256i ymm6 = _mm256_set1_epi32 (6); + __m256i ymm7 = _mm256_set1_epi32 (7); + __m256i ret = avx_test (ymm0, ymm1, ymm2, ymm3, + ymm4, ymm5, ymm6, ymm7); + ymm0 = _mm256_set1_epi32 (0x12349876); + if (memcmp (&ymm0, &ret, sizeof (ret))) + abort (); + return 0; +#else /* __AVX__ */ + return 77; +#endif /* __AVX__ */ +} diff --git a/sysdeps/x86_64/tst-avx.c b/sysdeps/x86_64/tst-avx.c new file mode 100644 index 0000000000..ec2e3a79ff --- /dev/null +++ b/sysdeps/x86_64/tst-avx.c @@ -0,0 +1,49 @@ +/* Test case for preserved AVX registers in dynamic linker. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +int tst_avx_aux (void); + +static int +avx_enabled (void) +{ + unsigned int eax, ebx, ecx, edx; + + if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0 + || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE)) + return 0; + + /* Check the OS has AVX and SSE saving enabled. */ + asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); + + return (eax & 6) == 6; +} + +static int +do_test (void) +{ + /* Run AVX test only if AVX is supported. */ + if (avx_enabled ()) + return tst_avx_aux (); + else + return 77; +} + +#define TEST_FUNCTION do_test () +#include "../../test-skeleton.c" diff --git a/sysdeps/x86_64/tst-avx512-aux.c b/sysdeps/x86_64/tst-avx512-aux.c new file mode 100644 index 0000000000..6cebc523f2 --- /dev/null +++ b/sysdeps/x86_64/tst-avx512-aux.c @@ -0,0 +1,48 @@ +/* Test case for preserved AVX512 registers in dynamic linker, + -mavx512 part. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +int +tst_avx512_aux (void) +{ +#ifdef __AVX512F__ + extern __m512i avx512_test (__m512i, __m512i, __m512i, __m512i, + __m512i, __m512i, __m512i, __m512i); + + __m512i zmm0 = _mm512_set1_epi32 (0); + __m512i zmm1 = _mm512_set1_epi32 (1); + __m512i zmm2 = _mm512_set1_epi32 (2); + __m512i zmm3 = _mm512_set1_epi32 (3); + __m512i zmm4 = _mm512_set1_epi32 (4); + __m512i zmm5 = _mm512_set1_epi32 (5); + __m512i zmm6 = _mm512_set1_epi32 (6); + __m512i zmm7 = _mm512_set1_epi32 (7); + __m512i ret = avx512_test (zmm0, zmm1, zmm2, zmm3, + zmm4, zmm5, zmm6, zmm7); + zmm0 = _mm512_set1_epi32 (0x12349876); + if (memcmp (&zmm0, &ret, sizeof (ret))) + abort (); + return 0; +#else /* __AVX512F__ */ + return 77; +#endif /* __AVX512F__ */ +} diff --git a/sysdeps/x86_64/tst-avx512.c b/sysdeps/x86_64/tst-avx512.c new file mode 100644 index 0000000000..a8e42ef553 --- /dev/null +++ b/sysdeps/x86_64/tst-avx512.c @@ -0,0 +1,57 @@ +/* Test case for preserved AVX512 registers in dynamic linker. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include + +int tst_avx512_aux (void); + +static int +avx512_enabled (void) +{ +#ifdef bit_AVX512F + unsigned int eax, ebx, ecx, edx; + + if (__get_cpuid (1, &eax, &ebx, &ecx, &edx) == 0 + || (ecx & (bit_AVX | bit_OSXSAVE)) != (bit_AVX | bit_OSXSAVE)) + return 0; + + __cpuid_count (7, 0, eax, ebx, ecx, edx); + if (!(ebx & bit_AVX512F)) + return 0; + + asm ("xgetbv" : "=a" (eax), "=d" (edx) : "c" (0)); + + /* Verify that ZMM, YMM and XMM states are enabled. */ + return (eax & 0xe6) == 0xe6; +#else + return 0; +#endif +} + +static int +do_test (void) +{ + /* Run AVX512 test only if AVX512 is supported. */ + if (avx512_enabled ()) + return tst_avx512_aux (); + else + return 77; +} + +#define TEST_FUNCTION do_test () +#include "../../test-skeleton.c" diff --git a/sysdeps/x86_64/tst-avx512mod.c b/sysdeps/x86_64/tst-avx512mod.c new file mode 100644 index 0000000000..4cfb3a2c3d --- /dev/null +++ b/sysdeps/x86_64/tst-avx512mod.c @@ -0,0 +1,48 @@ +/* Test case for x86-64 preserved AVX512 registers in dynamic linker. */ + +#ifdef __AVX512F__ +#include +#include +#include + +__m512i +avx512_test (__m512i x0, __m512i x1, __m512i x2, __m512i x3, + __m512i x4, __m512i x5, __m512i x6, __m512i x7) +{ + __m512i zmm; + + zmm = _mm512_set1_epi32 (0); + if (memcmp (&zmm, &x0, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (1); + if (memcmp (&zmm, &x1, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (2); + if (memcmp (&zmm, &x2, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (3); + if (memcmp (&zmm, &x3, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (4); + if (memcmp (&zmm, &x4, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (5); + if (memcmp (&zmm, &x5, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (6); + if (memcmp (&zmm, &x6, sizeof (zmm))) + abort (); + + zmm = _mm512_set1_epi32 (7); + if (memcmp (&zmm, &x7, sizeof (zmm))) + abort (); + + return _mm512_set1_epi32 (0x12349876); +} +#endif diff --git a/sysdeps/x86_64/tst-avxmod.c b/sysdeps/x86_64/tst-avxmod.c new file mode 100644 index 0000000000..6e5b154997 --- /dev/null +++ b/sysdeps/x86_64/tst-avxmod.c @@ -0,0 +1,48 @@ +/* Test case for x86-64 preserved AVX registers in dynamic linker. */ + +#ifdef __AVX__ +#include +#include +#include + +__m256i +avx_test (__m256i x0, __m256i x1, __m256i x2, __m256i x3, + __m256i x4, __m256i x5, __m256i x6, __m256i x7) +{ + __m256i ymm; + + ymm = _mm256_set1_epi32 (0); + if (memcmp (&ymm, &x0, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (1); + if (memcmp (&ymm, &x1, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (2); + if (memcmp (&ymm, &x2, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (3); + if (memcmp (&ymm, &x3, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (4); + if (memcmp (&ymm, &x4, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (5); + if (memcmp (&ymm, &x5, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (6); + if (memcmp (&ymm, &x6, sizeof (ymm))) + abort (); + + ymm = _mm256_set1_epi32 (7); + if (memcmp (&ymm, &x7, sizeof (ymm))) + abort (); + + return _mm256_set1_epi32 (0x12349876); +} +#endif diff --git a/sysdeps/x86_64/tst-sse.c b/sysdeps/x86_64/tst-sse.c new file mode 100644 index 0000000000..dd1537cf27 --- /dev/null +++ b/sysdeps/x86_64/tst-sse.c @@ -0,0 +1,46 @@ +/* Test case for preserved SSE registers in dynamic linker. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include + +extern __m128i sse_test (__m128i, __m128i, __m128i, __m128i, + __m128i, __m128i, __m128i, __m128i); + +static int +do_test (void) +{ + __m128i xmm0 = _mm_set1_epi32 (0); + __m128i xmm1 = _mm_set1_epi32 (1); + __m128i xmm2 = _mm_set1_epi32 (2); + __m128i xmm3 = _mm_set1_epi32 (3); + __m128i xmm4 = _mm_set1_epi32 (4); + __m128i xmm5 = _mm_set1_epi32 (5); + __m128i xmm6 = _mm_set1_epi32 (6); + __m128i xmm7 = _mm_set1_epi32 (7); + __m128i ret = sse_test (xmm0, xmm1, xmm2, xmm3, + xmm4, xmm5, xmm6, xmm7); + xmm0 = _mm_set1_epi32 (0x12349876); + if (memcmp (&xmm0, &ret, sizeof (ret))) + abort (); + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../../test-skeleton.c" diff --git a/sysdeps/x86_64/tst-ssemod.c b/sysdeps/x86_64/tst-ssemod.c new file mode 100644 index 0000000000..907a64c69e --- /dev/null +++ b/sysdeps/x86_64/tst-ssemod.c @@ -0,0 +1,46 @@ +/* Test case for x86-64 preserved SSE registers in dynamic linker. */ + +#include +#include +#include + +__m128i +sse_test (__m128i x0, __m128i x1, __m128i x2, __m128i x3, + __m128i x4, __m128i x5, __m128i x6, __m128i x7) +{ + __m128i xmm; + + xmm = _mm_set1_epi32 (0); + if (memcmp (&xmm, &x0, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (1); + if (memcmp (&xmm, &x1, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (2); + if (memcmp (&xmm, &x2, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (3); + if (memcmp (&xmm, &x3, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (4); + if (memcmp (&xmm, &x4, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (5); + if (memcmp (&xmm, &x5, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (6); + if (memcmp (&xmm, &x6, sizeof (xmm))) + abort (); + + xmm = _mm_set1_epi32 (7); + if (memcmp (&xmm, &x7, sizeof (xmm))) + abort (); + + return _mm_set1_epi32 (0x12349876); +} -- cgit v1.2.3 From bea3f92405f705684275bffee954cafe84ffb09d Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sun, 22 Oct 2017 08:24:00 -0700 Subject: x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve [BZ #21265] In _dl_runtime_resolve, use fxsave/xsave/xsavec to preserve all vector, mask and bound registers. It simplifies _dl_runtime_resolve and supports different calling conventions. ld.so code size is reduced by more than 1 KB. However, use fxsave/xsave/xsavec takes a little bit more cycles than saving and restoring vector and bound registers individually. Latency for _dl_runtime_resolve to lookup the function, foo, from one shared library plus libc.so: Before After Change Westmere (SSE)/fxsave 345 866 151% IvyBridge (AVX)/xsave 420 643 53% Haswell (AVX)/xsave 713 1252 75% Skylake (AVX+MPX)/xsavec 559 719 28% Skylake (AVX512+MPX)/xsavec 145 272 87% Ryzen (AVX)/xsavec 280 553 97% This is the worst case where portion of time spent for saving and restoring registers is bigger than majority of cases. With smaller _dl_runtime_resolve code size, overall performance impact is negligible. On IvyBridge, differences in build and test time of binutils with lazy binding GCC and binutils are noises. On Westmere, differences in bootstrap and "makc check" time of GCC 7 with lazy binding GCC and binutils are also noises. [BZ #21265] * sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET): New. * sysdeps/x86/cpu-features.c: Include . (get_common_indeces): Set xsave_state_size and bit_arch_XSAVEC_Usable if needed. (init_cpu_features): Remove bit_arch_Use_dl_runtime_resolve_slow and bit_arch_Use_dl_runtime_resolve_opt. * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): Removed. (bit_arch_Use_dl_runtime_resolve_slow): Likewise. (bit_arch_Prefer_No_AVX512): Updated. (bit_arch_MathVec_Prefer_No_AVX512): Likewise. (bit_arch_XSAVEC_Usable): New. (STATE_SAVE_OFFSET): Likewise. (STATE_SAVE_MASK): Likewise. [__ASSEMBLER__]: Include . (cpu_features): Add xsave_state_size. (index_arch_Use_dl_runtime_resolve_opt): Removed. (index_arch_Use_dl_runtime_resolve_slow): Likewise. (index_arch_XSAVEC_Usable): New. * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): Replace _dl_runtime_resolve_sse, _dl_runtime_resolve_avx, _dl_runtime_resolve_avx_slow, _dl_runtime_resolve_avx_opt, _dl_runtime_resolve_avx512 and _dl_runtime_resolve_avx512_opt with _dl_runtime_resolve_fxsave, _dl_runtime_resolve_xsave and _dl_runtime_resolve_xsavec. * sysdeps/x86_64/dl-trampoline.S (DL_RUNTIME_UNALIGNED_VEC_SIZE): Removed. (DL_RUNTIME_RESOLVE_REALIGN_STACK): Check STATE_SAVE_ALIGNMENT instead of VEC_SIZE. (REGISTER_SAVE_BND0): Removed. (REGISTER_SAVE_BND1): Likewise. (REGISTER_SAVE_BND3): Likewise. (REGISTER_SAVE_RAX): Always defined to 0. (VMOV): Removed. (_dl_runtime_resolve_avx): Likewise. (_dl_runtime_resolve_avx_slow): Likewise. (_dl_runtime_resolve_avx_opt): Likewise. (_dl_runtime_resolve_avx512): Likewise. (_dl_runtime_resolve_avx512_opt): Likewise. (_dl_runtime_resolve_sse): Likewise. (_dl_runtime_resolve_sse_vex): Likewise. (USE_FXSAVE): New. (_dl_runtime_resolve_fxsave): Likewise. (USE_XSAVE): Likewise. (_dl_runtime_resolve_xsave): Likewise. (USE_XSAVEC): Likewise. (_dl_runtime_resolve_xsavec): Likewise. * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx512): Removed. (_dl_runtime_resolve_avx512_opt): Likewise. (_dl_runtime_resolve_avx): Likewise. (_dl_runtime_resolve_avx_opt): Likewise. (_dl_runtime_resolve_sse): Likewise. (_dl_runtime_resolve_sse_vex): Likewise. (_dl_runtime_resolve_fxsave): New. (_dl_runtime_resolve_xsave): Likewise. (_dl_runtime_resolve_xsavec): Likewise. (cherry picked from commit b52b0d793dcb226ecb0ecca1e672ca265973233c) --- ChangeLog | 62 ++++++++ NEWS | 1 + sysdeps/x86/cpu-features-offsets.sym | 1 + sysdeps/x86/cpu-features.c | 83 ++++++++--- sysdeps/x86/cpu-features.h | 23 ++- sysdeps/x86_64/dl-machine.h | 38 ++--- sysdeps/x86_64/dl-trampoline.S | 87 ++++-------- sysdeps/x86_64/dl-trampoline.h | 267 ++++++++++------------------------- 8 files changed, 265 insertions(+), 297 deletions(-) diff --git a/ChangeLog b/ChangeLog index 84189ec762..9be47cd9ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,65 @@ +2017-10-22 H.J. Lu + + [BZ #21265] + * sysdeps/x86/cpu-features-offsets.sym (XSAVE_STATE_SIZE_OFFSET): + New. + * sysdeps/x86/cpu-features.c: Include . + (get_common_indeces): Set xsave_state_size and + bit_arch_XSAVEC_Usable if needed. + (init_cpu_features): Remove bit_arch_Use_dl_runtime_resolve_slow + and bit_arch_Use_dl_runtime_resolve_opt. + * sysdeps/x86/cpu-features.h (bit_arch_Use_dl_runtime_resolve_opt): + Removed. + (bit_arch_Use_dl_runtime_resolve_slow): Likewise. + (bit_arch_Prefer_No_AVX512): Updated. + (bit_arch_MathVec_Prefer_No_AVX512): Likewise. + (bit_arch_XSAVEC_Usable): New. + (STATE_SAVE_OFFSET): Likewise. + (STATE_SAVE_MASK): Likewise. + [__ASSEMBLER__]: Include . + (cpu_features): Add xsave_state_size. + (index_arch_Use_dl_runtime_resolve_opt): Removed. + (index_arch_Use_dl_runtime_resolve_slow): Likewise. + (index_arch_XSAVEC_Usable): New. + * sysdeps/x86_64/dl-machine.h (elf_machine_runtime_setup): + Replace _dl_runtime_resolve_sse, _dl_runtime_resolve_avx, + _dl_runtime_resolve_avx_slow, _dl_runtime_resolve_avx_opt, + _dl_runtime_resolve_avx512 and _dl_runtime_resolve_avx512_opt + with _dl_runtime_resolve_fxsave, _dl_runtime_resolve_xsave and + _dl_runtime_resolve_xsavec. + * sysdeps/x86_64/dl-trampoline.S (DL_RUNTIME_UNALIGNED_VEC_SIZE): + Removed. + (DL_RUNTIME_RESOLVE_REALIGN_STACK): Check STATE_SAVE_ALIGNMENT + instead of VEC_SIZE. + (REGISTER_SAVE_BND0): Removed. + (REGISTER_SAVE_BND1): Likewise. + (REGISTER_SAVE_BND3): Likewise. + (REGISTER_SAVE_RAX): Always defined to 0. + (VMOV): Removed. + (_dl_runtime_resolve_avx): Likewise. + (_dl_runtime_resolve_avx_slow): Likewise. + (_dl_runtime_resolve_avx_opt): Likewise. + (_dl_runtime_resolve_avx512): Likewise. + (_dl_runtime_resolve_avx512_opt): Likewise. + (_dl_runtime_resolve_sse): Likewise. + (_dl_runtime_resolve_sse_vex): Likewise. + (USE_FXSAVE): New. + (_dl_runtime_resolve_fxsave): Likewise. + (USE_XSAVE): Likewise. + (_dl_runtime_resolve_xsave): Likewise. + (USE_XSAVEC): Likewise. + (_dl_runtime_resolve_xsavec): Likewise. + * sysdeps/x86_64/dl-trampoline.h (_dl_runtime_resolve_avx512): + Removed. + (_dl_runtime_resolve_avx512_opt): Likewise. + (_dl_runtime_resolve_avx): Likewise. + (_dl_runtime_resolve_avx_opt): Likewise. + (_dl_runtime_resolve_sse): Likewise. + (_dl_runtime_resolve_sse_vex): Likewise. + (_dl_runtime_resolve_fxsave): New. + (_dl_runtime_resolve_xsave): Likewise. + (_dl_runtime_resolve_xsavec): Likewise. + 2017-10-19 H.J. Lu * sysdeps/x86_64/Makefile (tests): Add tst-sse, tst-avx and diff --git a/NEWS b/NEWS index 4831542023..9a9e487ee6 100644 --- a/NEWS +++ b/NEWS @@ -26,6 +26,7 @@ The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun [20978] Fix strlen on null pointer in nss_nisplus [21209] Ignore and remove LD_HWCAP_MASK for AT_SECURE programs + [21265] x86-64: Use fxsave/xsave/xsavec in _dl_runtime_resolve [21289] Fix symbol redirect for fts_set [21386] Assertion in fork for distinct parent PID is incorrect [21609] x86-64: Align the stack in __tls_get_addr diff --git a/sysdeps/x86/cpu-features-offsets.sym b/sysdeps/x86/cpu-features-offsets.sym index f6739fae81..33dd094e37 100644 --- a/sysdeps/x86/cpu-features-offsets.sym +++ b/sysdeps/x86/cpu-features-offsets.sym @@ -15,6 +15,7 @@ CPUID_ECX_OFFSET offsetof (struct cpuid_registers, ecx) CPUID_EDX_OFFSET offsetof (struct cpuid_registers, edx) FAMILY_OFFSET offsetof (struct cpu_features, family) MODEL_OFFSET offsetof (struct cpu_features, model) +XSAVE_STATE_SIZE_OFFSET offsetof (struct cpu_features, xsave_state_size) FEATURE_OFFSET offsetof (struct cpu_features, feature) FEATURE_SIZE sizeof (unsigned int) diff --git a/sysdeps/x86/cpu-features.c b/sysdeps/x86/cpu-features.c index 508ad2ae7b..9eca98817d 100644 --- a/sysdeps/x86/cpu-features.c +++ b/sysdeps/x86/cpu-features.c @@ -18,6 +18,7 @@ #include #include +#include static void get_common_indeces (struct cpu_features *cpu_features, @@ -88,6 +89,71 @@ get_common_indeces (struct cpu_features *cpu_features, cpu_features->feature[index_arch_FMA_Usable] |= bit_arch_FMA_Usable; } + + /* For _dl_runtime_resolve, set xsave_state_size to xsave area + size + integer register save size and align it to 64 bytes. */ + if (cpu_features->max_cpuid >= 0xd) + { + unsigned int eax, ebx, ecx, edx; + + __cpuid_count (0xd, 0, eax, ebx, ecx, edx); + if (ebx != 0) + { + cpu_features->xsave_state_size + = ALIGN_UP (ebx + STATE_SAVE_OFFSET, 64); + + __cpuid_count (0xd, 1, eax, ebx, ecx, edx); + + /* Check if XSAVEC is available. */ + if ((eax & (1 << 1)) != 0) + { + unsigned int xstate_comp_offsets[32]; + unsigned int xstate_comp_sizes[32]; + unsigned int i; + + xstate_comp_offsets[0] = 0; + xstate_comp_offsets[1] = 160; + xstate_comp_offsets[2] = 576; + xstate_comp_sizes[0] = 160; + xstate_comp_sizes[1] = 256; + + for (i = 2; i < 32; i++) + { + if ((STATE_SAVE_MASK & (1 << i)) != 0) + { + __cpuid_count (0xd, i, eax, ebx, ecx, edx); + xstate_comp_sizes[i] = eax; + } + else + { + ecx = 0; + xstate_comp_sizes[i] = 0; + } + + if (i > 2) + { + xstate_comp_offsets[i] + = (xstate_comp_offsets[i - 1] + + xstate_comp_sizes[i -1]); + if ((ecx & (1 << 1)) != 0) + xstate_comp_offsets[i] + = ALIGN_UP (xstate_comp_offsets[i], 64); + } + } + + /* Use XSAVEC. */ + unsigned int size + = xstate_comp_offsets[31] + xstate_comp_sizes[31]; + if (size) + { + cpu_features->xsave_state_size + = ALIGN_UP (size + STATE_SAVE_OFFSET, 64); + cpu_features->feature[index_arch_XSAVEC_Usable] + |= bit_arch_XSAVEC_Usable; + } + } + } + } } } @@ -213,23 +279,6 @@ init_cpu_features (struct cpu_features *cpu_features) 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. - Use _dl_runtime_resolve_opt only with AVX512F since it is - slower than _dl_runtime_resolve_slow with AVX. */ - cpu_features->feature[index_arch_Use_dl_runtime_resolve_slow] - |= bit_arch_Use_dl_runtime_resolve_slow; - if (CPU_FEATURES_ARCH_P (cpu_features, AVX512F_Usable) - && cpu_features->max_cpuid >= 0xd) - { - unsigned int eax; - - __cpuid_count (0xd, 1, eax, ebx, ecx, edx); - if ((eax & (1 << 2)) != 0) - cpu_features->feature[index_arch_Use_dl_runtime_resolve_opt] - |= bit_arch_Use_dl_runtime_resolve_opt; - } } /* This spells out "AuthenticAMD". */ else if (ebx == 0x68747541 && ecx == 0x444d4163 && edx == 0x69746e65) diff --git a/sysdeps/x86/cpu-features.h b/sysdeps/x86/cpu-features.h index 2609ac0999..507a141414 100644 --- a/sysdeps/x86/cpu-features.h +++ b/sysdeps/x86/cpu-features.h @@ -37,9 +37,8 @@ #define bit_arch_Prefer_No_VZEROUPPER (1 << 17) #define bit_arch_Fast_Unaligned_Copy (1 << 18) #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) +#define bit_arch_Prefer_No_AVX512 (1 << 20) +#define bit_arch_XSAVEC_Usable (1 << 21) /* CPUID Feature flags. */ @@ -82,6 +81,15 @@ /* The current maximum size of the feature integer bit array. */ #define FEATURE_INDEX_MAX 1 +/* Offset for fxsave/xsave area used by _dl_runtime_resolve. Also need + space to preserve RCX, RDX, RSI, RDI, R8, R9 and RAX. It must be + aligned to 16 bytes for fxsave and 64 bytes for xsave. */ +#define STATE_SAVE_OFFSET (8 * 7 + 8) + +/* Save SSE, AVX, AVX512, mask and bound registers. */ +#define STATE_SAVE_MASK \ + ((1 << 1) | (1 << 2) | (1 << 3) | (1 << 5) | (1 << 6) | (1 << 7)) + #ifdef __ASSEMBLER__ # include @@ -206,6 +214,12 @@ struct cpu_features } cpuid[COMMON_CPUID_INDEX_MAX]; unsigned int family; unsigned int model; + /* The type must be unsigned long int so that we use + + sub xsave_state_size_offset(%rip) %RSP_LP + + in _dl_runtime_resolve. */ + unsigned long int xsave_state_size; unsigned int feature[FEATURE_INDEX_MAX]; }; @@ -298,9 +312,8 @@ extern const struct cpu_features *__get_cpu_features (void) # define index_arch_Prefer_No_VZEROUPPER FEATURE_INDEX_1 # define index_arch_Fast_Unaligned_Copy FEATURE_INDEX_1 # 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 +# define index_arch_XSAVEC_Usable FEATURE_INDEX_1 #endif /* !__ASSEMBLER__ */ diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h index c0f0fa16a2..8355432dfc 100644 --- a/sysdeps/x86_64/dl-machine.h +++ b/sysdeps/x86_64/dl-machine.h @@ -66,12 +66,9 @@ static inline int __attribute__ ((unused, always_inline)) elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) { Elf64_Addr *got; - extern void _dl_runtime_resolve_sse (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx_slow (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx_opt (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx512 (ElfW(Word)) attribute_hidden; - extern void _dl_runtime_resolve_avx512_opt (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_fxsave (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_xsave (ElfW(Word)) attribute_hidden; + extern void _dl_runtime_resolve_xsavec (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_sse (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_avx (ElfW(Word)) attribute_hidden; extern void _dl_runtime_profile_avx512 (ElfW(Word)) attribute_hidden; @@ -120,29 +117,14 @@ elf_machine_runtime_setup (struct link_map *l, int lazy, int profile) /* This function will get called to fix up the GOT entry indicated by the offset on the stack, and then jump to the resolved address. */ - if (HAS_ARCH_FEATURE (AVX512F_Usable)) - { - if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt)) - *(ElfW(Addr) *) (got + 2) - = (ElfW(Addr)) &_dl_runtime_resolve_avx512_opt; - else - *(ElfW(Addr) *) (got + 2) - = (ElfW(Addr)) &_dl_runtime_resolve_avx512; - } - else if (HAS_ARCH_FEATURE (AVX_Usable)) - { - if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_opt)) - *(ElfW(Addr) *) (got + 2) - = (ElfW(Addr)) &_dl_runtime_resolve_avx_opt; - else if (HAS_ARCH_FEATURE (Use_dl_runtime_resolve_slow)) - *(ElfW(Addr) *) (got + 2) - = (ElfW(Addr)) &_dl_runtime_resolve_avx_slow; - else - *(ElfW(Addr) *) (got + 2) - = (ElfW(Addr)) &_dl_runtime_resolve_avx; - } + if (GLRO(dl_x86_cpu_features).xsave_state_size != 0) + *(ElfW(Addr) *) (got + 2) + = (HAS_ARCH_FEATURE (XSAVEC_Usable) + ? (ElfW(Addr)) &_dl_runtime_resolve_xsavec + : (ElfW(Addr)) &_dl_runtime_resolve_xsave); else - *(ElfW(Addr) *) (got + 2) = (ElfW(Addr)) &_dl_runtime_resolve_sse; + *(ElfW(Addr) *) (got + 2) + = (ElfW(Addr)) &_dl_runtime_resolve_fxsave; } } diff --git a/sysdeps/x86_64/dl-trampoline.S b/sysdeps/x86_64/dl-trampoline.S index 50b23633e3..b4cda0f535 100644 --- a/sysdeps/x86_64/dl-trampoline.S +++ b/sysdeps/x86_64/dl-trampoline.S @@ -34,41 +34,24 @@ # define DL_STACK_ALIGNMENT 8 #endif -#ifndef DL_RUNTIME_UNALIGNED_VEC_SIZE -/* The maximum size in bytes of unaligned vector load and store in the - dynamic linker. Since SSE optimized memory/string functions with - aligned SSE register load and store are used in the dynamic linker, - we must set this to 8 so that _dl_runtime_resolve_sse will align the - stack before calling _dl_fixup. */ -# define DL_RUNTIME_UNALIGNED_VEC_SIZE 8 -#endif - -/* True if _dl_runtime_resolve should align stack to VEC_SIZE bytes. */ +/* True if _dl_runtime_resolve should align stack for STATE_SAVE or align + stack to 16 bytes before calling _dl_fixup. */ #define DL_RUNTIME_RESOLVE_REALIGN_STACK \ - (VEC_SIZE > DL_STACK_ALIGNMENT \ - && VEC_SIZE > DL_RUNTIME_UNALIGNED_VEC_SIZE) - -/* Align vector register save area to 16 bytes. */ -#define REGISTER_SAVE_VEC_OFF 0 + (STATE_SAVE_ALIGNMENT > DL_STACK_ALIGNMENT \ + || 16 > DL_STACK_ALIGNMENT) /* Area on stack to save and restore registers used for parameter passing when calling _dl_fixup. */ #ifdef __ILP32__ -# define REGISTER_SAVE_RAX (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8) # define PRESERVE_BND_REGS_PREFIX #else -/* Align bound register save area to 16 bytes. */ -# define REGISTER_SAVE_BND0 (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 8) -# define REGISTER_SAVE_BND1 (REGISTER_SAVE_BND0 + 16) -# define REGISTER_SAVE_BND2 (REGISTER_SAVE_BND1 + 16) -# define REGISTER_SAVE_BND3 (REGISTER_SAVE_BND2 + 16) -# define REGISTER_SAVE_RAX (REGISTER_SAVE_BND3 + 16) # ifdef HAVE_MPX_SUPPORT # define PRESERVE_BND_REGS_PREFIX bnd # else # define PRESERVE_BND_REGS_PREFIX .byte 0xf2 # endif #endif +#define REGISTER_SAVE_RAX 0 #define REGISTER_SAVE_RCX (REGISTER_SAVE_RAX + 8) #define REGISTER_SAVE_RDX (REGISTER_SAVE_RCX + 8) #define REGISTER_SAVE_RSI (REGISTER_SAVE_RDX + 8) @@ -80,68 +63,56 @@ #define VEC_SIZE 64 #define VMOVA vmovdqa64 -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV vmovdqa64 -#else -# define VMOV vmovdqu64 -#endif #define VEC(i) zmm##i -#define _dl_runtime_resolve _dl_runtime_resolve_avx512 #define _dl_runtime_profile _dl_runtime_profile_avx512 #include "dl-trampoline.h" -#undef _dl_runtime_resolve #undef _dl_runtime_profile #undef VEC -#undef VMOV #undef VMOVA #undef VEC_SIZE #define VEC_SIZE 32 #define VMOVA vmovdqa -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV vmovdqa -#else -# define VMOV vmovdqu -#endif #define VEC(i) ymm##i -#define _dl_runtime_resolve _dl_runtime_resolve_avx -#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx_opt #define _dl_runtime_profile _dl_runtime_profile_avx #include "dl-trampoline.h" -#undef _dl_runtime_resolve -#undef _dl_runtime_resolve_opt #undef _dl_runtime_profile #undef VEC -#undef VMOV #undef VMOVA #undef VEC_SIZE /* movaps/movups is 1-byte shorter. */ #define VEC_SIZE 16 #define VMOVA movaps -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV movaps -#else -# define VMOV movups -#endif #define VEC(i) xmm##i -#define _dl_runtime_resolve _dl_runtime_resolve_sse #define _dl_runtime_profile _dl_runtime_profile_sse #undef RESTORE_AVX #include "dl-trampoline.h" -#undef _dl_runtime_resolve #undef _dl_runtime_profile -#undef VMOV +#undef VEC #undef VMOVA +#undef VEC_SIZE -/* Used by _dl_runtime_resolve_avx_opt/_dl_runtime_resolve_avx512_opt - to preserve the full vector registers with zero upper bits. */ -#define VMOVA vmovdqa -#if DL_RUNTIME_RESOLVE_REALIGN_STACK || VEC_SIZE <= DL_STACK_ALIGNMENT -# define VMOV vmovdqa -#else -# define VMOV vmovdqu -#endif -#define _dl_runtime_resolve _dl_runtime_resolve_sse_vex -#define _dl_runtime_resolve_opt _dl_runtime_resolve_avx512_opt +#define USE_FXSAVE +#define STATE_SAVE_ALIGNMENT 16 +#define _dl_runtime_resolve _dl_runtime_resolve_fxsave +#include "dl-trampoline.h" +#undef _dl_runtime_resolve +#undef USE_FXSAVE +#undef STATE_SAVE_ALIGNMENT + +#define USE_XSAVE +#define STATE_SAVE_ALIGNMENT 64 +#define _dl_runtime_resolve _dl_runtime_resolve_xsave +#include "dl-trampoline.h" +#undef _dl_runtime_resolve +#undef USE_XSAVE +#undef STATE_SAVE_ALIGNMENT + +#define USE_XSAVEC +#define STATE_SAVE_ALIGNMENT 64 +#define _dl_runtime_resolve _dl_runtime_resolve_xsavec #include "dl-trampoline.h" +#undef _dl_runtime_resolve +#undef USE_XSAVEC +#undef STATE_SAVE_ALIGNMENT diff --git a/sysdeps/x86_64/dl-trampoline.h b/sysdeps/x86_64/dl-trampoline.h index d21c5a987a..b9c2f1796f 100644 --- a/sysdeps/x86_64/dl-trampoline.h +++ b/sysdeps/x86_64/dl-trampoline.h @@ -16,140 +16,47 @@ License along with the GNU C Library; if not, see . */ -#undef REGISTER_SAVE_AREA_RAW -#ifdef __ILP32__ -/* X32 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as VEC0 to - VEC7. */ -# define REGISTER_SAVE_AREA_RAW (8 * 7 + VEC_SIZE * 8) -#else -/* X86-64 saves RCX, RDX, RSI, RDI, R8 and R9 plus RAX as well as - BND0, BND1, BND2, BND3 and VEC0 to VEC7. */ -# define REGISTER_SAVE_AREA_RAW (8 * 7 + 16 * 4 + VEC_SIZE * 8) -#endif + .text +#ifdef _dl_runtime_resolve -#undef REGISTER_SAVE_AREA -#undef LOCAL_STORAGE_AREA -#undef BASE -#if DL_RUNTIME_RESOLVE_REALIGN_STACK -# define REGISTER_SAVE_AREA (REGISTER_SAVE_AREA_RAW + 8) -/* Local stack area before jumping to function address: RBX. */ -# define LOCAL_STORAGE_AREA 8 -# define BASE rbx -# if (REGISTER_SAVE_AREA % VEC_SIZE) != 0 -# error REGISTER_SAVE_AREA must be multples of VEC_SIZE -# endif -#else -# define REGISTER_SAVE_AREA REGISTER_SAVE_AREA_RAW -/* Local stack area before jumping to function address: All saved - registers. */ -# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA -# define BASE rsp -# if (REGISTER_SAVE_AREA % 16) != 8 -# error REGISTER_SAVE_AREA must be odd multples of 8 +# undef REGISTER_SAVE_AREA +# undef LOCAL_STORAGE_AREA +# undef BASE + +# if (STATE_SAVE_ALIGNMENT % 16) != 0 +# error STATE_SAVE_ALIGNMENT must be multples of 16 # endif -#endif - .text -#ifdef _dl_runtime_resolve_opt -/* Use the smallest vector registers to preserve the full YMM/ZMM - registers to avoid SSE transition penalty. */ - -# if VEC_SIZE == 32 -/* Check if the upper 128 bits in %ymm0 - %ymm7 registers are non-zero - and preserve %xmm0 - %xmm7 registers with the zero upper bits. Since - there is no SSE transition penalty on AVX512 processors which don't - support XGETBV with ECX == 1, _dl_runtime_resolve_avx512_slow isn't - provided. */ - .globl _dl_runtime_resolve_avx_slow - .hidden _dl_runtime_resolve_avx_slow - .type _dl_runtime_resolve_avx_slow, @function - .align 16 -_dl_runtime_resolve_avx_slow: - cfi_startproc - cfi_adjust_cfa_offset(16) # Incorporate PLT - vorpd %ymm0, %ymm1, %ymm8 - vorpd %ymm2, %ymm3, %ymm9 - vorpd %ymm4, %ymm5, %ymm10 - vorpd %ymm6, %ymm7, %ymm11 - vorpd %ymm8, %ymm9, %ymm9 - vorpd %ymm10, %ymm11, %ymm10 - vpcmpeqd %xmm8, %xmm8, %xmm8 - vorpd %ymm9, %ymm10, %ymm10 - vptest %ymm10, %ymm8 - # Preserve %ymm0 - %ymm7 registers if the upper 128 bits of any - # %ymm0 - %ymm7 registers aren't zero. - PRESERVE_BND_REGS_PREFIX - jnc _dl_runtime_resolve_avx - # Use vzeroupper to avoid SSE transition penalty. - vzeroupper - # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits - # when the upper 128 bits of %ymm0 - %ymm7 registers are zero. - PRESERVE_BND_REGS_PREFIX - jmp _dl_runtime_resolve_sse_vex - cfi_adjust_cfa_offset(-16) # Restore PLT adjustment - cfi_endproc - .size _dl_runtime_resolve_avx_slow, .-_dl_runtime_resolve_avx_slow +# if (STATE_SAVE_OFFSET % STATE_SAVE_ALIGNMENT) != 0 +# error STATE_SAVE_OFFSET must be multples of STATE_SAVE_ALIGNMENT # endif -/* Use XGETBV with ECX == 1 to check which bits in vector registers are - non-zero and only preserve the non-zero lower bits with zero upper - bits. */ - .globl _dl_runtime_resolve_opt - .hidden _dl_runtime_resolve_opt - .type _dl_runtime_resolve_opt, @function - .align 16 -_dl_runtime_resolve_opt: - cfi_startproc - cfi_adjust_cfa_offset(16) # Incorporate PLT - pushq %rax - cfi_adjust_cfa_offset(8) - cfi_rel_offset(%rax, 0) - pushq %rcx - cfi_adjust_cfa_offset(8) - cfi_rel_offset(%rcx, 0) - pushq %rdx - cfi_adjust_cfa_offset(8) - cfi_rel_offset(%rdx, 0) - movl $1, %ecx - xgetbv - movl %eax, %r11d - popq %rdx - cfi_adjust_cfa_offset(-8) - cfi_restore (%rdx) - popq %rcx - cfi_adjust_cfa_offset(-8) - cfi_restore (%rcx) - popq %rax - cfi_adjust_cfa_offset(-8) - cfi_restore (%rax) -# if VEC_SIZE == 32 - # For YMM registers, check if YMM state is in use. - andl $bit_YMM_state, %r11d - # Preserve %xmm0 - %xmm7 registers with the zero upper 128 bits if - # YMM state isn't in use. - PRESERVE_BND_REGS_PREFIX - jz _dl_runtime_resolve_sse_vex -# 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 %zmm0 - %zmm7 registers if ZMM state is in use. - PRESERVE_BND_REGS_PREFIX - 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. +# if DL_RUNTIME_RESOLVE_REALIGN_STACK +/* Local stack area before jumping to function address: RBX. */ +# define LOCAL_STORAGE_AREA 8 +# define BASE rbx +# ifdef USE_FXSAVE +/* Use fxsave to save XMM registers. */ +# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET) +# if (REGISTER_SAVE_AREA % 16) != 0 +# error REGISTER_SAVE_AREA must be multples of 16 +# endif +# endif # else -# error Unsupported VEC_SIZE! +# ifndef USE_FXSAVE +# error USE_FXSAVE must be defined +# endif +/* Use fxsave to save XMM registers. */ +# define REGISTER_SAVE_AREA (512 + STATE_SAVE_OFFSET + 8) +/* Local stack area before jumping to function address: All saved + registers. */ +# define LOCAL_STORAGE_AREA REGISTER_SAVE_AREA +# define BASE rsp +# if (REGISTER_SAVE_AREA % 16) != 8 +# error REGISTER_SAVE_AREA must be odd multples of 8 +# endif # endif - cfi_adjust_cfa_offset(-16) # Restore PLT adjustment - cfi_endproc - .size _dl_runtime_resolve_opt, .-_dl_runtime_resolve_opt -#endif + .globl _dl_runtime_resolve .hidden _dl_runtime_resolve .type _dl_runtime_resolve, @function @@ -157,21 +64,30 @@ _dl_runtime_resolve_opt: cfi_startproc _dl_runtime_resolve: cfi_adjust_cfa_offset(16) # Incorporate PLT -#if DL_RUNTIME_RESOLVE_REALIGN_STACK -# if LOCAL_STORAGE_AREA != 8 -# error LOCAL_STORAGE_AREA must be 8 -# endif +# if DL_RUNTIME_RESOLVE_REALIGN_STACK +# if LOCAL_STORAGE_AREA != 8 +# error LOCAL_STORAGE_AREA must be 8 +# endif pushq %rbx # push subtracts stack by 8. cfi_adjust_cfa_offset(8) cfi_rel_offset(%rbx, 0) mov %RSP_LP, %RBX_LP cfi_def_cfa_register(%rbx) - and $-VEC_SIZE, %RSP_LP -#endif + and $-STATE_SAVE_ALIGNMENT, %RSP_LP +# endif +# ifdef REGISTER_SAVE_AREA sub $REGISTER_SAVE_AREA, %RSP_LP -#if !DL_RUNTIME_RESOLVE_REALIGN_STACK +# if !DL_RUNTIME_RESOLVE_REALIGN_STACK cfi_adjust_cfa_offset(REGISTER_SAVE_AREA) -#endif +# endif +# else + # Allocate stack space of the required size to save the state. +# if IS_IN (rtld) + sub _rtld_local_ro+RTLD_GLOBAL_RO_DL_X86_CPU_FEATURES_OFFSET+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP +# else + sub _dl_x86_cpu_features+XSAVE_STATE_SIZE_OFFSET(%rip), %RSP_LP +# endif +# endif # Preserve registers otherwise clobbered. movq %rax, REGISTER_SAVE_RAX(%rsp) movq %rcx, REGISTER_SAVE_RCX(%rsp) @@ -180,59 +96,42 @@ _dl_runtime_resolve: movq %rdi, REGISTER_SAVE_RDI(%rsp) movq %r8, REGISTER_SAVE_R8(%rsp) movq %r9, REGISTER_SAVE_R9(%rsp) - VMOV %VEC(0), (REGISTER_SAVE_VEC_OFF)(%rsp) - VMOV %VEC(1), (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp) - VMOV %VEC(2), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp) - VMOV %VEC(3), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp) - VMOV %VEC(4), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp) - VMOV %VEC(5), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp) - VMOV %VEC(6), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp) - VMOV %VEC(7), (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp) -#ifndef __ILP32__ - # We also have to preserve bound registers. These are nops if - # Intel MPX isn't available or disabled. -# ifdef HAVE_MPX_SUPPORT - bndmov %bnd0, REGISTER_SAVE_BND0(%rsp) - bndmov %bnd1, REGISTER_SAVE_BND1(%rsp) - bndmov %bnd2, REGISTER_SAVE_BND2(%rsp) - bndmov %bnd3, REGISTER_SAVE_BND3(%rsp) +# ifdef USE_FXSAVE + fxsave STATE_SAVE_OFFSET(%rsp) # else -# if REGISTER_SAVE_BND0 == 0 - .byte 0x66,0x0f,0x1b,0x04,0x24 + movl $STATE_SAVE_MASK, %eax + xorl %edx, %edx + # Clear the XSAVE Header. +# ifdef USE_XSAVE + movq %rdx, (STATE_SAVE_OFFSET + 512)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8)(%rsp) +# endif + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 2)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 3)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 4)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 5)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 6)(%rsp) + movq %rdx, (STATE_SAVE_OFFSET + 512 + 8 * 7)(%rsp) +# ifdef USE_XSAVE + xsave STATE_SAVE_OFFSET(%rsp) # else - .byte 0x66,0x0f,0x1b,0x44,0x24,REGISTER_SAVE_BND0 + xsavec STATE_SAVE_OFFSET(%rsp) # endif - .byte 0x66,0x0f,0x1b,0x4c,0x24,REGISTER_SAVE_BND1 - .byte 0x66,0x0f,0x1b,0x54,0x24,REGISTER_SAVE_BND2 - .byte 0x66,0x0f,0x1b,0x5c,0x24,REGISTER_SAVE_BND3 # endif -#endif # Copy args pushed by PLT in register. # %rdi: link_map, %rsi: reloc_index mov (LOCAL_STORAGE_AREA + 8)(%BASE), %RSI_LP mov LOCAL_STORAGE_AREA(%BASE), %RDI_LP call _dl_fixup # Call resolver. mov %RAX_LP, %R11_LP # Save return value -#ifndef __ILP32__ - # Restore bound registers. These are nops if Intel MPX isn't - # avaiable or disabled. -# ifdef HAVE_MPX_SUPPORT - bndmov REGISTER_SAVE_BND3(%rsp), %bnd3 - bndmov REGISTER_SAVE_BND2(%rsp), %bnd2 - bndmov REGISTER_SAVE_BND1(%rsp), %bnd1 - bndmov REGISTER_SAVE_BND0(%rsp), %bnd0 + # Get register content back. +# ifdef USE_FXSAVE + fxrstor STATE_SAVE_OFFSET(%rsp) # else - .byte 0x66,0x0f,0x1a,0x5c,0x24,REGISTER_SAVE_BND3 - .byte 0x66,0x0f,0x1a,0x54,0x24,REGISTER_SAVE_BND2 - .byte 0x66,0x0f,0x1a,0x4c,0x24,REGISTER_SAVE_BND1 -# if REGISTER_SAVE_BND0 == 0 - .byte 0x66,0x0f,0x1a,0x04,0x24 -# else - .byte 0x66,0x0f,0x1a,0x44,0x24,REGISTER_SAVE_BND0 -# endif + movl $STATE_SAVE_MASK, %eax + xorl %edx, %edx + xrstor STATE_SAVE_OFFSET(%rsp) # endif -#endif - # Get register content back. movq REGISTER_SAVE_R9(%rsp), %r9 movq REGISTER_SAVE_R8(%rsp), %r8 movq REGISTER_SAVE_RDI(%rsp), %rdi @@ -240,20 +139,12 @@ _dl_runtime_resolve: movq REGISTER_SAVE_RDX(%rsp), %rdx movq REGISTER_SAVE_RCX(%rsp), %rcx movq REGISTER_SAVE_RAX(%rsp), %rax - VMOV (REGISTER_SAVE_VEC_OFF)(%rsp), %VEC(0) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE)(%rsp), %VEC(1) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 2)(%rsp), %VEC(2) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 3)(%rsp), %VEC(3) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 4)(%rsp), %VEC(4) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 5)(%rsp), %VEC(5) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 6)(%rsp), %VEC(6) - VMOV (REGISTER_SAVE_VEC_OFF + VEC_SIZE * 7)(%rsp), %VEC(7) -#if DL_RUNTIME_RESOLVE_REALIGN_STACK +# if DL_RUNTIME_RESOLVE_REALIGN_STACK mov %RBX_LP, %RSP_LP cfi_def_cfa_register(%rsp) movq (%rsp), %rbx cfi_restore(%rbx) -#endif +# endif # Adjust stack(PLT did 2 pushes) add $(LOCAL_STORAGE_AREA + 16), %RSP_LP cfi_adjust_cfa_offset(-(LOCAL_STORAGE_AREA + 16)) @@ -262,11 +153,9 @@ _dl_runtime_resolve: jmp *%r11 # Jump to function address. cfi_endproc .size _dl_runtime_resolve, .-_dl_runtime_resolve +#endif -/* To preserve %xmm0 - %xmm7 registers, dl-trampoline.h is included - twice, for _dl_runtime_resolve_sse and _dl_runtime_resolve_sse_vex. - But we don't need another _dl_runtime_profile for XMM registers. */ #if !defined PROF && defined _dl_runtime_profile # if (LR_VECTOR_OFFSET % VEC_SIZE) != 0 # error LR_VECTOR_OFFSET must be multples of VEC_SIZE -- cgit v1.2.3 From 89bf8ef2dba93e19385bf922fdcee87a97db768f Mon Sep 17 00:00:00 2001 From: "H.J. Lu" Date: Sun, 20 Aug 2017 10:46:47 -0700 Subject: i386: Hide __old_glob64 [BZ #18822] Hide internal __old_glob64 function to allow direct access within libc.so and libc.a without using GOT nor PLT. [BZ #18822] * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add libc_hidden_proto and libc_hidden_def. (cherry picked from commit 2585d7b839559e665d5723734862fbe62264b25d) (cherry picked from commit 2b54f16a8a237a1f3e6f8b974cafda09ed75d292) --- ChangeLog | 6 ++++++ sysdeps/unix/sysv/linux/i386/glob64.c | 3 +++ 2 files changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 9be47cd9ec..e7f1e0feb7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-08-20 H.J. Lu + + [BZ #18822] + * sysdeps/unix/sysv/linux/i386/glob64.c (__old_glob64): Add + libc_hidden_proto and libc_hidden_def. + 2017-10-22 H.J. Lu [BZ #21265] diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c index 802c957d6c..30470c6ed9 100644 --- a/sysdeps/unix/sysv/linux/i386/glob64.c +++ b/sysdeps/unix/sysv/linux/i386/glob64.c @@ -53,6 +53,7 @@ libc_hidden_ver (__glob64, glob64) int __old_glob64 (const char *__pattern, int __flags, int (*__errfunc) (const char *, int), glob64_t *__pglob); +libc_hidden_proto (__old_glob64); #undef dirent #define dirent __old_dirent64 @@ -72,5 +73,7 @@ int __old_glob64 (const char *__pattern, int __flags, #include +libc_hidden_def (__old_glob64); + compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); #endif -- cgit v1.2.3 From 832e2ec56701f85b892b782b8b749bc5a33899fb Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Date: Mon, 4 Sep 2017 14:53:38 -0300 Subject: posix: Sync glob with gnulib [BZ #1062] This patch syncs posix/glob.c implementation with gnulib version b5ec983 (glob: simplify symlink detection). The only difference to gnulib code is * DT_UNKNOWN, DT_DIR, and DT_LNK definition in the case there were not already defined. Gnulib code which uses HAVE_STRUCT_DIRENT_D_TYPE will redefine them wrongly because GLIBC does not define HAVE_STRUCT_DIRENT_D_TYPE. Instead the patch check for each definition instead. Also, the patch requires additional globfree and globfree64 files for compatibility version on some architectures. Also the code simplification leads to not macro simplification (not need for NO_GLOB_PATTERN_P anymore). Checked on x86_64-linux-gnu and on a build using build-many-glibcs.py for all major architectures. [BZ #1062] * posix/Makefile (routines): Add globfree, globfree64, and glob_pattern_p. * posix/flexmember.h: New file. * posix/glob_internal.h: Likewise. * posix/glob_pattern_p.c: Likewise. * posix/globfree.c: Likewise. * posix/globfree64.c: Likewise. * sysdeps/gnu/globfree64.c: Likewise. * sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise. * sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise. * sysdeps/unix/sysv/linux/oldglob.c: Likewise. * sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise. * sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise. * sysdeps/wordsize-64/globfree.c: Likewise. * sysdeps/wordsize-64/globfree64.c: Likewise. * posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead. [NDEBUG): Remove comments. (GLOB_ONLY_P, _AMIGA, VMS): Remove define. (dirent_type): New type. Use uint_fast8_t not uint8_t, as C99 does not require uint8_t. (DT_UNKNOWN, DT_DIR, DT_LNK): New macros. (struct readdir_result): Use dirent_type. Do not define skip_entry unless it is needed; this saves a byte on platforms lacking d_ino. (readdir_result_type, readdir_result_skip_entry): New functions, replacing ... (readdir_result_might_be_symlink, readdir_result_might_be_dir): these functions, which were removed. This makes the callers easier to read. All callers changed. (D_INO_TO_RESULT): Now empty if there is no d_ino. (size_add_wrapv, glob_use_alloca): New static functions. (glob, glob_in_dir): Check for size_t overflow in several places, and fix some size_t checks that were not quite right. Remove old code using SHELL since Bash no longer uses this. (glob, prefix_array): Separate MS code better. (glob_in_dir): Remove old Amiga and VMS code. (globfree, __glob_pattern_type, __glob_pattern_p): Move to separate files. (glob_in_dir): Do not rely on undefined behavior in accessing struct members beyond their bounds. Use a flexible array member instead (link_stat): Rename from link_exists2_p and return -1/0 instead of 0/1. Caller changed. (glob): Fix memory leaks. * posix/glob64 (globfree64): Move to separate file. * sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define. (globfree64): Remove hidden alias. * sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add oldglob. * sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to separate file. * sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove define. Move compat code to separate file. * sysdeps/wordsize-64/glob.c (globfree): Move definitions to separate file. (cherry picked from commit c66c908230169c1bab1f83b071eb585baa214b9f) --- ChangeLog | 60 ++ posix/Makefile | 2 +- posix/flexmember.h | 45 ++ posix/glob.c | 774 ++++++++++----------- posix/glob64.c | 6 - posix/glob_internal.h | 57 ++ posix/glob_pattern_p.c | 33 + posix/globfree.c | 41 ++ posix/globfree64.c | 31 + sysdeps/gnu/glob64.c | 3 - sysdeps/gnu/globfree64.c | 10 + sysdeps/unix/sysv/linux/Makefile | 2 +- sysdeps/unix/sysv/linux/alpha/glob.c | 4 - sysdeps/unix/sysv/linux/alpha/globfree.c | 37 + sysdeps/unix/sysv/linux/i386/glob64.c | 39 +- .../unix/sysv/linux/mips/mips64/n64/globfree64.c | 1 + sysdeps/unix/sysv/linux/oldglob.c | 42 ++ sysdeps/unix/sysv/linux/wordsize-64/globfree64.c | 2 + sysdeps/unix/sysv/linux/x86_64/x32/globfree.c | 1 + sysdeps/wordsize-64/glob.c | 2 - sysdeps/wordsize-64/globfree.c | 5 + sysdeps/wordsize-64/globfree64.c | 1 + 22 files changed, 739 insertions(+), 459 deletions(-) create mode 100644 posix/flexmember.h create mode 100644 posix/glob_internal.h create mode 100644 posix/glob_pattern_p.c create mode 100644 posix/globfree.c create mode 100644 posix/globfree64.c create mode 100644 sysdeps/gnu/globfree64.c create mode 100644 sysdeps/unix/sysv/linux/alpha/globfree.c create mode 100644 sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c create mode 100644 sysdeps/unix/sysv/linux/oldglob.c create mode 100644 sysdeps/unix/sysv/linux/wordsize-64/globfree64.c create mode 100644 sysdeps/unix/sysv/linux/x86_64/x32/globfree.c create mode 100644 sysdeps/wordsize-64/globfree.c create mode 100644 sysdeps/wordsize-64/globfree64.c diff --git a/ChangeLog b/ChangeLog index e7f1e0feb7..7d47dd8d7d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,63 @@ +2017-09-08 Adhemerval Zanella + + [BZ #1062] + * posix/Makefile (routines): Add globfree, globfree64, and + glob_pattern_p. + * posix/flexmember.h: New file. + * posix/glob_internal.h: Likewise. + * posix/glob_pattern_p.c: Likewise. + * posix/globfree.c: Likewise. + * posix/globfree64.c: Likewise. + * sysdeps/gnu/globfree64.c: Likewise. + * sysdeps/unix/sysv/linux/alpha/globfree.c: Likewise. + * sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c: Likewise. + * sysdeps/unix/sysv/linux/oldglob.c: Likewise. + * sysdeps/unix/sysv/linux/wordsize-64/globfree64.c: Likewise. + * sysdeps/unix/sysv/linux/x86_64/x32/globfree.c: Likewise. + * sysdeps/wordsize-64/globfree.c: Likewise. + * sysdeps/wordsize-64/globfree64.c: Likewise. + * posix/glob.c (HAVE_CONFIG_H): Use !_LIBC instead. + [NDEBUG): Remove comments. + (GLOB_ONLY_P, _AMIGA, VMS): Remove define. + (dirent_type): New type. Use uint_fast8_t not + uint8_t, as C99 does not require uint8_t. + (DT_UNKNOWN, DT_DIR, DT_LNK): New macros. + (struct readdir_result): Use dirent_type. Do not define skip_entry + unless it is needed; this saves a byte on platforms lacking d_ino. + (readdir_result_type, readdir_result_skip_entry): + New functions, replacing ... + (readdir_result_might_be_symlink, readdir_result_might_be_dir): + these functions, which were removed. This makes the callers + easier to read. All callers changed. + (D_INO_TO_RESULT): Now empty if there is no d_ino. + (size_add_wrapv, glob_use_alloca): New static functions. + (glob, glob_in_dir): Check for size_t overflow in several places, + and fix some size_t checks that were not quite right. + Remove old code using SHELL since Bash no longer + uses this. + (glob, prefix_array): Separate MS code better. + (glob_in_dir): Remove old Amiga and VMS code. + (globfree, __glob_pattern_type, __glob_pattern_p): Move to + separate files. + (glob_in_dir): Do not rely on undefined behavior in accessing + struct members beyond their bounds. Use a flexible array member + instead + (link_stat): Rename from link_exists2_p and return -1/0 instead of + 0/1. Caller changed. + (glob): Fix memory leaks. + * posix/glob64 (globfree64): Move to separate file. + * sysdeps/gnu/glob64.c (NO_GLOB_PATTERN_P): Remove define. + (globfree64): Remove hidden alias. + * sysdeps/unix/sysv/linux/Makefile (sysdeps_routines): Add + oldglob. + * sysdeps/unix/sysv/linux/alpha/glob.c (__new_globfree): Move to + separate file. + * sysdeps/unix/sysv/linux/i386/glob64.c (NO_GLOB_PATTERN_P): Remove + define. + Move compat code to separate file. + * sysdeps/wordsize-64/glob.c (globfree): Move definitions to + separate file. + 2017-08-20 H.J. Lu [BZ #18822] diff --git a/posix/Makefile b/posix/Makefile index 5b0e298f75..2894af0cb9 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -43,7 +43,7 @@ routines := \ getpgid setpgid getpgrp bsd-getpgrp setpgrp getsid setsid \ getresuid getresgid setresuid setresgid \ pathconf sysconf fpathconf \ - glob glob64 fnmatch regex \ + glob glob64 globfree globfree64 glob_pattern_p fnmatch regex \ confstr \ getopt getopt1 getopt_init \ sched_setp sched_getp sched_sets sched_gets sched_yield sched_primax \ diff --git a/posix/flexmember.h b/posix/flexmember.h new file mode 100644 index 0000000000..107c1f09e9 --- /dev/null +++ b/posix/flexmember.h @@ -0,0 +1,45 @@ +/* Sizes of structs with flexible array members. + + Copyright 2016-2017 Free Software Foundation, Inc. + + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . + + Written by Paul Eggert. */ + +#include + +/* Nonzero multiple of alignment of TYPE, suitable for FLEXSIZEOF below. + On older platforms without _Alignof, use a pessimistic bound that is + safe in practice even if FLEXIBLE_ARRAY_MEMBER is 1. + On newer platforms, use _Alignof to get a tighter bound. */ + +#if !defined __STDC_VERSION__ || __STDC_VERSION__ < 201112 +# define FLEXALIGNOF(type) (sizeof (type) & ~ (sizeof (type) - 1)) +#else +# define FLEXALIGNOF(type) _Alignof (type) +#endif + +/* Upper bound on the size of a struct of type TYPE with a flexible + array member named MEMBER that is followed by N bytes of other data. + This is not simply sizeof (TYPE) + N, since it may require + alignment on unusually picky C11 platforms, and + FLEXIBLE_ARRAY_MEMBER may be 1 on pre-C11 platforms. + Yield a value less than N if and only if arithmetic overflow occurs. */ + +#define FLEXSIZEOF(type, member, n) \ + ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \ + & ~ (FLEXALIGNOF (type) - 1)) diff --git a/posix/glob.c b/posix/glob.c index ea4b0b61eb..ea6a240209 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -15,7 +15,7 @@ License along with the GNU C Library; if not, see . */ -#ifdef HAVE_CONFIG_H +#ifndef _LIBC # include #endif @@ -27,29 +27,15 @@ #include #include #include - -/* Outcomment the following line for production quality code. */ -/* #define NDEBUG 1 */ #include +#include -#include /* Needed on stupid SunOS for assert. */ - -#if !defined _LIBC || !defined GLOB_ONLY_P -#if defined HAVE_UNISTD_H || defined _LIBC -# include -# ifndef POSIX -# ifdef _POSIX_VERSION -# define POSIX -# endif -# endif +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +# define WINDOWS32 #endif -#include - -#if defined HAVE_STDINT_H || defined _LIBC -# include -#elif !defined UINTPTR_MAX -# define UINTPTR_MAX (~((size_t) 0)) +#ifndef WINDOWS32 +# include #endif #include @@ -57,24 +43,7 @@ # define __set_errno(val) errno = (val) #endif -#if defined HAVE_DIRENT_H || defined __GNU_LIBRARY__ -# include -#else -# define dirent direct -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include -# endif -# ifdef HAVE_VMSDIR_H -# include "vmsdir.h" -# endif /* HAVE_VMSDIR_H */ -#endif - +#include #include #include #include @@ -87,27 +56,29 @@ # define opendir(name) __opendir (name) # define readdir(str) __readdir64 (str) # define getpwnam_r(name, bufp, buf, len, res) \ - __getpwnam_r (name, bufp, buf, len, res) + __getpwnam_r (name, bufp, buf, len, res) # ifndef __stat64 # define __stat64(fname, buf) __xstat64 (_STAT_VER, fname, buf) # endif # define struct_stat64 struct stat64 +# define FLEXIBLE_ARRAY_MEMBER #else /* !_LIBC */ -# include "getlogin_r.h" -# include "mempcpy.h" -# include "stat-macros.h" -# include "strdup.h" -# define __stat64(fname, buf) stat (fname, buf) -# define struct_stat64 struct stat -# define __stat(fname, buf) stat (fname, buf) -# define __alloca alloca -# define __readdir readdir -# define __readdir64 readdir64 -# define __glob_pattern_p glob_pattern_p +# define __getlogin_r(buf, len) getlogin_r (buf, len) +# define __stat64(fname, buf) stat (fname, buf) +# define __fxstatat64(_, d, f, st, flag) fstatat (d, f, st, flag) +# define struct_stat64 struct stat +# ifndef __MVS__ +# define __alloca alloca +# endif +# define __readdir readdir +# define COMPILE_GLOB64 #endif /* _LIBC */ #include +#include +#include + #ifdef _SC_GETPW_R_SIZE_MAX # define GETPW_R_SIZE_MAX() sysconf (_SC_GETPW_R_SIZE_MAX) #else @@ -121,61 +92,59 @@ static const char *next_brace_sub (const char *begin, int flags) __THROWNL; +typedef uint_fast8_t dirent_type; + +#if !defined _LIBC && !defined HAVE_STRUCT_DIRENT_D_TYPE +/* Any distinct values will do here. + Undef any existing macros out of the way. */ +# undef DT_UNKNOWN +# undef DT_DIR +# undef DT_LNK +# define DT_UNKNOWN 0 +# define DT_DIR 1 +# define DT_LNK 2 +#endif + /* A representation of a directory entry which does not depend on the layout of struct dirent, or the size of ino_t. */ struct readdir_result { const char *name; -# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE - uint8_t type; -# endif +#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE + dirent_type type; +#endif +#if defined _LIBC || defined D_INO_IN_DIRENT bool skip_entry; +#endif }; -# if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE -/* Initializer based on the d_type member of struct dirent. */ -# define D_TYPE_TO_RESULT(source) (source)->d_type, - -/* True if the directory entry D might be a symbolic link. */ -static bool -readdir_result_might_be_symlink (struct readdir_result d) -{ - return d.type == DT_UNKNOWN || d.type == DT_LNK; -} - -/* True if the directory entry D might be a directory. */ -static bool -readdir_result_might_be_dir (struct readdir_result d) -{ - return d.type == DT_DIR || readdir_result_might_be_symlink (d); -} -# else /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ -# define D_TYPE_TO_RESULT(source) - -/* If we do not have type information, symbolic links and directories - are always a possibility. */ - -static bool -readdir_result_might_be_symlink (struct readdir_result d) +/* Initialize and return type member of struct readdir_result. */ +static dirent_type +readdir_result_type (struct readdir_result d) { - return true; +#if defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE +# define D_TYPE_TO_RESULT(source) (source)->d_type, + return d.type; +#else +# define D_TYPE_TO_RESULT(source) + return DT_UNKNOWN; +#endif } +/* Initialize and return skip_entry member of struct readdir_result. */ static bool -readdir_result_might_be_dir (struct readdir_result d) +readdir_result_skip_entry (struct readdir_result d) { - return true; -} - -# endif /* defined _DIRENT_HAVE_D_TYPE || defined HAVE_STRUCT_DIRENT_D_TYPE */ - -# if (defined POSIX || defined WINDOWS32) && !defined __GNU_LIBRARY__ /* Initializer for skip_entry. POSIX does not require that the d_ino field be present, and some systems do not provide it. */ -# define D_INO_TO_RESULT(source) false, -# else -# define D_INO_TO_RESULT(source) (source)->d_ino == 0, -# endif +#if defined _LIBC || defined D_INO_IN_DIRENT +# define D_INO_TO_RESULT(source) (source)->d_ino == 0, + return d.skip_entry; +#else +# define D_INO_TO_RESULT(source) + return false; +#endif +} /* Construct an initializer for a struct readdir_result object from a struct dirent *. No copy of the name is made. */ @@ -186,8 +155,6 @@ readdir_result_might_be_dir (struct readdir_result d) D_INO_TO_RESULT (source) \ } -#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ - /* Call gl_readdir on STREAM. This macro can be overridden to reduce type safety if an old interface version needs to be supported. */ #ifndef GL_READDIR @@ -225,18 +192,55 @@ convert_dirent64 (const struct dirent64 *source) } #endif +#ifndef _LIBC +/* The results of opendir() in this file are not used with dirfd and fchdir, + and we do not leak fds to any single-threaded code that could use stdio, + therefore save some unnecessary recursion in fchdir.c and opendir_safer.c. + FIXME - if the kernel ever adds support for multi-thread safety for + avoiding standard fds, then we should use opendir_safer. */ +# ifdef GNULIB_defined_opendir +# undef opendir +# endif +# ifdef GNULIB_defined_closedir +# undef closedir +# endif -#ifndef attribute_hidden -# define attribute_hidden +/* Just use malloc. */ +# define __libc_use_alloca(n) false +# define alloca_account(len, avar) ((void) (len), (void) (avar), (void *) 0) +# define extend_alloca_account(buf, len, newlen, avar) \ + ((void) (buf), (void) (len), (void) (newlen), (void) (avar), (void *) 0) #endif +/* Set *R = A + B. Return true if the answer is mathematically + incorrect due to overflow; in this case, *R is the low order + bits of the correct answer. */ + +static bool +size_add_wrapv (size_t a, size_t b, size_t *r) +{ +#if 5 <= __GNUC__ && !defined __ICC + return __builtin_add_overflow (a, b, r); +#else + *r = a + b; + return *r < a; +#endif +} + +static bool +glob_use_alloca (size_t alloca_used, size_t len) +{ + size_t size; + return (!size_add_wrapv (alloca_used, len, &size) + && __libc_use_alloca (size)); +} + static int glob_in_dir (const char *pattern, const char *directory, int flags, int (*errfunc) (const char *, int), glob_t *pglob, size_t alloca_used); extern int __glob_pattern_type (const char *pattern, int quote) attribute_hidden; -#if !defined _LIBC || !defined GLOB_ONLY_P static int prefix_array (const char *prefix, char **array, size_t n) __THROWNL; static int collated_compare (const void *, const void *) __THROWNL; @@ -265,16 +269,15 @@ next_brace_sub (const char *cp, int flags) return *cp != '\0' ? cp : NULL; } -#endif /* !defined _LIBC || !defined GLOB_ONLY_P */ /* Do glob searching for PATTERN, placing results in PGLOB. The bits defined above may be set in FLAGS. If a directory cannot be opened or read and ERRFUNC is not nil, it is called with the pathname that caused the error, and the - `errno' value from the failing call; if it returns non-zero - `glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. + 'errno' value from the failing call; if it returns non-zero + 'glob' returns GLOB_ABORTED; if it returns zero, the error is ignored. If memory cannot be allocated for PGLOB, GLOB_NOSPACE is returned. - Otherwise, `glob' returns zero. */ + Otherwise, 'glob' returns zero. */ int #ifdef GLOB_ATTRIBUTE GLOB_ATTRIBUTE @@ -292,9 +295,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), int malloc_dirname = 0; glob_t dirs; int retval = 0; -#ifdef _LIBC size_t alloca_used = 0; -#endif if (pattern == NULL || pglob == NULL || (flags & ~__GLOB_FLAGS) != 0) { @@ -308,7 +309,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), flags |= GLOB_ONLYDIR; if (!(flags & GLOB_DOOFFS)) - /* Have to do this so `globfree' knows where to start freeing. It + /* Have to do this so 'globfree' knows where to start freeing. It also makes all the code that uses gl_offs simpler. */ pglob->gl_offs = 0; @@ -350,14 +351,12 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t rest_len; char *onealt; size_t pattern_len = strlen (pattern) - 1; -#ifdef _LIBC - int alloca_onealt = __libc_use_alloca (alloca_used + pattern_len); + int alloca_onealt = glob_use_alloca (alloca_used, pattern_len); if (alloca_onealt) onealt = alloca_account (pattern_len, alloca_used); else -#endif { - onealt = (char *) malloc (pattern_len); + onealt = malloc (pattern_len); if (onealt == NULL) { if (!(flags & GLOB_APPEND)) @@ -377,11 +376,9 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), next = next_brace_sub (begin + 1, flags); if (next == NULL) { - /* It is an illegal expression. */ + /* It is an invalid expression. */ illegal_brace: -#ifdef _LIBC if (__glibc_unlikely (!alloca_onealt)) -#endif free (onealt); return glob (pattern, flags & ~GLOB_BRACE, errfunc, pglob); } @@ -429,9 +426,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* If we got an error, return it. */ if (result && result != GLOB_NOMATCH) { -#ifdef _LIBC if (__glibc_unlikely (!alloca_onealt)) -#endif free (onealt); if (!(flags & GLOB_APPEND)) { @@ -450,9 +445,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), assert (next != NULL); } -#ifdef _LIBC if (__glibc_unlikely (!alloca_onealt)) -#endif free (onealt); if (pglob->gl_pathc != firstc) @@ -489,14 +482,16 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Find the filename. */ filename = strrchr (pattern, '/'); + #if defined __MSDOS__ || defined WINDOWS32 - /* The case of "d:pattern". Since `:' is not allowed in + /* The case of "d:pattern". Since ':' is not allowed in file names, we can safely assume that wherever it happens in pattern, it signals the filename part. This is so we could some day support patterns like "[a-z]:foo". */ if (filename == NULL) filename = strchr (pattern, ':'); #endif /* __MSDOS__ || WINDOWS32 */ + dirname_modified = 0; if (filename == NULL) { @@ -521,11 +516,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } filename = pattern; -#ifdef _AMIGA - dirname = (char *) ""; -#else dirname = (char *) "."; -#endif dirlen = 0; } } @@ -549,22 +540,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), char *drive_spec; ++dirlen; - drive_spec = (char *) __alloca (dirlen + 1); + drive_spec = __alloca (dirlen + 1); *((char *) mempcpy (drive_spec, pattern, dirlen)) = '\0'; /* For now, disallow wildcards in the drive spec, to prevent infinite recursion in glob. */ if (__glob_pattern_p (drive_spec, !(flags & GLOB_NOESCAPE))) return GLOB_NOMATCH; - /* If this is "d:pattern", we need to copy `:' to DIRNAME + /* If this is "d:pattern", we need to copy ':' to DIRNAME as well. If it's "d:/pattern", don't remove the slash from "d:/", since "d:" and "d:/" are not the same.*/ } #endif -#ifdef _LIBC - if (__libc_use_alloca (alloca_used + dirlen + 1)) + + if (glob_use_alloca (alloca_used, dirlen + 1)) newp = alloca_account (dirlen + 1, alloca_used); else -#endif { newp = malloc (dirlen + 1); if (newp == NULL) @@ -575,14 +565,17 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirname = newp; ++filename; - if (filename[0] == '\0' #if defined __MSDOS__ || defined WINDOWS32 - && dirname[dirlen - 1] != ':' - && (dirlen < 3 || dirname[dirlen - 2] != ':' - || dirname[dirlen - 1] != '/') + bool drive_root = (dirlen > 1 + && (dirname[dirlen - 1] == ':' + || (dirlen > 2 && dirname[dirlen - 2] == ':' + && dirname[dirlen - 1] == '/'))); +#else + bool drive_root = false; #endif - && dirlen > 1) - /* "pattern/". Expand "pattern", appending slashes. */ + + if (filename[0] == '\0' && dirlen > 1 && !drive_root) + /* "pattern/". Expand "pattern", appending slashes. */ { int orig_flags = flags; if (!(flags & GLOB_NOESCAPE) && dirname[dirlen - 1] == '\\') @@ -615,7 +608,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } } -#ifndef VMS if ((flags & (GLOB_TILDE|GLOB_TILDE_CHECK)) && dirname[0] == '~') { if (dirname[1] == '\0' || dirname[1] == '/' @@ -625,100 +617,127 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Look up home directory. */ char *home_dir = getenv ("HOME"); int malloc_home_dir = 0; -# ifdef _AMIGA - if (home_dir == NULL || home_dir[0] == '\0') - home_dir = "SYS:"; -# else -# ifdef WINDOWS32 - if (home_dir == NULL || home_dir[0] == '\0') - home_dir = "c:/users/default"; /* poor default */ -# else if (home_dir == NULL || home_dir[0] == '\0') { +#ifdef WINDOWS32 + /* Windows NT defines HOMEDRIVE and HOMEPATH. But give + preference to HOME, because the user can change HOME. */ + const char *home_drive = getenv ("HOMEDRIVE"); + const char *home_path = getenv ("HOMEPATH"); + + if (home_drive != NULL && home_path != NULL) + { + size_t home_drive_len = strlen (home_drive); + size_t home_path_len = strlen (home_path); + char *mem = alloca (home_drive_len + home_path_len + 1); + + memcpy (mem, home_drive, home_drive_len); + memcpy (mem + home_drive_len, home_path, home_path_len + 1); + home_dir = mem; + } + else + home_dir = "c:/users/default"; /* poor default */ +#else int success; char *name; + int malloc_name = 0; size_t buflen = GET_LOGIN_NAME_MAX () + 1; if (buflen == 0) - /* `sysconf' does not support _SC_LOGIN_NAME_MAX. Try + /* 'sysconf' does not support _SC_LOGIN_NAME_MAX. Try a moderate value. */ buflen = 20; - name = alloca_account (buflen, alloca_used); + if (glob_use_alloca (alloca_used, buflen)) + name = alloca_account (buflen, alloca_used); + else + { + name = malloc (buflen); + if (name == NULL) + { + retval = GLOB_NOSPACE; + goto out; + } + malloc_name = 1; + } success = __getlogin_r (name, buflen) == 0; if (success) { struct passwd *p; -# if defined HAVE_GETPWNAM_R || defined _LIBC - long int pwbuflen = GETPW_R_SIZE_MAX (); + char *malloc_pwtmpbuf = NULL; char *pwtmpbuf; +# if defined HAVE_GETPWNAM_R || defined _LIBC + long int pwbuflenmax = GETPW_R_SIZE_MAX (); + size_t pwbuflen = pwbuflenmax; struct passwd pwbuf; - int malloc_pwtmpbuf = 0; int save = errno; -# ifndef _LIBC - if (pwbuflen == -1) - /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. +# ifndef _LIBC + if (! (0 < pwbuflenmax && pwbuflenmax <= SIZE_MAX)) + /* 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a moderate value. */ pwbuflen = 1024; -# endif - if (__libc_use_alloca (alloca_used + pwbuflen)) +# endif + if (glob_use_alloca (alloca_used, pwbuflen)) pwtmpbuf = alloca_account (pwbuflen, alloca_used); else { pwtmpbuf = malloc (pwbuflen); if (pwtmpbuf == NULL) { + if (__glibc_unlikely (malloc_name)) + free (name); retval = GLOB_NOSPACE; goto out; } - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf; } while (getpwnam_r (name, &pwbuf, pwtmpbuf, pwbuflen, &p) != 0) { + size_t newlen; + bool v; if (errno != ERANGE) { p = NULL; break; } - - if (!malloc_pwtmpbuf - && __libc_use_alloca (alloca_used - + 2 * pwbuflen)) + v = size_add_wrapv (pwbuflen, pwbuflen, &newlen); + if (!v && malloc_pwtmpbuf == NULL + && glob_use_alloca (alloca_used, newlen)) pwtmpbuf = extend_alloca_account (pwtmpbuf, pwbuflen, - 2 * pwbuflen, - alloca_used); + newlen, alloca_used); else { - char *newp = realloc (malloc_pwtmpbuf - ? pwtmpbuf : NULL, - 2 * pwbuflen); + char *newp = (v ? NULL + : realloc (malloc_pwtmpbuf, newlen)); if (newp == NULL) { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); + if (__glibc_unlikely (malloc_name)) + free (name); retval = GLOB_NOSPACE; goto out; } - pwtmpbuf = newp; - pwbuflen = 2 * pwbuflen; - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf = newp; } + pwbuflen = newlen; __set_errno (save); } -# else +# else p = getpwnam (name); -# endif +# endif + if (__glibc_unlikely (malloc_name)) + free (name); if (p != NULL) { - if (!malloc_pwtmpbuf) + if (malloc_pwtmpbuf == NULL) home_dir = p->pw_dir; else { size_t home_dir_len = strlen (p->pw_dir) + 1; - if (__libc_use_alloca (alloca_used + home_dir_len)) + if (glob_use_alloca (alloca_used, home_dir_len)) home_dir = alloca_account (home_dir_len, alloca_used); else @@ -733,26 +752,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), malloc_home_dir = 1; } memcpy (home_dir, p->pw_dir, home_dir_len); - - free (pwtmpbuf); } } + free (malloc_pwtmpbuf); } + else + { + if (__glibc_unlikely (malloc_name)) + free (name); + } +#endif /* WINDOWS32 */ } if (home_dir == NULL || home_dir[0] == '\0') { + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); if (flags & GLOB_TILDE_CHECK) { - if (__glibc_unlikely (malloc_home_dir)) - free (home_dir); retval = GLOB_NOMATCH; goto out; } else - home_dir = (char *) "~"; /* No luck. */ + { + home_dir = (char *) "~"; /* No luck. */ + malloc_home_dir = 0; + } } -# endif /* WINDOWS32 */ -# endif /* Now construct the full directory. */ if (dirname[1] == '\0') { @@ -767,8 +792,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { char *newp; size_t home_len = strlen (home_dir); - int use_alloca = __libc_use_alloca (alloca_used - + home_len + dirlen); + int use_alloca = glob_use_alloca (alloca_used, home_len + dirlen); if (use_alloca) newp = alloca_account (home_len + dirlen, alloca_used); else @@ -792,12 +816,15 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirname = newp; dirlen += home_len - 1; malloc_dirname = !use_alloca; + + if (__glibc_unlikely (malloc_home_dir)) + free (home_dir); } dirname_modified = 1; } -# if !defined _AMIGA && !defined WINDOWS32 else { +#ifndef WINDOWS32 char *end_name = strchr (dirname, '/'); char *user_name; int malloc_user_name = 0; @@ -819,7 +846,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), else { char *newp; - if (__libc_use_alloca (alloca_used + (end_name - dirname))) + if (glob_use_alloca (alloca_used, end_name - dirname)) newp = alloca_account (end_name - dirname, alloca_used); else { @@ -864,20 +891,21 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), /* Look up specific user's home directory. */ { struct passwd *p; + char *malloc_pwtmpbuf = NULL; # if defined HAVE_GETPWNAM_R || defined _LIBC - long int buflen = GETPW_R_SIZE_MAX (); + long int buflenmax = GETPW_R_SIZE_MAX (); + size_t buflen = buflenmax; char *pwtmpbuf; - int malloc_pwtmpbuf = 0; struct passwd pwbuf; int save = errno; # ifndef _LIBC - if (buflen == -1) - /* `sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a + if (! (0 <= buflenmax && buflenmax <= SIZE_MAX)) + /* Perhaps 'sysconf' does not support _SC_GETPW_R_SIZE_MAX. Try a moderate value. */ buflen = 1024; # endif - if (__libc_use_alloca (alloca_used + buflen)) + if (glob_use_alloca (alloca_used, buflen)) pwtmpbuf = alloca_account (buflen, alloca_used); else { @@ -890,32 +918,32 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), retval = GLOB_NOSPACE; goto out; } - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf; } while (getpwnam_r (user_name, &pwbuf, pwtmpbuf, buflen, &p) != 0) { + size_t newlen; + bool v; if (errno != ERANGE) { p = NULL; break; } - if (!malloc_pwtmpbuf - && __libc_use_alloca (alloca_used + 2 * buflen)) + v = size_add_wrapv (buflen, buflen, &newlen); + if (!v && malloc_pwtmpbuf == NULL + && glob_use_alloca (alloca_used, newlen)) pwtmpbuf = extend_alloca_account (pwtmpbuf, buflen, - 2 * buflen, alloca_used); + newlen, alloca_used); else { - char *newp = realloc (malloc_pwtmpbuf ? pwtmpbuf : NULL, - 2 * buflen); + char *newp = v ? NULL : realloc (malloc_pwtmpbuf, newlen); if (newp == NULL) { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); goto nomem_getpw; } - pwtmpbuf = newp; - malloc_pwtmpbuf = 1; + malloc_pwtmpbuf = pwtmpbuf = newp; } __set_errno (save); } @@ -936,7 +964,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), free (dirname); malloc_dirname = 0; - if (__libc_use_alloca (alloca_used + home_len + rest_len + 1)) + if (glob_use_alloca (alloca_used, home_len + rest_len + 1)) dirname = alloca_account (home_len + rest_len + 1, alloca_used); else @@ -944,8 +972,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirname = malloc (home_len + rest_len + 1); if (dirname == NULL) { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); retval = GLOB_NOSPACE; goto out; } @@ -957,24 +984,24 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), dirlen = home_len + rest_len; dirname_modified = 1; - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); } else { - if (__glibc_unlikely (malloc_pwtmpbuf)) - free (pwtmpbuf); + free (malloc_pwtmpbuf); if (flags & GLOB_TILDE_CHECK) - /* We have to regard it as an error if we cannot find the - home directory. */ - return GLOB_NOMATCH; + { + /* We have to regard it as an error if we cannot find the + home directory. */ + retval = GLOB_NOMATCH; + goto out; + } } } +#endif /* !WINDOWS32 */ } -# endif /* Not Amiga && not WINDOWS32. */ } -#endif /* Not VMS. */ /* Now test whether we looked for "~" or "~NAME". In this case we can give the answer now. */ @@ -993,19 +1020,18 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t newcount = pglob->gl_pathc + pglob->gl_offs; char **new_gl_pathv; - if (newcount > UINTPTR_MAX - (1 + 1) - || newcount + 1 + 1 > ~((size_t) 0) / sizeof (char *)) + if (newcount > SIZE_MAX / sizeof (char *) - 2) { nospace: free (pglob->gl_pathv); pglob->gl_pathv = NULL; pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } - new_gl_pathv - = (char **) realloc (pglob->gl_pathv, - (newcount + 1 + 1) * sizeof (char *)); + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); if (new_gl_pathv == NULL) goto nospace; pglob->gl_pathv = new_gl_pathv; @@ -1019,12 +1045,19 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), p = mempcpy (pglob->gl_pathv[newcount], dirname, dirlen); p[0] = '/'; p[1] = '\0'; + if (__glibc_unlikely (malloc_dirname)) + free (dirname); } else { - pglob->gl_pathv[newcount] = strdup (dirname); - if (pglob->gl_pathv[newcount] == NULL) - goto nospace; + if (__glibc_unlikely (malloc_dirname)) + pglob->gl_pathv[newcount] = dirname; + else + { + pglob->gl_pathv[newcount] = strdup (dirname); + if (pglob->gl_pathv[newcount] == NULL) + goto nospace; + } } pglob->gl_pathv[++newcount] = NULL; ++pglob->gl_pathc; @@ -1034,7 +1067,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), } /* Not found. */ - return GLOB_NOMATCH; + retval = GLOB_NOMATCH; + goto out; } meta = __glob_pattern_type (dirname, !(flags & GLOB_NOESCAPE)); @@ -1080,7 +1114,10 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), if (status != 0) { if ((flags & GLOB_NOCHECK) == 0 || status != GLOB_NOMATCH) - return status; + { + retval = status; + goto out; + } goto no_matches; } @@ -1091,19 +1128,6 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { size_t old_pathc; -#ifdef SHELL - { - /* Make globbing interruptible in the bash shell. */ - extern int interrupt_state; - - if (interrupt_state) - { - globfree (&dirs); - return GLOB_ABORTED; - } - } -#endif /* SHELL. */ - old_pathc = pglob->gl_pathc; status = glob_in_dir (filename, dirs.gl_pathv[i], ((flags | GLOB_APPEND) @@ -1118,7 +1142,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - return status; + retval = status; + goto out; } /* Stick the directory on the front of each name. */ @@ -1129,13 +1154,14 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } } flags |= GLOB_MAGCHAR; - /* We have ignored the GLOB_NOCHECK flag in the `glob_in_dir' calls. + /* We have ignored the GLOB_NOCHECK flag in the 'glob_in_dir' calls. But if we have not found any matching entry and the GLOB_NOCHECK flag was set we must return the input pattern itself. */ if (pglob->gl_pathc + pglob->gl_offs == oldcount) @@ -1147,28 +1173,28 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), size_t newcount = pglob->gl_pathc + pglob->gl_offs; char **new_gl_pathv; - if (newcount > UINTPTR_MAX - 2 - || newcount + 2 > ~((size_t) 0) / sizeof (char *)) + if (newcount > SIZE_MAX / sizeof (char *) - 2) { nospace2: globfree (&dirs); - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } - new_gl_pathv = (char **) realloc (pglob->gl_pathv, - (newcount + 2) - * sizeof (char *)); + new_gl_pathv = realloc (pglob->gl_pathv, + (newcount + 2) * sizeof (char *)); if (new_gl_pathv == NULL) goto nospace2; pglob->gl_pathv = new_gl_pathv; - pglob->gl_pathv[newcount] = __strdup (pattern); + pglob->gl_pathv[newcount] = strdup (pattern); if (pglob->gl_pathv[newcount] == NULL) { globfree (&dirs); globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } ++pglob->gl_pathc; @@ -1180,7 +1206,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), else { globfree (&dirs); - return GLOB_NOMATCH; + retval = GLOB_NOMATCH; + goto out; } } @@ -1226,7 +1253,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), flags = orig_flags; goto no_matches; } - return status; + retval = status; + goto out; } if (dirlen > 0) @@ -1238,7 +1266,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } } } @@ -1263,7 +1292,8 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), { globfree (pglob); pglob->gl_pathc = 0; - return GLOB_NOSPACE; + retval = GLOB_NOSPACE; + goto out; } strcpy (&new[len - 2], "/"); pglob->gl_pathv[i] = new; @@ -1289,32 +1319,12 @@ libc_hidden_def (glob) #endif -#if !defined _LIBC || !defined GLOB_ONLY_P - -/* Free storage allocated in PGLOB by a previous `glob' call. */ -void -globfree (glob_t *pglob) -{ - if (pglob->gl_pathv != NULL) - { - size_t i; - for (i = 0; i < pglob->gl_pathc; ++i) - free (pglob->gl_pathv[pglob->gl_offs + i]); - free (pglob->gl_pathv); - pglob->gl_pathv = NULL; - } -} -#if defined _LIBC && !defined globfree -libc_hidden_def (globfree) -#endif - - /* Do a collated comparison of A and B. */ static int collated_compare (const void *a, const void *b) { - const char *const s1 = *(const char *const * const) a; - const char *const s2 = *(const char *const * const) b; + char *const *ps1 = a; char *s1 = *ps1; + char *const *ps2 = b; char *s2 = *ps2; if (s1 == s2) return 0; @@ -1335,28 +1345,24 @@ prefix_array (const char *dirname, char **array, size_t n) { size_t i; size_t dirlen = strlen (dirname); -#if defined __MSDOS__ || defined WINDOWS32 - int sep_char = '/'; -# define DIRSEP_CHAR sep_char -#else -# define DIRSEP_CHAR '/' -#endif + char dirsep_char = '/'; if (dirlen == 1 && dirname[0] == '/') /* DIRNAME is just "/", so normal prepending would get us "//foo". We want "/foo" instead, so don't prepend any chars from DIRNAME. */ dirlen = 0; + #if defined __MSDOS__ || defined WINDOWS32 - else if (dirlen > 1) + if (dirlen > 1) { if (dirname[dirlen - 1] == '/' && dirname[dirlen - 2] == ':') /* DIRNAME is "d:/". Don't prepend the slash from DIRNAME. */ --dirlen; else if (dirname[dirlen - 1] == ':') { - /* DIRNAME is "d:". Use `:' instead of `/'. */ + /* DIRNAME is "d:". Use ':' instead of '/'. */ --dirlen; - sep_char = ':'; + dirsep_char = ':'; } } #endif @@ -1364,7 +1370,7 @@ prefix_array (const char *dirname, char **array, size_t n) for (i = 0; i < n; ++i) { size_t eltlen = strlen (array[i]) + 1; - char *new = (char *) malloc (dirlen + 1 + eltlen); + char *new = malloc (dirlen + 1 + eltlen); if (new == NULL) { while (i > 0) @@ -1374,7 +1380,7 @@ prefix_array (const char *dirname, char **array, size_t n) { char *endp = mempcpy (new, dirname, dirlen); - *endp++ = DIRSEP_CHAR; + *endp++ = dirsep_char; mempcpy (endp, array[i], eltlen); } free (array[i]); @@ -1384,103 +1390,57 @@ prefix_array (const char *dirname, char **array, size_t n) return 0; } - -/* We must not compile this function twice. */ -#if !defined _LIBC || !defined NO_GLOB_PATTERN_P -int -__glob_pattern_type (const char *pattern, int quote) -{ - const char *p; - int ret = 0; - - for (p = pattern; *p != '\0'; ++p) - switch (*p) - { - case '?': - case '*': - return 1; - - case '\\': - if (quote) - { - if (p[1] != '\0') - ++p; - ret |= 2; - } - break; - - case '[': - ret |= 4; - break; - - case ']': - if (ret & 4) - return 1; - break; - } - - return ret; -} - -/* Return nonzero if PATTERN contains any metacharacters. - Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ -int -__glob_pattern_p (const char *pattern, int quote) -{ - return __glob_pattern_type (pattern, quote) == 1; -} -# ifdef _LIBC -weak_alias (__glob_pattern_p, glob_pattern_p) -# endif -#endif - -#endif /* !GLOB_ONLY_P */ - - /* We put this in a separate function mainly to allow the memory allocated with alloca to be recycled. */ -#if !defined _LIBC || !defined GLOB_ONLY_P static int __attribute_noinline__ -link_exists2_p (const char *dir, size_t dirlen, const char *fname, - glob_t *pglob -# ifndef _LIBC - , int flags +link_stat (const char *dir, size_t dirlen, const char *fname, + glob_t *pglob +# if !defined _LIBC && !HAVE_FSTATAT + , int flags # endif - ) + ) { size_t fnamelen = strlen (fname); - char *fullname = (char *) __alloca (dirlen + 1 + fnamelen + 1); + char *fullname = __alloca (dirlen + 1 + fnamelen + 1); struct stat st; -# ifndef _LIBC - struct_stat64 st64; -# endif mempcpy (mempcpy (mempcpy (fullname, dir, dirlen), "/", 1), fname, fnamelen + 1); -# ifdef _LIBC - return (*pglob->gl_stat) (fullname, &st) == 0; -# else - return ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) - ? (*pglob->gl_stat) (fullname, &st) - : __stat64 (fullname, &st64)) == 0); +# if !defined _LIBC && !HAVE_FSTATAT + if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1)) + { + struct_stat64 st64; + return __stat64 (fullname, &st64); + } # endif + return (*pglob->gl_stat) (fullname, &st); } -# ifdef _LIBC -# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ - (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) \ - ? link_exists2_p (dirname, dirnamelen, fname, pglob) \ - : ({ struct stat64 st64; \ - __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; })) + +/* Return true if DIR/FNAME exists. */ +static int +link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname, + glob_t *pglob, int flags) +{ + int status; +# if defined _LIBC || HAVE_FSTATAT + if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) + status = link_stat (dir, dirlen, fname, pglob); + else + { + /* dfd cannot be -1 here, because dirfd never returns -1 on + glibc, or on hosts that have fstatat. */ + struct_stat64 st64; + status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0); + } # else -# define link_exists_p(dfd, dirname, dirnamelen, fname, pglob, flags) \ - link_exists2_p (dirname, dirnamelen, fname, pglob, flags) + status = link_stat (dir, dirlen, fname, pglob, flags); # endif -#endif - + return status == 0 || errno == EOVERFLOW; +} -/* Like `glob', but PATTERN is a final pathname component, +/* Like 'glob', but PATTERN is a final pathname component, and matches are searched for in DIRECTORY. The GLOB_NOSORT bit in FLAGS is ignored. No sorting is ever done. The GLOB_APPEND flag is assumed to be set (always appends). */ @@ -1491,25 +1451,25 @@ glob_in_dir (const char *pattern, const char *directory, int flags, { size_t dirlen = strlen (directory); void *stream = NULL; - struct globnames - { - struct globnames *next; - size_t count; - char *name[64]; - }; -#define INITIAL_COUNT sizeof (init_names.name) / sizeof (init_names.name[0]) - struct globnames init_names; - struct globnames *names = &init_names; - struct globnames *names_alloca = &init_names; +# define GLOBNAMES_MEMBERS(nnames) \ + struct globnames *next; size_t count; char *name[nnames]; + struct globnames { GLOBNAMES_MEMBERS (FLEXIBLE_ARRAY_MEMBER) }; + struct { GLOBNAMES_MEMBERS (64) } init_names_buf; + struct globnames *init_names = (struct globnames *) &init_names_buf; + struct globnames *names = init_names; + struct globnames *names_alloca = init_names; size_t nfound = 0; size_t cur = 0; int meta; int save; + int result; - alloca_used += sizeof (init_names); + alloca_used += sizeof init_names_buf; - init_names.next = NULL; - init_names.count = INITIAL_COUNT; + init_names->next = NULL; + init_names->count = ((sizeof init_names_buf + - offsetof (struct globnames, name)) + / sizeof init_names->name[0]); meta = __glob_pattern_type (pattern, !(flags & GLOB_NOESCAPE)); if (meta == 0 && (flags & (GLOB_NOCHECK|GLOB_NOMAGIC))) @@ -1529,14 +1489,16 @@ glob_in_dir (const char *pattern, const char *directory, int flags, struct_stat64 st64; } ust; size_t patlen = strlen (pattern); - int alloca_fullname = __libc_use_alloca (alloca_used - + dirlen + 1 + patlen + 1); + size_t fullsize; + bool alloca_fullname + = (! size_add_wrapv (dirlen + 1, patlen + 1, &fullsize) + && glob_use_alloca (alloca_used, fullsize)); char *fullname; if (alloca_fullname) - fullname = alloca_account (dirlen + 1 + patlen + 1, alloca_used); + fullname = alloca_account (fullsize, alloca_used); else { - fullname = malloc (dirlen + 1 + patlen + 1); + fullname = malloc (fullsize); if (fullname == NULL) return GLOB_NOSPACE; } @@ -1544,9 +1506,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags, mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), "/", 1), pattern, patlen + 1); - if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) ? (*pglob->gl_stat) (fullname, &ust.st) - : __stat64 (fullname, &ust.st64)) == 0) + : __stat64 (fullname, &ust.st64)) + == 0) + || errno == EOVERFLOW) /* We found this file to be existing. Now tell the rest of the function to copy this name into the result. */ flags |= GLOB_NOCHECK; @@ -1568,16 +1532,10 @@ glob_in_dir (const char *pattern, const char *directory, int flags, } else { -#ifdef _LIBC int dfd = (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) ? -1 : dirfd ((DIR *) stream)); -#endif int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) - | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) -#if defined _AMIGA || defined VMS - | FNM_CASEFOLD -#endif - ); + | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0)); flags |= GLOB_MAGCHAR; while (1) @@ -1597,19 +1555,24 @@ glob_in_dir (const char *pattern, const char *directory, int flags, } if (d.name == NULL) break; - if (d.skip_entry) + if (readdir_result_skip_entry (d)) continue; /* If we shall match only directories use the information provided by the dirent call if possible. */ - if ((flags & GLOB_ONLYDIR) && !readdir_result_might_be_dir (d)) - continue; + if (flags & GLOB_ONLYDIR) + switch (readdir_result_type (d)) + { + case DT_DIR: case DT_LNK: case DT_UNKNOWN: break; + default: continue; + } if (fnmatch (pattern, d.name, fnm_flags) == 0) { /* If the file we found is a symlink we have to make sure the target file exists. */ - if (!readdir_result_might_be_symlink (d) + dirent_type type = readdir_result_type (d); + if (! (type == DT_LNK || type == DT_UNKNOWN) || link_exists_p (dfd, directory, dirlen, d.name, pglob, flags)) { @@ -1617,10 +1580,13 @@ glob_in_dir (const char *pattern, const char *directory, int flags, { struct globnames *newnames; size_t count = names->count * 2; - size_t size = (sizeof (struct globnames) - + ((count - INITIAL_COUNT) - * sizeof (char *))); - if (__libc_use_alloca (alloca_used + size)) + size_t nameoff = offsetof (struct globnames, name); + size_t size = FLEXSIZEOF (struct globnames, name, + count * sizeof (char *)); + if ((SIZE_MAX - nameoff) / 2 / sizeof (char *) + < names->count) + goto memory_error; + if (glob_use_alloca (alloca_used, size)) newnames = names_alloca = alloca_account (size, alloca_used); else if ((newnames = malloc (size)) @@ -1636,6 +1602,8 @@ glob_in_dir (const char *pattern, const char *directory, int flags, goto memory_error; ++cur; ++nfound; + if (SIZE_MAX - pglob->gl_offs <= nfound) + goto memory_error; } } } @@ -1646,29 +1614,27 @@ glob_in_dir (const char *pattern, const char *directory, int flags, { size_t len = strlen (pattern); nfound = 1; - names->name[cur] = (char *) malloc (len + 1); + names->name[cur] = malloc (len + 1); if (names->name[cur] == NULL) goto memory_error; *((char *) mempcpy (names->name[cur++], pattern, len)) = '\0'; } - int result = GLOB_NOMATCH; + result = GLOB_NOMATCH; if (nfound != 0) { + char **new_gl_pathv; result = 0; - if (pglob->gl_pathc > UINTPTR_MAX - pglob->gl_offs - || pglob->gl_pathc + pglob->gl_offs > UINTPTR_MAX - nfound - || pglob->gl_pathc + pglob->gl_offs + nfound > UINTPTR_MAX - 1 - || (pglob->gl_pathc + pglob->gl_offs + nfound + 1 - > UINTPTR_MAX / sizeof (char *))) + if (SIZE_MAX / sizeof (char *) - pglob->gl_pathc + < pglob->gl_offs + nfound + 1) goto memory_error; - char **new_gl_pathv; new_gl_pathv - = (char **) realloc (pglob->gl_pathv, - (pglob->gl_pathc + pglob->gl_offs + nfound + 1) - * sizeof (char *)); + = realloc (pglob->gl_pathv, + (pglob->gl_pathc + pglob->gl_offs + nfound + 1) + * sizeof (char *)); + if (new_gl_pathv == NULL) { memory_error: @@ -1684,7 +1650,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, and this is the block assigned to OLD here. */ if (names == NULL) { - assert (old == &init_names); + assert (old == init_names); break; } cur = names->count; @@ -1710,7 +1676,7 @@ glob_in_dir (const char *pattern, const char *directory, int flags, and this is the block assigned to OLD here. */ if (names == NULL) { - assert (old == &init_names); + assert (old == init_names); break; } cur = names->count; diff --git a/posix/glob64.c b/posix/glob64.c index a5f5a7f9e2..39e54afe8b 100644 --- a/posix/glob64.c +++ b/posix/glob64.c @@ -43,10 +43,4 @@ glob64 (const char *pattern, int flags, } libc_hidden_def (glob64) -void -globfree64 (glob64_t *pglob) -{ -} -libc_hidden_def (globfree64) - stub_warning (glob64) diff --git a/posix/glob_internal.h b/posix/glob_internal.h new file mode 100644 index 0000000000..12c93660b7 --- /dev/null +++ b/posix/glob_internal.h @@ -0,0 +1,57 @@ +/* Shared definition for glob and glob_pattern_p. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef GLOB_INTERNAL_H +# define GLOB_INTERNAL_H + +static inline int +__glob_pattern_type (const char *pattern, int quote) +{ + const char *p; + int ret = 0; + + for (p = pattern; *p != '\0'; ++p) + switch (*p) + { + case '?': + case '*': + return 1; + + case '\\': + if (quote) + { + if (p[1] != '\0') + ++p; + ret |= 2; + } + break; + + case '[': + ret |= 4; + break; + + case ']': + if (ret & 4) + return 1; + break; + } + + return ret; +} + +#endif /* GLOB_INTERNAL_H */ diff --git a/posix/glob_pattern_p.c b/posix/glob_pattern_p.c new file mode 100644 index 0000000000..a17d337182 --- /dev/null +++ b/posix/glob_pattern_p.c @@ -0,0 +1,33 @@ +/* Return nonzero if PATTERN contains any metacharacters. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC +# include +#endif + +#include +#include "glob_internal.h" + +/* Return nonzero if PATTERN contains any metacharacters. + Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ +int +__glob_pattern_p (const char *pattern, int quote) +{ + return __glob_pattern_type (pattern, quote) == 1; +} +weak_alias (__glob_pattern_p, glob_pattern_p) diff --git a/posix/globfree.c b/posix/globfree.c new file mode 100644 index 0000000000..042e29d9b0 --- /dev/null +++ b/posix/globfree.c @@ -0,0 +1,41 @@ +/* Frees the dynamically allocated storage from an earlier call to glob. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC +# include +#endif + +#include +#include + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree (glob_t *pglob) +{ + if (pglob->gl_pathv != NULL) + { + size_t i; + for (i = 0; i < pglob->gl_pathc; ++i) + free (pglob->gl_pathv[pglob->gl_offs + i]); + free (pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} +#ifndef globfree +libc_hidden_def (globfree) +#endif diff --git a/posix/globfree64.c b/posix/globfree64.c new file mode 100644 index 0000000000..c9f8908a4e --- /dev/null +++ b/posix/globfree64.c @@ -0,0 +1,31 @@ +/* Frees the dynamically allocated storage from an earlier call to glob. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _LIBC +# include +#endif + +#include +#include + +/* Free storage allocated in PGLOB by a previous `glob' call. */ +void +globfree64 (glob64_t *pglob) +{ +} +libc_hidden_def (globfree64) diff --git a/sysdeps/gnu/glob64.c b/sysdeps/gnu/glob64.c index d1e4e6f0d5..52e97e2f6a 100644 --- a/sysdeps/gnu/glob64.c +++ b/sysdeps/gnu/glob64.c @@ -15,11 +15,8 @@ #undef __stat #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) -#define NO_GLOB_PATTERN_P 1 - #define COMPILE_GLOB64 1 #include libc_hidden_def (glob64) -libc_hidden_def (globfree64) diff --git a/sysdeps/gnu/globfree64.c b/sysdeps/gnu/globfree64.c new file mode 100644 index 0000000000..f092d0bf8b --- /dev/null +++ b/sysdeps/gnu/globfree64.c @@ -0,0 +1,10 @@ +#include +#include +#include + +#define glob_t glob64_t +#define globfree(pglob) globfree64 (pglob) + +#include + +libc_hidden_def (globfree64) diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile index 35e1ed48d2..32beaa67d0 100644 --- a/sysdeps/unix/sysv/linux/Makefile +++ b/sysdeps/unix/sysv/linux/Makefile @@ -140,7 +140,7 @@ endif ifeq ($(subdir),posix) sysdep_headers += bits/initspin.h -sysdep_routines += sched_getcpu +sysdep_routines += sched_getcpu oldglob tests += tst-affinity tst-affinity-pid diff --git a/sysdeps/unix/sysv/linux/alpha/glob.c b/sysdeps/unix/sysv/linux/alpha/glob.c index c5dfb85468..19eb9b1c07 100644 --- a/sysdeps/unix/sysv/linux/alpha/glob.c +++ b/sysdeps/unix/sysv/linux/alpha/glob.c @@ -42,10 +42,6 @@ extern void __new_globfree (glob_t *__pglob); #undef globfree64 versioned_symbol (libc, __new_glob, glob, GLIBC_2_1); -versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1); libc_hidden_ver (__new_glob, glob) -libc_hidden_ver (__new_globfree, globfree) weak_alias (__new_glob, glob64) -weak_alias (__new_globfree, globfree64) -libc_hidden_ver (__new_globfree, globfree64) diff --git a/sysdeps/unix/sysv/linux/alpha/globfree.c b/sysdeps/unix/sysv/linux/alpha/globfree.c new file mode 100644 index 0000000000..98cf1c200b --- /dev/null +++ b/sysdeps/unix/sysv/linux/alpha/globfree.c @@ -0,0 +1,37 @@ +/* Compat globfree. Linux/alpha version. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library. If not, see + . */ + +#define globfree64 __no_globfree64_decl +#include +#include +#include + +#define globfree(pglob) \ + __new_globfree (pglob) + +extern void __new_globfree (glob_t *__pglob); + +#include + +#undef globfree64 + +versioned_symbol (libc, __new_globfree, globfree, GLIBC_2_1); +libc_hidden_ver (__new_globfree, globfree) + +weak_alias (__new_globfree, globfree64) +libc_hidden_ver (__new_globfree, globfree64) diff --git a/sysdeps/unix/sysv/linux/i386/glob64.c b/sysdeps/unix/sysv/linux/i386/glob64.c index 30470c6ed9..c2cc85741f 100644 --- a/sysdeps/unix/sysv/linux/i386/glob64.c +++ b/sysdeps/unix/sysv/linux/i386/glob64.c @@ -19,6 +19,7 @@ #include #include #include +#include #define dirent dirent64 #define __readdir(dirp) __readdir64 (dirp) @@ -33,47 +34,9 @@ #undef __stat #define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) -#define NO_GLOB_PATTERN_P 1 - #define COMPILE_GLOB64 1 #include -#include "shlib-compat.h" - -libc_hidden_def (globfree64) - versioned_symbol (libc, __glob64, glob64, GLIBC_2_2); libc_hidden_ver (__glob64, glob64) - -#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) - -#include - -int __old_glob64 (const char *__pattern, int __flags, - int (*__errfunc) (const char *, int), - glob64_t *__pglob); -libc_hidden_proto (__old_glob64); - -#undef dirent -#define dirent __old_dirent64 -#undef GL_READDIR -# define GL_READDIR(pglob, stream) \ - ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) -#undef __readdir -#define __readdir(dirp) __old_readdir64 (dirp) -#undef glob -#define glob(pattern, flags, errfunc, pglob) \ - __old_glob64 (pattern, flags, errfunc, pglob) -#define convert_dirent __old_convert_dirent -#define glob_in_dir __old_glob_in_dir -#define GLOB_ATTRIBUTE attribute_compat_text_section - -#define GLOB_ONLY_P 1 - -#include - -libc_hidden_def (__old_glob64); - -compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); -#endif diff --git a/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c new file mode 100644 index 0000000000..abc35fdd2b --- /dev/null +++ b/sysdeps/unix/sysv/linux/mips/mips64/n64/globfree64.c @@ -0,0 +1 @@ +/* glob64 is in globfree64.c */ diff --git a/sysdeps/unix/sysv/linux/oldglob.c b/sysdeps/unix/sysv/linux/oldglob.c new file mode 100644 index 0000000000..8233e57ce9 --- /dev/null +++ b/sysdeps/unix/sysv/linux/oldglob.c @@ -0,0 +1,42 @@ +#include + +#if SHLIB_COMPAT(libc, GLIBC_2_1, GLIBC_2_2) + +#include +#include +#include + +#include + +int __old_glob64 (const char *__pattern, int __flags, + int (*__errfunc) (const char *, int), + glob64_t *__pglob); +libc_hidden_proto (__old_glob64); + +#define dirent __old_dirent64 +#define GL_READDIR(pglob, stream) \ + ((struct __old_dirent64 *) (pglob)->gl_readdir (stream)) +#undef __readdir +#define __readdir(dirp) __old_readdir64 (dirp) + +#define glob_t glob64_t +#define glob(pattern, flags, errfunc, pglob) \ + __old_glob64 (pattern, flags, errfunc, pglob) +#define globfree(pglob) globfree64(pglob) + +#define convert_dirent __old_convert_dirent +#define glob_in_dir __old_glob_in_dir + +#undef stat +#define stat stat64 +#undef __stat +#define __stat(file, buf) __xstat64 (_STAT_VER, file, buf) + +#define GLOB_ATTRIBUTE attribute_compat_text_section + +#include + +libc_hidden_def (__old_glob64); + +compat_symbol (libc, __old_glob64, glob64, GLIBC_2_1); +#endif diff --git a/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c new file mode 100644 index 0000000000..af035e1514 --- /dev/null +++ b/sysdeps/unix/sysv/linux/wordsize-64/globfree64.c @@ -0,0 +1,2 @@ +/* This file is here so sysdeps/gnu/glob64.c doesn't take precedence. */ +#include diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c new file mode 100644 index 0000000000..b76a761c17 --- /dev/null +++ b/sysdeps/unix/sysv/linux/x86_64/x32/globfree.c @@ -0,0 +1 @@ +#include diff --git a/sysdeps/wordsize-64/glob.c b/sysdeps/wordsize-64/glob.c index 082faf1c70..954e8d37e2 100644 --- a/sysdeps/wordsize-64/glob.c +++ b/sysdeps/wordsize-64/glob.c @@ -4,5 +4,3 @@ #undef glob64 #undef globfree64 weak_alias (glob, glob64) -weak_alias (globfree, globfree64) -libc_hidden_ver (globfree, globfree64) diff --git a/sysdeps/wordsize-64/globfree.c b/sysdeps/wordsize-64/globfree.c new file mode 100644 index 0000000000..ec8c35b489 --- /dev/null +++ b/sysdeps/wordsize-64/globfree.c @@ -0,0 +1,5 @@ +#define globfree64 __no_globfree64_decl +#include +#undef globfree64 +weak_alias (globfree, globfree64) +libc_hidden_ver (globfree, globfree64) diff --git a/sysdeps/wordsize-64/globfree64.c b/sysdeps/wordsize-64/globfree64.c new file mode 100644 index 0000000000..a0f57ff4b3 --- /dev/null +++ b/sysdeps/wordsize-64/globfree64.c @@ -0,0 +1 @@ +/* globfree64 is in globfree.c */ -- cgit v1.2.3 From 1f523e3c6efd673bdd05cbec85ff6ba178ba6e08 Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Fri, 20 Oct 2017 18:41:14 +0200 Subject: CVE-2017-15670: glob: Fix one-byte overflow [BZ #22320] (cherry picked from commit c369d66e5426a30e4725b100d5cd28e372754f90) --- ChangeLog | 6 ++++++ NEWS | 4 ++++ posix/glob.c | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 7d47dd8d7d..5229661ab1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-10-20 Paul Eggert + + [BZ #22320] + CVE-2017-15670 + * posix/glob.c (__glob): Fix one-byte overflow. + 2017-09-08 Adhemerval Zanella [BZ #1062] diff --git a/NEWS b/NEWS index 9a9e487ee6..8c10e88ec5 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,10 @@ Security related changes: question type which is outside the range of valid question type values. (CVE-2015-5180) +* CVE-2017-15670: The glob function, when invoked with GLOB_TILDE, suffered + from a one-byte overflow during ~ operator processing (either on the stack + or the heap, depending on the length of the user name). + The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun diff --git a/posix/glob.c b/posix/glob.c index ea6a240209..026bc063d3 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -883,7 +883,7 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), *p = '\0'; } else - *((char *) mempcpy (newp, dirname + 1, end_name - dirname)) + *((char *) mempcpy (newp, dirname + 1, end_name - dirname - 1)) = '\0'; user_name = newp; } -- cgit v1.2.3 From 5ff2eb52b236ca3d77f92272e8711b3c2b98140b Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sat, 21 Oct 2017 18:03:30 +0200 Subject: glob: Add new test tst-glob-tilde The new test checks for memory leaks (see bug 22325) and attempts to trigger the buffer overflow in bug 22320. (cherry picked from commit e80fc1fc98bf614eb01cf8325503df3a1451a99c) --- ChangeLog | 8 +++ posix/Makefile | 11 +++- posix/tst-glob-tilde.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 153 insertions(+), 2 deletions(-) create mode 100644 posix/tst-glob-tilde.c diff --git a/ChangeLog b/ChangeLog index 5229661ab1..756a3cc0f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-10-21 Florian Weimer + + * posix/Makefile (tests): Add tst-glob-tilde. + (tests-special): Add tst-glob-tilde-mem.out + (tst-glob-tilde-ENV): Set MALLOC_TRACE. + (tst-glob-tilde-mem.out): Add mtrace check. + * posix/tst-glob-tilde.c: New file. + 2017-10-20 Paul Eggert [BZ #22320] diff --git a/posix/Makefile b/posix/Makefile index 2894af0cb9..82a4020c76 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -90,7 +90,7 @@ tests := tstgetopt testfnm runtests runptests \ bug-getopt5 tst-getopt_long1 bug-regex34 bug-regex35 \ tst-pathconf tst-getaddrinfo4 tst-rxspencer-no-utf8 \ tst-fnmatch3 bug-regex36 tst-getaddrinfo5 \ - tst-posix_spawn-fd + tst-posix_spawn-fd tst-glob-tilde xtests := bug-ga2 ifeq (yes,$(build-shared)) test-srcs := globtest @@ -133,7 +133,8 @@ tests-special += $(objpfx)bug-regex2-mem.out $(objpfx)bug-regex14-mem.out \ $(objpfx)tst-rxspencer-no-utf8-mem.out $(objpfx)tst-pcre-mem.out \ $(objpfx)tst-boost-mem.out $(objpfx)tst-getconf.out \ $(objpfx)bug-glob2-mem.out $(objpfx)tst-vfork3-mem.out \ - $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out + $(objpfx)tst-fnmatch-mem.out $(objpfx)bug-regex36-mem.out \ + $(objpfx)tst-glob-tilde-mem.out xtests-special += $(objpfx)bug-ga2-mem.out endif @@ -340,6 +341,12 @@ $(objpfx)bug-glob2-mem.out: $(objpfx)bug-glob2.out $(common-objpfx)malloc/mtrace $(objpfx)bug-glob2.mtrace > $@; \ $(evaluate-test) +tst-glob-tilde-ENV = MALLOC_TRACE=$(objpfx)tst-glob-tilde.mtrace + +$(objpfx)tst-glob-tilde-mem.out: $(objpfx)tst-glob-tilde.out + $(common-objpfx)malloc/mtrace $(objpfx)tst-glob-tilde.mtrace > $@; \ + $(evaluate-test) + $(inst_libexecdir)/getconf: $(inst_bindir)/getconf \ $(objpfx)getconf.speclist FORCE $(addprefix $(..)./scripts/mkinstalldirs ,\ diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c new file mode 100644 index 0000000000..9518b4a6f8 --- /dev/null +++ b/posix/tst-glob-tilde.c @@ -0,0 +1,136 @@ +/* Check for GLOB_TIDLE heap allocation issues (bug 22320, bug 22325). + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#include +#include +#include +#include +#include +#include +#include +#include + +/* Flag which indicates whether to pass the GLOB_ONLYDIR flag. */ +static int do_onlydir; + +/* Flag which indicates whether to pass the GLOB_NOCHECK flag. */ +static int do_nocheck; + +/* Flag which indicates whether to pass the GLOB_MARK flag. */ +static int do_mark; + +static void +one_test (const char *prefix, const char *middle, const char *suffix) +{ + char *pattern = xasprintf ("%s%s%s", prefix, middle, suffix); + int flags = GLOB_TILDE; + if (do_onlydir) + flags |= GLOB_ONLYDIR; + if (do_nocheck) + flags |= GLOB_NOCHECK; + if (do_mark) + flags |= GLOB_MARK; + glob_t gl; + /* This glob call might result in crashes or memory leaks. */ + if (glob (pattern, flags, NULL, &gl) == 0) + globfree (&gl); + free (pattern); +} + +enum + { + /* The largest base being tested. */ + largest_base_size = 500000, + + /* The actual size is the base size plus a variable whose absolute + value is not greater than this. This helps malloc to trigger + overflows. */ + max_size_skew = 16, + + /* The maximum string length supported by repeating_string + below. */ + repeat_size = largest_base_size + max_size_skew, + }; + +/* Used to construct strings which repeat a single character 'x'. */ +static char *repeat; + +/* Return a string of SIZE characters. */ +const char * +repeating_string (int size) +{ + TEST_VERIFY (size >= 0); + TEST_VERIFY (size <= repeat_size); + const char *repeated_shifted = repeat + repeat_size - size; + TEST_VERIFY (strlen (repeated_shifted) == size); + return repeated_shifted; +} + +static int +do_test (void) +{ + /* Avoid network-based NSS modules and initialize nss_files with a + dummy lookup. This has to come before mtrace because NSS does + not free all memory. */ + __nss_configure_lookup ("passwd", "files"); + (void) getpwnam ("root"); + + mtrace (); + + repeat = xmalloc (repeat_size + 1); + memset (repeat, 'x', repeat_size); + repeat[repeat_size] = '\0'; + + /* These numbers control the size of the user name. The values + cover the minimum (0), a typical size (8), a large + stack-allocated size (100000), and a somewhat large + heap-allocated size (largest_base_size). */ + static const int base_sizes[] = { 0, 8, 100, 100000, largest_base_size, -1 }; + + for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir) + for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck) + for (do_mark = 0; do_mark < 2; ++do_mark) + for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx) + { + for (int size_skew = -max_size_skew; size_skew <= max_size_skew; + ++size_skew) + { + int size = base_sizes[base_idx] + size_skew; + if (size < 0) + continue; + + const char *user_name = repeating_string (size); + one_test ("~", user_name, "/a/b"); + } + + const char *user_name = repeating_string (base_sizes[base_idx]); + one_test ("~", user_name, ""); + one_test ("~", user_name, "/"); + one_test ("~", user_name, "/a"); + one_test ("~", user_name, "/*/*"); + one_test ("~", user_name, "\\/"); + one_test ("/~", user_name, ""); + one_test ("*/~", user_name, "/a/b"); + } + + free (repeat); + + return 0; +} + +#include -- cgit v1.2.3 From 1e53b88296dc95d325d6073910a33dca851b6bc4 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Sun, 22 Oct 2017 09:29:52 +0200 Subject: Update NEWS and ChangeLog for CVE-2017-15671 (cherry picked from commit 914c9994d27b80bc3b71c483e801a4f04e269ba6) --- ChangeLog | 1 + NEWS | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index 756a3cc0f0..01a1e99d83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -15,6 +15,7 @@ 2017-09-08 Adhemerval Zanella [BZ #1062] + CVE-2017-15671 * posix/Makefile (routines): Add globfree, globfree64, and glob_pattern_p. * posix/flexmember.h: New file. diff --git a/NEWS b/NEWS index 8c10e88ec5..a70d21eb40 100644 --- a/NEWS +++ b/NEWS @@ -25,6 +25,11 @@ Security related changes: from a one-byte overflow during ~ operator processing (either on the stack or the heap, depending on the length of the user name). +* CVE-2017-15671: The glob function, when invoked with GLOB_TILDE, + would sometimes fail to free memory allocated during ~ operator + processing, leading to a memory leak and, potentially, to a denial + of service. + The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun -- cgit v1.2.3 From 94825c8924b80518214ad9e3ca1f6589f209592c Mon Sep 17 00:00:00 2001 From: Paul Eggert Date: Sun, 22 Oct 2017 10:00:57 +0200 Subject: glob: Fix buffer overflow during GLOB_TILDE unescaping [BZ #22332] (cherry picked from commit a159b53fa059947cc2548e3b0d5bdcf7b9630ba8) --- ChangeLog | 6 ++++++ NEWS | 4 ++++ posix/glob.c | 4 ++-- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 01a1e99d83..77eea1e024 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +2017-10-22 Paul Eggert + + [BZ #22332] + * posix/glob.c (__glob): Fix buffer overflow during GLOB_TILDE + unescaping. + 2017-10-21 Florian Weimer * posix/Makefile (tests): Add tst-glob-tilde. diff --git a/NEWS b/NEWS index a70d21eb40..0531dfa9c6 100644 --- a/NEWS +++ b/NEWS @@ -30,6 +30,10 @@ Security related changes: processing, leading to a memory leak and, potentially, to a denial of service. +* The glob function, when invoked with GLOB_TILDE and without + GLOB_NOESCAPE, could write past the end of a buffer while + unescaping user names. Reported by Tim Rühsen. + The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun diff --git a/posix/glob.c b/posix/glob.c index 026bc063d3..f3fa807700 100644 --- a/posix/glob.c +++ b/posix/glob.c @@ -863,11 +863,11 @@ glob (const char *pattern, int flags, int (*errfunc) (const char *, int), char *p = mempcpy (newp, dirname + 1, unescape - dirname - 1); char *q = unescape; - while (*q != '\0') + while (q != end_name) { if (*q == '\\') { - if (q[1] == '\0') + if (q + 1 == end_name) { /* "~fo\\o\\" unescape to user_name "foo\\", but "~fo\\o\\/" unescape to user_name -- cgit v1.2.3 From bddc5728810859952a2acaec6302308361e828cc Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 2 Nov 2017 11:06:45 +0100 Subject: posix/tst-glob-tilde.c: Add test for bug 22332 (cherry picked from commit 2fac6a6cd50c22ac28c97d0864306594807ade3e) --- ChangeLog | 7 +++++++ posix/tst-glob-tilde.c | 53 ++++++++++++++++++++++++++++---------------------- 2 files changed, 37 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index 77eea1e024..172df43e16 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-11-02 Florian Weimer + + [BZ #22332] + * posix/tst-glob-tilde.c (do_noescape): New variable. + (one_test): Process it. + (do_test): Set do_noescape. Add unescaping test case. + 2017-10-22 Paul Eggert [BZ #22332] diff --git a/posix/tst-glob-tilde.c b/posix/tst-glob-tilde.c index 9518b4a6f8..6886f4371f 100644 --- a/posix/tst-glob-tilde.c +++ b/posix/tst-glob-tilde.c @@ -1,4 +1,4 @@ -/* Check for GLOB_TIDLE heap allocation issues (bug 22320, bug 22325). +/* Check for GLOB_TIDLE heap allocation issues (bugs 22320, 22325, 22332). Copyright (C) 2017 Free Software Foundation, Inc. This file is part of the GNU C Library. @@ -34,6 +34,9 @@ static int do_nocheck; /* Flag which indicates whether to pass the GLOB_MARK flag. */ static int do_mark; +/* Flag which indicates whether to pass the GLOB_NOESCAPE flag. */ +static int do_noescape; + static void one_test (const char *prefix, const char *middle, const char *suffix) { @@ -45,6 +48,8 @@ one_test (const char *prefix, const char *middle, const char *suffix) flags |= GLOB_NOCHECK; if (do_mark) flags |= GLOB_MARK; + if (do_noescape) + flags |= GLOB_NOESCAPE; glob_t gl; /* This glob call might result in crashes or memory leaks. */ if (glob (pattern, flags, NULL, &gl) == 0) @@ -105,28 +110,30 @@ do_test (void) for (do_onlydir = 0; do_onlydir < 2; ++do_onlydir) for (do_nocheck = 0; do_nocheck < 2; ++do_nocheck) for (do_mark = 0; do_mark < 2; ++do_mark) - for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx) - { - for (int size_skew = -max_size_skew; size_skew <= max_size_skew; - ++size_skew) - { - int size = base_sizes[base_idx] + size_skew; - if (size < 0) - continue; - - const char *user_name = repeating_string (size); - one_test ("~", user_name, "/a/b"); - } - - const char *user_name = repeating_string (base_sizes[base_idx]); - one_test ("~", user_name, ""); - one_test ("~", user_name, "/"); - one_test ("~", user_name, "/a"); - one_test ("~", user_name, "/*/*"); - one_test ("~", user_name, "\\/"); - one_test ("/~", user_name, ""); - one_test ("*/~", user_name, "/a/b"); - } + for (do_noescape = 0; do_noescape < 2; ++do_noescape) + for (int base_idx = 0; base_sizes[base_idx] >= 0; ++base_idx) + { + for (int size_skew = -max_size_skew; size_skew <= max_size_skew; + ++size_skew) + { + int size = base_sizes[base_idx] + size_skew; + if (size < 0) + continue; + + const char *user_name = repeating_string (size); + one_test ("~", user_name, "/a/b"); + one_test ("~", user_name, "x\\x\\x////x\\a"); + } + + const char *user_name = repeating_string (base_sizes[base_idx]); + one_test ("~", user_name, ""); + one_test ("~", user_name, "/"); + one_test ("~", user_name, "/a"); + one_test ("~", user_name, "/*/*"); + one_test ("~", user_name, "\\/"); + one_test ("/~", user_name, ""); + one_test ("*/~", user_name, "/a/b"); + } free (repeat); -- cgit v1.2.3 From d81254d2efcb839fd11df2960df5bba579193808 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Fri, 1 Dec 2017 21:53:51 +0100 Subject: Update NEWS to add CVE-2017-15804 entry (cherry picked from commit 15e84c63c05e0652047ba5e738c54d79d62ba74b) --- NEWS | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 0531dfa9c6..bc32643255 100644 --- a/NEWS +++ b/NEWS @@ -30,8 +30,8 @@ Security related changes: processing, leading to a memory leak and, potentially, to a denial of service. -* The glob function, when invoked with GLOB_TILDE and without - GLOB_NOESCAPE, could write past the end of a buffer while +* CVE-2017-15804: The glob function, when invoked with GLOB_TILDE and + without GLOB_NOESCAPE, could write past the end of a buffer while unescaping user names. Reported by Tim Rühsen. The following bugs are resolved with this release: -- cgit v1.2.3 From a4fc3a0ceb2f2d30a2d358a81fdecbe51681a3ab Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 2 Nov 2017 12:14:01 +0100 Subject: : New array_length and array_end macros (cherry picked from commit c94a5688fb1228a862b2d4a3f1239cdc0e3349e5) --- ChangeLog | 5 +++++ include/array_length.h | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 include/array_length.h diff --git a/ChangeLog b/ChangeLog index 172df43e16..6e648c310d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2017-11-02 Florian Weimer + + Add array_length and array_end macros. + * include/array_length.h: New file. + 2017-11-02 Florian Weimer [BZ #22332] diff --git a/include/array_length.h b/include/array_length.h new file mode 100644 index 0000000000..cb4a8b2a56 --- /dev/null +++ b/include/array_length.h @@ -0,0 +1,36 @@ +/* The array_length and array_end macros. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + +#ifndef _ARRAY_LENGTH_H +#define _ARRAY_LENGTH_H + +/* array_length (VAR) is the number of elements in the array VAR. VAR + must evaluate to an array, not a pointer. */ +#define array_length(var) \ + __extension__ ({ \ + _Static_assert (!__builtin_types_compatible_p \ + (__typeof (var), __typeof (&(var)[0])), \ + "argument must be an array"); \ + sizeof (var) / sizeof ((var)[0]); \ + }) + +/* array_end (VAR) is a pointer one past the end of the array VAR. + VAR must evaluate to an array, not a pointer. */ +#define array_end(var) (&(var)[array_length (var)]) + +#endif /* _ARRAY_LENGTH_H */ -- cgit v1.2.3 From 28aa53341abbc5843fc78f283c397d11d74a33db Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 14 Dec 2017 15:18:38 +0100 Subject: elf: Compute correct array size in _dl_init_paths [BZ #22606] (cherry picked from commit 8a0b17e48b83e933960dfeb8fa08b259f03f310e) --- ChangeLog | 8 ++++++++ NEWS | 5 +++++ elf/dl-load.c | 14 +++++++------- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e648c310d..90e4444444 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2017-12-14 Florian Weimer + + [BZ #22606] + CVE-2017-1000408 + * elf/dl-load.c (system_dirs): Update comment. + (nsystem_dirs_len): Use array_length. + (_dl_init_paths): Use nsystem_dirs_len to compute the array size. + 2017-11-02 Florian Weimer Add array_length and array_end macros. diff --git a/NEWS b/NEWS index bc32643255..9de14ffba0 100644 --- a/NEWS +++ b/NEWS @@ -34,6 +34,11 @@ Security related changes: without GLOB_NOESCAPE, could write past the end of a buffer while unescaping user names. Reported by Tim Rühsen. +* CVE-2017-1000408: Incorrect array size computation in _dl_init_paths leads + to the allocation of too much memory. (This is not a security bug per se, + it is mentioned here only because of the CVE assignment.) Reported by + Qualys. + The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun diff --git a/elf/dl-load.c b/elf/dl-load.c index c0d6249373..0d46c16ea7 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -103,7 +104,9 @@ static size_t ncapstr attribute_relro; static size_t max_capstrlen attribute_relro; -/* Get the generated information about the trusted directories. */ +/* Get the generated information about the trusted directories. Use + an array of concatenated strings to avoid relocations. See + gen-trusted-dirs.awk. */ #include "trusted-dirs.h" static const char system_dirs[] = SYSTEM_DIRS; @@ -111,9 +114,7 @@ static const size_t system_dirs_len[] = { SYSTEM_DIRS_LEN }; -#define nsystem_dirs_len \ - (sizeof (system_dirs_len) / sizeof (system_dirs_len[0])) - +#define nsystem_dirs_len array_length (system_dirs_len) static bool is_trusted_path (const char *path, size_t len) @@ -688,9 +689,8 @@ _dl_init_paths (const char *llp) + ncapstr * sizeof (enum r_dir_status)) / sizeof (struct r_search_path_elem)); - rtld_search_dirs.dirs[0] = (struct r_search_path_elem *) - malloc ((sizeof (system_dirs) / sizeof (system_dirs[0])) - * round_size * sizeof (struct r_search_path_elem)); + rtld_search_dirs.dirs[0] = malloc (nsystem_dirs_len * round_size + * sizeof (*rtld_search_dirs.dirs[0])); if (rtld_search_dirs.dirs[0] == NULL) { errstring = N_("cannot create cache for search path"); -- cgit v1.2.3 From c5b38f2ecec6facf818e3c50ad014be05b52c179 Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Thu, 14 Dec 2017 15:05:57 +0100 Subject: elf: Count components of the expanded path in _dl_init_path [BZ #22607] (cherry picked from commit 3ff3dfa5af313a6ea33f3393916f30eece4f0171) --- ChangeLog | 7 +++++++ NEWS | 6 ++++++ elf/dl-load.c | 13 ++++--------- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/ChangeLog b/ChangeLog index 90e4444444..2c2e9d5b19 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2017-12-14 Florian Weimer + + [BZ #22607] + CVE-2017-1000409 + * elf/dl-load.c (_dl_init_paths): Compute number of components in + the expanded path string. + 2017-12-14 Florian Weimer [BZ #22606] diff --git a/NEWS b/NEWS index 9de14ffba0..9e20117a81 100644 --- a/NEWS +++ b/NEWS @@ -39,6 +39,12 @@ Security related changes: it is mentioned here only because of the CVE assignment.) Reported by Qualys. +* CVE-2017-1000409: Buffer overflow in _dl_init_paths due to miscomputation + of the number of search path components. (This is not a security + vulnerability per se because no trust boundary is crossed if the fix for + CVE-2017-1000366 has been applied, but it is mentioned here only because + of the CVE assignment.) Reported by Qualys. + The following bugs are resolved with this release: [20790] Fix rpcgen buffer overrun diff --git a/elf/dl-load.c b/elf/dl-load.c index 0d46c16ea7..64f55145a2 100644 --- a/elf/dl-load.c +++ b/elf/dl-load.c @@ -776,8 +776,6 @@ _dl_init_paths (const char *llp) if (llp != NULL && *llp != '\0') { - size_t nllp; - const char *cp = llp; char *llp_tmp; #ifdef SHARED @@ -800,13 +798,10 @@ _dl_init_paths (const char *llp) /* Decompose the LD_LIBRARY_PATH contents. First determine how many elements it has. */ - nllp = 1; - while (*cp) - { - if (*cp == ':' || *cp == ';') - ++nllp; - ++cp; - } + size_t nllp = 1; + for (const char *cp = llp_tmp; *cp != '\0'; ++cp) + if (*cp == ':' || *cp == ';') + ++nllp; env_path_list.dirs = (struct r_search_path_elem **) malloc ((nllp + 1) * sizeof (struct r_search_path_elem *)); -- cgit v1.2.3