Compare commits

...
Author SHA1 Message Date
Florian Weimer f053ff88a4 Linux: Only define OPEN_TREE_* macros in <sys/mount.h> if undefined (bug 33921)
There is a conditional inclusion of <linux/mount.h> earlier in the file.
If that defines the macros, do not redefine them.  This addresses build
problems as the token sequence used by the UAPI macro definitions
changes between Linux versions.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit d12b017cdd)
2026-05-02 14:29:19 +02:00
DJ Delorie 9925e1d995 include: isolate __O_CLOEXEC flag for sys/mount.h and fcntl.h
Including sys/mount.h should not implicitly include fcntl.h
as that causes namespace pollution and conflicts with kernel
headers.  It only needs O_CLOEXEC for OPEN_TREE_CLOEXEC
(although it shouldn't need that, but it's defined that way)
so we provide that define (via a private version) separately.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Tested-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 419245719c)
2026-05-02 14:29:19 +02:00
Florian Weimer 55b2c0820d Use pending character state in IBM1390, IBM1399 character sets (CVE-2026-4046)
Follow the example in iso-2022-jp-3.c and use the __count state
variable to store the pending character.  This avoids restarting
the conversion if the output buffer ends between two 4-byte UCS-4
code points, so that the assert reported in the bug can no longer
happen.

Even though the fix is applied to ibm1364.c, the change is only
effective for the two HAS_COMBINED codecs for IBM1390, IBM1399.

The test case was mostly auto-generated using
claude-4.6-opus-high-thinking, and composer-2-fast shows up in the
log as well.  During review, gpt-5.4-xhigh flagged that the original
version of the test case was not exercising the new character
flush logic.

This fixes bug 33980.

Assisted-by: LLM
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit d6f08d1cf0)
2026-04-21 19:07:33 +02:00
Tianyu Chen 2fb4d17828 x86-64: Fix indentation in Makefile (use tabs, not spaces)
The previous commit c69b88fc71 introduced
incorrect indentation in sysdeps/x86_64/Makefile by using spaces where
Makefile rules require tabs.

Replace the leading spaces with the proper tab characters so the command
lines are recognized correctly by make.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
2026-04-21 07:49:08 +08:00
Xi Ruoyao 913802d292 elf: parse /proc/self/maps as the last resort to find the gap for tst-link-map-contiguous-ldso
The initialization process of libc.so calls mmap() several times and the
kernel may lay the maps into the gap.  If all pages in the gap are
occupied, the test would not be able to find the gap with mmap() and the
test would fail.

The failure reproduces most frequently on LoongArch because with the
commonly used page size (16 KiB) the gap only contains 4 pages and the
probability they are all occupied is not near to zero.

With the changes in the patch, a test run may output:

    info: ld.so link map is not contiguous
    info: object "/dev/zero" found at 0x7ffff1fe0000 - 0x7ffff1fe4000
    info: anonymous mapping found at 0x7ffff1fe4000 - 0x7ffff1fec000

Also take the chance to fix a mistake in the "object found at" message
which has puzzled me during the initial debug session.

Signed-off-by: Xi Ruoyao <xry111@xry111.site>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit aed8390a6a)
2026-03-29 23:17:43 +02:00
Carlos O'Donell ef8b716316 resolv: Check hostname for validity (CVE-2026-4438)
The processed hostname in getanswer_ptr should be correctly checked to
avoid invalid characters from being allowed, including shell
metacharacters. It is a security issue to fail to check the returned
hostname for validity.

A regression test is added for invalid metacharacters and other cases
of invalid or valid characters.

No regressions on x86_64-linux-gnu.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit e10977481f)
2026-03-29 16:14:56 +02:00
Carlos O'Donell 1583ad96e5 resolv: Count records correctly (CVE-2026-4437)
The answer section boundary was previously ignored, and the code in
getanswer_ptr would iterate past the last resource record, but not
beyond the end of the returned data.  This could lead to subsequent data
being interpreted as answer records, thus violating the DNS
specification.  Such resource records could be maliciously crafted and
hidden from other tooling, but processed by the glibc stub resolver and
acted upon by the application.  While we trust the data returned by the
configured recursive resolvers, we should not trust its format and
should validate it as required.  It is a security issue to incorrectly
process the DNS protocol.

A regression test is added for response section crossing.

No regressions on x86_64-linux-gnu.

Reviewed-by: Collin Funk <collin.funk1@gmail.com>
(cherry picked from commit 9f5f18aab4)
2026-03-29 16:14:56 +02:00
Florian Weimer d2f15e1aca posix: Run tst-wordexp-reuse-mem test
The test was not properly scheduled for execution with a Makefile
dependency.

Fixes commit 80cc58ea2d ("posix: Reset
wordexp_t fields with WRDE_REUSE (CVE-2025-15281 / BZ 33814").

(cherry picked from commit bed2db02f3)
2026-03-29 16:14:23 +02:00
Florian Weimer d0adddb19a iconvdata: Fix invalid pointer arithmetic in ANSI_X3.110 module
The expression inptr + 1 can technically be invalid: if inptr == inend,
inptr may point one element past the end of an array.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit e98bd0c54d)
2026-03-29 16:11:54 +02:00
Adhemerval Zanella d5409a1be0 posix: Reset wordexp_t fields with WRDE_REUSE (CVE-2025-15281 / BZ 33814)
The wordexp fails to properly initialize the input wordexp_t when
WRDE_REUSE is used. The wordexp_t struct is properly freed, but
reuses the old wc_wordc value and updates the we_wordv in the
wrong position.  A later wordfree will then call free with an
invalid pointer.

Checked on x86_64-linux-gnu and i686-linux-gnu.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 80cc58ea2d)
2026-01-20 14:37:35 -03:00
Carlos O'Donell 49125ffc8e resolv: Fix NSS DNS backend for getnetbyaddr (CVE-2026-0915)
The default network value of zero for net was never tested for and
results in a DNS query constructed from uninitialized stack bytes.
The solution is to provide a default query for the case where net
is zero.

Adding a test case for this was straight forward given the existence of
tst-resolv-network and if the test is added without the fix you observe
this failure:

FAIL: resolv/tst-resolv-network
original exit status 1
error: tst-resolv-network.c:174: invalid QNAME: \146\218\129\128
error: 1 test failures

With a random QNAME resulting from the use of uninitialized stack bytes.

After the fix the test passes.

Additionally verified using wireshark before and after to ensure
on-the-wire bytes for the DNS query were as expected.

No regressions on x86_64.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit e56ff82d50)
2026-01-16 09:32:00 -05:00
Siddhesh Poyarekar 744b63026a memalign: reinstate alignment overflow check (CVE-2026-0861)
The change to cap valid sizes to PTRDIFF_MAX inadvertently dropped the
overflow check for alignment in memalign functions, _mid_memalign and
_int_memalign.  Reinstate the overflow check in _int_memalign, aligned
with the PTRDIFF_MAX change since that is directly responsible for the
CVE.  The missing _mid_memalign check is not relevant (and does not have
a security impact) and may need a different approach to fully resolve,
so it has been omitted.

CVE-Id: CVE-2026-0861
Vulnerable-Commit: 9bf8e29ca1
Reported-by: Igor Morgenstern, Aisle Research
Fixes: BZ #33796
Reviewed-by: Wilco Dijkstra <Wilco.Dijkstra@arm.com>
Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
(cherry picked from commit c9188d3337)
2026-01-15 22:39:02 -05:00
Sunil K Pandey 7b8f497fe4 nptl: Optimize trylock for high cache contention workloads (BZ #33704)
Check lock availability before acquisition to reduce cache line
bouncing.  Significantly improves trylock throughput on multi-core
systems under heavy contention.

Tested on x86_64.

Fixes BZ #33704.

Co-authored-by: Alex M Wells <alex.m.wells@intel.com>
Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
(cherry picked from commit 63716823db)
2025-12-18 10:57:08 -08:00
Sachin Monga a965fb342e ppc64le: Power 10 rawmemchr clobbers v20 (bug #33091)
Replace non-volatile(v20) by volatile(v17)
since v20 is not restored

Reviewed-by: Peter Bergner <bergner@tenstorrent.com>
(cherry picked from commit b59799f14f)
2025-11-27 11:12:23 -05:00
Joe Ramsay 49c250106a AArch64: Optimise SVE scalar callbacks
Instead of using SVE instructions to marshall special results into the
correct lane, just write the entire vector (and the predicate) to
memory, then use cheaper scalar operations.

Geomean speedup of 16% in special intervals on Neoverse with GCC 14.

Reviewed-by: Wilco Dijkstra  <Wilco.Dijkstra@arm.com>
(cherry picked from commit 5b82fb1882)
2025-11-18 16:43:46 +00:00
Jiamei Xie 96f1804a0d x86: fix wmemset ifunc stray '!' (bug 33542)
The ifunc selector for wmemset had a stray '!' in the
X86_ISA_CPU_FEATURES_ARCH_P(...) check:

  if (X86_ISA_CPU_FEATURE_USABLE_P (cpu_features, AVX2)
      && X86_ISA_CPU_FEATURES_ARCH_P (cpu_features,
                                      AVX_Fast_Unaligned_Load, !))

This effectively negated the predicate and caused the AVX2/AVX512
paths to be skipped, making the dispatcher fall back to the SSE2
implementation even on CPUs where AVX2/AVX512 are available. The
regression leads to noticeable throughput loss for wmemset.

Remove the stray '!' so the AVX_Fast_Unaligned_Load capability is
tested as intended and the correct AVX2/EVEX variants are selected.

Impact:
- On AVX2/AVX512-capable x86_64, wmemset no longer incorrectly
  falls back to SSE2; perf now shows __wmemset_evex/avx2 variants.

Testing:
- benchtests/bench-wmemset shows improved bandwidth across sizes.
- perf confirm the selected symbol is no longer SSE2.

Signed-off-by: xiejiamei <xiejiamei@hygon.com>
Signed-off-by: Li jing <lijing@hygon.cn>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 4d86b6cdd8)
2025-11-04 12:23:06 +00:00
Florian Weimer 815233f54b x86: Skip XSAVE state size reset if ISA level requires XSAVE
If we have to use XSAVE or XSAVEC trampolines, do not adjust the size
information they need.  Technically, it is an operator error to try to
run with -XSAVE,-XSAVEC on such builds, but this change here disables
some unnecessary code with higher ISA levels and simplifies testing.

Related to commit befe2d3c4d
("x86-64: Don't use SSE resolvers for ISA level 3 or above").

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 59585ddaa2)
2025-10-17 09:00:58 +08:00
Sunil K Pandey 554716698b x86-64: Simplify minimum ISA check ifdef conditional with if
Replace minimum ISA check ifdef conditional with if.  Since
MINIMUM_X86_ISA_LEVEL and AVX_X86_ISA_LEVEL are compile time constants,
compiler will perform constant folding optimization, getting same
results.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit b6e3898194)
2025-10-17 08:04:37 +08:00
H.J. Lu 7dfafa866d x86-64: Don't use SSE resolvers for ISA level 3 or above
When glibc is built with ISA level 3 or above enabled, SSE resolvers
aren't available and glibc fails to build:

ld: .../elf/librtld.os: in function `init_cpu_features':
.../elf/../sysdeps/x86/cpu-features.c:1200:(.text+0x1445f): undefined reference to `_dl_runtime_resolve_fxsave'
ld: .../elf/librtld.os: relocation R_X86_64_PC32 against undefined hidden symbol `_dl_runtime_resolve_fxsave' can not be used when making a shared object
/usr/local/bin/ld: final link failed: bad value

For ISA level 3 or above, don't use _dl_runtime_resolve_fxsave nor
_dl_tlsdesc_dynamic_fxsave.

This fixes BZ #31429.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>

(cherry picked from commit befe2d3c4d)
2025-10-17 08:04:28 +08:00
H.J. Lu a921ae4701 i386: Add GLIBC_ABI_GNU_TLS version [BZ #33221]
On i386, programs and shared libraries with __thread usage may fail
silently at run-time against glibc without the TLS run-time fix for:

https://sourceware.org/bugzilla/show_bug.cgi?id=32996

Add GLIBC_ABI_GNU_TLS version to indicate that glibc has the working
GNU TLS run-time.  Linker can add the GLIBC_ABI_GNU_TLS version to
binaries which depend on the working TLS run-time so that such programs
and shared libraries will fail to load and run at run-time against
libc.so without the GLIBC_ABI_GNU_TLS version, instead of fail silently
at random.

This fixes BZ #33221.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit ed1b7a5a48)
2025-08-20 15:11:21 -07:00
H.J. Lu 0769ad2cdd i386: Also add GLIBC_ABI_GNU2_TLS version [BZ #33129]
Since the GNU2 TLS run-time bug:

https://sourceware.org/bugzilla/show_bug.cgi?id=31372

affects both i386 and x86-64, also add GLIBC_ABI_GNU2_TLS version to i386
to indicate the working GNU2 TLS run-time.  For x86-64, the additional
GNU2 TLS run-time bug fix is needed for

https://sourceware.org/bugzilla/show_bug.cgi?id=31501

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit bd4628f3f1)
2025-08-20 15:11:09 -07:00
H.J. Lu 3f0dd818e5 x86-64: Add GLIBC_ABI_GNU2_TLS version [BZ #33129]
Programs and shared libraries compiled with -mtls-dialect=gnu2 may fail
silently at run-time against glibc without the GNU2 TLS run-time fix
for:

https://sourceware.org/bugzilla/show_bug.cgi?id=31372

Add GLIBC_ABI_GNU2_TLS version to indicate that glibc has the working
GNU2 TLS run-time.  Linker can add the GLIBC_ABI_GNU2_TLS version to
binaries which depend on the working GNU2 TLS run-time:

https://sourceware.org/bugzilla/show_bug.cgi?id=33130

so that such programs and shared libraries will fail to load and run at
run-time against libc.so without the GLIBC_ABI_GNU2_TLS version, instead
of fail silently at random.

This fixes BZ #33129.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 9df8fa397d)
2025-08-20 13:31:34 -07:00
H.J. Lu 1ea16a207c i386: Update ___tls_get_addr to preserve vector registers
Compiler generates the following instruction sequence for dynamic TLS
access:

	leal	tls_var@tlsgd(,%ebx,1), %eax
	call	___tls_get_addr@PLT

CALL instruction is transparent to compiler which assumes all registers,
except for EFLAGS, AX, CX, and DX, are unchanged after CALL.  But
___tls_get_addr is a normal function which doesn't preserve any vector
registers.

1. Rename the generic __tls_get_addr function to ___tls_get_addr_internal.
2. Change ___tls_get_addr to a wrapper function with implementations for
FNSAVE, FXSAVE, XSAVE and XSAVEC to save and restore all vector registers.
3. dl-tlsdesc-dynamic.h has:

_dl_tlsdesc_dynamic:
	/* Like all TLS resolvers, preserve call-clobbered registers.
	   We need two scratch regs anyway.  */
	subl	$32, %esp
	cfi_adjust_cfa_offset (32)

It is wrong to use

	movl	%ebx, -28(%esp)
	movl	%esp, %ebx
	cfi_def_cfa_register(%ebx)
	...
	mov	%ebx, %esp
	cfi_def_cfa_register(%esp)
	movl	-28(%esp), %ebx

to preserve EBX on stack.  Fix it with:

	movl	%ebx, 28(%esp)
	movl	%esp, %ebx
	cfi_def_cfa_register(%ebx)
	...
	mov	%ebx, %esp
	cfi_def_cfa_register(%esp)
	movl	28(%esp), %ebx

4. Update _dl_tlsdesc_dynamic to call ___tls_get_addr_internal directly.
5. Add have-test-mtls-traditional to compile tst-tls23-mod.c with
traditional TLS variant to verify the fix.
6. Define DL_RUNTIME_RESOLVE_REALIGN_STACK in sysdeps/x86/sysdep.h.

This fixes BZ #32996.

Co-Authored-By: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 848f0e46f0)
2025-08-20 11:09:07 -07:00
Sunil K Pandey 2d34e48a28 x86: Optimize xstate size calculation
Scan xstate IDs up to the maximum supported xstate ID.  Remove the
separate AMX xstate calculation.  Instead, exclude the AMX space from
the start of TILECFG to the end of TILEDATA in xsave_state_size.

Completed validation on SKL/SKX/SPR/SDE and compared xsave state size
with "ld.so --list-diagnostics" option, no regression.

Co-Authored-By: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
(cherry picked from commit 70b6488551)
2025-08-20 11:09:07 -07:00
Florian Weimer e925c13e03 x86: Link tst-gnu2-tls2-x86-noxsave{,c,xsavec} with libpthread
This fixes a test build failure on Hurd.

Fixes commit 145097dff1 ("x86: Use separate
variable for TLSDESC XSAVE/XSAVEC state size (bug 32810)").

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit c6e2895695)
(cherry picked from commit 837a36c371)
2025-08-20 11:05:27 -07:00
Florian Weimer 5cb05015c9 x86: Use separate variable for TLSDESC XSAVE/XSAVEC state size (bug 32810)
Previously, the initialization code reused the xsave_state_full_size
member of struct cpu_features for the TLSDESC state size.  However,
the tunable processing code assumes that this member has the
original XSAVE (non-compact) state size, so that it can use its
value if XSAVEC is disabled via tunable.

This change uses a separate variable and not a struct member because
the value is only needed in ld.so and the static libc, but not in
libc.so.  As a result, struct cpu_features layout does not change,
helping a future backport of this change.

Fixes commit 9b7091415a ("x86-64:
Update _dl_tlsdesc_dynamic to preserve AMX registers").

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 145097dff1)
2025-08-20 06:14:48 -07:00
H.J. Lu a477851fd2 Apply the Makefile sorting fix
Apply the Makefile sorting fix generated by sort-makefile-lines.py.

(cherry picked from commit ef7f4b1fef)
2025-08-20 06:11:54 -07:00
H.J. Lu 2ce5eb61fc x86-64: Allocate state buffer space for RDI, RSI and RBX
_dl_tlsdesc_dynamic preserves RDI, RSI and RBX before realigning stack.
After realigning stack, it saves RCX, RDX, R8, R9, R10 and R11.  Define
TLSDESC_CALL_REGISTER_SAVE_AREA to allocate space for RDI, RSI and RBX
to avoid clobbering saved RDI, RSI and RBX values on stack by xsave to
STATE_SAVE_OFFSET(%rsp).

   +==================+<- stack frame start aligned at 8 or 16 bytes
   |                  |<- RDI saved in the red zone
   |                  |<- RSI saved in the red zone
   |                  |<- RBX saved in the red zone
   |                  |<- paddings for stack realignment of 64 bytes
   |------------------|<- xsave buffer end aligned at 64 bytes
   |                  |<-
   |                  |<-
   |                  |<-
   |------------------|<- xsave buffer start at STATE_SAVE_OFFSET(%rsp)
   |                  |<- 8-byte padding for 64-byte alignment
   |                  |<- 8-byte padding for 64-byte alignment
   |                  |<- R11
   |                  |<- R10
   |                  |<- R9
   |                  |<- R8
   |                  |<- RDX
   |                  |<- RCX
   +==================+<- RSP aligned at 64 bytes

Define TLSDESC_CALL_REGISTER_SAVE_AREA, the total register save area size
for all integer registers by adding 24 to STATE_SAVE_OFFSET since RDI, RSI
and RBX are saved onto stack without adjusting stack pointer first, using
the red-zone.  This fixes BZ #31501.
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>

(cherry picked from commit 717ebfa85c)
2025-08-19 18:22:00 -07:00
H.J. Lu 6f076f1366 x86-64: Update _dl_tlsdesc_dynamic to preserve AMX registers
_dl_tlsdesc_dynamic should also preserve AMX registers which are
caller-saved.  Add X86_XSTATE_TILECFG_ID and X86_XSTATE_TILEDATA_ID
to x86-64 TLSDESC_CALL_STATE_SAVE_MASK.  Compute the AMX state size
and save it in xsave_state_full_size which is only used by
_dl_tlsdesc_dynamic_xsave and _dl_tlsdesc_dynamic_xsavec.  This fixes
the AMX part of BZ #31372.  Tested on AMX processor.

AMX test is enabled only for compilers with the fix for

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114098

GCC 14 and GCC 11/12/13 branches have the bug fix.
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>

(cherry picked from commit 9b7091415a)
2025-08-19 18:22:00 -07:00
H.J. Lu 88866d885c x86: Update _dl_tlsdesc_dynamic to preserve caller-saved registers
Compiler generates the following instruction sequence for GNU2 dynamic
TLS access:

	leaq	tls_var@TLSDESC(%rip), %rax
	call	*tls_var@TLSCALL(%rax)

or

	leal	tls_var@TLSDESC(%ebx), %eax
	call	*tls_var@TLSCALL(%eax)

CALL instruction is transparent to compiler which assumes all registers,
except for EFLAGS and RAX/EAX, are unchanged after CALL.  When
_dl_tlsdesc_dynamic is called, it calls __tls_get_addr on the slow
path.  __tls_get_addr is a normal function which doesn't preserve any
caller-saved registers.  _dl_tlsdesc_dynamic saved and restored integer
caller-saved registers, but didn't preserve any other caller-saved
registers.  Add _dl_tlsdesc_dynamic IFUNC functions for FNSAVE, FXSAVE,
XSAVE and XSAVEC to save and restore all caller-saved registers.  This
fixes BZ #31372.

Add GLRO(dl_x86_64_runtime_resolve) with GLRO(dl_x86_tlsdesc_dynamic)
to optimize elf_machine_runtime_setup.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>

(cherry picked from commit 0aac205a81)
2025-08-19 18:22:00 -07:00
H.J. Lu 4b2071eb02 x32/cet: Support shadow stack during startup for Linux 6.10
Use RXX_LP in RTLD_START_ENABLE_X86_FEATURES.  Support shadow stack during
startup for Linux 6.10:

commit 2883f01ec37dd8668e7222dfdb5980c86fdfe277
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri Mar 15 07:04:33 2024 -0700

    x86/shstk: Enable shadow stacks for x32

    1. Add shadow stack support to x32 signal.
    2. Use the 64-bit map_shadow_stack syscall for x32.
    3. Set up shadow stack for x32.

Add the map_shadow_stack system call to <fixup-asm-unistd.h> and regenerate
arch-syscall.h.  Tested on Intel Tiger Lake with CET enabled x32.  There
are no regressions with CET enabled x86-64.  There are no changes in CET
enabled x86-64 _dl_start_user.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
(cherry picked from commit 8344c1f551)
2025-08-19 18:11:21 -07:00
H.J. Lu 8572a77d95 x86-64: Remove sysdeps/x86_64/x32/dl-machine.h
Remove sysdeps/x86_64/x32/dl-machine.h by folding x32 ARCH_LA_PLTENTER,
ARCH_LA_PLTEXIT and RTLD_START into sysdeps/x86_64/dl-machine.h.  There
are no regressions on x86-64 nor x32.  There are no changes in x86-64
_dl_start_user.  On x32, _dl_start_user changes are

 <_dl_start_user>:
 	mov    %eax,%r12d
+	mov    %esp,%r13d
 	mov    (%rsp),%edx
 	mov    %edx,%esi
-	mov    %esp,%r13d
 	and    $0xfffffff0,%esp
 	mov    0x0(%rip),%edi        # <_dl_start_user+0x14>
 	lea    0x8(%r13,%rdx,4),%ecx

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>
(cherry picked from commit 652c6cf269)
2025-08-19 18:11:21 -07:00
Michael Jeanson 89fd3b08ea x86/cet: fix shadow stack test scripts
Some shadow stack test scripts use the '==' operator with the 'test'
command to validate exit codes resulting in the following error:

  sysdeps/x86_64/tst-shstk-legacy-1e.sh: 31: test: 139: unexpected operator

The '==' operator is invalid for the 'test' command, use '-eq' like the
previous call to 'test'.

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 155bb9d036)
2025-08-19 15:39:23 -07:00
H.J. Lu e13036cefa x86-64/cet: Make CET feature check specific to Linux/x86
CET feature bits in TCB, which are Linux specific, are used to check if
CET features are active.  Move CET feature check to Linux/x86 directory.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>

(cherry picked from commit f2b65a4471)
2025-08-19 15:39:23 -07:00
H.J. Lu 0ca425964e i386: Remove CET support bits
1. Remove _dl_runtime_resolve_shstk and _dl_runtime_profile_shstk.
2. Move CET offsets from x86 cpu-features-offsets.sym to x86-64
features-offsets.sym.
3. Rename x86 cet-control.h to x86-64 feature-control.h since it is only
for x86-64 and also used for PLT rewrite.
4. Add x86-64 ldsodefs.h to include feature-control.h.
5. Change TUNABLE_CALLBACK (set_plt_rewrite) to x86-64 only.
6. Move x86 dl-procruntime.c to x86-64.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

(cherry picked from commit 874214db62)
2025-08-19 15:39:23 -07:00
H.J. Lu 90ee4db1bf x86-64/cet: Move check-cet.awk to x86_64
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 7d544dd049)
2025-08-19 15:39:23 -07:00
Adhemerval Zanella 1e739f0a04 x86: Move CET infrastructure to x86_64
The CET is only supported for x86_64 and there is no plan to add
kernel support for i386.  Move the Makefile rules and files from the
generic x86 folder to x86_64 one.

Checked on x86_64-linux-gnu and i686-linux-gnu.

(cherry picked from commit b7fc4a07f2)
2025-08-19 15:39:23 -07:00
H.J. Lu 5d884f8949 x86-64/cet: Move dl-cet.[ch] to x86_64 directories
Since CET is only enabled for x86-64, move dl-cet.[ch] to x86_64
directories.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

(cherry picked from commit a1bbee9fd1)
2025-08-19 15:39:23 -07:00
Adhemerval Zanella 16c478bc28 i386: Fail if configured with --enable-cet
Since it is only supported for x86_64.

Checked on i686-linux-gnu.

(cherry picked from commit a0cfc48e8a)
2025-08-19 15:39:23 -07:00
H.J. Lu 0412cc8b4f x86-64/cet: Check the restore token in longjmp
setcontext and swapcontext put a restore token on the old shadow stack
which is used to restore the target shadow stack when switching user
contexts.  When longjmp from a user context, the target shadow stack
can be different from the current shadow stack and INCSSP can't be
used to restore the shadow stack pointer to the target shadow stack.

Update longjmp to search for a restore token.  If found, use the token
to restore the shadow stack pointer before using INCSSP to pop the
shadow stack.  Stop the token search and use INCSSP if the shadow stack
entry value is the same as the current shadow stack pointer.

It is a user error if there is a shadow stack switch without leaving a
restore token on the old shadow stack.

The only difference between __longjmp.S and __longjmp_chk.S is that
__longjmp_chk.S has a check for invalid longjmp usages.  Merge
__longjmp.S and __longjmp_chk.S by adding the CHECK_INVALID_LONGJMP
macro.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>

(cherry picked from commit 35694d3416)
2025-08-19 15:39:23 -07:00
H.J. Lu 9800c19dde i386: Ignore --enable-cet
Since shadow stack is only supported for x86-64, ignore --enable-cet for
i386.  Always setting $(enable-cet) for i386 to "no" to support

ifneq ($(enable-cet),no)

in x86 Makefiles.  We can't use

ifeq ($(enable-cet),yes)

since $(enable-cet) can be "yes", "no" or "permissive".
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

(cherry picked from commit bbfb54930c)
2025-08-19 15:39:23 -07:00
H.J. Lu 78b4845046 x86/cet: Add -fcf-protection=none before -fcf-protection=branch
When shadow stack is enabled, some CET tests failed when compiled with
GCC 14:

FAIL: elf/tst-cet-legacy-4
FAIL: elf/tst-cet-legacy-5a
FAIL: elf/tst-cet-legacy-6a

which are caused by

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113039

These tests use -fcf-protection -fcf-protection=branch and assume that
-fcf-protection=branch will override -fcf-protection.  But this GCC 14
commit:

https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=1c6231c05bdcca

changed the -fcf-protection behavior such that

-fcf-protection -fcf-protection=branch

is treated the same as

-fcf-protection

Use

-fcf-protection -fcf-protection=none -fcf-protection=branch

as the workaround.  This fixes BZ #31187.

Tested with GCC 13 and GCC 14 on Intel Tiger Lake.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>

(cherry picked from commit b5dcccfb12)
2025-08-19 15:39:23 -07:00
H.J. Lu e053e7caaf x86/cet: Run some CET tests with shadow stack
When CET is disabled by default, run some CET tests with shadow stack
enabled using

$ export GLIBC_TUNABLES=glibc.cpu.hwcaps=SHSTK

(cherry picked from commit cf9481724b)
2025-08-19 15:39:23 -07:00
H.J. Lu 0d1abcab55 x86/cet: Don't set CET active by default
Not all CET enabled applications and libraries have been properly tested
in CET enabled environments.  Some CET enabled applications or libraries
will crash or misbehave when CET is enabled.  Don't set CET active by
default so that all applications and libraries will run normally regardless
of whether CET is active or not.  Shadow stack can be enabled by

$ export GLIBC_TUNABLES=glibc.cpu.hwcaps=SHSTK

at run-time if shadow stack can be enabled by kernel.

NB: This commit can be reverted if it is OK to enable CET by default for
all applications and libraries.

(cherry picked from commit 55d63e7312)
2025-08-19 15:39:23 -07:00
H.J. Lu 027b321811 x86/cet: Check feature_1 in TCB for active IBT and SHSTK
Initially, IBT and SHSTK are marked as active when CPU supports them
and CET are enabled in glibc.  They can be disabled early by tunables
before relocation.  Since after relocation, GLRO(dl_x86_cpu_features)
becomes read-only, we can't update GLRO(dl_x86_cpu_features) to mark
IBT and SHSTK as inactive.  Instead, check the feature_1 field in TCB
to decide if IBT and SHST are active.

(cherry picked from commit d360dcc001)
2025-08-19 15:39:23 -07:00
H.J. Lu 5f6e2a06f6 x86/cet: Enable shadow stack during startup
Previously, CET was enabled by kernel before passing control to user
space and the startup code must disable CET if applications or shared
libraries aren't CET enabled.  Since the current kernel only supports
shadow stack and won't enable shadow stack before passing control to
user space, we need to enable shadow stack during startup if the
application and all shared library are shadow stack enabled.  There
is no need to disable shadow stack at startup.  Shadow stack can only
be enabled in a function which will never return.  Otherwise, shadow
stack will underflow at the function return.

1. GL(dl_x86_feature_1) is set to the CET features which are supported
by the processor and are not disabled by the tunable.  Only non-zero
features in GL(dl_x86_feature_1) should be enabled.  After enabling
shadow stack with ARCH_SHSTK_ENABLE, ARCH_SHSTK_STATUS is used to check
if shadow stack is really enabled.
2. Use ARCH_SHSTK_ENABLE in RTLD_START in dynamic executable.  It is
safe since RTLD_START never returns.
3. Call arch_prctl (ARCH_SHSTK_ENABLE) from ARCH_SETUP_TLS in static
executable.  Since the start function using ARCH_SETUP_TLS never returns,
it is safe to enable shadow stack in ARCH_SETUP_TLS.

(cherry picked from commit 541641a3de)
2025-08-19 15:39:23 -07:00
H.J. Lu 99fd1f6454 x86/cet: Sync with Linux kernel 6.6 shadow stack interface
Sync with Linux kernel 6.6 shadow stack interface.  Since only x86-64 is
supported, i386 shadow stack codes are unchanged and CET shouldn't be
enabled for i386.

1. When the shadow stack base in TCB is unset, the default shadow stack
is in use.  Use the current shadow stack pointer as the marker for the
default shadow stack. It is used to identify if the current shadow stack
is the same as the target shadow stack when switching ucontexts.  If yes,
INCSSP will be used to unwind shadow stack.  Otherwise, shadow stack
restore token will be used.
2. Allocate shadow stack with the map_shadow_stack syscall.  Since there
is no function to explicitly release ucontext, there is no place to
release shadow stack allocated by map_shadow_stack in ucontext functions.
Such shadow stacks will be leaked.
3. Rename arch_prctl CET commands to ARCH_SHSTK_XXX.
4. Rewrite the CET control functions with the current kernel shadow stack
interface.

Since CET is no longer enabled by kernel, a separate patch will enable
shadow stack during startup.

(cherry picked from commit edb5e0c8f9)
2025-08-19 15:39:23 -07:00
H.J. Lu 9397174e48 x86/cet: Don't disable CET if not single threaded
In permissive mode, don't disable IBT nor SHSTK when dlopening a legacy
shared library if not single threaded since IBT and SHSTK may be still
enabled in other threads.  Other threads with IBT or SHSTK enabled will
crash when calling functions in the legacy shared library.  Instead, an
error will be issued.

(cherry picked from commit 41560a9312)
2025-08-19 15:39:23 -07:00
H.J. Lu cc47b51930 x86: Modularize sysdeps/x86/dl-cet.c
Improve readability and make maintenance easier for dl-feature.c by
modularizing sysdeps/x86/dl-cet.c:
1. Support processors with:
   a. Only IBT.  Or
   b. Only SHSTK.  Or
   c. Both IBT and SHSTK.
2. Lock CET features only if IBT or SHSTK are enabled and are not
enabled permissively.

(cherry picked from commit c04035809a)
2025-08-19 15:39:23 -07:00
H.J. Lu 4c69161b63 x86/cet: Update tst-cet-vfork-1
Change tst-cet-vfork-1.c to verify that vfork child return triggers
SIGSEGV due to shadow stack mismatch.

(cherry picked from commit 1a23b39f9d)
2025-08-19 15:39:23 -07:00
H.J. Lu 2c763f814e x86/cet: Check CPU_FEATURE_ACTIVE in permissive mode
Verify that CPU_FEATURE_ACTIVE works properly in permissive mode.

(cherry picked from commit 4d8a01d2b0)
2025-08-19 15:39:23 -07:00
H.J. Lu 1192cdd722 x86/cet: Check legacy shadow stack code in .init_array section
Verify that legacy shadow stack code in .init_array section in application
and shared library, which are marked as shadow stack enabled, will trigger
segfault.

(cherry picked from commit 28bd6f832d)
2025-08-19 15:39:23 -07:00
H.J. Lu db563af070 x86/cet: Add tests for GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK
Verify that GLIBC_TUNABLES=glibc.cpu.hwcaps=-SHSTK turns off shadow
stack properly.

(cherry picked from commit 9424ce80c2)
2025-08-19 15:39:23 -07:00
H.J. Lu a4003d1500 x86/cet: Check CPU_FEATURE_ACTIVE when CET is disabled
Verify that CPU_FEATURE_ACTIVE (SHSTK) works properly when CET is
disabled.

(cherry picked from commit 71c0cc3357)
2025-08-19 15:39:23 -07:00
H.J. Lu d5db2ef4ce x86/cet: Check legacy shadow stack applications
Add tests to verify that legacy shadow stack applications run properly
when shadow stack is enabled in Linux kernel.

(cherry picked from commit f418fe6f97)
2025-08-19 15:39:23 -07:00
H.J. Lu f258b3fa5a x86/cet: Don't assume that SHSTK implies IBT
Since shadow stack (SHSTK) is enabled in the Linux kernel without
enabling indirect branch tracking (IBT), don't assume that SHSTK
implies IBT.  Use "CPU_FEATURE_ACTIVE (IBT)" to check if IBT is active
and "CPU_FEATURE_ACTIVE (SHSTK)" to check if SHSTK is active.

(cherry picked from commit 442983319b)
2025-08-19 15:39:23 -07:00
H.J. Lu 27da1273b9 x86/cet: Check user_shstk in /proc/cpuinfo
Linux kernel reports CPU shadow stack feature in /proc/cpuinfo as
user_shstk, instead of shstk.

(cherry picked from commit 0b850186fd)
2025-08-19 15:39:23 -07:00
Joseph Myers 058c4723cb Update syscall lists for Linux 6.7
Linux 6.7 adds the futex_requeue, futex_wait and futex_wake syscalls,
and enables map_shadow_stack for architectures previously missing it.
Update syscall-names.list and regenerate the arch-syscall.h headers
with build-many-glibcs.py update-syscalls.

Tested with build-many-glibcs.py.

(cherry picked from commit df11c05be9)
2025-08-19 15:39:23 -07:00
Adhemerval Zanella ffdf8ef6c1 Update syscall lists for Linux 6.6
Linux 6.6 has one new syscall for all architectures, fchmodat2, and
the map_shadow_stack on x86_64.

(cherry picked from commit 582383b37d)
2025-08-19 15:39:23 -07:00
H.J. Lu d2d1978e9a Remove installed header rule on $(..)include/%.h
On x86-64 machine with

[hjl@gnu-cfl-3 x86-glibc]$ ls -l /usr/include/asm/prctl.h sysdeps/unix/sysv/linux/x86_64/include/asm/prctl.h
-rw-r--r-- 1 hjl  hjl   825 Jan  9 09:41 sysdeps/unix/sysv/linux/x86_64/include/asm/prctl.h
-rw-r--r-- 1 root root 1170 Nov 27 16:00 /usr/include/asm/prctl.h
[hjl@gnu-cfl-3 x86-glibc]$

glibc configured with --enable-cet build failed:

make[2]: Entering directory '/export/gnu/import/git/gitlab/x86-glibc/iconv'
../Makerules:327: update target
'/export/build/gnu/tools-build/glibc-cet-gitlab/build-x86_64-linux/gnu/lib-names-64.h'
due to: /export/build/gnu/tools-build/glibc-cet-gitlab/build-x86_64-linux/gnu/lib-names-64.stmp
:
../Makeconfig:1216: update target
'/export/build/gnu/tools-build/glibc-cet-gitlab/build-x86_64-linux/libc-modules.h'
due to: /export/build/gnu/tools-build/glibc-cet-gitlab/build-x86_64-linux/libc-modules.stmp
:
../Makerules:1126: update target '/usr/include/asm/prctl.h' due to:
../sysdeps/unix/sysv/linux/x86_64/64/../include/asm/prctl.h
force-install
/usr/bin/install -c -m 644
../sysdeps/unix/sysv/linux/x86_64/64/../include/asm/prctl.h
/usr/include/asm/prctl.h
/usr/bin/install: cannot remove '/usr/include/asm/prctl.h': Permission denied
make[2]: *** [../Makerules:1126: /usr/include/asm/prctl.h] Error 1
make[2]: Leaving directory '/export/gnu/import/git/gitlab/x86-glibc/iconv'
make[1]: *** [Makefile:484: iconv/subdir_lib] Error 2
make[1]: Leaving directory '/export/gnu/import/git/gitlab/x86-glibc'
make: *** [Makefile:9: all] Error 2

This is triggered by the rule in Makerules:

$(inst_includedir)/%.h: $(..)include/%.h $(+force)
  $(do-install)

Since no files under include/ should be installed, remove it from
Makerules.

Tested it on x86-64.  There are no differences in the installed header
files.

(cherry picked from commit 1eae989cb7)
2025-08-19 13:16:40 -07:00
Florian Weimer e4bd849a5d debug: Fix tst-longjmp_chk3 build failure on Hurd
Explicitly include <unistd.h> for _exit and getpid.

(cherry picked from commit 4836a9af89)
2025-08-19 09:01:21 -07:00
Florian Weimer 4db5358c9c debug: Wire up tst-longjmp_chk3
The test was added in commit ac8cc9e300
without all the required Makefile scaffolding.  Tweak the test
so that it actually builds (including with dynamic SIGSTKSZ).

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 4b7cfcc3fb)
2025-08-19 08:54:28 -07:00
Adhemerval Zanella 1fc2002d60 debug: Adapt fortify tests to libsupport
Checked on aarch64, armhf, x86_64, and i686.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

(cherry picked from commit 9556acd249)
2025-08-19 08:28:19 -07:00
H.J. Lu 9bb20abcaa x86-64: Save APX registers in ld.so trampoline
Add APX registers to STATE_SAVE_MASK so that APX registers are saved in
ld.so trampoline.  This fixes BZ #31371.

Also update STATE_SAVE_OFFSET and STATE_SAVE_MASK for i386 which will
be used by i386 _dl_tlsdesc_dynamic.
Reviewed-by: Noah Goldstein <goldstein.w.n@gmail.com>

(cherry picked from commit dfb05f8e70)
2025-08-19 07:37:54 -07:00
Adhemerval Zanella 768103fa49 i386: Remove CET support
CET is only support for x86_64, this patch reverts:

  - faaee1f07e x86: Support shadow stack pointer in setjmp/longjmp.
  - be9ccd27c0 i386: Add _CET_ENDBR to indirect jump targets in
    add_n.S/sub_n.S
  - c02695d776 x86/CET: Update vfork to prevent child return
  - 5d844e1b72 i386: Enable CET support in ucontext functions
  - 124bcde683 x86: Add _CET_ENDBR to functions in crti.S
  - 562837c002 x86: Add _CET_ENDBR to functions in dl-tlsdesc.S
  - f753fa7dea x86: Support IBT and SHSTK in Intel CET [BZ #21598]
  - 825b58f3fb i386-mcount.S: Add _CET_ENDBR to _mcount and __fentry__
  - 7e119cd582 i386: Use _CET_NOTRACK in i686/memcmp.S
  - 177824e232 i386: Use _CET_NOTRACK in memcmp-sse4.S
  - 0a899af097 i386: Use _CET_NOTRACK in memcpy-ssse3-rep.S
  - 7fb613361c i386: Use _CET_NOTRACK in memcpy-ssse3.S
  - 77a8ae0948 i386: Use _CET_NOTRACK in memset-sse2-rep.S
  - 00e7b76a8f i386: Use _CET_NOTRACK in memset-sse2.S
  - 90d15dc577 i386: Use _CET_NOTRACK in strcat-sse2.S
  - f1574581c7 i386: Use _CET_NOTRACK in strcpy-sse2.S
  - 4031d7484a i386/sub_n.S: Add a missing _CET_ENDBR to indirect jump
  - target
  -
Checked on i686-linux-gnu.

(cherry picked from commit 25f1e16ef0)
2025-08-19 06:29:04 -07:00
H.J. Lu c69b88fc71 x86-64: Add GLIBC_ABI_DT_X86_64_PLT [BZ #33212]
When the linker -z mark-plt option is used to add DT_X86_64_PLT,
DT_X86_64_PLTSZ and DT_X86_64_PLTENT, the r_addend field of the
R_X86_64_JUMP_SLOT relocation stores the offset of the indirect
branch instruction.  However, glibc versions without the commit:

commit f8587a6189
Author: H.J. Lu <hjl.tools@gmail.com>
Date:   Fri May 20 19:21:48 2022 -0700

    x86-64: Ignore r_addend for R_X86_64_GLOB_DAT/R_X86_64_JUMP_SLOT

    According to x86-64 psABI, r_addend should be ignored for R_X86_64_GLOB_DAT
    and R_X86_64_JUMP_SLOT.  Since linkers always set their r_addends to 0, we
    can ignore their r_addends.

    Reviewed-by: Fangrui Song <maskray@google.com>

won't ignore the r_addend value in the R_X86_64_JUMP_SLOT relocation.
Such programs and shared libraries will fail at run-time randomly.

Add GLIBC_ABI_DT_X86_64_PLT version to indicate that glibc is compatible
with DT_X86_64_PLT.

The linker can add the glibc GLIBC_ABI_DT_X86_64_PLT version dependency
whenever -z mark-plt is passed to the linker.  The resulting programs and
shared libraries will fail to load at run-time against libc.so without the
GLIBC_ABI_DT_X86_64_PLT version, instead of fail randomly.

This fixes BZ #33212.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 399384e0c8)
2025-08-15 22:42:29 +01:00
Florian Weimer 1bdce25455 elf: Handle ld.so with LOAD segment gaps in _dl_find_object (bug 31943)
Detect if ld.so not contiguous and handle that case in _dl_find_object.
Set l_find_object_processed even for initially loaded link maps,
otherwise dlopen of an initially loaded object adds it to
_dlfo_loaded_mappings (where maps are expected to be contiguous),
in addition to _dlfo_nodelete_mappings.

Test elf/tst-link-map-contiguous-ldso iterates over the loader
image, reading every word to make sure memory is actually mapped.
It only does that if the l_contiguous flag is set for the link map.
Otherwise, it finds gaps with mmap and checks that _dl_find_object
does not return the ld.so mapping for them.

The test elf/tst-link-map-contiguous-main does the same thing for
the libc.so shared object.  This only works if the kernel loaded
the main program because the glibc dynamic loader may fill
the gaps with PROT_NONE mappings in some cases, making it contiguous,
but accesses to individual words may still fault.

Test elf/tst-link-map-contiguous-libc is again slightly different
because the dynamic loader always fills the gaps with PROT_NONE
mappings, so a different form of probing has to be used.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 20681be149)
2025-08-14 09:08:15 +02:00
Florian Weimer c35196339c elf: Extract rtld_setup_phdr function from dl_main
Remove historic binutils reference from comment and update
how this data is used by applications.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 2cac9559e0)
2025-08-14 09:07:44 +02:00
Florian Weimer 93fa28a752 elf: Do not add a copy of _dl_find_object to libc.so
This reduces code size and dependencies on ld.so internals from
libc.so.

Fixes commit f4c142bb9f
("arm: Use _dl_find_object on __gnu_Unwind_Find_exidx (BZ 31405)").

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 96429bcc91)
2025-08-14 09:07:44 +02:00
Adhemerval Zanella 40aa3ade66 arm: Use _dl_find_object on __gnu_Unwind_Find_exidx (BZ 31405)
Instead of __dl_iterate_phdr. On ARM dlfo_eh_frame/dlfo_eh_count
maps to PT_ARM_EXIDX vaddr start / length.

On a Neoverse N1 machine with 160 cores, the following program:

  $ cat test.c
  #include <stdlib.h>
  #include <pthread.h>
  #include <assert.h>

  enum {
    niter = 1024,
    ntimes = 128,
  };

  static void *
  tf (void *arg)
  {
    int a = (int) arg;

    for (int i = 0; i < niter; i++)
      {
        void *p[ntimes];
        for (int j = 0; j < ntimes; j++)
  	p[j] = malloc (a * 128);
        for (int j = 0; j < ntimes; j++)
  	free (p[j]);
      }

    return NULL;
  }

  int main (int argc, char *argv[])
  {
    enum { nthreads = 16 };
    pthread_t t[nthreads];

    for (int i = 0; i < nthreads; i ++)
      assert (pthread_create (&t[i], NULL, tf, (void *) i) == 0);

    for (int i = 0; i < nthreads; i++)
      {
        void *r;
        assert (pthread_join (t[i], &r) == 0);
        assert (r == NULL);
      }

    return 0;
  }
  $ arm-linux-gnueabihf-gcc -fsanitize=address test.c -o test

Improves from ~15s to 0.5s.

Checked on arm-linux-gnueabihf.

(cherry picked from commit f4c142bb9f)
2025-08-14 09:07:33 +02:00
Florian Weimer 6a52d5cab0 posix: Fix double-free after allocation failure in regcomp (bug 33185)
If a memory allocation failure occurs during bracket expression
parsing in regcomp, a double-free error may result.

Reported-by: Anastasia Belova <abelova@astralinux.ru>
Co-authored-by: Paul Eggert <eggert@cs.ucla.edu>
Reviewed-by: Andreas K. Huettel <dilfridge@gentoo.org>
(cherry picked from commit 7ea06e9940)
2025-07-24 09:50:02 +02:00
Sam James 21019afe65 malloc: cleanup casts in tst-calloc
Followup to c3d1dac96b. As pointed out by
Maciej W. Rozycki, the casts are obviously useless now.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit fc8f253d80)
2025-07-11 13:57:07 -04:00
Sam James a637f2c42f malloc: obscure calloc use in tst-calloc
Similar to a9944a52c9 and
f9493a15ea, we need to hide calloc use from
the compiler to accommodate GCC's r15-6566-g804e9d55d9e54c change.

First, include tst-malloc-aux.h, but then use `volatile` variables
for size.

The test passes without the tst-malloc-aux.h change but IMO we want
it there for consistency and to avoid future problems (possibly silent).

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit c3d1dac96b)
2025-07-11 13:57:07 -04:00
Sam James 879f0ee122 malloc: add indirection for malloc(-like) functions in tests [BZ #32366]
GCC 15 introduces allocation dead code removal (DCE) for PR117370 in
r15-5255-g7828dc070510f8. This breaks various glibc tests which want
to assert various properties of the allocator without doing anything
obviously useful with the allocated memory.

Alexander Monakov rightly pointed out that we can and should do better
than passing -fno-malloc-dce to paper over the problem. Not least because
GCC 14 already does such DCE where there's no testing of malloc's return
value against NULL, and LLVM has such optimisations too.

Handle this by providing malloc (and friends) wrappers with a volatile
function pointer to obscure that we're calling malloc (et. al) from the
compiler.

Reviewed-by: Paul Eggert <eggert@cs.ucla.edu>
(cherry picked from commit a9944a52c9)
2025-07-11 13:57:07 -04:00
Florian Weimer 51210d6496 nptl: PTHREAD_COND_INITIALIZER compatibility with pre-2.41 versions (bug 32786)
[BZ #25847]

The new initializer and struct layout does not initialize the
__g_signals field in the old struct layout before the change in
commit c36fc50781 ("nptl: Remove
g_refs from condition variables").  Bring back fields at the end
of struct __pthread_cond_s, so that they are again zero-initialized.

(cherry picked from commit dbc5a50d12)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:56:56 -04:00
Malte Skarupke 39a80f4035 nptl: Use all of g1_start and g_signals
[BZ #25847]

The LSB of g_signals was unused. The LSB of g1_start was used to indicate
which group is G2. This was used to always go to sleep in pthread_cond_wait
if a waiter is in G2. A comment earlier in the file says that this is not
correct to do:

 "Waiters cannot determine whether they are currently in G2 or G1 -- but they
  do not have to because all they are interested in is whether there are
  available signals"

I either would have had to update the comment, or get rid of the check. I
chose to get rid of the check. In fact I don't quite know why it was there.
There will never be available signals for group G2, so we didn't need the
special case. Even if there were, this would just be a spurious wake. This
might have caught some cases where the count has wrapped around, but it
wouldn't reliably do that, (and even if it did, why would you want to force a
sleep in that case?) and we don't support that many concurrent waiters
anyway. Getting rid of it allows us to use one more bit, making us more
robust to wraparound.

(cherry picked from commit 91bb902f58)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:56:09 -04:00
Malte Skarupke 8899e89b29 nptl: rename __condvar_quiesce_and_switch_g1
[BZ #25847]

This function no longer waits for threads to leave g1, so rename it to
__condvar_switch_g1

(cherry picked from commit 4b79e27a50)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:56:03 -04:00
Malte Skarupke 5765653697 nptl: Fix indentation
[BZ #25847]

In my previous change I turned a nested loop into a simple loop. I'm doing
the resulting indentation changes in a separate commit to make the diff on
the previous commit easier to review.

(cherry picked from commit ee6c14ed59)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:55:48 -04:00
Malte Skarupke 6bac834c5a nptl: Use a single loop in pthread_cond_wait instaed of a nested loop
[BZ #25847]

The loop was a little more complicated than necessary. There was only one
break statement out of the inner loop, and the outer loop was nearly empty.
So just remove the outer loop, moving its code to the one break statement in
the inner loop. This allows us to replace all gotos with break statements.

(cherry picked from commit 929a4764ac)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:55:40 -04:00
Malte Skarupke 7625579f11 nptl: Remove g_refs from condition variables
[BZ #25847]

This variable used to be needed to wait in group switching until all sleepers
have confirmed that they have woken. This is no longer needed. Nothing waits
on this variable so there is no need to track how many threads are currently
asleep in each group.

(cherry picked from commit c36fc50781)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:55:31 -04:00
Malte Skarupke 44eaf0615d nptl: Remove unnecessary quadruple check in pthread_cond_wait
[BZ #25847]

pthread_cond_wait was checking whether it was in a closed group no less than
four times. Checking once is enough. Here are the four checks:

1. While spin-waiting. This was dead code: maxspin is set to 0 and has been
   for years.
2. Before deciding to go to sleep, and before incrementing grefs: I kept this
3. After incrementing grefs. There is no reason to think that the group would
   close while we do an atomic increment. Obviously it could close at any
   point, but that doesn't mean we have to recheck after every step. This
   check was equally good as check 2, except it has to do more work.
4. When we find ourselves in a group that has a signal. We only get here after
   we check that we're not in a closed group. There is no need to check again.
   The check would only have helped in cases where the compare_exchange in the
   next line would also have failed. Relying on the compare_exchange is fine.

Removing the duplicate checks clarifies the code.

(cherry picked from commit 4f7b051f8e)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:55:25 -04:00
Malte Skarupke 1fa5e51897 nptl: Remove unnecessary catch-all-wake in condvar group switch
[BZ #25847]

This wake is unnecessary. We only switch groups after every sleeper in a group
has been woken. Sure, they may take a while to actually wake up and may still
hold a reference, but waking them a second time doesn't speed that up. Instead
this just makes the code more complicated and may hide problems.

In particular this safety wake wouldn't even have helped with the bug that was
fixed by Barrus' patch: The bug there was that pthread_cond_signal would not
switch g1 when it should, so we wouldn't even have entered this code path.

(cherry picked from commit b42cc6af11)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:55:18 -04:00
Malte Skarupke b5c4727e59 nptl: Update comments and indentation for new condvar implementation
[BZ #25847]

Some comments were wrong after the most recent commit. This fixes that.

Also fixing indentation where it was using spaces instead of tabs.

(cherry picked from commit 0cc973160c)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:55:01 -04:00
Frank Barrus 1a0d73a625 pthreads NPTL: lost wakeup fix 2
[BZ #25847]

This fixes the lost wakeup (from a bug in signal stealing) with a change
in the usage of g_signals[] in the condition variable internal state.
It also completely eliminates the concept and handling of signal stealing,
as well as the need for signalers to block to wait for waiters to wake
up every time there is a G1/G2 switch.  This greatly reduces the average
and maximum latency for pthread_cond_signal.

The g_signals[] field now contains a signal count that is relative to
the current g1_start value.  Since it is a 32-bit field, and the LSB is
still reserved (though not currently used anymore), it has a 31-bit value
that corresponds to the low 31 bits of the sequence number in g1_start.
(since g1_start also has an LSB flag, this means bits 31:1 in g_signals
correspond to bits 31:1 in g1_start, plus the current signal count)

By making the signal count relative to g1_start, there is no longer
any ambiguity or A/B/A issue, and thus any checks before blocking,
including the futex call itself, are guaranteed not to block if the G1/G2
switch occurs, even if the signal count remains the same.  This allows
initially safely blocking in G2 until the switch to G1 occurs, and
then transitioning from G1 to a new G1 or G2, and always being able to
distinguish the state change.  This removes the race condition and A/B/A
problems that otherwise ocurred if a late (pre-empted) waiter were to
resume just as the futex call attempted to block on g_signal since
otherwise there was no last opportunity to re-check things like whether
the current G1 group was already closed.

By fixing these issues, the signal stealing code can be eliminated,
since there is no concept of signal stealing anymore.  The code to block
for all waiters to exit g_refs can also be removed, since any waiters
that are still in the g_refs region can be guaranteed to safely wake
up and exit.  If there are still any left at this time, they are all
sent one final futex wakeup to ensure that they are not blocked any
longer, but there is no need for the signaller to block and wait for
them to wake up and exit the g_refs region.

The signal count is then effectively "zeroed" but since it is now
relative to g1_start, this is done by advancing it to a new value that
can be observed by any pending blocking waiters.  Any late waiters can
always tell the difference, and can thus just cleanly exit if they are
in a stale G1 or G2.  They can never steal a signal from the current
G1 if they are not in the current G1, since the signal value that has
to match in the cmpxchg has the low 31 bits of the g1_start value
contained in it, and that's first checked, and then it won't match if
there's a G1/G2 change.

Note: the 31-bit sequence number used in g_signals is designed to
handle wrap-around when checking the signal count, but if the entire
31-bit wraparound (2 billion signals) occurs while there is still a
late waiter that has not yet resumed, and it happens to then match
the current g1_start low bits, and the pre-emption occurs after the
normal "closed group" checks (which are 64-bit) but then hits the
futex syscall and signal consuming code, then an A/B/A issue could
still result and cause an incorrect assumption about whether it
should block.  This particular scenario seems unlikely in practice.
Note that once awake from the futex, the waiter would notice the
closed group before consuming the signal (since that's still a 64-bit
check that would not be aliased in the wrap-around in g_signals),
so the biggest impact would be blocking on the futex until the next
full wakeup from a G1/G2 switch.

(cherry picked from commit 1db84775f8)

Signed-off-by: Sunil Dora <sunilkumar.dora@windriver.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
2025-07-11 13:54:25 -04:00
Florian Weimer 5a6276d97a Fix error reporting (false negatives) in SGID tests
And simplify the interface of support_capture_subprogram_self_sgid.

Use the existing framework for temporary directories (now with
mode 0700) and directory/file deletion.  Handle all execution
errors within support_capture_subprogram_self_sgid.  In particular,
this includes test failures because the invoked program did not
exit with exit status zero.  Existing tests that expect exit
status 42 are adjusted to use zero instead.

In addition, fix callers not to call exit (0) with test failures
pending (which may mask them, especially when running with --direct).

Fixes commit 35fc356fa3
("elf: Fix subprocess status handling for tst-dlopen-sgid (bug 32987)").

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 3a3fb2ed83)
2025-06-20 11:12:24 +02:00
Florian Weimer 81f58dd9b7 support: Pick group in support_capture_subprogram_self_sgid if UID == 0
When running as root, it is likely that we can run under any group.
Pick a harmless group from /etc/group in this case.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 2f769cec44)
2025-06-20 11:10:41 +02:00
Florian Weimer ca7e32d024 elf: Fix subprocess status handling for tst-dlopen-sgid (bug 32987)
This should really move into support_capture_subprogram_self_sgid.

Reviewed-by: Sam James <sam@gentoo.org>
(cherry picked from commit 35fc356fa3)
2025-05-21 08:57:17 +02:00
Sunil K Pandey ca41fe44a5 x86_64: Fix typo in ifunc-impl-list.c.
Fix wcsncpy and wcpncpy typo in ifunc-impl-list.c.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit f2aeb6ff94)
2025-05-20 16:49:58 -07:00
Florian Weimer 31fa0f73e2 elf: Test case for bug 32976 (CVE-2025-4802)
Check that LD_LIBRARY_PATH is ignored for AT_SECURE statically
linked binaries, using support_capture_subprogram_self_sgid.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit d8f7a79335)
2025-05-20 20:26:07 +02:00
Florian Weimer 4335cd9b58 support: Add support_record_failure_barrier
This can be used to stop execution after a TEST_COMPARE_BLOB
failure, for example.

(cherry picked from commit d0b8aa6de4)
2025-05-20 20:26:07 +02:00
Florian Weimer 454f24e981 support: Use const char * argument in support_capture_subprogram_self_sgid
The function does not modify the passed-in string, so make this clear
via the prototype.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit f0c09fe616)
2025-05-20 20:26:07 +02:00
Adhemerval Zanella 3be3728df2 elf: Ignore LD_LIBRARY_PATH and debug env var for setuid for static
It mimics the ld.so behavior.

Checked on x86_64-linux-gnu.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

(cherry picked from commit 5451fa962c)

Changes:

	git/elf/dl-support.c
	  (missing commit 55f41ef8de
	   ("elf: Remove LD_PROFILE for static binaries"))
2025-05-20 20:25:57 +02:00
Wilco Dijkstra 5a08d049dc math: Improve layout of exp/exp10 data
GCC aligns global data to 16 bytes if their size is >= 16 bytes.  This patch
changes the exp_data struct slightly so that the fields are better aligned
and without gaps.  As a result on targets that support them, more load-pair
instructions are used in exp.

The exp benchmark improves 2.5%, "144bits" by 7.2%, "768bits" by 12.7% on
Neoverse V2.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 5afaf99edb)
2025-02-28 14:52:00 +00:00
Wilco Dijkstra 097299ffa9 AArch64: Use prefer_sve_ifuncs for SVE memset
Use prefer_sve_ifuncs for SVE memset just like memcpy.

Reviewed-by: Yury Khrustalev <yury.khrustalev@arm.com>
(cherry picked from commit 0f044be1da)
2025-02-28 14:44:25 +00:00
Wilco Dijkstra 52c2b1556f AArch64: Add SVE memset
Add SVE memset based on the generic memset with predicated load for sizes < 16.
Unaligned memsets of 128-1024 are improved by ~20% on average by using aligned
stores for the last 64 bytes.  Performance of random memset benchmark improves
by ~2% on Neoverse V1.

Reviewed-by: Yury Khrustalev <yury.khrustalev@arm.com>
(cherry picked from commit 163b1bbb76)
2025-02-28 14:44:23 +00:00
Wilco Dijkstra 3de5112326 math: Improve layout of expf data
GCC aligns global data to 16 bytes if their size is >= 16 bytes.  This patch
changes the exp2f_data struct slightly so that the fields are better aligned.
As a result on targets that support them, load-pair instructions accessing
poly_scaled and invln2_scaled are now 16-byte aligned.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 44fa9c1080)
2025-02-28 14:42:29 +00:00
Wilco Dijkstra 5fe151d86a AArch64: Remove zva_128 from memset
Remove ZVA 128 support from memset - the new memset no longer
guarantees count >= 256, which can result in underflow and a
crash if ZVA size is 128 ([1]).  Since only one CPU uses a ZVA
size of 128 and its memcpy implementation was removed in commit
e162ab2bf1, remove this special
case too.

[1] https://sourceware.org/pipermail/libc-alpha/2024-November/161626.html

Reviewed-by: Andrew Pinski <quic_apinski@quicinc.com>
(cherry picked from commit a08d9a52f9)
2025-02-28 14:42:29 +00:00
Wilco Dijkstra 95aa21432c AArch64: Optimize memset
Improve small memsets by avoiding branches and use overlapping stores.
Use DC ZVA for copies over 128 bytes.  Remove unnecessary code for ZVA sizes
other than 64 and 128.  Performance of random memset benchmark improves by 24%
on Neoverse N1.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit cec3aef324)
2025-02-28 14:42:27 +00:00
Wilco Dijkstra 9ca74b8ad1 AArch64: Improve generic strlen
Improve performance by handling another 16 bytes before entering the loop.
Use ADDHN in the loop to avoid SHRN+FMOV when it terminates.  Change final
size computation to avoid increasing latency.  On Neoverse V1 performance
of the random strlen benchmark improves by 4.6%.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 3dc426b642)
2025-02-28 14:41:56 +00:00
Siddhesh Poyarekar f984e2d7e8 assert: Add test for CVE-2025-0395
Use the __progname symbol to override the program name to induce the
failure that CVE-2025-0395 describes.

This is related to BZ #32582

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit cdb9ba8419)
2025-02-13 13:02:23 -05:00
H.J. Lu 650a0aaaff stdlib: Test using setenv with updated environ [BZ #32588]
Add a test for setenv with updated environ.  Verify that BZ #32588 is
fixed.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 8ab34497de)
2025-01-25 10:30:58 +08:00
Siddhesh Poyarekar c32fd59314 Fix underallocation of abort_msg_s struct (CVE-2025-0395)
Include the space needed to store the length of the message itself, in
addition to the message string.  This resolves BZ #32582.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 68ee0f704c)
2025-01-22 17:10:37 +01:00
Florian Weimer 549e7f7c5a elf: Support recursive use of dynamic TLS in interposed malloc
It turns out that quite a few applications use bundled mallocs that
have been built to use global-dynamic TLS (instead of the recommended
initial-exec TLS).  The previous workaround from
commit afe42e935b ("elf: Avoid some
free (NULL) calls in _dl_update_slotinfo") does not fix all
encountered cases unfortunatelly.

This change avoids the TLS generation update for recursive use
of TLS from a malloc that was called during a TLS update.  This
is possible because an interposed malloc has a fixed module ID and
TLS slot.  (It cannot be unloaded.)  If an initially-loaded module ID
is encountered in __tls_get_addr and the dynamic linker is already
in the middle of a TLS update, use the outdated DTV, thus avoiding
another call into malloc.  It's still necessary to update the
DTV to the most recent generation, to get out of the slow path,
which is why the check for recursion is needed.

The bookkeeping is done using a global counter instead of per-thread
flag because TLS access in the dynamic linker is tricky.

All this will go away once the dynamic linker stops using malloc
for TLS, likely as part of a change that pre-allocates all TLS
during pthread_create/dlopen.

Fixes commit d2123d6827 ("elf: Fix slow
tls access after dlopen [BZ #19924]").

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 018f0fc3b8)
2025-01-10 16:49:38 -08:00
Florian Weimer 48642ef1a5 elf: Avoid some free (NULL) calls in _dl_update_slotinfo
This has been confirmed to work around some interposed mallocs.  Here
is a discussion of the impact test ust/libc-wrapper/test_libc-wrapper
in lttng-tools:

  New TLS usage in libgcc_s.so.1, compatibility impact
  <https://inbox.sourceware.org/libc-alpha/8734v1ieke.fsf@oldenburg.str.redhat.com/>

Reportedly, this patch also papers over a similar issue when tcmalloc
2.9.1 is not compiled with -ftls-model=initial-exec.  Of course the
goal really should be to compile mallocs with the initial-exec TLS
model, but this commit appears to be a useful interim workaround.

Fixes commit d2123d6827 ("elf: Fix slow
tls access after dlopen [BZ #19924]").

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit afe42e935b)
2025-01-10 16:48:26 -08:00
Noah Goldstein 12fec8aae5 x86/string: Fixup alignment of main loop in str{n}cmp-evex [BZ #32212]
The loop should be aligned to 32-bytes so that it can ideally run out
the DSB. This is particularly important on Skylake-Server where
deficiencies in it's DSB implementation make it prone to not being
able to run loops out of the DSB.

For example running strcmp-evex on 200Mb string:

32-byte aligned loop:
    - 43,399,578,766      idq.dsb_uops
not 32-byte aligned loop:
    - 6,060,139,704       idq.dsb_uops

This results in a 25% performance degradation for the non-aligned
version.

The fix is to just ensure the code layout is such that the loop is
aligned. (Which was previously the case but was accidentally dropped
in 84e7c46df).

NB: The fix was actually 64-byte alignment. This is because 64-byte
alignment generally produces more stable performance than 32-byte
aligned code (cache line crosses can affect perf), so if we are going
past 16-byte alignmnent, might as well go to 64. 64-byte alignment
also matches most other functions we over-align, so it creates a
common point of optimization.

Times are reported as ratio of Time_With_Patch /
Time_Without_Patch. Lower is better.

The values being reported is the geometric mean of the ratio across
all tests in bench-strcmp and bench-strncmp.

Note this patch is only attempting to improve the Skylake-Server
strcmp for long strings. The rest of the numbers are only to test for
regressions.

Tigerlake Results Strings <= 512:
    strcmp : 1.026
    strncmp: 0.949

Tigerlake Results Strings > 512:
    strcmp : 0.994
    strncmp: 0.998

Skylake-Server Results Strings <= 512:
    strcmp : 0.945
    strncmp: 0.943

Skylake-Server Results Strings > 512:
    strcmp : 0.778
    strncmp: 1.000

The 2.6% regression on TGL-strcmp is due to slowdowns caused by
changes in alignment of code handling small sizes (most on the
page-cross logic). These should be safe to ignore because 1) We
previously only 16-byte aligned the function so this behavior is not
new and was essentially up to chance before this patch and 2) this
type of alignment related regression on small sizes really only comes
up in tight micro-benchmark loops and is unlikely to have any affect
on realworld performance.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 483443d321)
2025-01-09 17:23:28 -08:00
Noah Goldstein 04b8d48432 x86: Improve large memset perf with non-temporal stores [RHEL-29312]
Previously we use `rep stosb` for all medium/large memsets. This is
notably worse than non-temporal stores for large (above a
few MBs) memsets.
See:
https://docs.google.com/spreadsheets/d/1opzukzvum4n6-RUVHTGddV6RjAEil4P2uMjjQGLbLcU/edit?usp=sharing
For data using different stategies for large memset on ICX and SKX.

Using non-temporal stores can be up to 3x faster on ICX and 2x faster
on SKX. Historically, these numbers would not have been so good
because of the zero-over-zero writeback optimization that `rep stosb`
is able to do. But, the zero-over-zero writeback optimization has been
removed as a potential side-channel attack, so there is no longer any
good reason to only rely on `rep stosb` for large memsets. On the flip
size, non-temporal writes can avoid data in their RFO requests saving
memory bandwidth.

All of the other changes to the file are to re-organize the
code-blocks to maintain "good" alignment given the new code added in
the `L(stosb_local)` case.

The results from running the GLIBC memset benchmarks on TGL-client for
N=20 runs:

Geometric Mean across the suite New / Old EXEX256: 0.979
Geometric Mean across the suite New / Old EXEX512: 0.979
Geometric Mean across the suite New / Old AVX2   : 0.986
Geometric Mean across the suite New / Old SSE2   : 0.979

Most of the cases are essentially unchanged, this is mostly to show
that adding the non-temporal case didn't add any regressions to the
other cases.

The results on the memset-large benchmark suite on TGL-client for N=20
runs:

Geometric Mean across the suite New / Old EXEX256: 0.926
Geometric Mean across the suite New / Old EXEX512: 0.925
Geometric Mean across the suite New / Old AVX2   : 0.928
Geometric Mean across the suite New / Old SSE2   : 0.924

So roughly a 7.5% speedup. This is lower than what we see on servers
(likely because clients typically have faster single-core bandwidth so
saving bandwidth on RFOs is less impactful), but still advantageous.

Full test-suite passes on x86_64 w/ and w/o multiarch.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>

(cherry picked from commit 5bf0ab8057)
2025-01-09 17:23:28 -08:00
Gabi Falk dc1762113d x86_64: Fix missing wcsncat function definition without multiarch (x86-64-v4)
This code expects the WCSCAT preprocessor macro to be predefined in case
the evex implementation of the function should be defined with a name
different from __wcsncat_evex.  However, when glibc is built for
x86-64-v4 without multiarch support, sysdeps/x86_64/wcsncat.S defines
WCSNCAT variable instead of WCSCAT to build it as wcsncat.  Rename the
variable to WCSNCAT, as it is actually a better naming choice for the
variable in this case.

Reported-by: Kenton Groombridge
Link: https://bugs.gentoo.org/921945
Fixes: 64b8b6516b ("x86: Add evex optimized functions for the wchar_t strcpy family")
Signed-off-by: Gabi Falk <gabifalk@gmx.com>
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>
(cherry picked from commit dd5f891c1a)
2025-01-09 17:23:28 -08:00
H.J. Lu 0d14bf0754 sysdeps/x86/Makefile: Split and sort tests
Put each test on a separate line and sort tests.

(cherry picked from commit 7e03e0de7e)
2025-01-09 17:23:28 -08:00
Noah Goldstein 5a64f93365 x86: Only align destination to 1x VEC_SIZE in memset 4x loop
Current code aligns to 2x VEC_SIZE. Aligning to 2x has no affect on
performance other than potentially resulting in an additional
iteration of the loop.
1x maintains aligned stores (the only reason to align in this case)
and doesn't incur any unnecessary loop iterations.
Reviewed-by: Sunil K Pandey <skpgkp2@gmail.com>

(cherry picked from commit 9469261cf1)
2025-01-09 17:23:28 -08:00
Szabolcs Nagy 7772f9358c elf: Fix slow tls access after dlopen [BZ #19924]
In short: __tls_get_addr checks the global generation counter and if
the current dtv is older then _dl_update_slotinfo updates dtv up to the
generation of the accessed module. So if the global generation is newer
than generation of the module then __tls_get_addr keeps hitting the
slow dtv update path. The dtv update path includes a number of checks
to see if any update is needed and this already causes measurable tls
access slow down after dlopen.

It may be possible to detect up-to-date dtv faster.  But if there are
many modules loaded (> TLS_SLOTINFO_SURPLUS) then this requires at
least walking the slotinfo list.

This patch tries to update the dtv to the global generation instead, so
after a dlopen the tls access slow path is only hit once.  The modules
with larger generation than the accessed one were not necessarily
synchronized before, so additional synchronization is needed.

This patch uses acquire/release synchronization when accessing the
generation counter.

Note: in the x86_64 version of dl-tls.c the generation is only loaded
once, since relaxed mo is not faster than acquire mo load.

I have not benchmarked this. Tested by Adhemerval Zanella on aarch64,
powerpc, sparc, x86 who reported that it fixes the performance issue
of bug 19924.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit d2123d6827)
2025-01-09 07:31:25 -08:00
H.J. Lu 58822f954f x86: Check the lower byte of EAX of CPUID leaf 2 [BZ #30643]
The old Intel software developer manual specified that the low byte of
EAX of CPUID leaf 2 returned 1 which indicated the number of rounds of
CPUDID leaf 2 was needed to retrieve the complete cache information. The
newer Intel manual has been changed to that it should always return 1
and be ignored.  If the lower byte isn't 1, CPUID leaf 2 can't be used.
In this case, we ignore CPUID leaf 2 and use CPUID leaf 4 instead.  If
CPUID leaf 4 doesn't contain the cache information, cache information
isn't available at all.  This addresses BZ #30643.

(cherry picked from commit 1493622f4f)
2025-01-09 07:31:17 -08:00
H.J. Lu c92946d9b2 x86_64: Add log1p with FMA
On Skylake, it changes log1p bench performance by:

        Before       After     Improvement
max     63.349       58.347       8%
min     4.448        5.651        -30%
mean    12.0674      10.336       14%

The minimum code path is

 if (hx < 0x3FDA827A)                          /* x < 0.41422  */
    {
      if (__glibc_unlikely (ax >= 0x3ff00000))           /* x <= -1.0 */
        {
	   ...
        }
      if (__glibc_unlikely (ax < 0x3e200000))           /* |x| < 2**-29 */
        {
          math_force_eval (two54 + x);          /* raise inexact */
          if (ax < 0x3c900000)                  /* |x| < 2**-54 */
            {
	      ...
            }
          else
            return x - x * x * 0.5;

FMA and non-FMA code sequences look similar.  Non-FMA version is slightly
faster.  Since log1p is called by asinh and atanh, it improves asinh
performance by:

        Before       After     Improvement
max     75.645       63.135       16%
min     10.074       10.071       0%
mean    15.9483      14.9089      6%

and improves atanh performance by:

        Before       After     Improvement
max     91.768       75.081       18%
min     15.548       13.883       10%
mean    18.3713      16.8011      8%

(cherry picked from commit a8ecb126d4)
2025-01-09 07:31:04 -08:00
H.J. Lu b2a45f1eee x86_64: Add expm1 with FMA
On Skylake, it improves expm1 bench performance by:

        Before       After     Improvement
max     70.204       68.054       3%
min     20.709       16.2         22%
mean    22.1221      16.7367      24%

NB: Add

extern long double __expm1l (long double);
extern long double __expm1f128 (long double);

for __typeof (__expm1l) and __typeof (__expm1f128) when __expm1 is
defined since __expm1 may be expanded in their declarations which
causes the build failure.

(cherry picked from commit 1b214630ce)
2025-01-09 07:30:51 -08:00
H.J. Lu 49016f2190 x86_64: Add log2 with FMA
On Skylake, it improves log2 bench performance by:

        Before       After     Improvement
max     208.779      63.827       69%
min     9.977        6.55         34%
mean    10.366       6.8191       34%

(cherry picked from commit f6b10ed8e9)
2025-01-09 07:30:41 -08:00
H.J. Lu 5c9be512ee x86_64: Sort fpu/multiarch/Makefile
Sort Makefile variables using scripts/sort-makefile-lines.py.

No code generation changes observed in libm.  No regressions on x86_64.

(cherry picked from commit 881546979d)
2025-01-09 07:30:32 -08:00
Florian Weimer cf06772360 x86: Avoid integer truncation with large cache sizes (bug 32470)
Some hypervisors report 1 TiB L3 cache size.  This results
in some variables incorrectly getting zeroed, causing crashes
in memcpy/memmove because invariants are violated.

(cherry picked from commit 61c3450db9)
2024-12-17 18:53:16 +01:00
Michael Jeanson 37ded328c4 nptl: initialize cpu_id_start prior to rseq registration
When adding explicit initialization of rseq fields prior to
registration, I glossed over the fact that 'cpu_id_start' is also
documented as initialized by user-space.

While current kernels don't validate the content of this field on
registration, future ones could.

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
(cherry picked from commit d9f40387d3)
2024-12-06 16:01:45 +00:00
Michael Jeanson 9423cc5387 nptl: initialize rseq area prior to registration
Per the rseq syscall documentation, 3 fields are required to be
initialized by userspace prior to registration, they are 'cpu_id',
'rseq_cs' and 'flags'. Since we have no guarantee that 'struct pthread'
is cleared on all architectures, explicitly set those 3 fields prior to
registration.

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 97f60abd25)
2024-12-06 16:01:45 +00:00
Florian Weimer fa4ad10406 elf: Change ldconfig auxcache magic number (bug 32231)
In commit c628c22963 (elf: Remove
ldconfig kernel version check), the layout of auxcache entries
changed because the osversion field was removed from
struct aux_cache_file_entry.  However, AUX_CACHEMAGIC was not
changed, so existing files are still used, potentially leading
to unintended ldconfig behavior.  This commit changes AUX_CACHEMAGIC,
so that the file is regenerated.

Reported-by: DJ Delorie <dj@redhat.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 0a536f6e2f)
2024-10-29 10:00:32 +01:00
H.J. Lu 4dd8641461 Add crt1-2.0.o for glibc 2.0 compatibility tests
Starting from glibc 2.1, crt1.o contains _IO_stdin_used which is checked
by _IO_check_libio to provide binary compatibility for glibc 2.0.  Add
crt1-2.0.o for tests against glibc 2.0.  Define tests-2.0 for glibc 2.0
compatibility tests.  Add and update glibc 2.0 compatibility tests for
stderr, matherr and pthread_kill.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit 5f245f3bfb)
2024-10-01 10:33:51 +08:00
Siddhesh Poyarekar 370be85892 libio: Attempt wide backup free only for non-legacy code
_wide_data and _mode are not available in legacy code, so do not attempt
to free the wide backup buffer in legacy code.

Resolves: BZ #32137 and BZ #27821

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit ae4d44b1d5)
2024-09-11 08:51:55 +02:00
Maciej W. Rozycki f30501ca75 nptl: Use <support/check.h> facilities in tst-setuid3
Remove local FAIL macro in favor to FAIL_EXIT1 from <support/check.h>,
which provides equivalent reporting, with the name of the file and the
line number within of the failure site additionally included.  Remove
FAIL_ERR altogether and include ": %m" explicitly with the format string
supplied to FAIL_EXIT1 as there seems little value to have a separate
macro just for this.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 8c98195af6)
2024-08-30 15:28:42 -04:00
Maciej W. Rozycki 15ca66303f posix: Use <support/check.h> facilities in tst-truncate and tst-truncate64
Remove local FAIL macro in favor to FAIL_RET from <support/check.h>,
which provides equivalent reporting, with the name of the file of the
failure site additionally included, for the tst-truncate-common core
shared between the tst-truncate and tst-truncate64 tests.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit fe47595504)
2024-08-30 15:28:38 -04:00
Siddhesh Poyarekar b9f72bd5de ungetc: Fix backup buffer leak on program exit [BZ #27821]
If a file descriptor is left unclosed and is cleaned up by _IO_cleanup
on exit, its backup buffer remains unfreed, registering as a leak in
valgrind.  This is not strictly an issue since (1) the program should
ideally be closing the stream once it's not in use and (2) the program
is about to exit anyway, so keeping the backup buffer around a wee bit
longer isn't a real problem.  Free it anyway to keep valgrind happy
when the streams in question are the standard ones, i.e. stdout, stdin
or stderr.

Also, the _IO_have_backup macro checks for _IO_save_base,
which is a roundabout way to check for a backup buffer instead of
directly looking for _IO_backup_base.  The roundabout check breaks when
the main get area has not been used and user pushes a char into the
backup buffer with ungetc.  Fix this to use the _IO_backup_base
directly.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 3e1d8d1d1d)
2024-08-28 16:45:25 -04:00
Siddhesh Poyarekar 804d3c8db7 ungetc: Fix uninitialized read when putting into unused streams [BZ #27821]
When ungetc is called on an unused stream, the backup buffer is
allocated without the main get area being present.  This results in
every subsequent ungetc (as the stream remains in the backup area)
checking uninitialized memory in the backup buffer when trying to put a
character back into the stream.

Avoid comparing the input character with buffer contents when in backup
to avoid this uninitialized read.  The uninitialized read is harmless in
this context since the location is promptly overwritten with the input
character, thus fulfilling ungetc functionality.

Also adjust wording in the manual to drop the paragraph that says glibc
cannot do multiple ungetc back to back since with this change, ungetc
can actually do this.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit cdf0f88f97)
2024-08-28 16:44:54 -04:00
Siddhesh Poyarekar 87a1968a72 Make tst-ungetc use libsupport
Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 3f7df7e757)
2024-08-28 16:44:54 -04:00
Maciej W. Rozycki 99ffa84bdc stdio-common: Add test for vfscanf with matches longer than INT_MAX [BZ #27650]
Complement commit b03e4d7bd2 ("stdio: fix vfscanf with matches longer
than INT_MAX (bug 27650)") and add a test case for the issue, inspired
by the reproducer provided with the bug report.

This has been verified to succeed as from the commit referred and fail
beforehand.

As the test requires 2GiB of data to be passed around its performance
has been evaluated using a choice of systems and the execution time
determined to be respectively in the range of 9s for POWER9@2.166GHz,
24s for FU740@1.2GHz, and 40s for 74Kf@950MHz.  As this is on the verge
of and beyond the default timeout it has been increased by the factor of
8.  Regardless, following recent practice the test has been added to the
standard rather than extended set.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 89cddc8a70)
2024-08-28 16:44:35 -04:00
Maciej W. Rozycki 28f358bc42 support: Add FAIL test failure helper
Add a FAIL test failure helper analogous to FAIL_RET, that does not
cause the current function to return, providing a standardized way to
report a test failure with a message supplied while permitting the
caller to continue executing, for further reporting, cleaning up, etc.

Update existing test cases that provide a conflicting definition of FAIL
by removing the local FAIL definition and then as follows:

- tst-fortify-syslog: provide a meaningful message in addition to the
  file name already added by <support/check.h>; 'support_record_failure'
  is already called by 'support_print_failure_impl' invoked by the new
  FAIL test failure helper.

- tst-ctype: no update to FAIL calls required, with the name of the file
  and the line number within of the failure site additionally included
  by the new FAIL test failure helper, and error counting plus count
  reporting upon test program termination also already provided by
  'support_record_failure' and 'support_report_failure' respectively,
  called by 'support_print_failure_impl' and 'adjust_exit_status' also
  respectively.  However in a number of places 'printf' is called and
  the error count adjusted by hand, so update these places to make use
  of FAIL instead.  And last but not least adjust the final summary just
  to report completion, with any error count following as reported by
  the test driver.

- test-tgmath2: no update to FAIL calls required, with the name of the
  file of the failure site additionally included by the new FAIL test
  failure helper.  Also there is no need to track the return status by
  hand as any call to FAIL will eventually cause the test case to return
  an unsuccesful exit status regardless of the return status from the
  test function, via a call to 'adjust_exit_status' made by the test
  driver.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 1b97a9f23b)
2024-08-28 16:43:33 -04:00
Noah Goldstein c005d1bd6f x86: Fix bug in strchrnul-evex512 [BZ #32078]
Issue was we were expecting not matches with CHAR before the start of
the string in the page cross case.

The check code in the page cross case:
```
    and    $0xffffffffffffffc0,%rax
    vmovdqa64 (%rax),%zmm17
    vpcmpneqb %zmm17,%zmm16,%k1
    vptestmb %zmm17,%zmm17,%k0{%k1}
    kmovq  %k0,%rax
    inc    %rax
    shr    %cl,%rax
    je     L(continue)
```

expects that all characters that neither match null nor CHAR will be
1s in `rax` prior to the `inc`. Then the `inc` will overflow all of
the 1s where no relevant match was found.

This is incorrect in the page-cross case, as the
`vmovdqa64 (%rax),%zmm17` loads from before the start of the input
string.

If there are matches with CHAR before the start of the string, `rax`
won't properly overflow.

The fix is quite simple. Just replace:

```
    inc    %rax
    shr    %cl,%rax
```
With:
```
    sar    %cl,%rax
    inc    %rax
```

The arithmetic shift will clear any matches prior to the start of the
string while maintaining the signbit so the 1s can properly overflow
to zero in the case of no matches.
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>

(cherry picked from commit 7da0886247)
2024-08-15 14:41:17 -07:00
Andreas Schwab 059f82c3b9 Fix name space violation in fortify wrappers (bug 32052)
Rename the identifier sz to __sz everywhere.

Fixes: a643f60c53 ("Make sure that the fortified function conditionals are constant")
(cherry picked from commit 39ca997ab3)
(redone from scratch because of many conflicts)
2024-08-06 08:23:15 +02:00
Florian Weimer 9184c13681 resolv: Fix tst-resolv-short-response for older GCC (bug 32042)
Previous GCC versions do not support the C23 change that
allows labels on declarations.

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit ec119972cb)
2024-08-01 21:09:49 +02:00
Joseph Myers 3ac7ba61d2 Update syscall lists for Linux 6.5
Linux 6.5 has one new syscall, cachestat, and also enables the
cacheflush syscall for hppa.  Update syscall-names.list and regenerate
the arch-syscall.h headers with build-many-glibcs.py update-syscalls.

Tested with build-many-glibcs.py.

(cherry picked from commit 72511f539c)
2024-08-01 15:06:23 +02:00
H.J. Lu 6bb75212e6 Add mremap tests
Add tests for MREMAP_MAYMOVE and MREMAP_FIXED.  On Linux, also test
MREMAP_DONTUNMAP.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit ff0320bec2)
2024-08-01 14:42:07 +02:00
H.J. Lu f0e2114535 mremap: Update manual entry
Update mremap manual entry:

1. Change mremap to variadic.
2. Document MREMAP_FIXED and MREMAP_DONTUNMAP.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit cb2dee4ecc)
2024-08-01 14:42:07 +02:00
H.J. Lu 0301637b99 linux: Update the mremap C implementation [BZ #31968]
Update the mremap C implementation to support the optional argument for
MREMAP_DONTUNMAP added in Linux 5.7 since it may not always be correct
to implement a variadic function as a non-variadic function on all Linux
targets.  Return MAP_FAILED and set errno to EINVAL for unknown flag bits.
This fixes BZ #31968.

Note: A test must be added when a new flag bit is introduced.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 6c40cb0e9f)
2024-08-01 14:41:48 +02:00
Florian Weimer 1bed6acf50 resolv: Track single-request fallback via _res._flags (bug 31476)
This avoids changing _res.options, which inteferes with change
detection as part of automatic reloading of /etc/resolv.conf.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 868ab8923a)
2024-07-24 15:36:10 +02:00
Florian Weimer 6cad0f543c resolv: Do not wait for non-existing second DNS response after error (bug 30081)
In single-request mode, there is no second response after an error
because the second query has not been sent yet.  Waiting for it
introduces an unnecessary timeout.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit af625987d6)
2024-07-24 14:06:00 +02:00
Florian Weimer dc512364e8 resolv: Allow short error responses to match any query (bug 31890)
Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 691a3b2e9b)
2024-07-24 14:05:31 +02:00
Florian Weimer bb30bd2162 Linux: Make __rseq_size useful for feature detection (bug 31965)
The __rseq_size value is now the active area of struct rseq
(so 20 initially), not the full struct size including padding
at the end (32 initially).

Update misc/tst-rseq to print some additional diagnostics.

Reviewed-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
(cherry picked from commit 2e456ccf0c)
2024-07-16 16:37:38 +02:00
Adhemerval Zanella d9d019d674 elf: Make dl-rseq-symbols Linux only
And avoid a Hurd build failures.

Checked on x86_64-linux-gnu.

(cherry picked from commit 9fc639f654)
2024-07-16 16:36:42 +02:00
Michael Jeanson 7bfc35959d nptl: fix potential merge of __rseq_* relro symbols
While working on a patch to add support for the extensible rseq ABI, we
came across an issue where a new 'const' variable would be merged with
the existing '__rseq_size' variable. We tracked this to the use of
'-fmerge-all-constants' which allows the compiler to merge identical
constant variables. This means that all 'const' variables in a compile
unit that are of the same size and are initialized to the same value can
be merged.

In this specific case, on 32 bit systems 'unsigned int' and 'ptrdiff_t'
are both 4 bytes and initialized to 0 which should trigger the merge.
However for reasons we haven't delved into when the attribute 'section
(".data.rel.ro")' is added to the mix, only variables of the same exact
types are merged. As far as we know this behavior is not specified
anywhere and could change with a new compiler version, hence this patch.

Move the definitions of these variables into an assembler file and add
hidden writable aliases for internal use. This has the added bonus of
removing the asm workaround to set the values on rseq registration.

Tested on Debian 12 with GCC 12.2.

Signed-off-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 2b92982e23)
2024-07-16 16:36:42 +02:00
Stefan Liebler 712453634c s390x: Fix segfault in wcsncmp [BZ #31934]
The z13/vector-optimized wcsncmp implementation segfaults if n=1
and there is only one character (equal on both strings) before
the page end.  Then it loads and compares one character and misses
to check n again.  The following load fails.

This patch removes the extra load and compare of the first character
and just start with the loop which uses vector-load-to-block-boundary.
This code-path also checks n.

With this patch both tests are passing:
- the simplified one mentioned in the bugzilla 31934
- the full one in Florian Weimer's patch:
"manual: Document a GNU extension for strncmp/wcsncmp"
(https://patchwork.sourceware.org/project/glibc/patch/874j9eml6y.fsf@oldenburg.str.redhat.com/):
On s390x-linux-gnu (z16), the new wcsncmp test fails due to bug 31934.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit 9b76514103)
2024-07-16 10:26:44 +02:00
Stafford Horne c8cb4d2b86 misc: Add support for Linux uio.h RWF_NOAPPEND flag
In Linux 6.9 a new flag is added to allow for Per-io operations to
disable append mode even if a file was opened with the flag O_APPEND.
This is done with the new RWF_NOAPPEND flag.

This caused two test failures as these tests expected the flag 0x00000020
to be unused.  Adding the flag definition now fixes these tests on Linux
6.9 (v6.9-rc1).

  FAIL: misc/tst-preadvwritev2
  FAIL: misc/tst-preadvwritev64v2

This patch adds the flag, adjusts the test and adds details to
documentation.

Link: https://lore.kernel.org/all/20200831153207.GO3265@brightrain.aerifal.cx/
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 3db9d208dd)
2024-05-29 14:20:58 +02:00
Sunil K Pandey 697ab62d11 i386: Disable Intel Xeon Phi tests for GCC 15 and above (BZ 31782)
This patch disables Intel Xeon Phi tests for GCC 15 and above.

GCC 15 removed Intel Xeon Phi ISA support.
commit e1a7e2c54d52d0ba374735e285b617af44841ace
Author: Haochen Jiang <haochen.jiang@intel.com>
Date:   Mon May 20 10:43:44 2024 +0800

    i386: Remove Xeon Phi ISA support

Fixes BZ 31782.

Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 1b713c9a53)
2024-05-28 09:33:22 -07:00
H.J. Lu 249646f12b Force DT_RPATH for --enable-hardcoded-path-in-tests
On Fedora 40/x86-64, linker enables --enable-new-dtags by default which
generates DT_RUNPATH instead of DT_RPATH.  Unlike DT_RPATH, DT_RUNPATH
only applies to DT_NEEDED entries in the executable and doesn't applies
to DT_NEEDED entries in shared libraries which are loaded via DT_NEEDED
entries in the executable.  Some glibc tests have libstdc++.so.6 in
DT_NEEDED, which has libm.so.6 in DT_NEEDED.  When DT_RUNPATH is generated,
/lib64/libm.so.6 is loaded for such tests.  If the newly built glibc is
older than glibc 2.36, these tests fail with

assert/tst-assert-c++: /export/build/gnu/tools-build/glibc-gitlab-release/build-x86_64-linux/libc.so.6: version `GLIBC_2.36' not found (required by /lib64/libm.so.6)
assert/tst-assert-c++: /export/build/gnu/tools-build/glibc-gitlab-release/build-x86_64-linux/libc.so.6: version `GLIBC_ABI_DT_RELR' not found (required by /lib64/libm.so.6)

Pass -Wl,--disable-new-dtags to linker when building glibc tests with
--enable-hardcoded-path-in-tests.  This fixes BZ #31719.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
(cherry picked from commit 2dcaf70643)
2024-05-10 05:05:10 -07:00
John David Anglin 5aa4bb67b9 resolv: Fix some unaligned accesses in resolver [BZ #30750]
Signed-off-by: John David Anglin <dave.anglin@bell.net>
2024-05-08 16:07:29 +00:00
Florian Weimer f510d75ff7 nscd: Use time_t for return type of addgetnetgrentX
Using int may give false results for future dates (timeouts after the
year 2028).

Fixes commit 04a21e050d64a1193a6daab872bca2528bda44b ("CVE-2024-33601,
CVE-2024-33602: nscd: netgroup: Use two buffers in addgetnetgrentX
(bug 31680)").

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 4bbca1a446)
2024-05-02 19:02:08 +02:00
H.J. Lu e9f05fa1c6 elf: Also compile dl-misc.os with $(rtld-early-cflags)
Also compile dl-misc.os with $(rtld-early-cflags) to avoid

Program received signal SIGILL, Illegal instruction.
0x00007ffff7fd36ea in _dl_strtoul (nptr=nptr@entry=0x7fffffffe2c9 "2",
    endptr=endptr@entry=0x7fffffffd728) at dl-misc.c:156
156	  bool positive = true;
(gdb) bt
 #0  0x00007ffff7fd36ea in _dl_strtoul (nptr=nptr@entry=0x7fffffffe2c9 "2",
    endptr=endptr@entry=0x7fffffffd728) at dl-misc.c:156
 #1  0x00007ffff7fdb1a9 in tunable_initialize (
    cur=cur@entry=0x7ffff7ffbc00 <tunable_list+2176>,
    strval=strval@entry=0x7fffffffe2c9 "2", len=len@entry=1)
    at dl-tunables.c:131
 #2  0x00007ffff7fdb3a2 in parse_tunables (valstring=<optimized out>)
    at dl-tunables.c:258
 #3  0x00007ffff7fdb5d9 in __GI___tunables_init (envp=0x7fffffffdd58)
    at dl-tunables.c:288
 #4  0x00007ffff7fe44c3 in _dl_sysdep_start (
    start_argptr=start_argptr@entry=0x7fffffffdcb0,
    dl_main=dl_main@entry=0x7ffff7fe5f80 <dl_main>)
    at ../sysdeps/unix/sysv/linux/dl-sysdep.c:110
 #5  0x00007ffff7fe5cae in _dl_start_final (arg=0x7fffffffdcb0) at rtld.c:494
 #6  _dl_start (arg=0x7fffffffdcb0) at rtld.c:581
 #7  0x00007ffff7fe4b38 in _start ()
(gdb)

when setting GLIBC_TUNABLES in glibc compiled with APX.
Reviewed-by: Florian Weimer <fweimer@redhat.com>

(cherry picked from commit 049b7684c9)
2024-04-25 08:21:13 -07:00
Florian Weimer 71af8ca864 CVE-2024-33601, CVE-2024-33602: nscd: netgroup: Use two buffers in addgetnetgrentX (bug 31680)
This avoids potential memory corruption when the underlying NSS
callback function does not use the buffer space to store all strings
(e.g., for constant strings).

Instead of custom buffer management, two scratch buffers are used.
This increases stack usage somewhat.

Scratch buffer allocation failure is handled by return -1
(an invalid timeout value) instead of terminating the process.
This fixes bug 31679.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit c04a21e050)
2024-04-25 15:39:23 +02:00
Florian Weimer 2ae9446c1b CVE-2024-33600: nscd: Avoid null pointer crashes after notfound response (bug 31678)
The addgetnetgrentX call in addinnetgrX may have failed to produce
a result, so the result variable in addinnetgrX can be NULL.
Use db->negtimeout as the fallback value if there is no result data;
the timeout is also overwritten below.

Also avoid sending a second not-found response.  (The client
disconnects after receiving the first response, so the data stream did
not go out of sync even without this fix.)  It is still beneficial to
add the negative response to the mapping, so that the client can get
it from there in the future, instead of going through the socket.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit b048a482f0)
2024-04-25 15:39:23 +02:00
Florian Weimer 541ea5172a CVE-2024-33600: nscd: Do not send missing not-found response in addgetnetgrentX (bug 31678)
If we failed to add a not-found response to the cache, the dataset
point can be null, resulting in a null pointer dereference.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 7835b00dbc)
2024-04-25 15:39:23 +02:00
Florian Weimer 5968aebb86 CVE-2024-33599: nscd: Stack-based buffer overflow in netgroup cache (bug 31677)
Using alloca matches what other caches do.  The request length is
bounded by MAXKEYLEN.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 87801a8fd0)
2024-04-25 15:39:23 +02:00
Florian Weimer 29e20bd122 i386: ulp update for SSE2 --disable-multi-arch configurations
(cherry picked from commit 3a3a449742)
2024-04-25 13:07:19 +02:00
Florian Weimer decc9f504a nptl: Fix tst-cancel30 on kernels without ppoll_time64 support
Fall back to ppoll if ppoll_time64 fails with ENOSYS.
Fixes commit 370da8a121 ("nptl: Fix
tst-cancel30 on sparc64").

Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit f4724843ad)
2024-04-23 21:18:04 +02:00
Florian Weimer 68bff88592 login: structs utmp, utmpx, lastlog _TIME_BITS independence (bug 30701)
These structs describe file formats under /var/log, and should not
depend on the definition of _TIME_BITS.  This is achieved by
defining __WORDSIZE_TIME64_COMPAT32 to 1 on 32-bit ports that
support 32-bit time_t values (where __time_t is 32 bits).

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 9abdae94c7)
2024-04-19 18:38:24 +02:00
Florian Weimer 78d9f91da6 login: Check default sizes of structs utmp, utmpx, lastlog
The default <utmp-size.h> is for ports with a 64-bit time_t.
Ports with a 32-bit time_t or with __WORDSIZE_TIME64_COMPAT32=1
need to override it.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 4d4da5aab9)
2024-04-19 18:38:23 +02:00
Adhemerval Zanella 61484011e7 sparc: Remove 64 bit check on sparc32 wordsize (BZ 27574)
The sparc32 is always 32 bits.

Checked on sparcv9-linux-gnu.

(cherry picked from commit dd57f5e7b6)
2024-04-19 18:38:23 +02:00
Charles FolandAdhemerval Zanella e1135387de iconv: ISO-2022-CN-EXT: fix out-of-bound writes when writing escape sequence (CVE-2024-2961)
ISO-2022-CN-EXT uses escape sequences to indicate character set changes
(as specified by RFC 1922).  While the SOdesignation has the expected
bounds checks, neither SS2designation nor SS3designation have its;
allowing a write overflow of 1, 2, or 3 bytes with fixed values:
'$+I', '$+J', '$+K', '$+L', '$+M', or '$*H'.

Checked on aarch64-linux-gnu.

Co-authored-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>

(cherry picked from commit f9dc609e06)
2024-04-17 14:05:00 -03:00
Florian Weimer 20534f8176 powerpc: Fix ld.so address determination for PCREL mode (bug 31640)
This seems to have stopped working with some GCC 14 versions,
which clobber r2.  With other compilers, the kernel-provided
r2 value is still available at this point.

Reviewed-by: Peter Bergner <bergner@linux.ibm.com>
(cherry picked from commit 14e56bd4ce)
2024-04-14 09:10:33 +02:00
Wilco Dijkstra 92da7c2cfe AArch64: Check kernel version for SVE ifuncs
Old Linux kernels disable SVE after every system call.  Calling the
SVE-optimized memcpy afterwards will then cause a trap to reenable SVE.
As a result, applications with a high use of syscalls may run slower with
the SVE memcpy.  This is true for kernels between 4.15.0 and before 6.2.0,
except for 5.14.0 which was patched.  Avoid this by checking the kernel
version and selecting the SVE ifunc on modern kernels.

Parse the kernel version reported by uname() into a 24-bit kernel.major.minor
value without calling any library functions.  If uname() is not supported or
if the version format is not recognized, assume the kernel is modern.

Tested-by: Florian Weimer <fweimer@redhat.com>
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 2e94e2f5d2)
2024-04-10 14:03:08 +01:00
Szabolcs Nagy 1bf17ce978 aarch64: fix check for SVE support in assembler
Due to GCC bug 110901 -mcpu can override -march setting when compiling
asm code and thus a compiler targetting a specific cpu can fail the
configure check even when binutils gas supports SVE.

The workaround is that explicit .arch directive overrides both -mcpu
and -march, and since that's what the actual SVE memcpy uses the
configure check should use that too even if the GCC issue is fixed
independently.

Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 73c26018ed)
2024-04-10 14:03:08 +01:00
Andreas Schwab 168ae58e6e aarch64: correct CFI in rawmemchr (bug 31113)
The .cfi_return_column directive changes the return column for the whole
FDE range.  But the actual intent is to tell the unwinder that the value
in x30 (lr) now resides in x15 after the move, and that is expressed by
the .cfi_register directive.

(cherry picked from commit 3f79842788)
2024-04-10 14:03:07 +01:00
Wilco Dijkstra a08ff92294 AArch64: Remove Falkor memcpy
The latest implementations of memcpy are actually faster than the Falkor
implementations [1], so remove the falkor/phecda ifuncs for memcpy and
the now unused IS_FALKOR/IS_PHECDA defines.

[1] https://sourceware.org/pipermail/libc-alpha/2022-December/144227.html

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 2f5524cc53)
2024-04-10 14:03:07 +01:00
Wilco Dijkstra 156e44845f AArch64: Add memset_zva64
Add a specialized memset for the common ZVA size of 64 to avoid the
overhead of reading the ZVA size.  Since the code is identical to
__memset_falkor, remove the latter.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 3d7090f14b)
2024-04-10 14:03:07 +01:00
Wilco Dijkstra 1521237c32 AArch64: Cleanup emag memset
Cleanup emag memset - merge the memset_base64.S file, remove
the unused ZVA code (since it is disabled on emag).

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 9627ab99b5)
2024-04-10 14:03:07 +01:00
Wilco Dijkstra 25b66e8c4a AArch64: Cleanup ifuncs
Cleanup ifuncs.  Remove uses of libc_hidden_builtin_def, use ENTRY rather than
ENTRY_ALIGN, remove unnecessary defines and conditional compilation.  Rename
strlen_mte to strlen_generic.  Remove rtld-memset.

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 9fd3409842)
2024-04-10 14:03:07 +01:00
Wilco Dijkstra d8a2b56b4f AArch64: Add support for MOPS memcpy/memmove/memset
Add support for MOPS in cpu_features and INIT_ARCH.  Add ifuncs using MOPS for
memcpy, memmove and memset (use .inst for now so it works with all binutils
versions without needing complex configure and conditional compilation).

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 2bd0017988)
2024-04-10 14:03:07 +01:00
Joseph Myers 5456ff5d80 Add HWCAP2_MOPS from Linux 6.5 to AArch64 bits/hwcap.h
Linux 6.5 adds a new AArch64 HWCAP2 value, HWCAP2_MOPS.  Add it to
glibc's bits/hwcap.h.

Tested with build-many-glibcs.py for aarch64-linux-gnu.

(cherry picked from commit ff5d2abd18)
2024-04-10 14:03:07 +01:00
caiyinyu 0518bb0c16 LoongArch: Correct {__ieee754, _}_scalb -> {__ieee754, _}_scalbf 2024-03-22 09:25:39 +08:00
Florian Weimer 5753cda1ca linux: Use rseq area unconditionally in sched_getcpu (bug 31479)
Originally, nptl/descr.h included <sys/rseq.h>, but we removed that
in commit 2c6b4b272e ("nptl:
Unconditionally use a 32-byte rseq area").  After that, it was
not ensured that the RSEQ_SIG macro was defined during sched_getcpu.c
compilation that provided a definition.  This commit always checks
the rseq area for CPU number information before using the other
approaches.

This adds an unnecessary (but well-predictable) branch on
architectures which do not define RSEQ_SIG, but its cost is small
compared to the system call.  Most architectures that have vDSO
acceleration for getcpu also have rseq support.

Fixes: 2c6b4b272e
Fixes: 1d350aa060
Reviewed-by: Arjun Shankar <arjun@redhat.com>
(cherry picked from commit 7a76f21867)
2024-03-18 11:30:00 +01:00
Stefan Liebler ee4806e978 S390: Do not clobber r7 in clone [BZ #31402]
Starting with commit e57d8fc97b
"S390: Always use svc 0"
clone clobbers the call-saved register r7 in error case:
function or stack is NULL.

This patch restores the saved registers also in the error case.
Furthermore the existing test misc/tst-clone is extended to check
all error cases and that clone does not clobber registers in this
error case.

(cherry picked from commit 02782fd128)
Note: Added ia64 __clone2 call to tst-clone.c.
2024-02-27 11:07:05 +01:00
Adhemerval Zanella 506e47da1d malloc: Use __get_nprocs on arena_get2 (BZ 30945)
This restore the 2.33 semantic for arena_get2.  It was changed by
11a02b035b to avoid arena_get2 call malloc (back when __get_nproc
was refactored to use an scratch_buffer - 903bc7dcc2).  The
__get_nproc was refactored over then and now it also avoid to call
malloc.

The 11a02b035b did not take in consideration any performance
implication, which should have been discussed properly.  The
__get_nprocs_sched is still used as a fallback mechanism if procfs
and sysfs is not acessible.

Checked on x86_64-linux-gnu.
Reviewed-by: DJ Delorie <dj@redhat.com>

(cherry picked from commit 472894d2cf)
2024-02-12 09:53:27 -03:00
Adhemerval Zanella b09073e631 arm: Remove wrong ldr from _dl_start_user (BZ 31339)
The commit 49d877a80b (arm: Remove
_dl_skip_args usage) removed the _SKIP_ARGS literal, which was
previously loader to r4 on loader _start.  However, the cleanup did not
remove the following 'ldr r4, [sl, r4]' on _dl_start_user, used to check
to skip the arguments after ld self-relocations.

In my testing, the kernel initially set r4 to 0, which makes the
ldr instruction just read the _GLOBAL_OFFSET_TABLE_.  However, since r4
is a callee-saved register; a different runtime might not zero
initialize it and thus trigger an invalid memory access.

Checked on arm-linux-gnu.

Reported-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 1e25112dc0)
2024-02-05 15:43:33 -03:00
Daniel Cederman 0c5e5bace5 sparc: Remove unwind information from signal return stubs [BZ #31244]
The functions were previously written in C, but were not compiled
with unwind information. The ENTRY/END macros includes .cfi_startproc
and .cfi_endproc which adds unwind information. This caused the
tests cleanup-8 and cleanup-10 in the GCC testsuite to fail.
This patch adds a version of the ENTRY/END macros without the
CFI instructions that can be used instead.

sigaction registers a restorer address that is located two instructions
before the stub function. This patch adds a two instruction padding to
avoid that the unwinder accesses the unwind information from the function
that the linker has placed right before it in memory. This fixes an issue
with pthread_cancel that caused tst-mutex8-static (and other tests) to fail.

Signed-off-by: Daniel Cederman <cederman@gaisler.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 7bd06985c0)
2024-02-02 09:49:30 -03:00
Adhemerval Zanella aac57faf54 sparc: Fix sparc64 memmove length comparison (BZ 31266)
The small counts copy bytes comparsion should be unsigned (as the
memmove size argument).  It fixes string/tst-memmove-overflow on
sparcv9, where the input size triggers an invalid code path.

Checked on sparc64-linux-gnu and sparcv9-linux-gnu.

(cherry picked from commit 926a4bdbb5)
2024-02-02 09:49:30 -03:00
Adhemerval Zanella 0e383d2d4e sparc64: Remove unwind information from signal return stubs [BZ#31244]
Similar to sparc32 fix, remove the unwind information on the signal
return stubs.  This fixes the regressions:

FAIL: nptl/tst-cancel24-static
FAIL: nptl/tst-cond8-static
FAIL: nptl/tst-mutex8-static
FAIL: nptl/tst-mutexpi8-static
FAIL: nptl/tst-mutexpi9

On sparc64-linux-gnu.

(cherry picked from commit 369efd8177)
2024-02-02 09:49:30 -03:00
Andreas Larsson 6f68075869 sparc: Fix broken memset for sparc32 [BZ #31068]
Fixes commit a61933fe27 ("sparc: Remove bzero optimization") that
after moving code jumped to the wrong label 4.

Verfied by successfully running string/test-memset on sparc32.

Signed-off-by: Andreas Larsson <andreas@gaisler.com>
Signed-off-by: Ludwig Rydberg <ludwig.rydberg@gaisler.com>
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 578190b7e4)
2024-02-01 17:46:09 -03:00
Stefan Liebler 18876c9ff5 S390: Fix building with --disable-mutli-arch [BZ #31196]
Starting with commits
- 7ea510127e
string: Add libc_hidden_proto for strchrnul
- 22999b2f0f
string: Add libc_hidden_proto for memrchr

building glibc on s390x with --disable-multi-arch fails if only
the C-variant of strchrnul / memrchr is used.  This is the case
if gcc uses -march < z13.

The build fails with:
../sysdeps/s390/strchrnul-c.c:28:49: error: ‘__strchrnul_c’ undeclared here (not in a function); did you mean ‘__strchrnul’?
   28 | __hidden_ver1 (__strchrnul_c, __GI___strchrnul, __strchrnul_c);

With --disable-multi-arch, __strchrnul_c is not available as string/strchrnul.c
is just included without defining STRCHRNUL and thus we also don't have to create
the internal hidden symbol.

Tested-by: Andreas K. Hüttel <dilfridge@gentoo.org>
(cherry picked from commit cc1b91eabd)
2024-02-01 10:09:31 +01:00
Sunil K Pandey 30e546d76e x86_64: Optimize ffsll function code size.
Ffsll function randomly regress by ~20%, depending on how code gets
aligned in memory.  Ffsll function code size is 17 bytes.  Since default
function alignment is 16 bytes, it can load on 16, 32, 48 or 64 bytes
aligned memory.  When ffsll function load at 16, 32 or 64 bytes aligned
memory, entire code fits in single 64 bytes cache line.  When ffsll
function load at 48 bytes aligned memory, it splits in two cache line,
hence random regression.

Ffsll function size reduction from 17 bytes to 12 bytes ensures that it
will always fit in single 64 bytes cache line.

This patch fixes ffsll function random performance regression.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 9d94997b5f)
2024-01-31 18:31:28 -08:00
Arjun Shankar d37c2b20a4 syslog: Fix integer overflow in __vsyslog_internal (CVE-2023-6780)
__vsyslog_internal calculated a buffer size by adding two integers, but
did not first check if the addition would overflow.  This commit fixes
that.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit ddf542da94)
2024-01-30 15:55:43 +01:00
Arjun Shankar d0338312aa syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6779)
__vsyslog_internal used the return value of snprintf/vsnprintf to
calculate buffer sizes for memory allocation.  If these functions (for
any reason) failed and returned -1, the resulting buffer would be too
small to hold output.  This commit fixes that.

All snprintf/vsnprintf calls are checked for negative return values and
the function silently returns upon encountering them.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 7e5a0c286d)
2024-01-30 15:55:43 +01:00
Arjun Shankar 23514c72b7 syslog: Fix heap buffer overflow in __vsyslog_internal (CVE-2023-6246)
__vsyslog_internal did not handle a case where printing a SYSLOG_HEADER
containing a long program name failed to update the required buffer
size, leading to the allocation and overflow of a too-small buffer on
the heap.  This commit fixes that.  It also adds a new regression test
that uses glibc.malloc.check.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 6bd0e4efcc)
2024-01-30 15:55:43 +01:00
Florian Weimer cfe1219100 libio: Check remaining buffer size in _IO_wdo_write (bug 31183)
The multibyte character needs to fit into the remaining buffer space,
not the already-written buffer space.  Without the fix, we were never
moving the write pointer from the start of the buffer, always using
the single-character fallback buffer.

Fixes commit 04b76b5aa8 ("Don't error out writing
a multibyte character to an unbuffered stream (bug 17522)").

(cherry picked from commit ecc7c3deb9)
2024-01-02 14:37:42 +01:00
Andreas Schwab ae1e521702 getaddrinfo: translate ENOMEM to EAI_MEMORY (bug 31163)
When __resolv_context_get returns NULL due to out of memory, translate it
to a return value of EAI_MEMORY.

(cherry picked from commit 5eabdb6a6a)
2024-01-02 14:37:02 +01:00
H.J. Lu 27339a3eb8 NEWS: Mention bug fixes for 30745/30843 2023-12-23 06:27:50 -08:00
H.J. Lu d25e2c8d5c NEWS: Mention bug fixes for 29039/30694/30709/30721 2023-12-23 06:24:41 -08:00
H.J. Lu 968c983d43 x86-64: Fix the tcb field load for x32 [BZ #31185]
_dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic access the thread pointer
via the tcb field in TCB:

_dl_tlsdesc_undefweak:
        _CET_ENDBR
        movq    8(%rax), %rax
        subq    %fs:0, %rax
        ret

_dl_tlsdesc_dynamic:
	...
        subq    %fs:0, %rax
        movq    -8(%rsp), %rdi
        ret

Since the tcb field in TCB is a pointer, %fs:0 is a 32-bit location,
not 64-bit. It should use "sub %fs:0, %RAX_LP" instead.  Since
_dl_tlsdesc_undefweak returns ptrdiff_t and _dl_make_tlsdesc_dynamic
returns void *, RAX_LP is appropriate here for x32 and x86-64.  This
fixes BZ #31185.

(cherry picked from commit 81be2a61da)
2023-12-23 06:08:14 -08:00
H.J. Lu 35ea754975 x86-64: Fix the dtv field load for x32 [BZ #31184]
On x32, I got

FAIL: elf/tst-tlsgap

$ gdb elf/tst-tlsgap
...
open tst-tlsgap-mod1.so

Thread 2 "tst-tlsgap" received signal SIGSEGV, Segmentation fault.
[Switching to LWP 2268754]
_dl_tlsdesc_dynamic () at ../sysdeps/x86_64/dl-tlsdesc.S:108
108		movq	(%rsi), %rax
(gdb) p/x $rsi
$4 = 0xf7dbf9005655fb18
(gdb)

This is caused by

_dl_tlsdesc_dynamic:
        _CET_ENDBR
        /* Preserve call-clobbered registers that we modify.
           We need two scratch regs anyway.  */
        movq    %rsi, -16(%rsp)
        movq    %fs:DTV_OFFSET, %rsi

Since the dtv field in TCB is a pointer, %fs:DTV_OFFSET is a 32-bit
location, not 64-bit.  Load the dtv field to RSI_LP instead of rsi.
This fixes BZ #31184.

(cherry picked from commit 3502440397)
2023-12-23 06:06:26 -08:00
Szabolcs Nagy 0de9082ed8 elf: Add TLS modid reuse test for bug 29039
This is a minimal regression test for bug 29039 which only affects
targets with TLSDESC and a reproducer requires that

1) Have modid gaps (closed modules) with old generation.
2) Update a DTV to a newer generation (needs a newer dlopen).
3) But do not update the closed gap entry in that DTV.
4) Reuse the modid gap for a new module (another dlopen).
5) Use dynamic TLSDESC in that new module with old generation (bug).
6) Access TLS via this TLSDESC and the now outdated DTV.

However step (3) in practice rarely happens: during DTV update the
entries for closed modids are initialized to "unallocated" and then
dynamic TLSDESC calls __tls_get_addr independently of its generation.
The only exception to this is DTV setup at thread creation (gaps are
initialized to NULL instead of unallocated) or DTV resize where the
gap entries are outside the previous DTV array (again NULL instead
of unallocated, and this requires loading > DTV_SURPLUS modules).

So the bug can only cause NULL (+ offset) dereference, not use after
free. And the easiest way to get (3) is via thread creation.

Note that step (5) requires that the newly loaded module has larger
TLS than the remaining optional static TLS. And for (6) there cannot
be other TLS access or dlopen in the thread that updates the DTV.

Tested on aarch64-linux-gnu.

Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
(cherry picked from commit 980450f126)
2023-12-22 14:29:47 +00:00
Hector Martin ccdc4cba07 elf: Fix TLS modid reuse generation assignment (BZ 29039)
_dl_assign_tls_modid() assigns a slotinfo entry for a new module, but
does *not* do anything to the generation counter. The first time this
happens, the generation is zero and map_generation() returns the current
generation to be used during relocation processing. However, if
a slotinfo entry is later reused, it will already have a generation
assigned. If this generation has fallen behind the current global max
generation, then this causes an obsolete generation to be assigned
during relocation processing, as map_generation() returns this
generation if nonzero. _dl_add_to_slotinfo() eventually resets the
generation, but by then it is too late. This causes DTV updates to be
skipped, leading to NULL or broken TLS slot pointers and segfaults.

Fix this by resetting the generation to zero in _dl_assign_tls_modid(),
so it behaves the same as the first time a slot is assigned.
_dl_add_to_slotinfo() will still assign the correct static generation
later during module load, but relocation processing will no longer use
an obsolete generation.

Note that slotinfo entry (aka modid) reuse typically happens after a
dlclose and only TLS access via dynamic tlsdesc is affected. Because
tlsdesc is optimized to use the optional part of static TLS, dynamic
tlsdesc can be avoided by increasing the glibc.rtld.optional_static_tls
tunable to a large enough value, or by LD_PRELOAD-ing the affected
modules.

Fixes bug 29039.

Reviewed-by: Szabolcs Nagy <szabolcs.nagy@arm.com>
(cherry picked from commit 3921c5b40f)
2023-12-22 14:27:26 +00:00
caiyinyu 44f757a636 LoongArch: Delete excessively allocated memory.
Backported from glibc 2.39 development.
2023-12-10 15:09:59 +08:00
Adhemerval Zanella bf5aa419cb elf: Fix wrong break removal from 8ee878592c
Reported-by: Alexander Monakov <amonakov@ispras.ru>
(cherry picked from commit 546a1ba664)
2023-12-07 11:20:44 -03:00
Sergio Durigan Junior 63dbbc5c52 sysdeps: sem_open: Clear O_CREAT when semaphore file is expected to exist [BZ #30789]
When invoking sem_open with O_CREAT as one of its flags, we'll end up
in the second part of sem_open's "if ((oflag & O_CREAT) == 0 || (oflag
& O_EXCL) == 0)", which means that we don't expect the semaphore file
to exist.

In that part, open_flags is initialized as "O_RDWR | O_CREAT | O_EXCL
| O_CLOEXEC" and there's an attempt to open(2) the file, which will
likely fail because it won't exist.  After that first (expected)
failure, some cleanup is done and we go back to the label "try_again",
which lives in the first part of the aforementioned "if".

The problem is that, in that part of the code, we expect the semaphore
file to exist, and as such O_CREAT (this time the flag we pass to
open(2)) needs to be cleaned from open_flags, otherwise we'll see
another failure (this time unexpected) when trying to open the file,
which will lead the call to sem_open to fail as well.

This can cause very strange bugs, especially with OpenMPI, which makes
extensive use of semaphores.

Fix the bug by simplifying the logic when choosing open(2) flags and
making sure O_CREAT is not set when the semaphore file is expected to
exist.

A regression test for this issue would require a complex and cpu time
consuming logic, since to trigger the wrong code path is not
straightforward due the racy condition.  There is a somewhat reliable
reproducer in the bug, but it requires using OpenMPI.

This resolves BZ #30789.

See also: https://bugs.launchpad.net/ubuntu/+source/h5py/+bug/2031912

Signed-off-by: Sergio Durigan Junior <sergiodj@sergiodj.net>
Co-Authored-By: Simon Chopin <simon.chopin@canonical.com>
Co-Authored-By: Adhemerval Zanella Netto <adhemerval.zanella@linaro.org>
Fixes: 533deafbdf ("Use O_CLOEXEC in more places (BZ #15722)")
(cherry picked from commit f957f47df7)
2023-11-25 21:46:18 +01:00
Florian Weimer 1e04dcec49 Revert "elf: Move l_init_called_next to old place of l_text_end in link map"
This reverts commit d3ba6c1333.

Reason: Preserve internal ABI.
2023-10-19 09:17:38 +02:00
Florian Weimer 719866ab2f Revert "elf: Always call destructors in reverse constructor order (bug 30785)"
This reverts commit a3189f66a5.

Reason for revert: Incompatibility with existing applications.
2023-10-18 14:25:46 +02:00
Florian Weimer e0b6c9706c Revert "elf: Remove unused l_text_end field from struct link_map"
This reverts commit 750f19526a.

Reason for revert: Restore ABI after revert of commit a3189f66a5.
2023-10-18 14:22:59 +02:00
Siddhesh Poyarekar 750a45a783 tunables: Terminate if end of input is reached (CVE-2023-4911)
The string parsing routine may end up writing beyond bounds of tunestr
if the input tunable string is malformed, of the form name=name=val.
This gets processed twice, first as name=name=val and next as name=val,
resulting in tunestr being name=name=val:name=val, thus overflowing
tunestr.

Terminate the parsing loop at the first instance itself so that tunestr
does not overflow.

This also fixes up tst-env-setuid-tunables to actually handle failures
correct and add new tests to validate the fix for this CVE.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 1056e5b4c3)
2023-10-02 15:37:20 -04:00
Siddhesh Poyarekar 73e3fcd1a5 Propagate GLIBC_TUNABLES in setxid binaries
GLIBC_TUNABLES scrubbing happens earlier than envvar scrubbing and some
tunables are required to propagate past setxid boundary, like their
env_alias.  Rely on tunable scrubbing to clean out GLIBC_TUNABLES like
before, restoring behaviour in glibc 2.37 and earlier.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 0d5f9ea97f)
2023-10-02 15:37:16 -04:00
Siddhesh Poyarekar f6445dc94d Document CVE-2023-4806 and CVE-2023-5156 in NEWS
These are tracked in BZ #30884 and BZ #30843.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit fd134feba3)
2023-09-26 10:15:46 -04:00
Romain Geissler 5ee59ca371 Fix leak in getaddrinfo introduced by the fix for CVE-2023-4806 [BZ #30843]
This patch fixes a very recently added leak in getaddrinfo.

This was assigned CVE-2023-5156.

Resolves: BZ #30884
Related: BZ #30842

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit ec6b95c330)
2023-09-26 10:14:37 -04:00
Mark Wielaard 0e1ef6779a manual/jobs.texi: Add missing @item EPERM for getpgid
The missing @item makes it look like errno will be set to ESRCH
if a cross-session getpgid is not permitted.

Found by ulfvonbelow on irc.

(cherry picked from commit 5a21cefd5a)
2023-09-15 23:57:43 +02:00
Mahesh Bodapati d94461bb86 string: Fix tester build with fortify enable with gcc < 12
When building with fortify enabled, GCC < 12 issues a warning on the
fortify strncat wrapper might overflow the destination buffer (the
failure is tied to -Werror).

Checked on ppc64 and x86_64.
Reviewed-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>

(cherry picked from commit f1c7ed0859)
2023-09-15 23:56:26 +02:00
Andreas Schwab 63250e9c57 iconv: restore verbosity with unrecognized encoding names (bug 30694)
Commit 91927b7c76 ("Rewrite iconv option parsing [BZ #19519]") changed the
iconv program to call __gconv_open directly instead of the iconv_open
wrapper, but the former does not set errno.  Update the caller to
interpret the return codes like iconv_open does.

(cherry picked from commit fc72b6d7d8)
2023-09-15 23:55:01 +02:00
Siddhesh Poyarekar 00ae4f10b5 getaddrinfo: Fix use after free in getcanonname (CVE-2023-4806)
When an NSS plugin only implements the _gethostbyname2_r and
_getcanonname_r callbacks, getaddrinfo could use memory that was freed
during tmpbuf resizing, through h_name in a previous query response.

The backing store for res->at->name when doing a query with
gethostbyname3_r or gethostbyname2_r is tmpbuf, which is reallocated in
gethosts during the query.  For AF_INET6 lookup with AI_ALL |
AI_V4MAPPED, gethosts gets called twice, once for a v6 lookup and second
for a v4 lookup.  In this case, if the first call reallocates tmpbuf
enough number of times, resulting in a malloc, th->h_name (that
res->at->name refers to) ends up on a heap allocated storage in tmpbuf.
Now if the second call to gethosts also causes the plugin callback to
return NSS_STATUS_TRYAGAIN, tmpbuf will get freed, resulting in a UAF
reference in res->at->name.  This then gets dereferenced in the
getcanonname_r plugin call, resulting in the use after free.

Fix this by copying h_name over and freeing it at the end.  This
resolves BZ #30843, which is assigned CVE-2023-4806.

Signed-off-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 973fe93a56)
2023-09-15 14:41:36 -04:00
Florian Weimer b25508dd77 CVE-2023-4527: Stack read overflow with large TCP responses in no-aaaa mode
Without passing alt_dns_packet_buffer, __res_context_search can only
store 2048 bytes (what fits into dns_packet_buffer).  However,
the function returns the total packet size, and the subsequent
DNS parsing code in _nss_dns_gethostbyname4_r reads beyond the end
of the stack-allocated buffer.

Fixes commit f282cdbe7f ("resolv: Implement no-aaaa
stub resolver option") and bug 30842.

(cherry picked from commit bd77dd7e73)
2023-09-13 14:13:36 +02:00
Florian Weimer 89da8bc588 NEWS: Add the 2.38.1 bug list 2023-09-11 10:06:15 +02:00
Florian Weimer d3ba6c1333 elf: Move l_init_called_next to old place of l_text_end in link map
This preserves all member offsets and the GLIBC_PRIVATE ABI
for backporting.
2023-09-11 09:29:51 +02:00
Florian Weimer 750f19526a elf: Remove unused l_text_end field from struct link_map
It is a left-over from commit 52a01100ad
("elf: Remove ad-hoc restrictions on dlopen callers [BZ #22787]").

When backporting commmit 6985865bc3
("elf: Always call destructors in reverse constructor order
(bug 30785)"), we can move the l_init_called_next field to this
place, so that the internal GLIBC_PRIVATE ABI does not change.

Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Tested-by: Carlos O'Donell <carlos@redhat.com>
(cherry picked from commit 53df2ce688)
2023-09-11 09:29:51 +02:00
Florian Weimer a3189f66a5 elf: Always call destructors in reverse constructor order (bug 30785)
The current implementation of dlclose (and process exit) re-sorts the
link maps before calling ELF destructors.  Destructor order is not the
reverse of the constructor order as a result: The second sort takes
relocation dependencies into account, and other differences can result
from ambiguous inputs, such as cycles.  (The force_first handling in
_dl_sort_maps is not effective for dlclose.)  After the changes in
this commit, there is still a required difference due to
dlopen/dlclose ordering by the application, but the previous
discrepancies went beyond that.

A new global (namespace-spanning) list of link maps,
_dl_init_called_list, is updated right before ELF constructors are
called from _dl_init.

In dl_close_worker, the maps variable, an on-stack variable length
array, is eliminated.  (VLAs are problematic, and dlclose should not
call malloc because it cannot readily deal with malloc failure.)
Marking still-used objects uses the namespace list directly, with
next and next_idx replacing the done_index variable.

After marking, _dl_init_called_list is used to call the destructors
of now-unused maps in reverse destructor order.  These destructors
can call dlopen.  Previously, new objects do not have l_map_used set.
This had to change: There is no copy of the link map list anymore,
so processing would cover newly opened (and unmarked) mappings,
unloading them.  Now, _dl_init (indirectly) sets l_map_used, too.
(dlclose is handled by the existing reentrancy guard.)

After _dl_init_called_list traversal, two more loops follow.  The
processing order changes to the original link map order in the
namespace.  Previously, dependency order was used.  The difference
should not matter because relocation dependencies could already
reorder link maps in the old code.

The changes to _dl_fini remove the sorting step and replace it with
a traversal of _dl_init_called_list.  The l_direct_opencount
decrement outside the loader lock is removed because it appears
incorrect: the counter manipulation could race with other dynamic
loader operations.

tst-audit23 needs adjustments to the changes in LA_ACT_DELETE
notifications.  The new approach for checking la_activity should
make it clearer that la_activty calls come in pairs around namespace
updates.

The dependency sorting test cases need updates because the destructor
order is always the opposite order of constructor order, even with
relocation dependencies or cycles present.

There is a future cleanup opportunity to remove the now-constant
force_first and for_fini arguments from the _dl_sort_maps function.

Fixes commit 1df71d32fe ("elf: Implement
force_first handling in _dl_sort_maps_dfs (bug 28937)").

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 6985865bc3)
2023-09-11 09:29:49 +02:00
Florian Weimer 7ae211a01b elf: Do not run constructors for proxy objects
Otherwise, the ld.so constructor runs for each audit namespace
and each dlmopen namespace.

(cherry picked from commit f6c8204fd7)
2023-09-11 09:15:40 +02:00
Adam Jackson 92201f16cb libio: Fix oversized __io_vtables
IO_VTABLES_LEN is the size of the struct array in bytes, not the number
of __IO_jump_t's in the array. Drops just under 384kb from .rodata on
LP64 machines.

Fixes: 3020f72618 ("libio: Remove the usage of __libc_IO_vtables")
Signed-off-by: Adam Jackson <ajax@redhat.com>
Reviewed-by: Florian Weimer <fweimer@redhat.com>
Tested-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 8cb69e0543)
2023-09-08 23:07:46 +02:00
Aurelien Jarno 5bdef6f27c io: Fix record locking contants for powerpc64 with __USE_FILE_OFFSET64
Commit 5f828ff824 ("io: Fix F_GETLK, F_SETLK, and F_SETLKW for
powerpc64") fixed an issue with the value of the lock constants on
powerpc64 when not using __USE_FILE_OFFSET64, but it ended-up also
changing the value when using __USE_FILE_OFFSET64 causing an API change.

Fix that by also checking that define, restoring the pre
4d0fe291ae commit values:

Default values:
- F_GETLK: 5
- F_SETLK: 6
- F_SETLKW: 7

With -D_FILE_OFFSET_BITS=64:
- F_GETLK: 12
- F_SETLK: 13
- F_SETLKW: 14

At the same time, it has been noticed that there was no test for io lock
with __USE_FILE_OFFSET64, so just add one.

Tested on x86_64-linux-gnu, i686-linux-gnu and
powerpc64le-unknown-linux-gnu.

Resolves: BZ #30804.
Co-authored-by: Adhemerval Zanella  <adhemerval.zanella@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
(cherry picked from commit 434bf72a94)
2023-09-07 22:45:43 +02:00
Sam James 1aed90c9c8 sysdeps: tst-bz21269: fix -Wreturn-type
Thanks to Andreas Schwab for reporting.

Fixes: 652b9fdb77
Signed-off-by: Sam James <sam@gentoo.org>
(cherry picked from commit 369f373057)
2023-08-24 13:17:10 +01:00
Sam James ad9b839953 sysdeps: tst-bz21269: handle ENOSYS & skip appropriately
SYS_modify_ldt requires CONFIG_MODIFY_LDT_SYSCALL to be set in the kernel, which
some distributions may disable for hardening. Check if that's the case (unset)
and mark the test as UNSUPPORTED if so.

Reviewed-by: DJ Delorie <dj@redhat.com>
Signed-off-by: Sam James <sam@gentoo.org>
(cherry picked from commit 652b9fdb77)
2023-08-24 13:17:10 +01:00
Sam James c8ecda6251 sysdeps: tst-bz21269: fix test parameter
All callers pass 1 or 0x11 anyway (same meaning according to man page),
but still.

Reviewed-by: DJ Delorie <dj@redhat.com>
Signed-off-by: Sam James <sam@gentoo.org>
(cherry picked from commit e0b712dd91)
2023-08-24 13:17:10 +01:00
Florian Weimer 2af141bda3 malloc: Remove bin scanning from memalign (bug 30723)
On the test workload (mpv --cache=yes with VP9 video decoding), the
bin scanning has a very poor success rate (less than 2%).  The tcache
scanning has about 50% success rate, so keep that.

Update comments in malloc/tst-memalign-2 to indicate the purpose
of the tests.  Even with the scanning removed, the additional
merging opportunities since commit 542b110585
("malloc: Enable merging of remainders in memalign (bug 30723)")
are sufficient to pass the existing large bins test.

Remove leftover variables from _int_free from refactoring in the
same commit.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 0dc7fc1cf0)
2023-08-22 16:33:35 +02:00
Florian Weimer 98c293c61f malloc: Enable merging of remainders in memalign (bug 30723)
Previously, calling _int_free from _int_memalign could put remainders
into the tcache or into fastbins, where they are invisible to the
low-level allocator.  This results in missed merge opportunities
because once these freed chunks become available to the low-level
allocator, further memalign allocations (even of the same size are)
likely obstructing merges.

Furthermore, during forwards merging in _int_memalign, do not
completely give up when the remainder is too small to serve as a
chunk on its own.  We can still give it back if it can be merged
with the following unused chunk.  This makes it more likely that
memalign calls in a loop achieve a compact memory layout,
independently of initial heap layout.

Drop some useless (unsigned long) casts along the way, and tweak
the style to more closely match GNU on changed lines.

Reviewed-by: DJ Delorie <dj@redhat.com>
(cherry picked from commit 542b110585)
2023-08-22 16:31:29 +02:00
Adhemerval Zanella 7ac405a74c i686: Fix build with --disable-multiarch
Since i686 provides the fortified wrappers for memcpy, mempcpy,
memmove, and memset on the same string implementation, the static
build tries to optimized it by not tying the fortified wrappers
to string routine (to avoid pulling the fortify function if
they are not required).

Checked on i686-linux-gnu building with different option:
default and --disable-multi-arch plus default, --disable-default-pie,
--enable-fortify-source={2,3}, and --enable-fortify-source={2,3}
with --disable-default-pie.
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

(cherry picked from commit c73c96a4a1)
2023-08-17 23:38:14 +02:00
Adhemerval Zanella 6135d50e44 x86_64: Fix build with --disable-multiarch (BZ 30721)
With multiarch disabled, the default memmove implementation provides
the fortify routines for memcpy, mempcpy, and memmove.  However, it
does not provide the internal hidden definitions used when building
with fortify enabled.  The memset has a similar issue.

Checked on x86_64-linux-gnu building with different options:
default and --disable-multi-arch plus default, --disable-default-pie,
--enable-fortify-source={2,3}, and --enable-fortify-source={2,3}
with --disable-default-pie.
Tested-by: Andreas K. Huettel <dilfridge@gentoo.org>
Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>

(cherry picked from commit 51cb52214f)
2023-08-17 23:37:28 +02:00
Noah Goldstein 5ea70cc026 x86: Fix incorrect scope of setting shared_per_thread [BZ# 30745]
The:

```
    if (shared_per_thread > 0 && threads > 0)
      shared_per_thread /= threads;
```

Code was accidentally moved to inside the else scope.  This doesn't
match how it was previously (before af992e7abd).

This patch fixes that by putting the division after the `else` block.

(cherry picked from commit 084fb31bc2)
2023-08-12 23:59:04 -05:00
Florian Weimer 6b99458d19 nscd: Do not rebuild getaddrinfo (bug 30709)
The nscd daemon caches hosts data from NSS modules verbatim, without
filtering protocol families or sorting them (otherwise separate caches
would be needed for certain ai_flags combinations).  The cache
implementation is complete separate from the getaddrinfo code.  This
means that rebuilding getaddrinfo is not needed.  The only function
actually used is __bump_nl_timestamp from check_pf.c, and this change
moves it into nscd/connections.c.

Tested on x86_64-linux-gnu with -fexceptions, built with
build-many-glibcs.py.  I also backported this patch into a distribution
that still supports nscd and verified manually that caching still works.

Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
(cherry picked from commit 039ff51ac7)
2023-08-11 10:55:10 +02:00
Sajan Karumanchi ced101ed9d x86: Fix for cache computation on AMD legacy cpus.
Some legacy AMD CPUs and hypervisors have the _cpuid_ '0x8000_001D'
set to Zero, thus resulting in zeroed-out computed cache values.
This patch reintroduces the old way of cache computation as a
fail-safe option to handle these exceptions.
Fixed 'level4_cache_size' value through handle_amd().

Reviewed-by: Premachandra Mallappa <premachandra.mallappa@amd.com>
Tested-by: Florian Weimer <fweimer@redhat.com>
2023-08-06 19:18:44 +05:30
Florian Weimer d97cca1e5d stdlib: Improve tst-realpath compatibility with source fortification
On GCC before 11, IPA can make the fortified realpath aware that the
buffer size is not large enough (8 bytes instead of PATH_MAX bytes).
Fix this by using a buffer that is large enough.

(cherry picked from commit 510fc20d73)
2023-08-06 18:13:38 +02:00
505 changed files with 10240 additions and 4815 deletions
+6 -10
View File
@@ -141,17 +141,13 @@ if CFLAGS is specified it must enable optimization. For example:
indirect branch tracking (IBT) and shadow stack (SHSTK). When CET
is enabled, the GNU C Library is compatible with all existing
executables and shared libraries. This feature is currently
supported on i386, x86_64 and x32 with GCC 8 and binutils 2.29 or
later. Note that when CET is enabled, the GNU C Library requires
CPUs capable of multi-byte NOPs, like x86-64 processors as well as
Intel Pentium Pro or newer. With --enable-cet, it is an error to
dlopen a non CET enabled shared library in CET enabled application.
With --enable-cet=permissive, CET is disabled when dlopening a
non CET enabled shared library in CET enabled application.
supported on x86_64 and x32 with GCC 8 and binutils 2.29 or later.
With --enable-cet, it is an error to dlopen a non CET enabled
shared library in CET enabled application. With
--enable-cet=permissive, CET is disabled when dlopening a non CET
enabled shared library in CET enabled application.
NOTE: --enable-cet has been tested for i686, x86_64 and x32 on
non-CET processors. --enable-cet has been tested for i686,
x86_64 and x32 on CET processors.
NOTE: --enable-cet is only supported on x86_64 and x32.
--enable-memory-tagging
Enable memory tagging support if the architecture supports it.
+27 -3
View File
@@ -360,6 +360,8 @@ whole-archive = -Wl,--whole-archive
# Installed name of the startup code.
# The ELF convention is that the startfile is called crt1.o
start-installed-name = crt1.o
# Similar to crt1.o, but without _IO_stdin_used.
start-name-2.0 = crt1-2.0.o
# On systems that do not need a special startfile for statically linked
# binaries, simply set it to the normal name.
ifndef static-start-installed-name
@@ -537,6 +539,25 @@ else # build-static
endif # build-shared
endif # +link
# Command for linking test programs with crt1.o from glibc 2.0.
+link-2.0-before-inputs = -nostdlib -nostartfiles $(no-pie-ldflag) \
$(sysdep-LDFLAGS) $(LDFLAGS) $(LDFLAGS-$(@F)) \
$(relro-LDFLAGS) $(hashstyle-LDFLAGS) \
$(firstword $(CRT-$(@F)) $(csu-objpfx)$(start-name-2.0)) \
$(+preinit) $(+prector)
+link-2.0-before-libc = -o $@ $(+link-2.0-before-inputs) \
$(filter-out $(addprefix $(csu-objpfx),start.o \
$(start-name-2.0))\
$(+preinit) $(link-extra-libs) \
$(common-objpfx)libc% $(+postinit),$^) \
$(link-extra-libs)
+link-after-libc = $(+postctor) $(+postinit)
define +link-2.0-tests
$(CC) $(+link-2.0-before-libc) $(rtld-tests-LDFLAGS) $(link-libc-tests) \
$(+link-after-libc)
$(call after-link,$@)
endef
# The pretty printer test programs need to be compiled without optimizations
# so they won't confuse gdb. We could use either the 'GCC optimize' pragma
# or the 'optimize' function attribute to achieve this; however, at least on
@@ -586,10 +607,13 @@ link-libc-rpath-link = -Wl,-rpath-link=$(rpath-link)
# before the expansion of LDLIBS-* variables).
# Tests use -Wl,-rpath instead of -Wl,-rpath-link for
# build-hardcoded-path-in-tests.
# build-hardcoded-path-in-tests. Add -Wl,--disable-new-dtags to force
# DT_RPATH instead of DT_RUNPATH which only applies to DT_NEEDED entries
# in the executable and doesn't applies to DT_NEEDED entries in shared
# libraries which are loaded via DT_NEEDED entries in the executable.
ifeq (yes,$(build-hardcoded-path-in-tests))
link-libc-tests-rpath-link = $(link-libc-rpath)
link-test-modules-rpath-link = $(link-libc-rpath)
link-libc-tests-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
link-test-modules-rpath-link = $(link-libc-rpath) -Wl,--disable-new-dtags
else
link-libc-tests-rpath-link = $(link-libc-rpath-link)
link-test-modules-rpath-link =
-2
View File
@@ -1122,8 +1122,6 @@ $(inst_includedir)/%.h: $(common-objpfx)%.h $(+force)
$(do-install)
$(inst_includedir)/%.h: %.h $(+force)
$(do-install)
$(inst_includedir)/%.h: $(..)include/%.h $(+force)
$(do-install)
headers-nonh := $(filter-out %.h,$(headers))
ifdef headers-nonh
$(addprefix $(inst_includedir)/,$(headers-nonh)): $(inst_includedir)/%: \
+79
View File
@@ -5,6 +5,85 @@ See the end for copying conditions.
Please send GNU C library bug reports via <https://sourceware.org/bugzilla/>
using `glibc' in the "product" field.
Version 2.38.1
* Sync with Linux kernel 6.6 shadow stack interface. The --enable-cet
configure option in only supported on x86-64.
The following bugs are resolved with this release:
[32810] Crash on x86-64 if XSAVEC disable via tunable
Deprecated and removed features, and other changes affecting compatibility:
* __rseq_size now denotes the size of the active rseq area (20 bytes
initially), not the size of struct rseq (32 bytes initially).
Security related changes:
CVE-2023-4527: If the system is configured in no-aaaa mode via
/etc/resolv.conf, getaddrinfo is called for the AF_UNSPEC address
family, and a DNS response is received over TCP that is larger than
2048 bytes, getaddrinfo may potentially disclose stack contents via
the returned address data, or crash.
CVE-2023-4806: When an NSS plugin only implements the
_gethostbyname2_r and _getcanonname_r callbacks, getaddrinfo could use
memory that was freed during buffer resizing, potentially causing a
crash or read or write to arbitrary memory.
CVE-2023-5156: The fix for CVE-2023-4806 introduced a memory leak when
an application calls getaddrinfo for AF_INET6 with AI_CANONNAME,
AI_ALL and AI_V4MAPPED flags set.
CVE-2023-4911: If a tunable of the form NAME=NAME=VAL is passed in the
environment of a setuid program and NAME is valid, it may result in a
buffer overflow, which could be exploited to achieve escalated
privileges. This flaw was introduced in glibc 2.34.
CVE-2025-0395: When the assert() function fails, it does not allocate
enough space for the assertion failure message string and size
information, which may lead to a buffer overflow if the message string
size aligns to page size.
GLIBC-SA-2026-0003
wordexp with WRDE_REUSE and WRDE_APPEND may return uninitialized
memory (CVE-2025-15281)
The following bugs are resolved with this release:
[27821] ungetc: Fix backup buffer leak on program exit
[29039] Corrupt DTV after reuse of a TLS module ID following dlclose with unused TLS
[30081] resolv: Do not wait for non-existing second DNS response after error
[30694] The iconv program no longer tells the user which given encoding name was wrong
[30709] nscd fails to build with cleanup handler if built with -fexceptions
[30721] x86_64: Fix build with --disable-multiarch
[30723] posix_memalign repeatedly scans long bin lists
[30745] Slight bug in cache info codes for x86
[30789] sem_open will fail on multithreaded scenarios when semaphore
file doesn't exist (O_CREAT)
[30804] F_GETLK, F_SETLK, and F_SETLKW value change for powerpc64 with
-D_FILE_OFFSET_BITS=64
[30842] Stack read overflow in getaddrinfo in no-aaaa mode (CVE-2023-4527)
[30843] potential use-after-free in getcanonname (CVE-2023-4806)
[31183] Wide stream buffer size reduced MB_LEN_MAX bytes after bug 17522 fix
[31184] FAIL: elf/tst-tlsgap
[31185] Incorrect thread point access in _dl_tlsdesc_undefweak and _dl_tlsdesc_dynamic
[31476] resolv: Track single-request fallback via _res._flags
[31890] resolv: Allow short error responses to match any DNS query
[31943] _dl_find_object can fail if ld.so contains gaps between load segments
[31965] rseq extension mechanism does not work as intended
[31968] mremap implementation in C does not handle arguments correctly
[32052] Name space violation in fortify wrappers
[32137] libio: Attempt wide backup free only for non-legacy code
[32231] elf: Change ldconfig auxcache magic number
[32470] x86: Avoid integer truncation with large cache sizes
[32582] Fix underallocation of abort_msg_s struct (CVE-2025-0395)
[32987] elf: Fix subprocess status handling for tst-dlopen-sgid
[33185] Fix double-free after allocation failure in regcomp
[33814] glob: wordexp with WRDE_REUSE and WRDE_APPEND may return
uninitialized memory
Version 2.38
Major new features:
+12 -1
View File
@@ -188,6 +188,7 @@ binaries-all = $(binaries-all-notests) $(binaries-all-tests)
binaries-static-notests = $(others-static)
binaries-static-tests = $(tests-static) $(xtests-static)
binaries-static = $(binaries-static-notests) $(binaries-static-tests)
binaries-shared-2.0-tests = $(tests-2.0)
ifeq (yesyes,$(have-fpie)$(build-shared))
binaries-pie-tests = $(tests-pie) $(xtests-pie)
binaries-pie-notests = $(others-pie)
@@ -215,7 +216,8 @@ binaries-malloc-hugetlb2-tests =
endif
binaries-pie = $(binaries-pie-tests) $(binaries-pie-notests)
binaries-shared-tests = $(filter-out $(binaries-pie) $(binaries-static), \
binaries-shared-tests = $(filter-out $(binaries-pie) $(binaries-static) \
$(binaries-shared-2.0-tests), \
$(binaries-all-tests))
binaries-shared-notests = $(filter-out $(binaries-pie) $(binaries-static), \
$(binaries-all-notests))
@@ -235,6 +237,15 @@ $(addprefix $(objpfx),$(binaries-shared-tests)): %: %.o \
$(+link-tests)
endif
# Linking test programs with crt1.o from glibc 2.0.
ifneq "$(strip $(binaries-shared-2.0-tests))" ""
$(addprefix $(objpfx),$(binaries-shared-2.0-tests)): %: %.o \
$(link-extra-libs-tests) \
$(sort $(filter $(common-objpfx)lib%,$(link-libc))) \
$(addprefix $(csu-objpfx),start.o) $(+preinit) $(+postinit)
$(+link-2.0-tests)
endif
ifneq "$(strip $(binaries-mcheck-tests))" ""
$(addprefix $(objpfx),$(binaries-mcheck-tests)): %-mcheck: %.o \
$(link-extra-libs-tests) \
+1
View File
@@ -38,6 +38,7 @@ tests := \
test-assert-perr \
tst-assert-c++ \
tst-assert-g++ \
tst-assert-sa-2025-0001 \
# tests
ifeq ($(have-cxx-thread_local),yes)
+3 -1
View File
@@ -18,6 +18,7 @@
#include <assert.h>
#include <atomic.h>
#include <ldsodefs.h>
#include <libc-pointer-arith.h>
#include <libintl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -64,7 +65,8 @@ __assert_fail_base (const char *fmt, const char *assertion, const char *file,
(void) __fxprintf (NULL, "%s", str);
(void) fflush (stderr);
total = (total + 1 + GLRO(dl_pagesize) - 1) & ~(GLRO(dl_pagesize) - 1);
total = ALIGN_UP (total + sizeof (struct abort_msg_s) + 1,
GLRO(dl_pagesize));
struct abort_msg_s *buf = __mmap (NULL, total, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_PRIVATE, -1, 0);
if (__glibc_likely (buf != MAP_FAILED))
+92
View File
@@ -0,0 +1,92 @@
/* Test for CVE-2025-0395.
Copyright The GNU Toolchain Authors.
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
<https://www.gnu.org/licenses/>. */
/* Test that a large enough __progname does not result in a buffer overflow
when printing an assertion failure. This was CVE-2025-0395. */
#include <assert.h>
#include <inttypes.h>
#include <signal.h>
#include <stdbool.h>
#include <string.h>
#include <sys/mman.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xstdio.h>
#include <support/xunistd.h>
extern const char *__progname;
int
do_test (int argc, char **argv)
{
support_need_proc ("Reads /proc/self/maps to add guards to writable maps.");
ignore_stderr ();
/* XXX assumes that the assert is on a 2 digit line number. */
const char *prompt = ": %s:99: do_test: Assertion `argc < 1' failed.\n";
int ret = fprintf (stderr, prompt, __FILE__);
if (ret < 0)
FAIL_EXIT1 ("fprintf failed: %m\n");
size_t pagesize = getpagesize ();
size_t namesize = pagesize - 1 - ret;
/* Alter the progname so that the assert message fills the entire page. */
char progname[namesize];
memset (progname, 'A', namesize - 1);
progname[namesize - 1] = '\0';
__progname = progname;
FILE *f = xfopen ("/proc/self/maps", "r");
char *line = NULL;
size_t len = 0;
uintptr_t prev_to = 0;
/* Pad the beginning of every writable mapping with a PROT_NONE map. This
ensures that the mmap in the assert_fail path never ends up below a
writable map and will terminate immediately in case of a buffer
overflow. */
while (xgetline (&line, &len, f))
{
uintptr_t from, to;
char perm[4];
sscanf (line, "%" SCNxPTR "-%" SCNxPTR " %c%c%c%c ",
&from, &to,
&perm[0], &perm[1], &perm[2], &perm[3]);
bool writable = (memchr (perm, 'w', 4) != NULL);
if (prev_to != 0 && from - prev_to > pagesize && writable)
xmmap ((void *) from - pagesize, pagesize, PROT_NONE,
MAP_ANONYMOUS | MAP_PRIVATE, 0);
prev_to = to;
}
xfclose (f);
assert (argc < 1);
return 0;
}
#define EXPECTED_SIGNAL SIGABRT
#define TEST_FUNCTION_ARGV do_test
#include <support/test-driver.c>
+4 -2
View File
@@ -21,7 +21,9 @@
#define __WORDSIZE32_PTRDIFF_LONG
/* Set to 1 in order to force time types to be 32 bits instead of 64 bits in
struct lastlog and struct utmp{,x} on 64-bit ports. This may be done in
struct lastlog and struct utmp{,x}. This may be done in
order to make 64-bit ports compatible with 32-bit ports. Set to 0 for
64-bit ports where the time types are 64-bits or for any 32-bit ports. */
64-bit ports where the time types are 64-bits and new 32-bit ports
where time_t is 64 bits, and there is no companion architecture with
32-bit time_t. */
#define __WORDSIZE_TIME64_COMPAT32
Vendored
+35
View File
@@ -4896,6 +4896,9 @@ libc_config_ok=no
# whether to use such directories.
with_fp_cond=1
# A preconfigure script may define another name to traditional TLS variant
mtls_traditional=gnu
if frags=`ls -d $srcdir/sysdeps/*/preconfigure 2> /dev/null`
then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for sysdeps preconfigure fragments" >&5
@@ -7175,6 +7178,38 @@ printf "%s\n" "$libc_cv_mtls_dialect_gnu2" >&6; }
config_vars="$config_vars
have-mtls-dialect-gnu2 = $libc_cv_mtls_dialect_gnu2"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for traditional tls support" >&5
printf %s "checking for traditional tls support... " >&6; }
if test ${libc_cv_test_mtls_traditional+y}
then :
printf %s "(cached) " >&6
else $as_nop
cat > conftest.c <<EOF
__thread int i;
void foo (void)
{
i = 10;
}
EOF
if { ac_try='${CC-cc} $CFLAGS $CPPFLAGS -fPIC -mtls-dialect=$mtls_traditional -nostdlib -nostartfiles
-shared conftest.c -o conftest 1>&5'
{ { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
(eval $ac_try) 2>&5
ac_status=$?
printf "%s\n" "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
test $ac_status = 0; }; }
then
libc_cv_test_mtls_traditional=$mtls_traditional
else
libc_cv_test_mtls_traditional=no
fi
rm -f conftest*
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $libc_cv_test_mtls_traditional" >&5
printf "%s\n" "$libc_cv_test_mtls_traditional" >&6; }
config_vars="$config_vars
have-test-mtls-traditional = $libc_cv_test_mtls_traditional"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if -Wno-ignored-attributes is required for aliases" >&5
printf %s "checking if -Wno-ignored-attributes is required for aliases... " >&6; }
if test ${libc_cv_wno_ignored_attributes+y}
+25
View File
@@ -517,6 +517,9 @@ libc_config_ok=no
# whether to use such directories.
with_fp_cond=1
# A preconfigure script may define another name to traditional TLS variant
mtls_traditional=gnu
dnl Let sysdeps/*/preconfigure act here.
LIBC_PRECONFIGURE([$srcdir], [for sysdeps])
@@ -1382,6 +1385,28 @@ rm -f conftest*])
AC_SUBST(libc_cv_mtls_dialect_gnu2)
LIBC_CONFIG_VAR([have-mtls-dialect-gnu2], [$libc_cv_mtls_dialect_gnu2])
dnl Check if CC supports traditional tls.
AC_CACHE_CHECK([for traditional tls support],
libc_cv_test_mtls_traditional,
[dnl
cat > conftest.c <<EOF
__thread int i;
void foo (void)
{
i = 10;
}
EOF
if AC_TRY_COMMAND([${CC-cc} $CFLAGS $CPPFLAGS -fPIC -mtls-dialect=$mtls_traditional -nostdlib -nostartfiles
-shared conftest.c -o conftest 1>&AS_MESSAGE_LOG_FD])
then
libc_cv_test_mtls_traditional=$mtls_traditional
else
libc_cv_test_mtls_traditional=no
fi
rm -f conftest*])
LIBC_CONFIG_VAR([have-test-mtls-traditional],
[$libc_cv_test_mtls_traditional])
dnl clang emits an warning for a double alias redirection, to warn the
dnl original symbol is sed even when weak definition overrides it.
dnl It is a usual pattern for weak_alias, where multiple alias point to
+4 -1
View File
@@ -33,7 +33,7 @@ elide-routines.os = libc-tls
csu-dummies = $(filter-out $(start-installed-name),crt1.o Mcrt1.o)
extra-objs = start.o \
$(start-installed-name) g$(start-installed-name) $(csu-dummies) \
S$(start-installed-name)
S$(start-installed-name) $(start-name-2.0)
omit-deps = $(patsubst %.o,%,$(start-installed-name) g$(start-installed-name) \
b$(start-installed-name) $(csu-dummies) \
S$(start-installed-name) \
@@ -138,6 +138,9 @@ ifndef start-installed-name-rule
$(objpfx)$(start-installed-name): $(objpfx)start.o $(objpfx)abi-note.o \
$(objpfx)init.o $(objpfx)static-reloc.o
$(link-relocatable)
$(objpfx)$(start-name-2.0): $(objpfx)start.o $(objpfx)abi-note.o \
$(objpfx)static-reloc.o
$(link-relocatable)
$(objpfx)r$(start-installed-name): $(objpfx)start.o $(objpfx)abi-note.o \
$(objpfx)init.o
$(link-relocatable)
+1
View File
@@ -283,6 +283,7 @@ tests = \
tst-backtrace6 \
tst-longjmp_chk \
tst-longjmp_chk2 \
tst-longjmp_chk3 \
tst-realpath-chk \
tst-sprintf-fortify-unchecked \
# tests
+1 -1
View File
@@ -19,7 +19,7 @@
#define STRCPY_RESULT(dst, len) ((dst) + (len))
#define TEST_MAIN
#define TEST_NAME "stpcpy_chk"
#include "../string/test-string.h"
#include <string/test-string.h>
extern void __attribute__ ((noreturn)) __chk_fail (void);
char *simple_stpcpy_chk (char *, const char *, size_t);
+1 -1
View File
@@ -20,7 +20,7 @@
# define STRCPY_RESULT(dst, len) dst
# define TEST_MAIN
# define TEST_NAME "strcpy_chk"
# include "../string/test-string.h"
# include <string/test-string.h>
/* This test case implicitly tests the availability of the __chk_fail
symbol, which is part of the public ABI and may be used
+29 -26
View File
@@ -23,6 +23,7 @@
#include <assert.h>
#include <fcntl.h>
#include <limits.h>
#include <locale.h>
#include <obstack.h>
#include <setjmp.h>
@@ -36,6 +37,10 @@
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <paths.h>
#include <support/temp_file.h>
#include <support/support.h>
#ifndef _GNU_SOURCE
# define MEMPCPY memcpy
@@ -52,15 +57,10 @@
#define obstack_chunk_alloc malloc
#define obstack_chunk_free free
char *temp_filename;
static void do_prepare (void);
static int do_test (void);
#define PREPARE(argc, argv) do_prepare ()
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
static char *temp_filename;
static void
do_prepare (void)
do_prepare (int argc, char *argv[])
{
int temp_fd = create_temp_file ("tst-chk1.", &temp_filename);
if (temp_fd == -1)
@@ -77,10 +77,11 @@ do_prepare (void)
exit (1);
}
}
#define PREPARE do_prepare
volatile int chk_fail_ok;
volatile int ret;
jmp_buf chk_fail_buf;
static volatile int chk_fail_ok;
static volatile int ret;
static jmp_buf chk_fail_buf;
static void
handler (int sig)
@@ -102,22 +103,22 @@ wchar_t wbuf[10];
#define buf_size sizeof (buf)
#endif
volatile size_t l0;
volatile char *p;
volatile wchar_t *wp;
const char *str1 = "JIHGFEDCBA";
const char *str2 = "F";
const char *str3 = "%s%n%s%n";
const char *str4 = "Hello, ";
const char *str5 = "World!\n";
const wchar_t *wstr1 = L"JIHGFEDCBA";
const wchar_t *wstr2 = L"F";
const wchar_t *wstr3 = L"%s%n%s%n";
const wchar_t *wstr4 = L"Hello, ";
const wchar_t *wstr5 = L"World!\n";
char buf2[10] = "%s";
int num1 = 67;
int num2 = 987654;
static volatile size_t l0;
static volatile char *p;
static volatile wchar_t *wp;
static const char *str1 = "JIHGFEDCBA";
static const char *str2 = "F";
static const char *str3 = "%s%n%s%n";
static const char *str4 = "Hello, ";
static const char *str5 = "World!\n";
static const wchar_t *wstr1 = L"JIHGFEDCBA";
static const wchar_t *wstr2 = L"F";
static const wchar_t *wstr3 = L"%s%n%s%n";
static const wchar_t *wstr4 = L"Hello, ";
static const wchar_t *wstr5 = L"World!\n";
static char buf2[10] = "%s";
static int num1 = 67;
static int num2 = 987654;
#define FAIL() \
do { printf ("Failure on line %d\n", __LINE__); ret = 1; } while (0)
@@ -1815,3 +1816,5 @@ do_test (void)
return ret;
}
#include <support/test-driver.c>
+3 -5
View File
@@ -10,11 +10,7 @@
#include <stdlib.h>
#include <unistd.h>
static int do_test(void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include <support/support.h>
static jmp_buf b;
@@ -76,3 +72,5 @@ do_test (void)
puts ("second longjmp returned");
return 1;
}
#include <support/test-driver.c>
+3 -3
View File
@@ -10,9 +10,7 @@
#include <sys/resource.h>
#include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include <support/support.h>
static jmp_buf mainloop;
static sigset_t mainsigset;
@@ -126,3 +124,5 @@ do_test (void)
return 0;
}
#include <support/test-driver.c>
+11 -7
View File
@@ -18,13 +18,13 @@
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
static int do_test (void);
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"
#include <support/support.h>
static char buf[SIGSTKSZ * 4];
static char *buf;
static jmp_buf jb;
static void
@@ -53,8 +53,10 @@ do_test (void)
set_fortify_handler (handler);
/* Create a valid signal stack and enable it. */
size_t bufsize = SIGSTKSZ * 4;
buf = xmalloc (bufsize);
ss.ss_sp = buf;
ss.ss_size = sizeof (buf);
ss.ss_size = bufsize;
ss.ss_flags = 0;
if (sigaltstack (&ss, NULL) < 0)
{
@@ -69,8 +71,8 @@ do_test (void)
/* Shrink the signal stack so the jmpbuf is now invalid.
We adjust the start & end to handle stacks that grow up & down. */
ss.ss_sp = buf + sizeof (buf) / 2;
ss.ss_size = sizeof (buf) / 4;
ss.ss_sp = buf + bufsize / 2;
ss.ss_size = bufsize / 4;
if (sigaltstack (&ss, NULL) < 0)
{
printf ("second sigaltstack failed: %m\n");
@@ -83,3 +85,5 @@ do_test (void)
puts ("longjmp returned and shouldn't");
return 1;
}
#include <support/test-driver.c>
+79
View File
@@ -166,6 +166,7 @@ CFLAGS-.op += $(call elide-stack-protector,.op,$(elide-routines.os))
CFLAGS-.os += $(call elide-stack-protector,.os,$(all-rtld-routines))
# Add the requested compiler flags to the early startup code.
CFLAGS-dl-misc.os += $(rtld-early-cflags)
CFLAGS-dl-printf.os += $(rtld-early-cflags)
CFLAGS-dl-setup_hash.os += $(rtld-early-cflags)
CFLAGS-dl-sysdep.os += $(rtld-early-cflags)
@@ -261,6 +262,7 @@ tests-static-normal := \
tst-array1-static \
tst-array5-static \
tst-dl-iter-static \
tst-dlopen-sgid \
tst-dst-static \
tst-env-setuid \
tst-env-setuid-tunables \
@@ -417,6 +419,7 @@ tests += \
tst-glibc-hwcaps-prepend \
tst-global1 \
tst-global2 \
tst-gnu2-tls2 \
tst-initfinilazyfail \
tst-initorder \
tst-initorder2 \
@@ -431,6 +434,7 @@ tests += \
tst-p_align1 \
tst-p_align2 \
tst-p_align3 \
tst-recursive-tls \
tst-relsort1 \
tst-ro-dynamic \
tst-rtld-run-static \
@@ -457,8 +461,10 @@ tests += \
tst-tls19 \
tst-tls20 \
tst-tls21 \
tst-tls23 \
tst-tlsalign \
tst-tlsalign-extern \
tst-tlsgap \
tst-unique1 \
tst-unique2 \
tst-unwind-ctor \
@@ -493,6 +499,8 @@ tests-internal += \
tst-dl_find_object \
tst-dl_find_object-threads \
tst-dlmopen2 \
tst-link-map-contiguous-ldso \
tst-link-map-contiguous-libc \
tst-ptrguard1 \
tst-stackguard1 \
tst-tls-surplus \
@@ -504,6 +512,10 @@ tests-internal += \
unload2 \
# tests-internal
ifeq ($(build-hardcoded-path-in-tests),yes)
tests-internal += tst-link-map-contiguous-main
endif
tests-container += \
tst-dlopen-self-container \
tst-dlopen-tlsmodid-container \
@@ -824,6 +836,7 @@ modules-names += \
tst-dlmopen-twice-mod1 \
tst-dlmopen-twice-mod2 \
tst-dlmopen1mod \
tst-dlopen-sgid-mod \
tst-dlopenfaillinkmod \
tst-dlopenfailmod1 \
tst-dlopenfailmod2 \
@@ -835,6 +848,9 @@ modules-names += \
tst-filterobj-flt \
tst-finilazyfailmod \
tst-globalmod2 \
tst-gnu2-tls2mod0 \
tst-gnu2-tls2mod1 \
tst-gnu2-tls2mod2 \
tst-initlazyfailmod \
tst-initorder2a \
tst-initorder2b \
@@ -858,6 +874,23 @@ modules-names += \
tst-null-argv-lib \
tst-p_alignmod-base \
tst-p_alignmod3 \
tst-recursive-tlsmallocmod \
tst-recursive-tlsmod0 \
tst-recursive-tlsmod1 \
tst-recursive-tlsmod2 \
tst-recursive-tlsmod3 \
tst-recursive-tlsmod4 \
tst-recursive-tlsmod5 \
tst-recursive-tlsmod6 \
tst-recursive-tlsmod7 \
tst-recursive-tlsmod8 \
tst-recursive-tlsmod9 \
tst-recursive-tlsmod10 \
tst-recursive-tlsmod11 \
tst-recursive-tlsmod12 \
tst-recursive-tlsmod13 \
tst-recursive-tlsmod14 \
tst-recursive-tlsmod15 \
tst-relsort1mod1 \
tst-relsort1mod2 \
tst-ro-dynamic-mod \
@@ -882,7 +915,11 @@ modules-names += \
tst-tls19mod3 \
tst-tls20mod-bad \
tst-tls21mod \
tst-tls23-mod \
tst-tlsalign-lib \
tst-tlsgap-mod0 \
tst-tlsgap-mod1 \
tst-tlsgap-mod2 \
tst-tlsmod1 \
tst-tlsmod10 \
tst-tlsmod11 \
@@ -3009,3 +3046,45 @@ LDFLAGS-tst-dlclose-lazy-mod1.so = -Wl,-z,lazy,--no-as-needed
$(objpfx)tst-dlclose-lazy-mod1.so: $(objpfx)tst-dlclose-lazy-mod2.so
$(objpfx)tst-dlclose-lazy.out: \
$(objpfx)tst-dlclose-lazy-mod1.so $(objpfx)tst-dlclose-lazy-mod2.so
$(objpfx)tst-tlsgap: $(shared-thread-library)
$(objpfx)tst-tlsgap.out: \
$(objpfx)tst-tlsgap-mod0.so \
$(objpfx)tst-tlsgap-mod1.so \
$(objpfx)tst-tlsgap-mod2.so
$(objpfx)tst-gnu2-tls2: $(shared-thread-library)
$(objpfx)tst-gnu2-tls2.out: \
$(objpfx)tst-gnu2-tls2mod0.so \
$(objpfx)tst-gnu2-tls2mod1.so \
$(objpfx)tst-gnu2-tls2mod2.so
ifeq (yes,$(have-mtls-dialect-gnu2))
# This test fails if dl_tlsdesc_dynamic doesn't preserve all caller-saved
# registers. See https://sourceware.org/bugzilla/show_bug.cgi?id=31372
test-xfail-tst-gnu2-tls2 = yes
CFLAGS-tst-tlsgap-mod0.c += -mtls-dialect=gnu2
CFLAGS-tst-tlsgap-mod1.c += -mtls-dialect=gnu2
CFLAGS-tst-tlsgap-mod2.c += -mtls-dialect=gnu2
CFLAGS-tst-gnu2-tls2mod0.c += -mtls-dialect=gnu2
CFLAGS-tst-gnu2-tls2mod1.c += -mtls-dialect=gnu2
CFLAGS-tst-gnu2-tls2mod2.c += -mtls-dialect=gnu2
endif
$(objpfx)tst-tls23: $(shared-thread-library)
$(objpfx)tst-tls23.out: $(objpfx)tst-tls23-mod.so
ifneq (no,$(have-test-mtls-traditional))
CFLAGS-tst-tls23-mod.c += -mtls-dialect=$(have-test-mtls-traditional)
endif
$(objpfx)tst-recursive-tls: $(objpfx)tst-recursive-tlsmallocmod.so
# More objects than DTV_SURPLUS, to trigger DTV reallocation.
$(objpfx)tst-recursive-tls.out: \
$(patsubst %,$(objpfx)tst-recursive-tlsmod%.so, \
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15)
$(objpfx)tst-recursive-tlsmod%.os: tst-recursive-tlsmodN.c
$(compile-command.c) -DVAR=thread_$* -DFUNC=get_threadvar_$*
$(objpfx)tst-dlopen-sgid.out: $(objpfx)tst-dlopen-sgid-mod.so
+1 -1
View File
@@ -823,7 +823,7 @@ struct aux_cache_entry
struct aux_cache_entry *next;
};
#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-1.0"
#define AUX_CACHEMAGIC "glibc-ld.so.auxcache-2.0"
struct aux_cache_file_entry
{
+1 -1
View File
@@ -703,7 +703,7 @@ _dl_close_worker (struct link_map *map, bool force)
if (__glibc_unlikely (newgen == 0))
_dl_fatal_printf ("TLS generation counter wrapped! Please report as described in "REPORT_BUGS_TO".\n");
/* Can be read concurrently. */
atomic_store_relaxed (&GL(dl_tls_generation), newgen);
atomic_store_release (&GL(dl_tls_generation), newgen);
if (tls_free_end == GL(dl_tls_static_used))
GL(dl_tls_static_used) = tls_free_start;
+49 -29
View File
@@ -465,6 +465,37 @@ _dl_find_object (void *pc1, struct dl_find_object *result)
}
rtld_hidden_def (_dl_find_object)
/* Subroutine of _dlfo_process_initial to split out noncontigous link
maps. NODELETE is the number of used _dlfo_nodelete_mappings
elements. It is incremented as needed, and the new NODELETE value
is returned. */
static size_t
_dlfo_process_initial_noncontiguous_map (struct link_map *map,
size_t nodelete)
{
struct dl_find_object_internal dlfo;
_dl_find_object_from_map (map, &dlfo);
/* PT_LOAD segments for a non-contiguous link map are added to the
non-closeable mappings. */
const ElfW(Phdr) *ph = map->l_phdr;
const ElfW(Phdr) *ph_end = map->l_phdr + map->l_phnum;
for (; ph < ph_end; ++ph)
if (ph->p_type == PT_LOAD)
{
if (_dlfo_nodelete_mappings != NULL)
{
/* Second pass only. */
_dlfo_nodelete_mappings[nodelete] = dlfo;
ElfW(Addr) start = ph->p_vaddr + map->l_addr;
_dlfo_nodelete_mappings[nodelete].map_start = start;
_dlfo_nodelete_mappings[nodelete].map_end = start + ph->p_memsz;
}
++nodelete;
}
return nodelete;
}
/* _dlfo_process_initial is called twice. First to compute the array
sizes from the initial loaded mappings. Second to fill in the
bases and infos arrays with the (still unsorted) data. Returns the
@@ -476,29 +507,8 @@ _dlfo_process_initial (void)
size_t nodelete = 0;
if (!main_map->l_contiguous)
{
struct dl_find_object_internal dlfo;
_dl_find_object_from_map (main_map, &dlfo);
/* PT_LOAD segments for a non-contiguous are added to the
non-closeable mappings. */
for (const ElfW(Phdr) *ph = main_map->l_phdr,
*ph_end = main_map->l_phdr + main_map->l_phnum;
ph < ph_end; ++ph)
if (ph->p_type == PT_LOAD)
{
if (_dlfo_nodelete_mappings != NULL)
{
/* Second pass only. */
_dlfo_nodelete_mappings[nodelete] = dlfo;
_dlfo_nodelete_mappings[nodelete].map_start
= ph->p_vaddr + main_map->l_addr;
_dlfo_nodelete_mappings[nodelete].map_end
= _dlfo_nodelete_mappings[nodelete].map_start + ph->p_memsz;
}
++nodelete;
}
}
/* Contiguous case already handled in _dl_find_object_init. */
nodelete = _dlfo_process_initial_noncontiguous_map (main_map, nodelete);
size_t loaded = 0;
for (Lmid_t ns = 0; ns < GL(dl_nns); ++ns)
@@ -510,11 +520,22 @@ _dlfo_process_initial (void)
/* lt_library link maps are implicitly NODELETE. */
if (l->l_type == lt_library || l->l_nodelete_active)
{
if (_dlfo_nodelete_mappings != NULL)
/* Second pass only. */
_dl_find_object_from_map
(l, _dlfo_nodelete_mappings + nodelete);
++nodelete;
/* The kernel may have loaded ld.so with gaps. */
if (!l->l_contiguous
#ifdef SHARED
&& l == &GL(dl_rtld_map)
#endif
)
nodelete
= _dlfo_process_initial_noncontiguous_map (l, nodelete);
else
{
if (_dlfo_nodelete_mappings != NULL)
/* Second pass only. */
_dl_find_object_from_map
(l, _dlfo_nodelete_mappings + nodelete);
++nodelete;
}
}
else if (l->l_type == lt_loaded)
{
@@ -756,7 +777,6 @@ _dl_find_object_update_1 (struct link_map **loaded, size_t count)
/* Prefer newly loaded link map. */
assert (loaded_index1 > 0);
_dl_find_object_from_map (loaded[loaded_index1 - 1], dlfo);
loaded[loaded_index1 - 1]->l_find_object_processed = 1;
--loaded_index1;
}
+3 -1
View File
@@ -87,7 +87,7 @@ _dl_find_object_to_external (struct dl_find_object_internal *internal,
}
/* Extract the object location data from a link map and writes it to
*RESULT using relaxed MO stores. */
*RESULT using relaxed MO stores. Set L->l_find_object_processed. */
static void __attribute__ ((unused))
_dl_find_object_from_map (struct link_map *l,
struct dl_find_object_internal *result)
@@ -100,6 +100,8 @@ _dl_find_object_from_map (struct link_map *l,
atomic_store_relaxed (&result->eh_dbase, (void *) l->l_info[DT_PLTGOT]);
#endif
l->l_find_object_processed = 1;
for (const ElfW(Phdr) *ph = l->l_phdr, *ph_end = l->l_phdr + l->l_phnum;
ph < ph_end; ++ph)
if (ph->p_type == DLFO_EH_SEGMENT_TYPE)
+6 -2
View File
@@ -25,10 +25,14 @@
static void
call_init (struct link_map *l, int argc, char **argv, char **env)
{
/* Do not run constructors for proxy objects. */
if (l != l->l_real)
return;
/* If the object has not been relocated, this is a bug. The
function pointers are invalid in this case. (Executables do not
need relocation, and neither do proxy objects.) */
assert (l->l_real->l_relocated || l->l_real->l_type == lt_executable);
need relocation.) */
assert (l->l_relocated || l->l_type == lt_executable);
if (l->l_init_called)
/* This object is all done. */
+4 -4
View File
@@ -405,7 +405,7 @@ update_tls_slotinfo (struct link_map *new)
_dl_fatal_printf (N_("\
TLS generation counter wrapped! Please report this."));
/* Can be read concurrently. */
atomic_store_relaxed (&GL(dl_tls_generation), newgen);
atomic_store_release (&GL(dl_tls_generation), newgen);
/* We need a second pass for static tls data, because
_dl_update_slotinfo must not be run while calls to
@@ -422,8 +422,8 @@ TLS generation counter wrapped! Please report this."));
now, but we can delay updating the DTV. */
imap->l_need_tls_init = 0;
#ifdef SHARED
/* Update the slot information data for at least the
generation of the DSO we are allocating data for. */
/* Update the slot information data for the current
generation. */
/* FIXME: This can terminate the process on memory
allocation failure. It is not possible to raise
@@ -431,7 +431,7 @@ TLS generation counter wrapped! Please report this."));
_dl_update_slotinfo would have to be split into two
operations, similar to resize_scopes and update_scopes
above. This is related to bug 16134. */
_dl_update_slotinfo (imap->l_tls_modid);
_dl_update_slotinfo (imap->l_tls_modid, newgen);
#endif
dl_init_static_tls (imap);
+3 -3
View File
@@ -112,11 +112,11 @@ _dl_try_allocate_static_tls (struct link_map *map, bool optional)
if (map->l_real->l_relocated)
{
#ifdef SHARED
/* Update the DTV of the current thread. Note: GL(dl_load_tls_lock)
is held here so normal load of the generation counter is valid. */
if (__builtin_expect (THREAD_DTV()[0].counter != GL(dl_tls_generation),
0))
/* Update the slot information data for at least the generation of
the DSO we are allocating data for. */
(void) _dl_update_slotinfo (map->l_tls_modid);
(void) _dl_update_slotinfo (map->l_tls_modid, GL(dl_tls_generation));
#endif
dl_init_static_tls (map);
+16 -16
View File
@@ -276,8 +276,6 @@ _dl_non_dynamic_init (void)
_dl_main_map.l_phdr = GL(dl_phdr);
_dl_main_map.l_phnum = GL(dl_phnum);
_dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
/* Set up the data structures for the system-supplied DSO early,
so they can influence _dl_init_paths. */
setup_vdso (NULL, NULL);
@@ -285,6 +283,22 @@ _dl_non_dynamic_init (void)
/* With vDSO setup we can initialize the function pointers. */
setup_vdso_pointers ();
if (__libc_enable_secure)
{
static const char unsecure_envvars[] =
UNSECURE_ENVVARS
;
const char *cp = unsecure_envvars;
while (cp < unsecure_envvars + sizeof (unsecure_envvars))
{
__unsetenv (cp);
cp = strchr (cp, '\0') + 1;
}
}
_dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1;
/* Initialize the data structures for the search paths for shared
objects. */
_dl_init_paths (getenv ("LD_LIBRARY_PATH"), "LD_LIBRARY_PATH",
@@ -306,20 +320,6 @@ _dl_non_dynamic_init (void)
_dl_profile_output
= &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0];
if (__libc_enable_secure)
{
static const char unsecure_envvars[] =
UNSECURE_ENVVARS
;
const char *cp = unsecure_envvars;
while (cp < unsecure_envvars + sizeof (unsecure_envvars))
{
__unsetenv (cp);
cp = strchr (cp, '\0') + 1;
}
}
#ifdef DL_PLATFORM_INIT
DL_PLATFORM_INIT;
#endif
+152 -60
View File
@@ -75,6 +75,31 @@
/* Default for dl_tls_static_optional. */
#define OPTIONAL_TLS 512
/* Used to count the number of threads currently executing dynamic TLS
updates. Used to avoid recursive malloc calls in __tls_get_addr
for an interposed malloc that uses global-dynamic TLS (which is not
recommended); see _dl_tls_allocate_active checks. This could be a
per-thread flag, but would need TLS access in the dynamic linker. */
unsigned int _dl_tls_threads_in_update;
static inline void
_dl_tls_allocate_begin (void)
{
atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, 1);
}
static inline void
_dl_tls_allocate_end (void)
{
atomic_fetch_add_relaxed (&_dl_tls_threads_in_update, -1);
}
static inline bool
_dl_tls_allocate_active (void)
{
return atomic_load_relaxed (&_dl_tls_threads_in_update) > 0;
}
/* Compute the static TLS surplus based on the namespace count and the
TLS space that can be used for optimizations. */
static inline int
@@ -154,6 +179,7 @@ _dl_assign_tls_modid (struct link_map *l)
{
/* Mark the entry as used, so any dependency see it. */
atomic_store_relaxed (&runp->slotinfo[result - disp].map, l);
atomic_store_relaxed (&runp->slotinfo[result - disp].gen, 0);
break;
}
@@ -424,12 +450,18 @@ _dl_allocate_tls_storage (void)
size += TLS_PRE_TCB_SIZE;
#endif
/* Perform the allocation. Reserve space for the required alignment
and the pointer to the original allocation. */
/* Reserve space for the required alignment and the pointer to the
original allocation. */
size_t alignment = GLRO (dl_tls_static_align);
/* Perform the allocation. */
_dl_tls_allocate_begin ();
void *allocated = malloc (size + alignment + sizeof (void *));
if (__glibc_unlikely (allocated == NULL))
return NULL;
{
_dl_tls_allocate_end ();
return NULL;
}
/* Perform alignment and allocate the DTV. */
#if TLS_TCB_AT_TP
@@ -465,6 +497,8 @@ _dl_allocate_tls_storage (void)
result = allocate_dtv (result);
if (result == NULL)
free (allocated);
_dl_tls_allocate_end ();
return result;
}
@@ -482,6 +516,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
size_t newsize = max_modid + DTV_SURPLUS;
size_t oldsize = dtv[-1].counter;
_dl_tls_allocate_begin ();
if (dtv == GL(dl_initial_dtv))
{
/* This is the initial dtv that was either statically allocated in
@@ -501,6 +536,7 @@ _dl_resize_dtv (dtv_t *dtv, size_t max_modid)
if (newp == NULL)
oom ();
}
_dl_tls_allocate_end ();
newp[0].counter = newsize;
@@ -675,7 +711,9 @@ allocate_dtv_entry (size_t alignment, size_t size)
if (powerof2 (alignment) && alignment <= _Alignof (max_align_t))
{
/* The alignment is supported by malloc. */
_dl_tls_allocate_begin ();
void *ptr = malloc (size);
_dl_tls_allocate_end ();
return (struct dtv_pointer) { ptr, ptr };
}
@@ -687,7 +725,10 @@ allocate_dtv_entry (size_t alignment, size_t size)
/* Perform the allocation. This is the pointer we need to free
later. */
_dl_tls_allocate_begin ();
void *start = malloc (alloc_size);
_dl_tls_allocate_end ();
if (start == NULL)
return (struct dtv_pointer) {};
@@ -715,57 +756,57 @@ allocate_and_init (struct link_map *map)
struct link_map *
_dl_update_slotinfo (unsigned long int req_modid)
_dl_update_slotinfo (unsigned long int req_modid, size_t new_gen)
{
struct link_map *the_map = NULL;
dtv_t *dtv = THREAD_DTV ();
/* The global dl_tls_dtv_slotinfo array contains for each module
index the generation counter current when the entry was created.
/* CONCURRENCY NOTES:
The global dl_tls_dtv_slotinfo_list array contains for each module
index the generation counter current when that entry was updated.
This array never shrinks so that all module indices which were
valid at some time can be used to access it. Before the first
use of a new module index in this function the array was extended
appropriately. Access also does not have to be guarded against
modifications of the array. It is assumed that pointer-size
values can be read atomically even in SMP environments. It is
possible that other threads at the same time dynamically load
code and therefore add to the slotinfo list. This is a problem
since we must not pick up any information about incomplete work.
The solution to this is to ignore all dtv slots which were
created after the one we are currently interested. We know that
dynamic loading for this module is completed and this is the last
load operation we know finished. */
unsigned long int idx = req_modid;
valid at some time can be used to access it. Concurrent loading
and unloading of modules can update slotinfo entries or extend
the array. The updates happen under the GL(dl_load_tls_lock) and
finish with the release store of the generation counter to
GL(dl_tls_generation) which is synchronized with the load of
new_gen in the caller. So updates up to new_gen are synchronized
but updates for later generations may not be.
Here we update the thread dtv from old_gen (== dtv[0].counter) to
new_gen generation. For this, each dtv[i] entry is either set to
an unallocated state (set), or left unmodified (nop). Where (set)
may resize the dtv first if modid i >= dtv[-1].counter. The rules
for the decision between (set) and (nop) are
(1) If slotinfo entry i is concurrently updated then either (set)
or (nop) is valid: TLS access cannot use dtv[i] unless it is
synchronized with a generation > new_gen.
Otherwise, if the generation of slotinfo entry i is gen and the
loaded module for this entry is map then
(2) If gen <= old_gen then do (nop).
(3) If old_gen < gen <= new_gen then
(3.1) if map != 0 then (set)
(3.2) if map == 0 then either (set) or (nop).
Note that (1) cannot be reliably detected, but since both actions
are valid it does not have to be. Only (2) and (3.1) cases need
to be distinguished for which relaxed mo access of gen and map is
enough: their value is synchronized when it matters.
Note that a relaxed mo load may give an out-of-thin-air value since
it is used in decisions that can affect concurrent stores. But this
should only happen if the OOTA value causes UB that justifies the
concurrent store of the value. This is not expected to be an issue
in practice. */
struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
while (idx >= listp->len)
if (dtv[0].counter < new_gen)
{
idx -= listp->len;
listp = listp->next;
}
if (dtv[0].counter < listp->slotinfo[idx].gen)
{
/* CONCURRENCY NOTES:
Here the dtv needs to be updated to new_gen generation count.
This code may be called during TLS access when GL(dl_load_tls_lock)
is not held. In that case the user code has to synchronize with
dlopen and dlclose calls of relevant modules. A module m is
relevant if the generation of m <= new_gen and dlclose of m is
synchronized: a memory access here happens after the dlopen and
before the dlclose of relevant modules. The dtv entries for
relevant modules need to be updated, other entries can be
arbitrary.
This e.g. means that the first part of the slotinfo list can be
accessed race free, but the tail may be concurrently extended.
Similarly relevant slotinfo entries can be read race free, but
other entries are racy. However updating a non-relevant dtv
entry does not affect correctness. For a relevant module m,
max_modid >= modid of m. */
size_t new_gen = listp->slotinfo[idx].gen;
size_t total = 0;
size_t max_modid = atomic_load_relaxed (&GL(dl_tls_max_dtv_idx));
assert (max_modid >= req_modid);
@@ -778,31 +819,33 @@ _dl_update_slotinfo (unsigned long int req_modid)
{
size_t modid = total + cnt;
/* Later entries are not relevant. */
/* Case (1) for all later modids. */
if (modid > max_modid)
break;
size_t gen = atomic_load_relaxed (&listp->slotinfo[cnt].gen);
/* Case (1). */
if (gen > new_gen)
/* Not relevant. */
continue;
/* If the entry is older than the current dtv layout we
know we don't have to handle it. */
/* Case (2) or (1). */
if (gen <= dtv[0].counter)
continue;
/* Case (3) or (1). */
/* If there is no map this means the entry is empty. */
struct link_map *map
= atomic_load_relaxed (&listp->slotinfo[cnt].map);
/* Check whether the current dtv array is large enough. */
if (dtv[-1].counter < modid)
{
/* Case (3.2) or (1). */
if (map == NULL)
continue;
/* Resize the dtv. */
/* Resizing the dtv aborts on failure: bug 16134. */
dtv = _dl_resize_dtv (dtv, max_modid);
assert (modid <= dtv[-1].counter);
@@ -813,10 +856,21 @@ _dl_update_slotinfo (unsigned long int req_modid)
}
/* If there is currently memory allocate for this
dtv entry free it. */
dtv entry free it. Note: this is not AS-safe. */
/* XXX Ideally we will at some point create a memory
pool. */
free (dtv[modid].pointer.to_free);
/* Avoid calling free on a null pointer. Some mallocs
incorrectly use dynamic TLS, and depending on how the
free function was compiled, it could call
__tls_get_addr before the null pointer check in the
free implementation. Checking here papers over at
least some dynamic TLS usage by interposed mallocs. */
if (dtv[modid].pointer.to_free != NULL)
{
_dl_tls_allocate_begin ();
free (dtv[modid].pointer.to_free);
_dl_tls_allocate_end ();
}
dtv[modid].pointer.val = TLS_DTV_UNALLOCATED;
dtv[modid].pointer.to_free = NULL;
@@ -908,9 +962,9 @@ tls_get_addr_tail (GET_ADDR_ARGS, dtv_t *dtv, struct link_map *the_map)
static struct link_map *
__attribute_noinline__
update_get_addr (GET_ADDR_ARGS)
update_get_addr (GET_ADDR_ARGS, size_t gen)
{
struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE);
struct link_map *the_map = _dl_update_slotinfo (GET_ADDR_MODULE, gen);
dtv_t *dtv = THREAD_DTV ();
void *p = dtv[GET_ADDR_MODULE].pointer.val;
@@ -940,12 +994,29 @@ __tls_get_addr (GET_ADDR_ARGS)
dtv_t *dtv = THREAD_DTV ();
/* Update is needed if dtv[0].counter < the generation of the accessed
module. The global generation counter is used here as it is easier
to check. Synchronization for the relaxed MO access is guaranteed
by user code, see CONCURRENCY NOTES in _dl_update_slotinfo. */
module, but the global generation counter is easier to check (which
must be synchronized up to the generation of the accessed module by
user code doing the TLS access so relaxed mo read is enough). */
size_t gen = atomic_load_relaxed (&GL(dl_tls_generation));
if (__glibc_unlikely (dtv[0].counter != gen))
return update_get_addr (GET_ADDR_PARAM);
{
if (_dl_tls_allocate_active ()
&& GET_ADDR_MODULE < _dl_tls_initial_modid_limit)
/* This is a reentrant __tls_get_addr call, but we can
satisfy it because it's an initially-loaded module ID.
These TLS slotinfo slots do not change, so the
out-of-date generation counter does not matter. However,
if not in a TLS update, still update_get_addr below, to
get off the slow path eventually. */
;
else
{
/* Update DTV up to the global generation, see CONCURRENCY NOTES
in _dl_update_slotinfo. */
gen = atomic_load_acquire (&GL(dl_tls_generation));
return update_get_addr (GET_ADDR_PARAM, gen);
}
}
void *p = dtv[GET_ADDR_MODULE].pointer.val;
@@ -954,7 +1025,7 @@ __tls_get_addr (GET_ADDR_ARGS)
return (char *) p + GET_ADDR_OFFSET;
}
#endif
#endif /* SHARED */
/* Look up the module's TLS block as for __tls_get_addr,
@@ -1003,6 +1074,25 @@ _dl_tls_get_addr_soft (struct link_map *l)
return data;
}
size_t _dl_tls_initial_modid_limit;
void
_dl_tls_initial_modid_limit_setup (void)
{
struct dtv_slotinfo_list *listp = GL(dl_tls_dtv_slotinfo_list);
size_t idx;
for (idx = 0; idx < listp->len; ++idx)
{
struct link_map *l = listp->slotinfo[idx].map;
if (l == NULL
/* The object can be unloaded, so its modid can be
reassociated. */
|| !(l->l_type == lt_executable || l->l_type == lt_library))
break;
}
_dl_tls_initial_modid_limit = idx;
}
void
_dl_add_to_slotinfo (struct link_map *l, bool do_add)
@@ -1035,9 +1125,11 @@ _dl_add_to_slotinfo (struct link_map *l, bool do_add)
the first slot. */
assert (idx == 0);
_dl_tls_allocate_begin ();
listp = (struct dtv_slotinfo_list *)
malloc (sizeof (struct dtv_slotinfo_list)
+ TLS_SLOTINFO_SURPLUS * sizeof (struct dtv_slotinfo));
_dl_tls_allocate_end ();
if (listp == NULL)
{
/* We ran out of memory while resizing the dtv slotinfo list. */
+10 -7
View File
@@ -180,11 +180,7 @@ parse_tunables (char *tunestr, char *valstring)
/* If we reach the end of the string before getting a valid name-value
pair, bail out. */
if (p[len] == '\0')
{
if (__libc_enable_secure)
tunestr[off] = '\0';
return;
}
break;
/* We did not find a valid name-value pair before encountering the
colon. */
@@ -244,9 +240,16 @@ parse_tunables (char *tunestr, char *valstring)
}
}
if (p[len] != '\0')
p += len + 1;
/* We reached the end while processing the tunable string. */
if (p[len] == '\0')
break;
p += len + 1;
}
/* Terminate tunestr before we leave. */
if (__libc_enable_secure)
tunestr[off] = '\0';
}
/* Enable the glibc.malloc.check tunable in SETUID/SETGID programs only when
+1
View File
@@ -107,6 +107,7 @@ process_elf_file (const char *file_name, const char *lib, int *flag,
case PT_INTERP:
program_interpreter = (char *) (file_contents + segment->p_offset);
check_ptr (program_interpreter);
break;
case PT_GNU_PROPERTY:
/* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes
+57 -27
View File
@@ -789,6 +789,8 @@ init_tls (size_t naudit)
_dl_fatal_printf ("\
cannot allocate TLS data structures for initial thread\n");
_dl_tls_initial_modid_limit_setup ();
/* Store for detection of the special case by __tls_get_addr
so it knows not to pass this dtv to the normal realloc. */
GL(dl_initial_dtv) = GET_DTV (tcbp);
@@ -1288,6 +1290,60 @@ rtld_setup_main_map (struct link_map *main_map)
return has_interp;
}
/* Set up the program header information for the dynamic linker
itself. It can be accessed via _r_debug and dl_iterate_phdr
callbacks, and it is used by _dl_find_object. */
static void
rtld_setup_phdr (void)
{
/* Starting from binutils-2.23, the linker will define the magic
symbol __ehdr_start to point to our own ELF header if it is
visible in a segment that also includes the phdrs. */
const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
GL(dl_rtld_map).l_phdr = rtld_phdr;
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
GL(dl_rtld_map).l_contiguous = 1;
/* The linker may not have produced a contiguous object. The kernel
will load the object with actual gaps (unlike the glibc loader
for shared objects, which always produces a contiguous mapping).
See similar logic in rtld_setup_main_map above. */
{
ElfW(Addr) expected_load_address = 0;
for (const ElfW(Phdr) *ph = rtld_phdr; ph < &rtld_phdr[rtld_ehdr->e_phnum];
++ph)
if (ph->p_type == PT_LOAD)
{
ElfW(Addr) mapstart = ph->p_vaddr & ~(GLRO(dl_pagesize) - 1);
if (GL(dl_rtld_map).l_contiguous && expected_load_address != 0
&& expected_load_address != mapstart)
GL(dl_rtld_map).l_contiguous = 0;
ElfW(Addr) allocend = ph->p_vaddr + ph->p_memsz;
/* The next expected address is the page following this load
segment. */
expected_load_address = ((allocend + GLRO(dl_pagesize) - 1)
& ~(GLRO(dl_pagesize) - 1));
}
}
/* PT_GNU_RELRO is usually the last phdr. */
size_t cnt = rtld_ehdr->e_phnum;
while (cnt-- > 0)
if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
{
GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
break;
}
}
/* Adjusts the contents of the stack and related globals for the user
entry point. The ld.so processed skip_args arguments and bumped
_dl_argv and _dl_argc accordingly. Those arguments are removed from
@@ -1753,33 +1809,7 @@ dl_main (const ElfW(Phdr) *phdr,
++GL(dl_ns)[LM_ID_BASE]._ns_nloaded;
++GL(dl_load_adds);
/* Starting from binutils-2.23, the linker will define the magic symbol
__ehdr_start to point to our own ELF header if it is visible in a
segment that also includes the phdrs. If that's not available, we use
the old method that assumes the beginning of the file is part of the
lowest-addressed PT_LOAD segment. */
/* Set up the program header information for the dynamic linker
itself. It is needed in the dl_iterate_phdr callbacks. */
const ElfW(Ehdr) *rtld_ehdr = &__ehdr_start;
assert (rtld_ehdr->e_ehsize == sizeof *rtld_ehdr);
assert (rtld_ehdr->e_phentsize == sizeof (ElfW(Phdr)));
const ElfW(Phdr) *rtld_phdr = (const void *) rtld_ehdr + rtld_ehdr->e_phoff;
GL(dl_rtld_map).l_phdr = rtld_phdr;
GL(dl_rtld_map).l_phnum = rtld_ehdr->e_phnum;
/* PT_GNU_RELRO is usually the last phdr. */
size_t cnt = rtld_ehdr->e_phnum;
while (cnt-- > 0)
if (rtld_phdr[cnt].p_type == PT_GNU_RELRO)
{
GL(dl_rtld_map).l_relro_addr = rtld_phdr[cnt].p_vaddr;
GL(dl_rtld_map).l_relro_size = rtld_phdr[cnt].p_memsz;
break;
}
rtld_setup_phdr ();
/* Add the dynamic linker to the TLS list if it also uses TLS. */
if (GL(dl_rtld_map).l_tls_blocksize != 0)
+1
View File
@@ -0,0 +1 @@
/* Opening this object should not succeed. */
+106
View File
@@ -0,0 +1,106 @@
/* Test case for ignored LD_LIBRARY_PATH in static startug (bug 32976).
Copyright (C) 2025 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
<https://www.gnu.org/licenses/>. */
#include <dlfcn.h>
#include <gnu/lib-names.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <support/capture_subprocess.h>
#include <support/check.h>
#include <support/support.h>
#include <support/temp_file.h>
#include <support/test-driver.h>
#include <sys/wait.h>
#include <unistd.h>
/* This is the name of our test object. Use a custom module for
testing, so that this object does not get picked up from the system
path. */
static const char dso_name[] = "tst-dlopen-sgid-mod.so";
/* Used to mark the recursive invocation. */
static const char magic_argument[] = "run-actual-test";
static int
do_test (void)
{
/* Pathname of the directory that receives the shared objects this
test attempts to load. */
char *libdir = support_create_temp_directory ("tst-dlopen-sgid-");
/* This is supposed to be ignored and stripped. */
TEST_COMPARE (setenv ("LD_LIBRARY_PATH", libdir, 1), 0);
/* Copy of libc.so.6. */
{
char *from = xasprintf ("%s/%s", support_objdir_root, LIBC_SO);
char *to = xasprintf ("%s/%s", libdir, LIBC_SO);
add_temp_file (to);
support_copy_file (from, to);
free (to);
free (from);
}
/* Copy of the test object. */
{
char *from = xasprintf ("%s/elf/%s", support_objdir_root, dso_name);
char *to = xasprintf ("%s/%s", libdir, dso_name);
add_temp_file (to);
support_copy_file (from, to);
free (to);
free (from);
}
free (libdir);
support_capture_subprogram_self_sgid (magic_argument);
return 0;
}
static void
alternative_main (int argc, char **argv)
{
if (argc == 2 && strcmp (argv[1], magic_argument) == 0)
{
if (getgid () == getegid ())
/* This can happen if the file system is mounted nosuid. */
FAIL_UNSUPPORTED ("SGID failed: GID and EGID match (%jd)\n",
(intmax_t) getgid ());
/* Should be removed due to SGID. */
TEST_COMPARE_STRING (getenv ("LD_LIBRARY_PATH"), NULL);
TEST_VERIFY (dlopen (dso_name, RTLD_NOW) == NULL);
{
const char *message = dlerror ();
TEST_COMPARE_STRING (message,
"tst-dlopen-sgid-mod.so:"
" cannot open shared object file:"
" No such file or directory");
}
support_record_failure_barrier ();
exit (EXIT_SUCCESS);
}
}
#define PREPARE alternative_main
#include <support/test-driver.c>
+22 -15
View File
@@ -50,6 +50,8 @@ const char *teststrings[] =
"glibc.malloc.perturb=0x800:not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.not_valid.check=2:glibc.malloc.mmap_threshold=4096",
"not_valid.malloc.check=2:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
"glibc.malloc.check=2",
"glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096:glibc.malloc.check=2",
"glibc.malloc.check=4:glibc.malloc.garbage=2:glibc.maoc.mmap_threshold=4096",
":glibc.malloc.garbage=2:glibc.malloc.check=1",
@@ -68,6 +70,8 @@ const char *resultstrings[] =
"glibc.malloc.perturb=0x800:glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=4096",
"glibc.malloc.mmap_threshold=glibc.malloc.mmap_threshold=4096",
"",
"",
"",
"",
@@ -81,11 +85,18 @@ test_child (int off)
{
const char *val = getenv ("GLIBC_TUNABLES");
printf (" [%d] GLIBC_TUNABLES is %s\n", off, val);
fflush (stdout);
if (val != NULL && strcmp (val, resultstrings[off]) == 0)
return 0;
if (val != NULL)
printf ("[%d] Unexpected GLIBC_TUNABLES VALUE %s\n", off, val);
printf (" [%d] Unexpected GLIBC_TUNABLES VALUE %s, expected %s\n",
off, val, resultstrings[off]);
else
printf (" [%d] GLIBC_TUNABLES environment variable absent\n", off);
fflush (stdout);
return 1;
}
@@ -105,32 +116,28 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
exit (EXIT_SUCCESS);
return 0;
}
else
{
int ret = 0;
/* Spawn tests. */
for (int i = 0; i < array_length (teststrings); i++)
{
char buf[INT_BUFSIZE_BOUND (int)];
printf ("Spawned test for %s (%d)\n", teststrings[i], i);
printf ("[%d] Spawned test for %s\n", i, teststrings[i]);
snprintf (buf, sizeof (buf), "%d\n", i);
fflush (stdout);
if (setenv ("GLIBC_TUNABLES", teststrings[i], 1) != 0)
exit (1);
{
printf (" [%d] Failed to set GLIBC_TUNABLES: %m", i);
support_record_failure ();
continue;
}
int status = support_capture_subprogram_self_sgid (buf);
/* Bail out early if unsupported. */
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
ret |= status;
support_capture_subprogram_self_sgid (buf);
}
return ret;
return 0;
}
}
+2 -8
View File
@@ -104,20 +104,14 @@ do_test (int argc, char **argv)
if (ret != 0)
exit (1);
exit (EXIT_SUCCESS);
return 0;
}
else
{
if (test_parent () != 0)
exit (1);
int status = support_capture_subprogram_self_sgid (SETGID_CHILD);
if (WEXITSTATUS (status) == EXIT_UNSUPPORTED)
return EXIT_UNSUPPORTED;
if (!WIFEXITED (status))
FAIL_EXIT1 ("Unexpected exit status %d from child process\n", status);
support_capture_subprogram_self_sgid (SETGID_CHILD);
return 0;
}
+122
View File
@@ -0,0 +1,122 @@
/* Test TLSDESC relocation.
Copyright (C) 2024 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <pthread.h>
#include <support/xdlfcn.h>
#include <support/xthread.h>
#include <support/check.h>
#include <support/test-driver.h>
#include "tst-gnu2-tls2.h"
#ifndef IS_SUPPORTED
# define IS_SUPPORTED() true
#endif
/* An architecture can define it to clobber caller-saved registers in
malloc below to verify that the implicit TLSDESC call won't change
caller-saved registers. */
#ifndef PREPARE_MALLOC
# define PREPARE_MALLOC()
#endif
extern void * __libc_malloc (size_t);
size_t malloc_counter = 0;
void *
malloc (size_t n)
{
PREPARE_MALLOC ();
malloc_counter++;
return __libc_malloc (n);
}
static void *mod[3];
#ifndef MOD
# define MOD(i) "tst-gnu2-tls2mod" #i ".so"
#endif
static const char *modname[3] = { MOD(0), MOD(1), MOD(2) };
#undef MOD
static void
open_mod (int i)
{
mod[i] = xdlopen (modname[i], RTLD_LAZY);
printf ("open %s\n", modname[i]);
}
static void
close_mod (int i)
{
xdlclose (mod[i]);
mod[i] = NULL;
printf ("close %s\n", modname[i]);
}
static void
access_mod (int i, const char *sym)
{
struct tls var = { -1, -1, -1, -1 };
struct tls *(*f) (struct tls *) = xdlsym (mod[i], sym);
/* Check that our malloc is called. */
malloc_counter = 0;
struct tls *p = f (&var);
TEST_VERIFY (malloc_counter != 0);
printf ("access %s: %s() = %p\n", modname[i], sym, p);
TEST_VERIFY_EXIT (memcmp (p, &var, sizeof (var)) == 0);
++(p->a);
}
static void *
start (void *arg)
{
/* The DTV generation is at the last dlopen of mod0 and the
entry for mod1 is NULL. */
open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS. */
/* Force the slow path in GNU2 TLS descriptor call. */
access_mod (1, "apply_tls");
return arg;
}
static int
do_test (void)
{
if (!IS_SUPPORTED ())
return EXIT_UNSUPPORTED;
open_mod (0);
open_mod (1);
open_mod (2);
close_mod (0);
close_mod (1); /* Create modid gap at mod1. */
open_mod (0); /* Reuse modid of mod0, bump generation count. */
/* Create a thread where DTV of mod1 is NULL. */
pthread_t t = xpthread_create (NULL, start, NULL);
xpthread_join (t);
return 0;
}
#include <support/test-driver.c>
+36
View File
@@ -0,0 +1,36 @@
/* Test TLSDESC relocation.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include <stdint.h>
struct tls
{
int64_t a, b, c, d;
};
extern struct tls *apply_tls (struct tls *);
/* An architecture can define them to verify that clobber caller-saved
registers aren't changed by the implicit TLSDESC call. */
#ifndef BEFORE_TLSDESC_CALL
# define BEFORE_TLSDESC_CALL()
#endif
#ifndef AFTER_TLSDESC_CALL
# define AFTER_TLSDESC_CALL()
#endif
@@ -1,5 +1,6 @@
/* Linux/x86 CET initializers function.
Copyright (C) 2018-2023 Free Software Foundation, Inc.
/* DSO used by tst-gnu2-tls2.
Copyright (C) 2024 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
@@ -15,18 +16,16 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
#include <sys/prctl.h>
#include <asm/prctl.h>
#include "tst-gnu2-tls2.h"
static inline int __attribute__ ((always_inline))
dl_cet_disable_cet (unsigned int cet_feature)
{
return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_CET_DISABLE,
cet_feature);
}
__thread struct tls tls_var0 __attribute__ ((visibility ("hidden")));
static inline int __attribute__ ((always_inline))
dl_cet_lock_cet (void)
struct tls *
apply_tls (struct tls *p)
{
return (int) INTERNAL_SYSCALL_CALL (arch_prctl, ARCH_CET_LOCK, 0);
BEFORE_TLSDESC_CALL ();
tls_var0 = *p;
struct tls *ret = &tls_var0;
AFTER_TLSDESC_CALL ();
return ret;
}
+31
View File
@@ -0,0 +1,31 @@
/* DSO used by tst-gnu2-tls2.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include "tst-gnu2-tls2.h"
__thread struct tls tls_var1[100] __attribute__ ((visibility ("hidden")));
struct tls *
apply_tls (struct tls *p)
{
BEFORE_TLSDESC_CALL ();
tls_var1[1] = *p;
struct tls *ret = &tls_var1[1];
AFTER_TLSDESC_CALL ();
return ret;
}
+31
View File
@@ -0,0 +1,31 @@
/* DSO used by tst-gnu2-tls2.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include "tst-gnu2-tls2.h"
__thread struct tls tls_var2 __attribute__ ((visibility ("hidden")));
struct tls *
apply_tls (struct tls *p)
{
BEFORE_TLSDESC_CALL ();
tls_var2 = *p;
struct tls *ret = &tls_var2;
AFTER_TLSDESC_CALL ();
return ret;
}
+158
View File
@@ -0,0 +1,158 @@
/* Check that _dl_find_object behavior matches up with gaps.
Copyright (C) 2025 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
<https://www.gnu.org/licenses/>. */
#include <dlfcn.h>
#include <gnu/lib-names.h>
#include <inttypes.h>
#include <link.h>
#include <stdbool.h>
#include <stdio.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xdlfcn.h>
#include <support/xunistd.h>
#include <support/xstdio.h>
#include <sys/mman.h>
#include <unistd.h>
/* Slow path in case we cannot find a gap with mmap (when the runtime has
mapped all the pages in the gap for some reason). */
static bool
find_gap_with_proc_self_map (const struct link_map *l)
{
int pagesize = getpagesize ();
support_need_proc ("Reads /proc/self/maps to find gap in ld.so mapping");
/* Parse /proc/self/maps and find all the mappings in the ld.so range
but not from ld.so. */
FILE *f = xfopen ("/proc/self/maps", "r");
char *line = NULL, *path_ldso = NULL;
size_t len;
bool found = false;
while (xgetline (&line, &len, f))
{
uintptr_t from, to;
char *path = NULL;
int r = sscanf (line, "%" SCNxPTR "-%" SCNxPTR "%*s%*s%*s%*s%ms",
&from, &to, &path);
TEST_VERIFY (r == 2 || r == 3);
TEST_COMPARE (from % pagesize, 0);
TEST_COMPARE (to % pagesize, 0);
if (path_ldso == NULL && l->l_map_start == from)
{
TEST_COMPARE (r, 3);
path_ldso = path;
continue;
}
if (from > l->l_map_start && to < l->l_map_end
&& (r == 2 || (path_ldso != NULL && strcmp (path, path_ldso))))
{
if (r == 2)
printf ("info: anonymous mapping found at 0x%" PRIxPTR " - 0x%"
PRIxPTR "\n", from, to);
else
printf ("info: object \"%s\" found at 0x%" PRIxPTR " - 0x%"
PRIxPTR "\n", path, from, to);
found = true;
}
free (path);
}
free (path_ldso);
free (line);
xfclose (f);
return found;
}
static int
do_test (void)
{
struct link_map *l = xdlopen (LD_SO, RTLD_NOW);
if (!l->l_contiguous)
{
puts ("info: ld.so link map is not contiguous");
/* Try to find holes by probing with mmap. */
int pagesize = getpagesize ();
bool gap_found = false;
ElfW(Addr) addr = l->l_map_start;
TEST_COMPARE (addr % pagesize, 0);
while (addr < l->l_map_end)
{
void *expected = (void *) addr;
void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1);
struct dl_find_object dlfo;
int dlfo_ret = _dl_find_object (expected, &dlfo);
if (ptr == expected)
{
if (dlfo_ret < 0)
{
TEST_COMPARE (dlfo_ret, -1);
printf ("info: hole without mapping data found at %p\n", ptr);
}
else
FAIL ("object \"%s\" found in gap at %p",
dlfo.dlfo_link_map->l_name, ptr);
gap_found = true;
}
else if (dlfo_ret == 0)
{
if ((void *) dlfo.dlfo_link_map != (void *) l)
{
printf ("info: object \"%s\" found at %p\n",
dlfo.dlfo_link_map->l_name, expected);
gap_found = true;
}
}
else
TEST_COMPARE (dlfo_ret, -1);
xmunmap (ptr, 1);
addr += pagesize;
}
if (!gap_found && !find_gap_with_proc_self_map (l))
FAIL ("no ld.so gap found");
}
else
{
puts ("info: ld.so link map is contiguous");
/* Assert that ld.so is truly contiguous in memory. */
volatile long int *p = (volatile long int *) l->l_map_start;
volatile long int *end = (volatile long int *) l->l_map_end;
while (p < end)
{
*p;
++p;
}
}
xdlclose (l);
return 0;
}
#include <support/test-driver.c>
+57
View File
@@ -0,0 +1,57 @@
/* Check that the entire libc.so program image is readable if contiguous.
Copyright (C) 2025 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
<https://www.gnu.org/licenses/>. */
#include <gnu/lib-names.h>
#include <link.h>
#include <support/check.h>
#include <support/xdlfcn.h>
#include <support/xunistd.h>
#include <sys/mman.h>
#include <unistd.h>
static int
do_test (void)
{
struct link_map *l = xdlopen (LIBC_SO, RTLD_NOW);
/* The dynamic loader fills holes with PROT_NONE mappings. */
if (!l->l_contiguous)
FAIL_EXIT1 ("libc.so link map is not contiguous");
/* Direct probing does not work because not everything is readable
due to PROT_NONE mappings. */
int pagesize = getpagesize ();
ElfW(Addr) addr = l->l_map_start;
TEST_COMPARE (addr % pagesize, 0);
while (addr < l->l_map_end)
{
void *expected = (void *) addr;
void *ptr = xmmap (expected, 1, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1);
if (ptr == expected)
FAIL ("hole in libc.so memory image after %lu bytes",
(unsigned long int) (addr - l->l_map_start));
xmunmap (ptr, 1);
addr += pagesize;
}
xdlclose (l);
return 0;
}
#include <support/test-driver.c>
+45
View File
@@ -0,0 +1,45 @@
/* Check that the entire main program image is readable if contiguous.
Copyright (C) 2025 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
<https://www.gnu.org/licenses/>. */
#include <link.h>
#include <support/check.h>
#include <support/xdlfcn.h>
static int
do_test (void)
{
struct link_map *l = xdlopen ("", RTLD_NOW);
if (!l->l_contiguous)
FAIL_UNSUPPORTED ("main link map is not contiguous");
/* This check only works if the kernel loaded the main program. The
dynamic loader replaces gaps with PROT_NONE mappings, resulting
in faults. */
volatile long int *p = (volatile long int *) l->l_map_start;
volatile long int *end = (volatile long int *) l->l_map_end;
while (p < end)
{
*p;
++p;
}
xdlclose (l);
return 0;
}
#include <support/test-driver.c>
+60
View File
@@ -0,0 +1,60 @@
/* Test with interposed malloc with dynamic TLS.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include <array_length.h>
#include <stdio.h>
#include <support/check.h>
#include <support/xdlfcn.h>
/* Defined in tst-recursive-tlsmallocmod.so. */
extern __thread unsigned int malloc_subsytem_counter;
static int
do_test (void)
{
/* 16 is large enough to exercise the DTV resizing case. */
void *handles[16];
for (unsigned int i = 0; i < array_length (handles); ++i)
{
/* Re-use the TLS slot for module 0. */
if (i > 0)
xdlclose (handles[0]);
char soname[30];
snprintf (soname, sizeof (soname), "tst-recursive-tlsmod%u.so", i);
handles[i] = xdlopen (soname, RTLD_NOW);
if (i > 0)
{
handles[0] = xdlopen ("tst-recursive-tlsmod0.so", RTLD_NOW);
int (*fptr) (void) = xdlsym (handles[0], "get_threadvar_0");
/* May trigger TLS storage allocation using malloc. */
TEST_COMPARE (fptr (), 0);
}
}
for (unsigned int i = 0; i < array_length (handles); ++i)
xdlclose (handles[i]);
printf ("info: malloc subsystem calls: %u\n", malloc_subsytem_counter);
TEST_VERIFY (malloc_subsytem_counter > 0);
return 0;
}
#include <support/test-driver.c>
+64
View File
@@ -0,0 +1,64 @@
/* Interposed malloc with dynamic TLS.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include <stdlib.h>
#include <dlfcn.h>
__thread unsigned int malloc_subsytem_counter;
static __typeof (malloc) *malloc_fptr;
static __typeof (free) *free_fptr;
static __typeof (calloc) *calloc_fptr;
static __typeof (realloc) *realloc_fptr;
static void __attribute__ ((constructor))
init (void)
{
malloc_fptr = dlsym (RTLD_NEXT, "malloc");
free_fptr = dlsym (RTLD_NEXT, "free");
calloc_fptr = dlsym (RTLD_NEXT, "calloc");
realloc_fptr = dlsym (RTLD_NEXT, "realloc");
}
void *
malloc (size_t size)
{
++malloc_subsytem_counter;
return malloc_fptr (size);
}
void
free (void *ptr)
{
++malloc_subsytem_counter;
return free_fptr (ptr);
}
void *
calloc (size_t a, size_t b)
{
++malloc_subsytem_counter;
return calloc_fptr (a, b);
}
void *
realloc (void *ptr, size_t size)
{
++malloc_subsytem_counter;
return realloc_fptr (ptr, size);
}
+28
View File
@@ -0,0 +1,28 @@
/* Test module with global-dynamic TLS. Used to trigger DTV reallocation.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
/* Compiled with VAR and FUNC set via -D. FUNC requires some
relocation against TLS variable VAR. */
__thread int VAR;
int
FUNC (void)
{
return VAR;
}
+32
View File
@@ -0,0 +1,32 @@
/* DSO used by tst-tls23.
Copyright (C) 2025 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
<https://www.gnu.org/licenses/>. */
#include <tst-tls23.h>
__thread struct tls tls_var0 __attribute__ ((visibility ("hidden")));
struct tls *
apply_tls (struct tls *p)
{
INIT_TLS_CALL ();
BEFORE_TLS_CALL ();
tls_var0 = *p;
struct tls *ret = &tls_var0;
AFTER_TLS_CALL ();
return ret;
}
+106
View File
@@ -0,0 +1,106 @@
/* Test that __tls_get_addr preserves caller-saved registers.
Copyright (C) 2025 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dlfcn.h>
#include <pthread.h>
#include <support/xdlfcn.h>
#include <support/xthread.h>
#include <support/check.h>
#include <support/test-driver.h>
#include <tst-tls23.h>
#ifndef IS_SUPPORTED
# define IS_SUPPORTED() true
#endif
/* An architecture can define it to clobber caller-saved registers in
malloc below to verify that __tls_get_addr won't change caller-saved
registers. */
#ifndef PREPARE_MALLOC
# define PREPARE_MALLOC()
#endif
extern void * __libc_malloc (size_t);
size_t malloc_counter = 0;
void *
malloc (size_t n)
{
PREPARE_MALLOC ();
malloc_counter++;
return __libc_malloc (n);
}
static void *mod;
static const char *modname = "tst-tls23-mod.so";
static void
open_mod (void)
{
mod = xdlopen (modname, RTLD_LAZY);
printf ("open %s\n", modname);
}
static void
close_mod (void)
{
xdlclose (mod);
mod = NULL;
printf ("close %s\n", modname);
}
static void
access_mod (const char *sym)
{
struct tls var = { -4, -4, -4, -4 };
struct tls *(*f) (struct tls *) = xdlsym (mod, sym);
/* Check that our malloc is called. */
malloc_counter = 0;
struct tls *p = f (&var);
TEST_VERIFY (malloc_counter != 0);
printf ("access %s: %s() = %p\n", modname, sym, p);
TEST_VERIFY_EXIT (memcmp (p, &var, sizeof (var)) == 0);
++(p->a);
}
static void *
start (void *arg)
{
access_mod ("apply_tls");
return arg;
}
static int
do_test (void)
{
if (!IS_SUPPORTED ())
return EXIT_UNSUPPORTED;
open_mod ();
pthread_t t = xpthread_create (NULL, start, NULL);
xpthread_join (t);
close_mod ();
return 0;
}
#include <support/test-driver.c>
+40
View File
@@ -0,0 +1,40 @@
/* Test that __tls_get_addr preserves caller-saved registers.
Copyright (C) 2025 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
<https://www.gnu.org/licenses/>. */
#include <stdint.h>
struct tls
{
int64_t a, b, c, d;
};
extern struct tls *apply_tls (struct tls *);
/* An architecture can define them to verify that caller-saved registers
aren't changed by __tls_get_addr. */
#ifndef INIT_TLS_CALL
# define INIT_TLS_CALL()
#endif
#ifndef BEFORE_TLS_CALL
# define BEFORE_TLS_CALL()
#endif
#ifndef AFTER_TLS_CALL
# define AFTER_TLS_CALL()
#endif
+2
View File
@@ -0,0 +1,2 @@
int __thread tls0;
int *f0(void) { return &tls0; }
+2
View File
@@ -0,0 +1,2 @@
int __thread tls1[100]; /* Size > glibc.rtld.optional_static_tls / 2. */
int *f1(void) { return tls1; }
+2
View File
@@ -0,0 +1,2 @@
int __thread tls2;
int *f2(void) { return &tls2; }
+92
View File
@@ -0,0 +1,92 @@
/* TLS modid gap reuse regression test for bug 29039.
Copyright (C) 2023 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <dlfcn.h>
#include <pthread.h>
#include <support/xdlfcn.h>
#include <support/xthread.h>
#include <support/check.h>
static void *mod[3];
#define MOD(i) "tst-tlsgap-mod" #i ".so"
static const char *modname[3] = { MOD(0), MOD(1), MOD(2) };
#undef MOD
static void
open_mod (int i)
{
mod[i] = xdlopen (modname[i], RTLD_LAZY);
printf ("open %s\n", modname[i]);
}
static void
close_mod (int i)
{
xdlclose (mod[i]);
mod[i] = NULL;
printf ("close %s\n", modname[i]);
}
static void
access_mod (int i, const char *sym)
{
int *(*f) (void) = xdlsym (mod[i], sym);
int *p = f ();
printf ("access %s: %s() = %p\n", modname[i], sym, p);
TEST_VERIFY_EXIT (p != NULL);
++*p;
}
static void *
start (void *arg)
{
/* The DTV generation is at the last dlopen of mod0 and the
entry for mod1 is NULL. */
open_mod (1); /* Reuse modid of mod1. Uses dynamic TLS. */
/* DTV is unchanged: dlopen only updates the DTV to the latest
generation if static TLS is allocated for a loaded module.
With bug 29039, the TLSDESC relocation in mod1 uses the old
dlclose generation of mod1 instead of the new dlopen one so
DTV is not updated on TLS access. */
access_mod (1, "f1");
return arg;
}
static int
do_test (void)
{
open_mod (0);
open_mod (1);
open_mod (2);
close_mod (0);
close_mod (1); /* Create modid gap at mod1. */
open_mod (0); /* Reuse modid of mod0, bump generation count. */
/* Create a thread where DTV of mod1 is NULL. */
pthread_t t = xpthread_create (NULL, start, NULL);
xpthread_join (t);
return 0;
}
#include <support/test-driver.c>
+1 -1
View File
@@ -187,7 +187,7 @@ main (int argc, char *argv[])
if (res != __GCONV_OK)
{
if (errno == EINVAL)
if (res == __GCONV_NOCONV || res == __GCONV_NODB)
{
/* Try to be nice with the user and tell her which of the
two encoding names is wrong. This is possible because
+6 -1
View File
@@ -75,7 +75,8 @@ ifeq (yes,$(build-shared))
tests = bug-iconv1 bug-iconv2 tst-loading tst-e2big tst-iconv4 bug-iconv4 \
tst-iconv6 bug-iconv5 bug-iconv6 tst-iconv7 bug-iconv8 bug-iconv9 \
bug-iconv10 bug-iconv11 bug-iconv12 tst-iconv-big5-hkscs-to-2ucs4 \
bug-iconv13 bug-iconv14 bug-iconv15
bug-iconv13 bug-iconv14 bug-iconv15 \
tst-iconv-iso-2022-cn-ext tst-bug33980
ifeq ($(have-thread-library),yes)
tests += bug-iconv3
endif
@@ -330,6 +331,10 @@ $(objpfx)bug-iconv14.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)bug-iconv15.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)tst-iconv-iso-2022-cn-ext.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)tst-bug33980.out: $(addprefix $(objpfx), $(gconv-modules)) \
$(addprefix $(objpfx),$(modules.so))
$(objpfx)iconv-test.out: run-iconv-test.sh \
$(addprefix $(objpfx), $(gconv-modules)) \
+1 -1
View File
@@ -407,7 +407,7 @@ static const char from_ucs4[][2] =
is also available. */ \
uint32_t ch2; \
\
if (inptr + 1 >= inend) \
if (inend - inptr <= 1) \
{ \
/* The second character is not available. */ \
result = __GCONV_INCOMPLETE_INPUT; \
+55 -15
View File
@@ -67,12 +67,29 @@
/* Since this is a stateful encoding we have to provide code which resets
the output state to the initial state. This has to be done during the
flushing. */
flushing. For the to-internal direction (FROM_DIRECTION is true),
there may be a pending character that needs flushing. */
#define EMIT_SHIFT_TO_INIT \
if ((data->__statep->__count & ~7) != sb) \
{ \
if (FROM_DIRECTION) \
data->__statep->__count &= 7; \
{ \
uint32_t ch = data->__statep->__count >> 7; \
if (__glibc_unlikely (ch != 0)) \
{ \
if (__glibc_unlikely (outend - outbuf < 4)) \
status = __GCONV_FULL_OUTPUT; \
else \
{ \
put32 (outbuf, ch); \
outbuf += 4; \
/* Clear character and db bit. */ \
data->__statep->__count &= 7; \
} \
} \
else \
data->__statep->__count &= 7; \
} \
else \
{ \
/* We are not in the initial state. To switch back we have \
@@ -99,11 +116,13 @@
*curcsp = save_curcs
/* Current codeset type. */
/* Current codeset type. The bit is stored in the __count variable of
the conversion state. If the db bit is set, bit 7 and above store
a pending UCS-4 code point if non-zero. */
enum
{
sb = 0,
db = 64
sb = 0, /* Single byte mode. */
db = 64 /* Double byte mode. */
};
@@ -119,21 +138,29 @@ enum
} \
else \
{ \
/* This is a combined character. Make sure we have room. */ \
if (__glibc_unlikely (outptr + 8 > outend)) \
{ \
result = __GCONV_FULL_OUTPUT; \
break; \
} \
\
const struct divide *cmbp \
= &DB_TO_UCS4_COMB[ch - __TO_UCS4_COMBINED_MIN]; \
assert (cmbp->res1 != 0 && cmbp->res2 != 0); \
\
put32 (outptr, cmbp->res1); \
outptr += 4; \
put32 (outptr, cmbp->res2); \
outptr += 4; \
\
/* See whether we have room for the second character. */ \
if (outend - outptr >= 4) \
{ \
put32 (outptr, cmbp->res2); \
outptr += 4; \
} \
else \
{ \
/* Otherwise store only the first character now, and \
put the second one into the queue. */ \
curcs |= cmbp->res2 << 7; \
inptr += 2; \
/* Tell the caller why we terminate the loop. */ \
result = __GCONV_FULL_OUTPUT; \
break; \
} \
} \
}
#else
@@ -153,7 +180,20 @@ enum
#define LOOPFCT FROM_LOOP
#define BODY \
{ \
uint32_t ch = *inptr; \
uint32_t ch; \
\
ch = curcs >> 7; \
if (__glibc_unlikely (ch != 0)) \
{ \
put32 (outptr, ch); \
outptr += 4; \
/* Remove the pending character, but preserve state bits. */ \
curcs &= (1 << 7) - 1; \
continue; \
} \
\
/* Otherwise read the next input byte. */ \
ch = *inptr; \
\
if (__builtin_expect (ch, 0) == SO) \
{ \
+12
View File
@@ -574,6 +574,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
{ \
const char *escseq; \
\
if (outptr + 4 > outend) \
{ \
result = __GCONV_FULL_OUTPUT; \
break; \
} \
\
assert (used == CNS11643_2_set); /* XXX */ \
escseq = "*H"; \
*outptr++ = ESC; \
@@ -587,6 +593,12 @@ DIAG_IGNORE_Os_NEEDS_COMMENT (5, "-Wmaybe-uninitialized");
{ \
const char *escseq; \
\
if (outptr + 4 > outend) \
{ \
result = __GCONV_FULL_OUTPUT; \
break; \
} \
\
assert ((used >> 5) >= 3 && (used >> 5) <= 7); \
escseq = "+I+J+K+L+M" + ((used >> 5) - 3) * 2; \
*outptr++ = ESC; \
+153
View File
@@ -0,0 +1,153 @@
/* Test for bug 33980: combining characters in IBM1390/IBM1399.
Copyright (C) 2026 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
<https://www.gnu.org/licenses/>. */
#include <alloc_buffer.h>
#include <errno.h>
#include <iconv.h>
#include <stdbool.h>
#include <string.h>
#include <support/check.h>
#include <support/next_to_fault.h>
#include <support/support.h>
/* Run iconv in a loop with a small output buffer of OUTBUFSIZE bytes
starting at OUTBUF. OUTBUF should be right before an unmapped page
so that writing past the end will fault. Skip SHIFT bytes at the
start of the input and output, to exercise different buffer
alignment. TRUNCATE indicates skipped bytes at the end of
input (0 and 1 a valid). */
static void
test_one (const char *encoding, unsigned int shift, unsigned int truncate,
char *outbuf, size_t outbufsize)
{
/* In IBM1390 and IBM1399, the DBCS code 0xECB5 expands to two
Unicode code points when translated. */
static char input[] =
{
/* 8 letters X. */
0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7, 0xe7,
/* SO, 0xECB5, SI: shift to DBCS, special character, shift back. */
0x0e, 0xec, 0xb5, 0x0f
};
/* Expected output after UTF-8 conversion. */
static char expected[] =
{
'X', 'X', 'X', 'X', 'X', 'X', 'X', 'X',
/* U+304B (HIRAGANA LETTER KA). */
0xe3, 0x81, 0x8b,
/* U+309A (COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK). */
0xe3, 0x82, 0x9a
};
iconv_t cd = iconv_open ("UTF-8", encoding);
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
char result_storage[64];
struct alloc_buffer result_buf
= alloc_buffer_create (result_storage, sizeof (result_storage));
char *inptr = &input[shift];
size_t inleft = sizeof (input) - shift - truncate;
while (inleft > 0)
{
char *outptr = outbuf;
size_t outleft = outbufsize;
size_t inleft_before = inleft;
size_t ret = iconv (cd, &inptr, &inleft, &outptr, &outleft);
size_t produced = outptr - outbuf;
alloc_buffer_copy_bytes (&result_buf, outbuf, produced);
if (ret == (size_t) -1 && errno == E2BIG)
{
if (produced == 0 && inleft == inleft_before)
{
/* Output buffer too small to make progress. This is
expected for very small output buffer sizes. */
TEST_VERIFY_EXIT (outbufsize < 3);
break;
}
continue;
}
if (ret == (size_t) -1)
FAIL_EXIT1 ("%s (outbufsize %zu): iconv: %m", encoding, outbufsize);
break;
}
/* Flush any pending state (e.g. a buffered combined character).
With outbufsize < 3, we could not store the first character, so
the second character did not become pending, and there is nothing
to flush. */
{
char *outptr = outbuf;
size_t outleft = outbufsize;
size_t ret = iconv (cd, NULL, NULL, &outptr, &outleft);
TEST_VERIFY_EXIT (ret == 0);
size_t produced = outptr - outbuf;
alloc_buffer_copy_bytes (&result_buf, outbuf, produced);
/* Second flush does not provide more data. */
outptr = outbuf;
outleft = outbufsize;
ret = iconv (cd, NULL, NULL, &outptr, &outleft);
TEST_VERIFY_EXIT (ret == 0);
TEST_VERIFY (outptr == outbuf);
}
TEST_VERIFY_EXIT (!alloc_buffer_has_failed (&result_buf));
size_t result_used
= sizeof (result_storage) - alloc_buffer_size (&result_buf);
if (outbufsize >= 3)
{
TEST_COMPARE (inleft, 0);
TEST_COMPARE (result_used, sizeof (expected) - shift);
TEST_COMPARE_BLOB (result_storage, result_used,
&expected[shift], sizeof (expected) - shift);
}
else
/* If the buffer is too small, only the leading X could be converted. */
TEST_COMPARE (result_used, 8 - shift);
TEST_VERIFY_EXIT (iconv_close (cd) == 0);
}
static int
do_test (void)
{
struct support_next_to_fault ntf
= support_next_to_fault_allocate (8);
for (int shift = 0; shift <= 8; ++shift)
for (int truncate = 0; truncate < 2; ++truncate)
for (size_t outbufsize = 1; outbufsize <= 8; outbufsize++)
{
char *outbuf = ntf.buffer + ntf.length - outbufsize;
test_one ("IBM1390", shift, truncate, outbuf, outbufsize);
test_one ("IBM1399", shift, truncate, outbuf, outbufsize);
}
support_next_to_fault_free (&ntf);
return 0;
}
#include <support/test-driver.c>
+128
View File
@@ -0,0 +1,128 @@
/* Verify ISO-2022-CN-EXT does not write out of the bounds.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <iconv.h>
#include <sys/mman.h>
#include <support/xunistd.h>
#include <support/check.h>
#include <support/support.h>
/* The test sets up a two memory page buffer with the second page marked
PROT_NONE to trigger a fault if the conversion writes beyond the exact
expected amount. Then we carry out various conversions and precisely
place the start of the output buffer in order to trigger a SIGSEGV if the
process writes anywhere between 1 and page sized bytes more (only one
PROT_NONE page is setup as a canary) than expected. These tests exercise
all three of the cases in ISO-2022-CN-EXT where the converter must switch
character sets and may run out of buffer space while doing the
operation. */
static int
do_test (void)
{
iconv_t cd = iconv_open ("ISO-2022-CN-EXT", "UTF-8");
TEST_VERIFY_EXIT (cd != (iconv_t) -1);
char *ntf;
size_t ntfsize;
char *outbufbase;
{
int pgz = getpagesize ();
TEST_VERIFY_EXIT (pgz > 0);
ntfsize = 2 * pgz;
ntf = xmmap (NULL, ntfsize, PROT_READ | PROT_WRITE, MAP_PRIVATE
| MAP_ANONYMOUS, -1);
xmprotect (ntf + pgz, pgz, PROT_NONE);
outbufbase = ntf + pgz;
}
/* Check if SOdesignation escape sequence does not trigger an OOB write. */
{
char inbuf[] = "\xe4\xba\xa4\xe6\x8d\xa2";
for (int i = 0; i < 9; i++)
{
char *inp = inbuf;
size_t inleft = sizeof (inbuf) - 1;
char *outp = outbufbase - i;
size_t outleft = i;
TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
== (size_t) -1);
TEST_COMPARE (errno, E2BIG);
TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
}
}
/* Same as before for SS2designation. */
{
char inbuf[] = "\xe3\xb4\xbd";
for (int i = 0; i < 14; i++)
{
char *inp = inbuf;
size_t inleft = sizeof (inbuf) - 1;
char *outp = outbufbase - i;
size_t outleft = i;
TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
== (size_t) -1);
TEST_COMPARE (errno, E2BIG);
TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
}
}
/* Same as before for SS3designation. */
{
char inbuf[] = "\xe5\x8a\x84";
for (int i = 0; i < 14; i++)
{
char *inp = inbuf;
size_t inleft = sizeof (inbuf) - 1;
char *outp = outbufbase - i;
size_t outleft = i;
TEST_VERIFY_EXIT (iconv (cd, &inp, &inleft, &outp, &outleft)
== (size_t) -1);
TEST_COMPARE (errno, E2BIG);
TEST_VERIFY_EXIT (iconv (cd, NULL, NULL, NULL, NULL) == 0);
}
}
TEST_VERIFY_EXIT (iconv_close (cd) != -1);
xmunmap (ntf, ntfsize);
return 0;
}
#include <support/test-driver.c>
-4
View File
@@ -34,9 +34,5 @@ extern void __check_native (uint32_t a1_index, int *a1_native,
uint32_t a2_index, int *a2_native)
attribute_hidden;
#if IS_IN (nscd)
extern uint32_t __bump_nl_timestamp (void) attribute_hidden;
#endif
# endif /* !_ISOMAC */
#endif /* ifaddrs.h */
+4
View File
@@ -278,6 +278,10 @@ struct link_map
/* List of object in order of the init and fini calls. */
struct link_map **l_initfini;
/* Linked list of objects in reverse ELF constructor execution
order. Head of list is stored in _dl_init_called_list. */
struct link_map *l_init_called_next;
/* List of the dependencies introduced through symbol binding. */
struct link_map_reldeps
{
-4
View File
@@ -14,10 +14,6 @@ libc_hidden_proto (__get_nprocs_conf)
extern int __get_nprocs (void);
libc_hidden_proto (__get_nprocs)
/* Return the number of available processors which the process can
be scheduled. */
extern int __get_nprocs_sched (void) attribute_hidden;
/* Return number of physical pages of memory in the system. */
extern long int __get_phys_pages (void);
libc_hidden_proto (__get_phys_pages)
-9
View File
@@ -60,12 +60,3 @@ __free_in6ai (struct in6addrinfo *in6ai)
{
/* Nothing to do. */
}
#if IS_IN (nscd)
uint32_t
__bump_nl_timestamp (void)
{
return 0;
}
#endif
+1
View File
@@ -192,6 +192,7 @@ tests := \
tst-fchownat \
tst-fcntl \
tst-fcntl-lock \
tst-fcntl-lock-lfs \
tst-fstatat \
tst-fts \
tst-fts-lfs \
+4
View File
@@ -18,6 +18,10 @@
#include <errno.h>
#include <fcntl.h>
#ifndef __O_CLOEXEC
# error __O_CLOEXEC not defined by fcntl.h/cloexec.h
#endif
/* Perform file control operations on FD. */
int
__fcntl (int fd, int cmd, ...)
+2
View File
@@ -0,0 +1,2 @@
#define _FILE_OFFSET_BITS 64
#include <io/tst-fcntl-lock.c>
+6
View File
@@ -212,6 +212,12 @@ aux := fileops genops stdfiles stdio strops
ifeq ($(build-shared),yes)
generated += tst-bz24228.mtrace tst-bz24228.check
aux += oldfileops oldstdfiles
tests += \
tst-stderr-compat \
# tests
tests-2.0 += \
tst-stderr-compat \
# tests-2.0
endif
shared-only-routines = oldiofopen oldiofdopen oldiofclose oldfileops \
+20 -20
View File
@@ -194,36 +194,36 @@ gets (char *__str)
__fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
fgets (char *__restrict __s, int __n, FILE *__restrict __stream)
{
size_t sz = __glibc_objsize (__s);
if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
size_t __sz = __glibc_objsize (__s);
if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
return __fgets_alias (__s, __n, __stream);
if (__glibc_unsafe_len (__n, sizeof (char), sz))
return __fgets_chk_warn (__s, sz, __n, __stream);
return __fgets_chk (__s, sz, __n, __stream);
if (__glibc_unsafe_len (__n, sizeof (char), __sz))
return __fgets_chk_warn (__s, __sz, __n, __stream);
return __fgets_chk (__s, __sz, __n, __stream);
}
__fortify_function __wur size_t
fread (void *__restrict __ptr, size_t __size, size_t __n,
FILE *__restrict __stream)
{
size_t sz = __glibc_objsize0 (__ptr);
if (__glibc_safe_or_unknown_len (__n, __size, sz))
size_t __sz = __glibc_objsize0 (__ptr);
if (__glibc_safe_or_unknown_len (__n, __size, __sz))
return __fread_alias (__ptr, __size, __n, __stream);
if (__glibc_unsafe_len (__n, __size, sz))
return __fread_chk_warn (__ptr, sz, __size, __n, __stream);
return __fread_chk (__ptr, sz, __size, __n, __stream);
if (__glibc_unsafe_len (__n, __size, __sz))
return __fread_chk_warn (__ptr, __sz, __size, __n, __stream);
return __fread_chk (__ptr, __sz, __size, __n, __stream);
}
#ifdef __USE_GNU
__fortify_function __wur __fortified_attr_access (__write_only__, 1, 2) char *
fgets_unlocked (char *__restrict __s, int __n, FILE *__restrict __stream)
{
size_t sz = __glibc_objsize (__s);
if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
size_t __sz = __glibc_objsize (__s);
if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
return __fgets_unlocked_alias (__s, __n, __stream);
if (__glibc_unsafe_len (__n, sizeof (char), sz))
return __fgets_unlocked_chk_warn (__s, sz, __n, __stream);
return __fgets_unlocked_chk (__s, sz, __n, __stream);
if (__glibc_unsafe_len (__n, sizeof (char), __sz))
return __fgets_unlocked_chk_warn (__s, __sz, __n, __stream);
return __fgets_unlocked_chk (__s, __sz, __n, __stream);
}
#endif
@@ -233,8 +233,8 @@ __fortify_function __wur size_t
fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
FILE *__restrict __stream)
{
size_t sz = __glibc_objsize0 (__ptr);
if (__glibc_safe_or_unknown_len (__n, __size, sz))
size_t __sz = __glibc_objsize0 (__ptr);
if (__glibc_safe_or_unknown_len (__n, __size, __sz))
{
# ifdef __USE_EXTERN_INLINES
if (__builtin_constant_p (__size)
@@ -259,9 +259,9 @@ fread_unlocked (void *__restrict __ptr, size_t __size, size_t __n,
# endif
return __fread_unlocked_alias (__ptr, __size, __n, __stream);
}
if (__glibc_unsafe_len (__n, __size, sz))
return __fread_unlocked_chk_warn (__ptr, sz, __size, __n, __stream);
return __fread_unlocked_chk (__ptr, sz, __size, __n, __stream);
if (__glibc_unsafe_len (__n, __size, __sz))
return __fread_unlocked_chk_warn (__ptr, __sz, __size, __n, __stream);
return __fread_unlocked_chk (__ptr, __sz, __size, __n, __stream);
}
#endif
+7 -1
View File
@@ -635,7 +635,7 @@ _IO_sputbackc (FILE *fp, int c)
{
int result;
if (fp->_IO_read_ptr > fp->_IO_read_base
if (fp->_IO_read_ptr > fp->_IO_read_base && !_IO_in_backup (fp)
&& (unsigned char)fp->_IO_read_ptr[-1] == (unsigned char)c)
{
fp->_IO_read_ptr--;
@@ -789,6 +789,12 @@ _IO_unbuffer_all (void)
legacy = 1;
#endif
/* Free up the backup area if it was ever allocated. */
if (_IO_have_backup (fp))
_IO_free_backup_area (fp);
if (!legacy && fp->_mode > 0 && _IO_have_wbackup (fp))
_IO_free_wbackup_area (fp);
if (! (fp->_flags & _IO_UNBUFFERED)
/* Iff stream is un-orientated, it wasn't used. */
&& (legacy || fp->_mode != 0))
+2 -2
View File
@@ -577,8 +577,8 @@ extern void _IO_old_init (FILE *fp, int flags) __THROW;
((__fp)->_wide_data->_IO_write_base \
= (__fp)->_wide_data->_IO_write_ptr = __p, \
(__fp)->_wide_data->_IO_write_end = (__ep))
#define _IO_have_backup(fp) ((fp)->_IO_save_base != NULL)
#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_save_base != NULL)
#define _IO_have_backup(fp) ((fp)->_IO_backup_base != NULL)
#define _IO_have_wbackup(fp) ((fp)->_wide_data->_IO_backup_base != NULL)
#define _IO_in_backup(fp) ((fp)->_flags & _IO_IN_BACKUP)
#define _IO_have_markers(fp) ((fp)->_markers != NULL)
#define _IO_blen(fp) ((fp)->_IO_buf_end - (fp)->_IO_buf_base)
+52
View File
@@ -0,0 +1,52 @@
/* Test that fclose works on stderr from glibc 2.0.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include <shlib-compat.h>
#if TEST_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
# define _LIBC
# define _IO_USE_OLD_IO_FILE
# include <stdio.h>
# include <support/check.h>
extern FILE _IO_stderr_;
compat_symbol_reference (libc, _IO_stderr_, _IO_stderr_, GLIBC_2_0);
compat_symbol_reference (libc, fclose, fclose, GLIBC_2_0);
__attribute__ ((weak, noclone, noinline))
void
do_fclose (FILE *fp)
{
TEST_VERIFY_EXIT (fclose (fp) == 0);
}
static int
do_test (void)
{
do_fclose (&_IO_stderr_);
return 0;
}
#else
static int
do_test (void)
{
return 0;
}
#endif
#include <support/test-driver.c>
+4 -1
View File
@@ -20,6 +20,7 @@
#include <libioP.h>
#include <stdio.h>
#include <ldsodefs.h>
#include <array_length.h>
#include <pointer_guard.h>
#include <libio-macros.h>
@@ -88,7 +89,7 @@
# pragma weak __wprintf_buffer_as_file_xsputn
#endif
const struct _IO_jump_t __io_vtables[IO_VTABLES_LEN] attribute_relro =
const struct _IO_jump_t __io_vtables[] attribute_relro =
{
/* _IO_str_jumps */
[IO_STR_JUMPS] =
@@ -485,6 +486,8 @@ const struct _IO_jump_t __io_vtables[IO_VTABLES_LEN] attribute_relro =
},
#endif
};
_Static_assert (array_length (__io_vtables) == IO_VTABLES_NUM,
"initializer count");
#ifdef SHARED
+1 -1
View File
@@ -55,7 +55,7 @@ _IO_wdo_write (FILE *fp, const wchar_t *data, size_t to_do)
char mb_buf[MB_LEN_MAX];
char *write_base, *write_ptr, *buf_end;
if (fp->_IO_write_ptr - fp->_IO_write_base < sizeof (mb_buf))
if (fp->_IO_buf_end - fp->_IO_write_ptr < sizeof (mb_buf))
{
/* Make sure we have room for at least one multibyte
character. */
+9 -31
View File
@@ -21,6 +21,8 @@
#include <stdio.h>
#include <string.h>
#include <support/check.h>
static const char lower[] = "abcdefghijklmnopqrstuvwxyz";
static const char upper[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
@@ -53,19 +55,11 @@ static struct classes
#define nclasses (sizeof (classes) / sizeof (classes[0]))
#define FAIL(str, args...) \
{ \
printf (" " str "\n", ##args); \
++errors; \
}
static int
do_test (void)
{
const char *cp;
const char *cp2;
int errors = 0;
char *inpline = NULL;
size_t inplinelen = 0;
char *resline = NULL;
@@ -394,11 +388,8 @@ punct = %04x alnum = %04x\n",
{
if (((__ctype_b[(unsigned int) *inp] & classes[n].mask) != 0)
!= (*resp != '0'))
{
printf (" is%s('%c' = '\\x%02x') %s true\n", inpline,
*inp, *inp, *resp == '1' ? "not" : "is");
++errors;
}
FAIL (" is%s('%c' = '\\x%02x') %s true\n", inpline,
*inp, *inp, *resp == '1' ? "not" : "is");
++inp;
++resp;
}
@@ -408,11 +399,8 @@ punct = %04x alnum = %04x\n",
while (*inp != '\0')
{
if (tolower (*inp) != *resp)
{
printf (" tolower('%c' = '\\x%02x') != '%c'\n",
*inp, *inp, *resp);
++errors;
}
FAIL (" tolower('%c' = '\\x%02x') != '%c'\n",
*inp, *inp, *resp);
++inp;
++resp;
}
@@ -422,11 +410,8 @@ punct = %04x alnum = %04x\n",
while (*inp != '\0')
{
if (toupper (*inp) != *resp)
{
printf (" toupper('%c' = '\\x%02x') != '%c'\n",
*inp, *inp, *resp);
++errors;
}
FAIL (" toupper('%c' = '\\x%02x') != '%c'\n",
*inp, *inp, *resp);
++inp;
++resp;
}
@@ -436,14 +421,7 @@ punct = %04x alnum = %04x\n",
}
if (errors != 0)
{
printf (" %d error%s for `%s' locale\n\n\n", errors,
errors == 1 ? "" : "s", setlocale (LC_ALL, NULL));
return 1;
}
printf (" No errors for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
printf ("Completed testing for `%s' locale\n\n\n", setlocale (LC_ALL, NULL));
return 0;
}
+3 -1
View File
@@ -44,7 +44,9 @@ subdir-dirs = programs
vpath %.c programs
tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname tst-getlogin tst-updwtmpx \
tst-pututxline-lockfail tst-pututxline-cache
tst-pututxline-lockfail tst-pututxline-cache tst-utmp-size tst-utmp-size-64
CFLAGS-tst-utmp-size-64.c += -D_FILE_OFFSET_BITS=64 -D_TIME_BITS=64
# Empty compatibility library for old binaries.
extra-libs := libutil
+2
View File
@@ -0,0 +1,2 @@
/* The on-disk layout must not change in time64 mode. */
#include "tst-utmp-size.c"
+33
View File
@@ -0,0 +1,33 @@
/* Check expected sizes of struct utmp, struct utmpx, struct lastlog.
Copyright (C) 2024 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
<https://www.gnu.org/licenses/>. */
#include <utmp.h>
#include <utmpx.h>
#include <utmp-size.h>
static int
do_test (void)
{
_Static_assert (sizeof (struct utmp) == UTMP_SIZE, "struct utmp size");
_Static_assert (sizeof (struct utmpx) == UTMP_SIZE, "struct utmpx size");
_Static_assert (sizeof (struct lastlog) == LASTLOG_SIZE,
"struct lastlog size");
return 0;
}
#include <support/test-driver.c>
+1 -1
View File
@@ -820,7 +820,7 @@ arena_get2 (size_t size, mstate avoid_arena)
narenas_limit = mp_.arena_max;
else if (narenas > mp_.arena_test)
{
int n = __get_nprocs_sched ();
int n = __get_nprocs ();
if (n >= 1)
narenas_limit = NARENAS_FROM_NCORES (n);
+128 -239
View File
@@ -1086,6 +1086,11 @@ typedef struct malloc_chunk* mchunkptr;
static void* _int_malloc(mstate, size_t);
static void _int_free(mstate, mchunkptr, int);
static void _int_free_merge_chunk (mstate, mchunkptr, INTERNAL_SIZE_T);
static INTERNAL_SIZE_T _int_free_create_chunk (mstate,
mchunkptr, INTERNAL_SIZE_T,
mchunkptr, INTERNAL_SIZE_T);
static void _int_free_maybe_consolidate (mstate, INTERNAL_SIZE_T);
static void* _int_realloc(mstate, mchunkptr, INTERNAL_SIZE_T,
INTERNAL_SIZE_T);
static void* _int_memalign(mstate, size_t, size_t);
@@ -4483,12 +4488,6 @@ _int_free (mstate av, mchunkptr p, int have_lock)
{
INTERNAL_SIZE_T size; /* its size */
mfastbinptr *fb; /* associated fastbin */
mchunkptr nextchunk; /* next contiguous chunk */
INTERNAL_SIZE_T nextsize; /* its size */
int nextinuse; /* true if nextchunk is used */
INTERNAL_SIZE_T prevsize; /* size of previous contiguous chunk */
mchunkptr bck; /* misc temp for linking */
mchunkptr fwd; /* misc temp for linking */
size = chunksize (p);
@@ -4637,31 +4636,52 @@ _int_free (mstate av, mchunkptr p, int have_lock)
if (!have_lock)
__libc_lock_lock (av->mutex);
nextchunk = chunk_at_offset(p, size);
_int_free_merge_chunk (av, p, size);
/* Lightweight tests: check whether the block is already the
top block. */
if (__glibc_unlikely (p == av->top))
malloc_printerr ("double free or corruption (top)");
/* Or whether the next chunk is beyond the boundaries of the arena. */
if (__builtin_expect (contiguous (av)
&& (char *) nextchunk
>= ((char *) av->top + chunksize(av->top)), 0))
malloc_printerr ("double free or corruption (out)");
/* Or whether the block is actually not marked used. */
if (__glibc_unlikely (!prev_inuse(nextchunk)))
malloc_printerr ("double free or corruption (!prev)");
if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/
nextsize = chunksize(nextchunk);
if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("free(): invalid next size (normal)");
else {
munmap_chunk (p);
}
}
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
/* Try to merge chunk P of SIZE bytes with its neighbors. Put the
resulting chunk on the appropriate bin list. P must not be on a
bin list yet, and it can be in use. */
static void
_int_free_merge_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size)
{
mchunkptr nextchunk = chunk_at_offset(p, size);
/* consolidate backward */
if (!prev_inuse(p)) {
prevsize = prev_size (p);
/* Lightweight tests: check whether the block is already the
top block. */
if (__glibc_unlikely (p == av->top))
malloc_printerr ("double free or corruption (top)");
/* Or whether the next chunk is beyond the boundaries of the arena. */
if (__builtin_expect (contiguous (av)
&& (char *) nextchunk
>= ((char *) av->top + chunksize(av->top)), 0))
malloc_printerr ("double free or corruption (out)");
/* Or whether the block is actually not marked used. */
if (__glibc_unlikely (!prev_inuse(nextchunk)))
malloc_printerr ("double free or corruption (!prev)");
INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
if (__builtin_expect (chunksize_nomask (nextchunk) <= CHUNK_HDR_SZ, 0)
|| __builtin_expect (nextsize >= av->system_mem, 0))
malloc_printerr ("free(): invalid next size (normal)");
free_perturb (chunk2mem(p), size - CHUNK_HDR_SZ);
/* Consolidate backward. */
if (!prev_inuse(p))
{
INTERNAL_SIZE_T prevsize = prev_size (p);
size += prevsize;
p = chunk_at_offset(p, -((long) prevsize));
if (__glibc_unlikely (chunksize(p) != prevsize))
@@ -4669,9 +4689,25 @@ _int_free (mstate av, mchunkptr p, int have_lock)
unlink_chunk (av, p);
}
if (nextchunk != av->top) {
/* Write the chunk header, maybe after merging with the following chunk. */
size = _int_free_create_chunk (av, p, size, nextchunk, nextsize);
_int_free_maybe_consolidate (av, size);
}
/* Create a chunk at P of SIZE bytes, with SIZE potentially increased
to cover the immediately following chunk NEXTCHUNK of NEXTSIZE
bytes (if NEXTCHUNK is unused). The chunk at P is not actually
read and does not have to be initialized. After creation, it is
placed on the appropriate bin list. The function returns the size
of the new chunk. */
static INTERNAL_SIZE_T
_int_free_create_chunk (mstate av, mchunkptr p, INTERNAL_SIZE_T size,
mchunkptr nextchunk, INTERNAL_SIZE_T nextsize)
{
if (nextchunk != av->top)
{
/* get and clear inuse bit */
nextinuse = inuse_bit_at_offset(nextchunk, nextsize);
bool nextinuse = inuse_bit_at_offset (nextchunk, nextsize);
/* consolidate forward */
if (!nextinuse) {
@@ -4686,8 +4722,8 @@ _int_free (mstate av, mchunkptr p, int have_lock)
been given one chance to be used in malloc.
*/
bck = unsorted_chunks(av);
fwd = bck->fd;
mchunkptr bck = unsorted_chunks (av);
mchunkptr fwd = bck->fd;
if (__glibc_unlikely (fwd->bk != bck))
malloc_printerr ("free(): corrupted unsorted chunks");
p->fd = fwd;
@@ -4706,61 +4742,52 @@ _int_free (mstate av, mchunkptr p, int have_lock)
check_free_chunk(av, p);
}
/*
If the chunk borders the current high end of memory,
consolidate into top
*/
else {
else
{
/* If the chunk borders the current high end of memory,
consolidate into top. */
size += nextsize;
set_head(p, size | PREV_INUSE);
av->top = p;
check_chunk(av, p);
}
/*
If freeing a large space, consolidate possibly-surrounding
chunks. Then, if the total unused topmost memory exceeds trim
threshold, ask malloc_trim to reduce top.
return size;
}
Unless max_fast is 0, we don't know if there are fastbins
bordering top, so we cannot tell for sure whether threshold
has been reached unless fastbins are consolidated. But we
don't want to consolidate on each free. As a compromise,
consolidation is performed if FASTBIN_CONSOLIDATION_THRESHOLD
is reached.
*/
if ((unsigned long)(size) >= FASTBIN_CONSOLIDATION_THRESHOLD) {
/* If freeing a large space, consolidate possibly-surrounding
chunks. Then, if the total unused topmost memory exceeds trim
threshold, ask malloc_trim to reduce top. */
static void
_int_free_maybe_consolidate (mstate av, INTERNAL_SIZE_T size)
{
/* Unless max_fast is 0, we don't know if there are fastbins
bordering top, so we cannot tell for sure whether threshold has
been reached unless fastbins are consolidated. But we don't want
to consolidate on each free. As a compromise, consolidation is
performed if FASTBIN_CONSOLIDATION_THRESHOLD is reached. */
if (size >= FASTBIN_CONSOLIDATION_THRESHOLD)
{
if (atomic_load_relaxed (&av->have_fastchunks))
malloc_consolidate(av);
if (av == &main_arena) {
if (av == &main_arena)
{
#ifndef MORECORE_CANNOT_TRIM
if ((unsigned long)(chunksize(av->top)) >=
(unsigned long)(mp_.trim_threshold))
systrim(mp_.top_pad, av);
if (chunksize (av->top) >= mp_.trim_threshold)
systrim (mp_.top_pad, av);
#endif
} else {
/* Always try heap_trim(), even if the top chunk is not
large, because the corresponding heap might go away. */
heap_info *heap = heap_for_ptr(top(av));
}
else
{
/* Always try heap_trim, even if the top chunk is not large,
because the corresponding heap might go away. */
heap_info *heap = heap_for_ptr (top (av));
assert(heap->ar_ptr == av);
heap_trim(heap, mp_.top_pad);
}
assert (heap->ar_ptr == av);
heap_trim (heap, mp_.top_pad);
}
}
if (!have_lock)
__libc_lock_unlock (av->mutex);
}
/*
If the chunk was allocated via mmap, release via munmap().
*/
else {
munmap_chunk (p);
}
}
/*
@@ -4999,42 +5026,6 @@ _int_realloc (mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize,
------------------------------ memalign ------------------------------
*/
/* Returns 0 if the chunk is not and does not contain the requested
aligned sub-chunk, else returns the amount of "waste" from
trimming. NB is the *chunk* byte size, not the user byte
size. */
static size_t
chunk_ok_for_memalign (mchunkptr p, size_t alignment, size_t nb)
{
void *m = chunk2mem (p);
INTERNAL_SIZE_T size = chunksize (p);
void *aligned_m = m;
if (__glibc_unlikely (misaligned_chunk (p)))
malloc_printerr ("_int_memalign(): unaligned chunk detected");
aligned_m = PTR_ALIGN_UP (m, alignment);
INTERNAL_SIZE_T front_extra = (intptr_t) aligned_m - (intptr_t) m;
/* We can't trim off the front as it's too small. */
if (front_extra > 0 && front_extra < MINSIZE)
return 0;
/* If it's a perfect fit, it's an exception to the return value rule
(we would return zero waste, which looks like "not usable"), so
handle it here by returning a small non-zero value instead. */
if (size == nb && front_extra == 0)
return 1;
/* If the block we need fits in the chunk, calculate total waste. */
if (size > nb + front_extra)
return size - nb;
/* Can't use this chunk. */
return 0;
}
/* BYTES is user requested bytes, not requested chunksize bytes. */
static void *
_int_memalign (mstate av, size_t alignment, size_t bytes)
@@ -5049,10 +5040,9 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
mchunkptr remainder; /* spare room at end to split off */
unsigned long remainder_size; /* its size */
INTERNAL_SIZE_T size;
mchunkptr victim;
nb = checked_request2size (bytes);
if (nb == 0)
if (nb == 0 || alignment > PTRDIFF_MAX)
{
__set_errno (ENOMEM);
return NULL;
@@ -5068,129 +5058,16 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
we don't find anything in those bins, the common malloc code will
scan starting at 2x. */
/* This will be set if we found a candidate chunk. */
victim = NULL;
/* Call malloc with worst case padding to hit alignment. ALIGNMENT is a
power of 2, so it tops out at (PTRDIFF_MAX >> 1) + 1, leaving plenty of
space to add MINSIZE and whatever checked_request2size adds to BYTES to
get NB. Consequently, total below also does not overflow. */
m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
/* Fast bins are singly-linked, hard to remove a chunk from the middle
and unlikely to meet our alignment requirements. We have not done
any experimentation with searching for aligned fastbins. */
if (m == 0)
return 0; /* propagate failure */
if (av != NULL)
{
int first_bin_index;
int first_largebin_index;
int last_bin_index;
if (in_smallbin_range (nb))
first_bin_index = smallbin_index (nb);
else
first_bin_index = largebin_index (nb);
if (in_smallbin_range (nb * 2))
last_bin_index = smallbin_index (nb * 2);
else
last_bin_index = largebin_index (nb * 2);
first_largebin_index = largebin_index (MIN_LARGE_SIZE);
int victim_index; /* its bin index */
for (victim_index = first_bin_index;
victim_index < last_bin_index;
victim_index ++)
{
victim = NULL;
if (victim_index < first_largebin_index)
{
/* Check small bins. Small bin chunks are doubly-linked despite
being the same size. */
mchunkptr fwd; /* misc temp for linking */
mchunkptr bck; /* misc temp for linking */
bck = bin_at (av, victim_index);
fwd = bck->fd;
while (fwd != bck)
{
if (chunk_ok_for_memalign (fwd, alignment, nb) > 0)
{
victim = fwd;
/* Unlink it */
victim->fd->bk = victim->bk;
victim->bk->fd = victim->fd;
break;
}
fwd = fwd->fd;
}
}
else
{
/* Check large bins. */
mchunkptr fwd; /* misc temp for linking */
mchunkptr bck; /* misc temp for linking */
mchunkptr best = NULL;
size_t best_size = 0;
bck = bin_at (av, victim_index);
fwd = bck->fd;
while (fwd != bck)
{
int extra;
if (chunksize (fwd) < nb)
break;
extra = chunk_ok_for_memalign (fwd, alignment, nb);
if (extra > 0
&& (extra <= best_size || best == NULL))
{
best = fwd;
best_size = extra;
}
fwd = fwd->fd;
}
victim = best;
if (victim != NULL)
{
unlink_chunk (av, victim);
break;
}
}
if (victim != NULL)
break;
}
}
/* Strategy: find a spot within that chunk that meets the alignment
request, and then possibly free the leading and trailing space.
This strategy is incredibly costly and can lead to external
fragmentation if header and footer chunks are unused. */
if (victim != NULL)
{
p = victim;
m = chunk2mem (p);
set_inuse (p);
if (av != &main_arena)
set_non_main_arena (p);
}
else
{
/* Call malloc with worst case padding to hit alignment. */
m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
if (m == 0)
return 0; /* propagate failure */
p = mem2chunk (m);
}
p = mem2chunk (m);
if ((((unsigned long) (m)) % alignment) != 0) /* misaligned */
{
@@ -5221,7 +5098,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_inuse_bit_at_offset (newp, newsize);
set_head_size (p, leadsize | (av != &main_arena ? NON_MAIN_ARENA : 0));
_int_free (av, p, 1);
_int_free_merge_chunk (av, p, leadsize);
p = newp;
assert (newsize >= nb &&
@@ -5232,15 +5109,27 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
if (!chunk_is_mmapped (p))
{
size = chunksize (p);
if ((unsigned long) (size) > (unsigned long) (nb + MINSIZE))
mchunkptr nextchunk = chunk_at_offset(p, size);
INTERNAL_SIZE_T nextsize = chunksize(nextchunk);
if (size > nb)
{
remainder_size = size - nb;
remainder = chunk_at_offset (p, nb);
set_head (remainder, remainder_size | PREV_INUSE |
(av != &main_arena ? NON_MAIN_ARENA : 0));
set_head_size (p, nb);
_int_free (av, remainder, 1);
}
if (remainder_size >= MINSIZE
|| nextchunk == av->top
|| !inuse_bit_at_offset (nextchunk, nextsize))
{
/* We can only give back the tail if it is larger than
MINSIZE, or if the following chunk is unused (top
chunk or unused in-heap chunk). Otherwise we would
create a chunk that is smaller than MINSIZE. */
remainder = chunk_at_offset (p, nb);
set_head_size (p, nb);
remainder_size = _int_free_create_chunk (av, remainder,
remainder_size,
nextchunk, nextsize);
_int_free_maybe_consolidate (av, remainder_size);
}
}
}
check_inuse_chunk (av, p);
+2
View File
@@ -25,6 +25,8 @@
#include <libc-diag.h>
#include <support/check.h>
#include "tst-malloc-aux.h"
static int
do_test (void)
{
+8 -4
View File
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <libc-diag.h>
#include "tst-malloc-aux.h"
/* Number of samples per size. */
#define N 50000
@@ -94,16 +95,19 @@ random_test (void)
static void
null_test (void)
{
/* Obscure allocation size from the compiler. */
volatile size_t max_size = UINT_MAX;
volatile size_t zero_size = 0;
/* If the size is 0 the result is implementation defined. Just make
sure the program doesn't crash. The result of calloc is
deliberately ignored, so do not warn about that. */
DIAG_PUSH_NEEDS_COMMENT;
DIAG_IGNORE_NEEDS_COMMENT (10, "-Wunused-result");
calloc (0, 0);
calloc (0, UINT_MAX);
calloc (UINT_MAX, 0);
calloc (0, ~((size_t) 0));
calloc (~((size_t) 0), 0);
calloc (0, max_size);
calloc (max_size, 0);
calloc (0, ~zero_size);
calloc (~zero_size, 0);
DIAG_POP_NEEDS_COMMENT;
}
+2
View File
@@ -25,6 +25,8 @@
#include <support/check.h>
#include <support/support.h>
#include "tst-malloc-aux.h"
extern void (*volatile __free_hook) (void *, const void *);
extern void *(*volatile __malloc_hook)(size_t, const void *);
extern void *(*volatile __realloc_hook)(void *, size_t, const void *);
+41
View File
@@ -0,0 +1,41 @@
/* Wrappers for malloc-like functions to allow testing the implementation
without optimization.
Copyright (C) 2024 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; see the file COPYING.LIB. If
not, see <https://www.gnu.org/licenses/>. */
#ifndef TST_MALLOC_AUX_H
#define TST_MALLOC_AUX_H
#include <stddef.h>
#include <stdlib.h>
static void *(*volatile aligned_alloc_indirect)(size_t, size_t) = aligned_alloc;
static void *(*volatile calloc_indirect)(size_t, size_t) = calloc;
static void *(*volatile malloc_indirect)(size_t) = malloc;
static void *(*volatile realloc_indirect)(void*, size_t) = realloc;
#undef aligned_alloc
#undef calloc
#undef malloc
#undef realloc
#define aligned_alloc aligned_alloc_indirect
#define calloc calloc_indirect
#define malloc malloc_indirect
#define realloc realloc_indirect
#endif /* TST_MALLOC_AUX_H */
+2
View File
@@ -20,6 +20,8 @@
#include <stdlib.h>
#include <libc-diag.h>
#include "tst-malloc-aux.h"
static int errors = 0;
static void
+3 -8
View File
@@ -43,6 +43,7 @@
#include <unistd.h>
#include <sys/param.h>
#include "tst-malloc-aux.h"
/* This function prepares for each 'too-large memory allocation' test by
performing a small successful malloc/free and resetting errno prior to
@@ -151,7 +152,6 @@ test_large_allocations (size_t size)
}
static long pagesize;
/* This function tests the following aligned memory allocation functions
using several valid alignments and precedes each allocation test with a
@@ -170,8 +170,8 @@ test_large_aligned_allocations (size_t size)
/* All aligned memory allocation functions expect an alignment that is a
power of 2. Given this, we test each of them with every valid
alignment from 1 thru PAGESIZE. */
for (align = 1; align <= pagesize; align *= 2)
alignment for the type of ALIGN, i.e. until it wraps to 0. */
for (align = 1; align > 0; align <<= 1)
{
test_setup ();
#if __GNUC_PREREQ (7, 0)
@@ -264,11 +264,6 @@ do_test (void)
DIAG_IGNORE_NEEDS_COMMENT (7, "-Walloc-size-larger-than=");
#endif
/* Aligned memory allocation functions need to be tested up to alignment
size equivalent to page size, which should be a power of 2. */
pagesize = sysconf (_SC_PAGESIZE);
TEST_VERIFY_EXIT (powerof2 (pagesize));
/* Loop 1: Ensure that all allocations with SIZE close to SIZE_MAX, i.e.
in the range (SIZE_MAX - 2^14, SIZE_MAX], fail.
+2
View File
@@ -20,6 +20,8 @@
#include <stdio.h>
#include <libc-diag.h>
#include "tst-malloc-aux.h"
static int errors = 0;
static void
+5 -2
View File
@@ -86,7 +86,8 @@ do_test (void)
TEST_VERIFY (tcache_allocs[i].ptr1 == tcache_allocs[i].ptr2);
}
/* Test for non-head tcache hits. */
/* Test for non-head tcache hits. This exercises the memalign
scanning code to find matching allocations. */
for (i = 0; i < array_length (ptr); ++ i)
{
if (i == 4)
@@ -113,7 +114,9 @@ do_test (void)
free (p);
TEST_VERIFY (count > 0);
/* Large bins test. */
/* Large bins test. This verifies that the over-allocated parts
that memalign releases for future allocations can be reused by
memalign itself at least in some cases. */
for (i = 0; i < LN; ++ i)
{
+2
View File
@@ -23,6 +23,8 @@
#include <libc-diag.h>
#include <support/check.h>
#include "tst-malloc-aux.h"
static int
do_test (void)
{
+3 -7
View File
@@ -169,17 +169,13 @@ Enable Intel Control-flow Enforcement Technology (CET) support. When
is protected with indirect branch tracking (IBT) and shadow stack
(SHSTK)@. When CET is enabled, @theglibc{} is compatible with all
existing executables and shared libraries. This feature is currently
supported on i386, x86_64 and x32 with GCC 8 and binutils 2.29 or later.
Note that when CET is enabled, @theglibc{} requires CPUs capable of
multi-byte NOPs, like x86-64 processors as well as Intel Pentium Pro or
newer. With @option{--enable-cet}, it is an error to dlopen a non CET
supported on x86_64 and x32 with GCC 8 and binutils 2.29 or later.
With @option{--enable-cet}, it is an error to dlopen a non CET
enabled shared library in CET enabled application. With
@option{--enable-cet=permissive}, CET is disabled when dlopening a
non CET enabled shared library in CET enabled application.
NOTE: @option{--enable-cet} has been tested for i686, x86_64 and x32
on non-CET processors. @option{--enable-cet} has been tested for
i686, x86_64 and x32 on CET processors.
NOTE: @option{--enable-cet} is only supported on x86_64 and x32.
@item --enable-memory-tagging
Enable memory tagging support if the architecture supports it. When
+1
View File
@@ -1133,6 +1133,7 @@ following @code{errno} error conditions are defined for this function:
@table @code
@item ESRCH
There is no process with the given process ID @var{pid}.
@item EPERM
The calling process and the process specified by @var{pid} are in
different sessions, and the implementation doesn't allow to access the
process group ID of the process with ID @var{pid} from the calling
+39 -7
View File
@@ -1339,6 +1339,10 @@ will fail and set @code{errno} to @code{EAGAIN} if the operation would block.
@item RWF_APPEND
Per-IO synchronization as if the file was opened with @code{O_APPEND} flag.
@item RWF_NOAPPEND
This flag allows an offset to be honored, even if the file was opened with
@code{O_APPEND} flag.
@end vtable
When the source file is compiled with @code{_FILE_OFFSET_BITS == 64} the
@@ -1777,7 +1781,7 @@ There is no existing mapping in at least part of the given region.
@end deftypefun
@deftypefun {void *} mremap (void *@var{address}, size_t @var{length}, size_t @var{new_length}, int @var{flag})
@deftypefun {void *} mremap (void *@var{address}, size_t @var{length}, size_t @var{new_length}, int @var{flag}, ... /* void *@var{new_address} */)
@standards{GNU, sys/mman.h}
@safety{@prelim{}@mtsafe{}@assafe{}@acsafe{}}
@@ -1786,12 +1790,40 @@ area. @var{address} and @var{length} must cover a region entirely mapped
in the same @code{mmap} statement. A new mapping with the same
characteristics will be returned with the length @var{new_length}.
One option is possible, @code{MREMAP_MAYMOVE}. If it is given in
@var{flags}, the system may remove the existing mapping and create a new
one of the desired length in another location.
Possible flags are
The address of the resulting mapping is returned, or @math{-1}. Possible
error codes include:
@table @code
@item MREMAP_MAYMOVE
If it is given in @var{flags}, the system may remove the existing mapping
and create a new one of the desired length in another location.
@item MREMAP_FIXED
If it is given in @var{flags}, @code{mremap} accepts a fifth argument,
@code{void *new_address}, which specifies a page-aligned address to
which the mapping must be moved. Any previous mapping at the address
range specified by @var{new_address} and @var{new_size} is unmapped.
@code{MREMAP_FIXED} must be used together with @code{MREMAP_MAYMOVE}.
@item MREMAP_DONTUNMAP
If it is given in @var{flags}, @code{mremap} accepts a fifth argument,
@code{void *new_address}, which specifies a page-aligned address. Any
previous mapping at the address range specified by @var{new_address} and
@var{new_size} is unmapped. If @var{new_address} is @code{NULL}, the
kernel chooses the page-aligned address at which to create the mapping.
Otherwise, the kernel takes it as a hint about where to place the mapping.
The mapping at the address range specified by @var{old_address} and
@var{old_size} isn't unmapped.
@code{MREMAP_DONTUNMAP} must be used together with @code{MREMAP_MAYMOVE}.
@var{old_size} must be the same as @var{new_size}. This flag bit is
Linux-specific.
@end table
The address of the resulting mapping is returned, or @code{MAP_FAILED}.
Possible error codes include:
@table @code
@@ -1800,7 +1832,7 @@ There is no existing mapping in at least part of the original region, or
the region covers two or more distinct mappings.
@item EINVAL
The address given is misaligned or inappropriate.
Any arguments are inappropriate, including unknown @var{flags} values.
@item EAGAIN
The region has pages locked, and if extended it would exceed the
+3 -5
View File
@@ -1474,11 +1474,9 @@ program; usually @code{ungetc} is used only to unread a character that
was just read from the same stream. @Theglibc{} supports this
even on files opened in binary mode, but other systems might not.
@Theglibc{} only supports one character of pushback---in other
words, it does not work to call @code{ungetc} twice without doing input
in between. Other systems might let you push back multiple characters;
then reading from the stream retrieves the characters in the reverse
order that they were pushed.
@Theglibc{} supports pushing back multiple characters; subsequently
reading from the stream retrieves the characters in the reverse order
that they were pushed.
Pushing back characters doesn't alter the file; only the internal
buffering for the stream is affected. If a file positioning function
+6 -2
View File
@@ -1007,8 +1007,12 @@ This variable is either zero (if restartable sequence registration
failed or has been disabled) or the size of the restartable sequence
registration. This can be different from the size of @code{struct rseq}
if the kernel has extended the size of the registration. If
registration is successful, @code{__rseq_size} is at least 32 (the
initial size of @code{struct rseq}).
registration is successful, @code{__rseq_size} is at least 20 (the
initially active size of @code{struct rseq}).
Previous versions of @theglibc{} set this to 32 even if the kernel only
supported the initial area of 20 bytes because the value included unused
padding at the end of the restartable sequence area.
@end deftypevar
@deftypevar {unsigned int} __rseq_flags
+1 -1
View File
@@ -529,7 +529,7 @@ This tunable is specific to powerpc, powerpc64 and powerpc64le.
@deftp Tunable glibc.cpu.name
The @code{glibc.cpu.name=xxx} tunable allows the user to tell @theglibc{} to
assume that the CPU is @code{xxx} where xxx may have one of these values:
@code{generic}, @code{falkor}, @code{thunderxt88}, @code{thunderx2t99},
@code{generic}, @code{thunderxt88}, @code{thunderx2t99},
@code{thunderx2t99p1}, @code{ares}, @code{emag}, @code{kunpeng},
@code{a64fx}.
+3
View File
@@ -261,6 +261,9 @@ tests-static = test-fpucw-static test-fpucw-ieee-static \
# The tested symbols matherr, _LIB_VERSION have been removed in glibc 2.27.
ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes)
tests += test-matherr test-matherr-2
tests-2.0 += \
test-matherr-2 \
# tests-2.0
endif
# These tests use internal (unexported) GMP functions and are linked
+3 -10
View File
@@ -24,6 +24,8 @@
#include <string.h>
#include <tgmath.h>
#include <support/check.h>
//#define DEBUG
typedef complex float cfloat;
@@ -87,13 +89,6 @@ enum
int count;
int counts[Tlast][C_last];
#define FAIL(str) \
do \
{ \
printf ("%s failure on line %d\n", (str), __LINE__); \
result = 1; \
} \
while (0)
#define TEST_TYPE_ONLY(expr, rettype) \
do \
{ \
@@ -133,8 +128,6 @@ int counts[Tlast][C_last];
int
test_cos (const int Vint4, const long long int Vllong4)
{
int result = 0;
TEST (cos (vfloat1), float, cos);
TEST (cos (vdouble1), double, cos);
TEST (cos (vldouble1), ldouble, cos);
@@ -152,7 +145,7 @@ test_cos (const int Vint4, const long long int Vllong4)
TEST (cos (Vcdouble1), cdouble, cos);
TEST (cos (Vcldouble1), cldouble, cos);
return result;
return 0;
}
int
+9 -1
View File
@@ -251,6 +251,8 @@ tests := \
tst-mntent-blank-passno \
tst-mntent-escape \
tst-mntent2 \
tst-mremap1 \
tst-mremap2 \
tst-preadvwritev \
tst-preadvwritev2 \
tst-preadvwritev64 \
@@ -289,7 +291,10 @@ tests-special += $(objpfx)tst-error1-mem.out \
$(objpfx)tst-allocate_once-mem.out
endif
tests-container := tst-syslog
tests-container := \
tst-syslog \
tst-syslog-long-progname \
# tests-container
CFLAGS-select.c += -fexceptions -fasynchronous-unwind-tables
CFLAGS-tsearch.c += $(uses-callbacks)
@@ -351,6 +356,9 @@ $(objpfx)tst-allocate_once-mem.out: $(objpfx)tst-allocate_once.out
$(common-objpfx)malloc/mtrace $(objpfx)tst-allocate_once.mtrace > $@; \
$(evaluate-test)
tst-syslog-long-progname-ENV = GLIBC_TUNABLES=glibc.malloc.check=3 \
LD_PRELOAD=libc_malloc_debug.so.0
$(objpfx)tst-select: $(librt)
$(objpfx)tst-select-time64: $(librt)
$(objpfx)tst-pselect: $(librt)
-6
View File
@@ -44,12 +44,6 @@ weak_alias (__get_nprocs, get_nprocs)
link_warning (get_nprocs, "warning: get_nprocs will always return 1")
int
__get_nprocs_sched (void)
{
return 1;
}
long int
__get_phys_pages (void)
{

Some files were not shown because too many files have changed in this diff Show More