Skip to content
Snippets Groups Projects
Commit c419a934 authored by Rocky Automation's avatar Rocky Automation :tv:
Browse files

import glibc-2.39-29.el10

parent d5e13cae
No related branches found
Tags imports/r10s/glibc-2.39-29.el10
No related merge requests found
Showing
with 2864 additions and 0 deletions
commit 461cab1de747f3842f27a5d24977d78d561d45f9
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
Date: Wed Sep 18 16:01:22 2024 +0200
linux: Add support for getrandom vDSO
Linux 6.11 has getrandom() in vDSO. It operates on a thread-local opaque
state allocated with mmap using flags specified by the vDSO.
Multiple states are allocated at once, as many as fit into a page, and
these are held in an array of available states to be doled out to each
thread upon first use, and recycled when a thread terminates. As these
states run low, more are allocated.
To make this procedure async-signal-safe, a simple guard is used in the
LSB of the opaque state address, falling back to the syscall if there's
reentrancy contention.
Also, _Fork() is handled by blocking signals on opaque state allocation
(so _Fork() always sees a consistent state even if it interrupts a
getrandom() call) and by iterating over the thread stack cache on
reclaim_stack. Each opaque state will be in the free states list
(grnd_alloc.states) or allocated to a running thread.
The cancellation is handled by always using GRND_NONBLOCK flags while
calling the vDSO, and falling back to the cancellable syscall if the
kernel returns EAGAIN (would block). Since getrandom is not defined by
POSIX and cancellation is supported as an extension, the cancellation is
handled as 'may occur' instead of 'shall occur' [1], meaning that if
vDSO does not block (the expected behavior) getrandom will not act as a
cancellation entrypoint. It avoids a pthread_testcancel call on the fast
path (different than 'shall occur' functions, like sem_wait()).
It is currently enabled for x86_64, which is available in Linux 6.11,
and aarch64, powerpc32, powerpc64, loongarch64, and s390x, which are
available in Linux 6.12.
Link: https://pubs.opengroup.org/onlinepubs/9799919799/nframe.html [1]
Co-developed-by: Jason A. Donenfeld <Jason@zx2c4.com>
Tested-by: Jason A. Donenfeld <Jason@zx2c4.com> # x86_64
Tested-by: Adhemerval Zanella <adhemerval.zanella@linaro.org> # x86_64, aarch64
Tested-by: Xi Ruoyao <xry111@xry111.site> # x86_64, aarch64, loongarch64
Tested-by: Stefan Liebler <stli@linux.ibm.com> # s390x
Conflicts:
stdlib/Makefile
(usual test differences)
sysdeps/unix/sysv/linux/dl-vdso-setup.h
(glibc-2.39 does not have riscv hwprobe vdso support)
diff --git a/elf/libc_early_init.c b/elf/libc_early_init.c
index 575b837f8f43cb75..20c71fd48b5bd604 100644
--- a/elf/libc_early_init.c
+++ b/elf/libc_early_init.c
@@ -23,6 +23,7 @@
#include <lowlevellock.h>
#include <pthread_early_init.h>
#include <sys/single_threaded.h>
+#include <getrandom-internal.h>
#ifdef SHARED
_Bool __libc_initial;
@@ -43,6 +44,8 @@ __libc_early_init (_Bool initial)
__pthread_early_init ();
+ __getrandom_early_init (initial);
+
#if ENABLE_ELISION_SUPPORT
__lll_elision_init ();
#endif
diff --git a/malloc/malloc.c b/malloc/malloc.c
index bcb6e5b83ca9777d..9e577ab90010a0f1 100644
--- a/malloc/malloc.c
+++ b/malloc/malloc.c
@@ -3140,8 +3140,8 @@ static void
tcache_key_initialize (void)
{
/* We need to use the _nostatus version here, see BZ 29624. */
- if (__getrandom_nocancel_nostatus (&tcache_key, sizeof(tcache_key),
- GRND_NONBLOCK)
+ if (__getrandom_nocancel_nostatus_direct (&tcache_key, sizeof(tcache_key),
+ GRND_NONBLOCK)
!= sizeof (tcache_key))
{
tcache_key = random_bits ();
diff --git a/nptl/allocatestack.c b/nptl/allocatestack.c
index f35a8369bd5d197a..9ed886573fdc3b7d 100644
--- a/nptl/allocatestack.c
+++ b/nptl/allocatestack.c
@@ -132,6 +132,8 @@ get_cached_stack (size_t *sizep, void **memp)
__libc_lock_init (result->exit_lock);
memset (&result->tls_state, 0, sizeof result->tls_state);
+ result->getrandom_buf = NULL;
+
/* Clear the DTV. */
dtv_t *dtv = GET_DTV (TLS_TPADJ (result));
for (size_t cnt = 0; cnt < dtv[-1].counter; ++cnt)
diff --git a/nptl/descr.h b/nptl/descr.h
index 8cef95810c81eb3b..4697f633e16c7359 100644
--- a/nptl/descr.h
+++ b/nptl/descr.h
@@ -404,6 +404,9 @@ struct pthread
/* Used on strsignal. */
struct tls_internal_t tls_state;
+ /* getrandom vDSO per-thread opaque state. */
+ void *getrandom_buf;
+
/* rseq area registered with the kernel. Use a custom definition
here to isolate from kernel struct rseq changes. The
implementation of sched_getcpu needs acccess to the cpu_id field;
diff --git a/nptl/pthread_create.c b/nptl/pthread_create.c
index 1d3665d5edb684e3..ef3ec3329027ac9f 100644
--- a/nptl/pthread_create.c
+++ b/nptl/pthread_create.c
@@ -38,6 +38,7 @@
#include <version.h>
#include <clone_internal.h>
#include <futex-internal.h>
+#include <getrandom-internal.h>
#include <shlib-compat.h>
@@ -549,6 +550,10 @@ start_thread (void *arg)
}
#endif
+ /* Release the vDSO getrandom per-thread buffer with all signal blocked,
+ to avoid creating a new free-state block during thread release. */
+ __getrandom_vdso_release (pd);
+
if (!pd->user_stack)
advise_stack_range (pd->stackblock, pd->stackblock_size, (uintptr_t) pd,
pd->guardsize);
diff --git a/stdlib/Makefile b/stdlib/Makefile
index 9898cc5d8a560625..44a118da59f96c17 100644
--- a/stdlib/Makefile
+++ b/stdlib/Makefile
@@ -276,6 +276,7 @@ tests := \
tst-cxa_atexit \
tst-environ \
tst-getrandom \
+ tst-getrandom2 \
tst-labs \
tst-limits \
tst-llabs \
@@ -622,3 +623,4 @@ $(objpfx)tst-setcontext3.out: tst-setcontext3.sh $(objpfx)tst-setcontext3
$(evaluate-test)
$(objpfx)tst-qsort5: $(libm)
+$(objpfx)tst-getrandom2: $(shared-thread-library)
diff --git a/stdlib/tst-getrandom2.c b/stdlib/tst-getrandom2.c
new file mode 100644
index 0000000000000000..f085b4b74fcf1a28
--- /dev/null
+++ b/stdlib/tst-getrandom2.c
@@ -0,0 +1,47 @@
+/* Tests for the getrandom functions.
+ 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 <gnu/lib-names.h>
+#include <support/check.h>
+#include <support/xdlfcn.h>
+#include <support/xthread.h>
+#include <sys/random.h>
+
+static __typeof (getrandom) *getrandom_ptr;
+
+static void *
+threadfunc (void *ignored)
+{
+ char buffer;
+ TEST_COMPARE (getrandom_ptr (&buffer, 1, 0), 1);
+ return NULL;
+}
+
+static int
+do_test (void)
+{
+ /* Check if issuing getrandom in the secondary libc.so works when
+ the vDSO might be potentially used. */
+ void *handle = xdlmopen (LM_ID_NEWLM, LIBC_SO, RTLD_NOW);
+ getrandom_ptr = xdlsym (handle, "getrandom");
+ for (int i = 0; i < 1000; ++i)
+ xpthread_join (xpthread_create (NULL, threadfunc, NULL));
+ return 0;
+}
+
+#include <support/test-driver.c>
diff --git a/sysdeps/generic/getrandom-internal.h b/sysdeps/generic/getrandom-internal.h
new file mode 100644
index 0000000000000000..3fe46532a0ed3834
--- /dev/null
+++ b/sysdeps/generic/getrandom-internal.h
@@ -0,0 +1,26 @@
+/* Internal definitions for getrandom implementation.
+ 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/>. */
+
+#ifndef _GETRANDOM_INTERNAL_H
+#define _GETRANDOM_INTERNAL_H
+
+static inline void __getrandom_early_init (_Bool)
+{
+}
+
+#endif
diff --git a/sysdeps/generic/not-cancel.h b/sysdeps/generic/not-cancel.h
index 2dd10646004611cf..8e3f49cc07c85d76 100644
--- a/sysdeps/generic/not-cancel.h
+++ b/sysdeps/generic/not-cancel.h
@@ -51,7 +51,9 @@
__fcntl64 (fd, cmd, __VA_ARGS__)
#define __getrandom_nocancel(buf, size, flags) \
__getrandom (buf, size, flags)
-#define __getrandom_nocancel_nostatus(buf, size, flags) \
+#define __getrandom_nocancel_direct(buf, size, flags) \
+ __getrandom (buf, size, flags)
+#define __getrandom_nocancel_nostatus_direct(buf, size, flags) \
__getrandom (buf, size, flags)
#define __poll_infinity_nocancel(fds, nfds) \
__poll (fds, nfds, -1)
diff --git a/sysdeps/mach/hurd/not-cancel.h b/sysdeps/mach/hurd/not-cancel.h
index 69fb3c00ef774d00..ec5f5aa8954baa4d 100644
--- a/sysdeps/mach/hurd/not-cancel.h
+++ b/sysdeps/mach/hurd/not-cancel.h
@@ -79,7 +79,7 @@ __typeof (__fcntl) __fcntl_nocancel;
/* Non cancellable getrandom syscall that does not also set errno in case of
failure. */
static inline ssize_t
-__getrandom_nocancel_nostatus (void *buf, size_t buflen, unsigned int flags)
+__getrandom_nocancel_nostatus_direct (void *buf, size_t buflen, unsigned int flags)
{
int save_errno = errno;
ssize_t r = __getrandom (buf, buflen, flags);
@@ -90,6 +90,8 @@ __getrandom_nocancel_nostatus (void *buf, size_t buflen, unsigned int flags)
#define __getrandom_nocancel(buf, size, flags) \
__getrandom (buf, size, flags)
+#define __getrandom_nocancel_direct(buf, size, flags) \
+ __getrandom (buf, size, flags)
#define __poll_infinity_nocancel(fds, nfds) \
__poll (fds, nfds, -1)
diff --git a/sysdeps/nptl/_Fork.c b/sysdeps/nptl/_Fork.c
index ef199ddbc37e556c..c82fd50649c427c9 100644
--- a/sysdeps/nptl/_Fork.c
+++ b/sysdeps/nptl/_Fork.c
@@ -18,6 +18,7 @@
#include <arch-fork.h>
#include <pthreadP.h>
+#include <getrandom-internal.h>
pid_t
_Fork (void)
@@ -43,6 +44,7 @@ _Fork (void)
self->robust_head.list = &self->robust_head;
INTERNAL_SYSCALL_CALL (set_robust_list, &self->robust_head,
sizeof (struct robust_list_head));
+ call_function_static_weak (__getrandom_fork_subprocess);
}
return pid;
}
diff --git a/sysdeps/nptl/fork.h b/sysdeps/nptl/fork.h
index 7643926df9e3a22e..eabf3c81b0127b34 100644
--- a/sysdeps/nptl/fork.h
+++ b/sysdeps/nptl/fork.h
@@ -26,6 +26,7 @@
#include <mqueue.h>
#include <pthreadP.h>
#include <sysdep.h>
+#include <getrandom-internal.h>
static inline void
fork_system_setup (void)
@@ -46,6 +47,7 @@ fork_system_setup_after_fork (void)
call_function_static_weak (__mq_notify_fork_subprocess);
call_function_static_weak (__timer_fork_subprocess);
+ call_function_static_weak (__getrandom_fork_subprocess);
}
/* In case of a fork() call the memory allocation in the child will be
@@ -128,9 +130,19 @@ reclaim_stacks (void)
curp->specific_used = true;
}
}
+
+ call_function_static_weak (__getrandom_reset_state, curp);
}
}
+ /* Also reset stale getrandom states for user stack threads. */
+ list_for_each (runp, &GL (dl_stack_user))
+ {
+ struct pthread *curp = list_entry (runp, struct pthread, list);
+ if (curp != self)
+ call_function_static_weak (__getrandom_reset_state, curp);
+ }
+
/* Add the stack of all running threads to the cache. */
list_splice (&GL (dl_stack_used), &GL (dl_stack_cache));
diff --git a/sysdeps/unix/sysv/linux/aarch64/sysdep.h b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
index bbbe35723cac80ef..974b503b2f93511d 100644
--- a/sysdeps/unix/sysv/linux/aarch64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/aarch64/sysdep.h
@@ -164,6 +164,7 @@
# define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres"
# define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime"
# define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday"
+# define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom"
# define HAVE_CLONE3_WRAPPER 1
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.c b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
index 5dd7ed9d126feedc..9afde3d589199e7a 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.c
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.c
@@ -66,6 +66,11 @@ PROCINFO_CLASS int (*_dl_vdso_clock_getres) (clockid_t,
PROCINFO_CLASS int (*_dl_vdso_clock_getres_time64) (clockid_t,
struct __timespec64 *) RELRO;
# endif
+# ifdef HAVE_GETRANDOM_VSYSCALL
+PROCINFO_CLASS ssize_t (*_dl_vdso_getrandom) (void *buffer, size_t len,
+ unsigned int flags, void *state,
+ size_t state_len) RELRO;
+# endif
/* PowerPC specific ones. */
# ifdef HAVE_GET_TBFREQ
diff --git a/sysdeps/unix/sysv/linux/dl-vdso-setup.h b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
index e87d88694098588e..e8faeaef7d2c127a 100644
--- a/sysdeps/unix/sysv/linux/dl-vdso-setup.h
+++ b/sysdeps/unix/sysv/linux/dl-vdso-setup.h
@@ -47,6 +47,9 @@ setup_vdso_pointers (void)
#ifdef HAVE_GET_TBFREQ
GLRO(dl_vdso_get_tbfreq) = dl_vdso_vsym (HAVE_GET_TBFREQ);
#endif
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ GLRO(dl_vdso_getrandom) = dl_vdso_vsym (HAVE_GETRANDOM_VSYSCALL);
+#endif
}
#endif
diff --git a/sysdeps/unix/sysv/linux/getrandom-internal.h b/sysdeps/unix/sysv/linux/getrandom-internal.h
new file mode 100644
index 0000000000000000..37e6c9bc150ba061
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/getrandom-internal.h
@@ -0,0 +1,29 @@
+/* Internal definitions for Linux getrandom implementation.
+ 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/>. */
+
+#ifndef _GETRANDOM_INTERNAL_H
+#define _GETRANDOM_INTERNAL_H
+
+#include <pthreadP.h>
+
+extern void __getrandom_early_init (_Bool) attribute_hidden;
+
+extern void __getrandom_fork_subprocess (void) attribute_hidden;
+extern void __getrandom_vdso_release (struct pthread *curp) attribute_hidden;
+extern void __getrandom_reset_state (struct pthread *curp) attribute_hidden;
+#endif
diff --git a/sysdeps/unix/sysv/linux/getrandom.c b/sysdeps/unix/sysv/linux/getrandom.c
index 777d1decf0fa50ea..c8c578263da456b2 100644
--- a/sysdeps/unix/sysv/linux/getrandom.c
+++ b/sysdeps/unix/sysv/linux/getrandom.c
@@ -21,12 +21,314 @@
#include <unistd.h>
#include <sysdep-cancel.h>
+static inline ssize_t
+getrandom_syscall (void *buffer, size_t length, unsigned int flags,
+ bool cancel)
+{
+ return cancel
+ ? SYSCALL_CANCEL (getrandom, buffer, length, flags)
+ : INLINE_SYSCALL_CALL (getrandom, buffer, length, flags);
+}
+
+#ifdef HAVE_GETRANDOM_VSYSCALL
+# include <assert.h>
+# include <ldsodefs.h>
+# include <libc-lock.h>
+# include <list.h>
+# include <setvmaname.h>
+# include <sys/mman.h>
+# include <sys/sysinfo.h>
+# include <tls-internal.h>
+
+/* These values will be initialized at loading time by calling the
+ _dl_vdso_getrandom with a special value. The 'state_size' is the opaque
+ state size per-thread allocated with a mmap using 'mmap_prot' and
+ 'mmap_flags' argument. */
+static uint32_t state_size;
+static uint32_t state_size_cache_aligned;
+static uint32_t mmap_prot;
+static uint32_t mmap_flags;
+
+/* The function below are used on reentracy handling with (i.e. SA_NODEFER).
+ Before allocating a new state or issue the vDSO, atomically read the
+ current thread buffer, and if this is already reserved (is_reserved_ptr)
+ fallback to the syscall. Otherwise, reserve the buffer by atomically
+ setting the LSB of the opaque state pointer. The bit is cleared after the
+ vDSO is called, or before issuing the fallback syscall. */
+
+static inline void *reserve_ptr (void *p)
+{
+ return (void *) ((uintptr_t) (p) | 1UL);
+}
+
+static inline void *release_ptr (void *p)
+{
+ return (void *) ((uintptr_t) (p) & ~1UL);
+}
+
+static inline bool is_reserved_ptr (void *p)
+{
+ return (uintptr_t) (p) & 1UL;
+}
+
+static struct
+{
+ __libc_lock_define (, lock);
+
+ void **states; /* Queue of opaque states allocated with the kernel
+ provided flags and used on getrandom vDSO call. */
+ size_t len; /* Number of available free states in the queue. */
+ size_t total; /* Number of states allocated from the kernel. */
+ size_t cap; /* Total number of states that 'states' can hold before
+ needed to be resized. */
+} grnd_alloc = {
+ .lock = LLL_LOCK_INITIALIZER
+};
+
+static bool
+vgetrandom_get_state_alloc (void)
+{
+ /* Start by allocating one page for the opaque states. */
+ size_t block_size = ALIGN_UP (state_size_cache_aligned, GLRO(dl_pagesize));
+ size_t states_per_page = GLRO (dl_pagesize) / state_size_cache_aligned;
+ void *block = __mmap (NULL, GLRO(dl_pagesize), mmap_prot, mmap_flags, -1, 0);
+ if (block == MAP_FAILED)
+ return false;
+ __set_vma_name (block, block_size, " glibc: getrandom");
+
+ if (grnd_alloc.total + states_per_page > grnd_alloc.cap)
+ {
+ /* Use a new mmap instead of trying to mremap. It avoids a
+ potential multithread fork issue where fork is called just after
+ mremap returns but before assigning to the grnd_alloc.states,
+ thus making the its value invalid in the child. */
+ void *old_states = grnd_alloc.states;
+ size_t new_states_size = ALIGN_UP ((grnd_alloc.total + states_per_page)
+ * sizeof (*grnd_alloc.states),
+ GLRO(dl_pagesize));
+
+ /* There is no need to memcpy any opaque state information because
+ all the allocated opaque states are assigned to running threads
+ (meaning that if we iterate over them we can reconstruct the state
+ list). */
+ void **states = __mmap (NULL, new_states_size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (states == MAP_FAILED)
+ {
+ __munmap (block, block_size);
+ return false;
+ }
+
+ /* Atomically replace the old state, so if a fork happens the child
+ process will see a consistent free state buffer. The size might
+ not be updated, but it does not really matter since the buffer is
+ always increased. */
+ grnd_alloc.states = states;
+ atomic_thread_fence_seq_cst ();
+ if (old_states != NULL)
+ __munmap (old_states, grnd_alloc.cap * sizeof (*grnd_alloc.states));
+
+ __set_vma_name (states, new_states_size, " glibc: getrandom states");
+ grnd_alloc.cap = new_states_size / sizeof (*grnd_alloc.states);
+ atomic_thread_fence_seq_cst ();
+ }
+
+ for (size_t i = 0; i < states_per_page; ++i)
+ {
+ /* There is no need to handle states that straddle a page because
+ we allocate only one page. */
+ grnd_alloc.states[i] = block;
+ block += state_size_cache_aligned;
+ }
+ /* Concurrent fork should not observe the previous pointer value. */
+ grnd_alloc.len = states_per_page;
+ grnd_alloc.total += states_per_page;
+ atomic_thread_fence_seq_cst ();
+
+ return true;
+}
+
+/* Allocate an opaque state for vgetrandom. If the grnd_alloc does not have
+ any, mmap() another page of them using the vgetrandom parameters. */
+static void *
+vgetrandom_get_state (void)
+{
+ void *state = NULL;
+
+ /* The signal blocking avoid the potential issue where _Fork() (which is
+ async-signal-safe) is called with the lock taken. The function is
+ called only once during thread lifetime, so the overhead should be
+ minimal. */
+ internal_sigset_t set;
+ internal_signal_block_all (&set);
+ __libc_lock_lock (grnd_alloc.lock);
+
+ if (grnd_alloc.len > 0 || vgetrandom_get_state_alloc ())
+ state = grnd_alloc.states[--grnd_alloc.len];
+
+ __libc_lock_unlock (grnd_alloc.lock);
+ internal_signal_restore_set (&set);
+
+ return state;
+}
+
+/* Returns true when vgetrandom is used successfully. Returns false if the
+ syscall fallback should be issued in the case the vDSO is not present, in
+ the case of reentrancy, or if any memory allocation fails. */
+static ssize_t
+getrandom_vdso (void *buffer, size_t length, unsigned int flags, bool cancel)
+{
+ if (__glibc_unlikely (state_size == 0))
+ return getrandom_syscall (buffer, length, flags, cancel);
+
+ struct pthread *self = THREAD_SELF;
+
+ void *state = atomic_load_relaxed (&self->getrandom_buf);
+ if (is_reserved_ptr (state))
+ return getrandom_syscall (buffer, length, flags, cancel);
+ atomic_store_relaxed (&self->getrandom_buf, reserve_ptr (state));
+ __atomic_signal_fence (__ATOMIC_ACQ_REL);
+
+ bool r = false;
+ if (state == NULL)
+ {
+ state = vgetrandom_get_state ();
+ if (state == NULL)
+ goto out;
+ }
+
+ /* Since the vDSO implementation does not issue the syscall with the
+ cancellation bridge (__syscall_cancel_arch), use GRND_NONBLOCK so there
+ is no potential unbounded blocking in the kernel. It should be a rare
+ situation, only at system startup when RNG is not initialized. */
+ ssize_t ret = GLRO (dl_vdso_getrandom) (buffer,
+ length,
+ flags | GRND_NONBLOCK,
+ state,
+ state_size);
+ if (INTERNAL_SYSCALL_ERROR_P (ret))
+ {
+ /* Fallback to the syscall if the kernel would block. */
+ int err = INTERNAL_SYSCALL_ERRNO (ret);
+ if (err == EAGAIN && !(flags & GRND_NONBLOCK))
+ goto out;
+
+ __set_errno (err);
+ ret = -1;
+ }
+ r = true;
+
+out:
+ __atomic_signal_fence (__ATOMIC_ACQ_REL);
+ atomic_store_relaxed (&self->getrandom_buf, state);
+ return r ? ret : getrandom_syscall (buffer, length, flags, cancel);
+}
+#endif
+
+void
+__getrandom_early_init (_Bool initial)
+{
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ /* libcs loaded for audit modules, dlmopen, etc. fallback to syscall. */
+ if (initial && (GLRO (dl_vdso_getrandom) != NULL))
+ {
+ /* Used to query the vDSO for the required mmap flags and the opaque
+ per-thread state size. Defined by linux/random.h. */
+ struct vgetrandom_opaque_params
+ {
+ uint32_t size_of_opaque_state;
+ uint32_t mmap_prot;
+ uint32_t mmap_flags;
+ uint32_t reserved[13];
+ } params;
+ if (GLRO(dl_vdso_getrandom) (NULL, 0, 0, &params, ~0UL) == 0)
+ {
+ /* Align each opaque state to L1 data cache size to avoid false
+ sharing. If the size can not be obtained, use the kernel
+ provided one. */
+ state_size = params.size_of_opaque_state;
+
+ long int ld1sz = __sysconf (_SC_LEVEL1_DCACHE_LINESIZE);
+ if (ld1sz <= 0)
+ ld1sz = 1;
+ state_size_cache_aligned = ALIGN_UP (state_size, ld1sz);
+ /* Do not enable vDSO if the required opaque state size is larger
+ than a page because we only allocate one page per time to hold
+ the states. */
+ if (state_size_cache_aligned > GLRO(dl_pagesize))
+ {
+ state_size = 0;
+ return;
+ }
+ mmap_prot = params.mmap_prot;
+ mmap_flags = params.mmap_flags;
+ }
+ }
+#endif
+}
+
+/* Re-add the state state from CURP on the free list. This function is
+ called after fork returns in the child, so no locking is required. */
+void
+__getrandom_reset_state (struct pthread *curp)
+{
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ if (grnd_alloc.states == NULL || curp->getrandom_buf == NULL)
+ return;
+ assert (grnd_alloc.len < grnd_alloc.cap);
+ grnd_alloc.states[grnd_alloc.len++] = release_ptr (curp->getrandom_buf);
+ curp->getrandom_buf = NULL;
+#endif
+}
+
+/* Called when a thread terminates, and adds its random buffer back into the
+ allocator pool for use in a future thread. This is called by
+ pthread_create during thread termination, and after signal has been
+ blocked. */
+void
+__getrandom_vdso_release (struct pthread *curp)
+{
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ if (curp->getrandom_buf == NULL)
+ return;
+
+ __libc_lock_lock (grnd_alloc.lock);
+ grnd_alloc.states[grnd_alloc.len++] = curp->getrandom_buf;
+ __libc_lock_unlock (grnd_alloc.lock);
+#endif
+}
+
+/* Reset the internal lock state in case another thread has locked while
+ this thread calls fork. The stale thread states will be handled by
+ reclaim_stacks which calls __getrandom_reset_state on each thread. */
+void
+__getrandom_fork_subprocess (void)
+{
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ grnd_alloc.lock = LLL_LOCK_INITIALIZER;
+#endif
+}
+
+ssize_t
+__getrandom_nocancel (void *buffer, size_t length, unsigned int flags)
+{
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ return getrandom_vdso (buffer, length, flags, false);
+#else
+ return getrandom_syscall (buffer, length, flags, false);
+#endif
+}
+
/* Write up to LENGTH bytes of randomness starting at BUFFER.
Return the number of bytes written, or -1 on error. */
ssize_t
__getrandom (void *buffer, size_t length, unsigned int flags)
{
- return SYSCALL_CANCEL (getrandom, buffer, length, flags);
+#ifdef HAVE_GETRANDOM_VSYSCALL
+ return getrandom_vdso (buffer, length, flags, true);
+#else
+ return getrandom_syscall (buffer, length, flags, true);
+#endif
}
libc_hidden_def (__getrandom)
weak_alias (__getrandom, getrandom)
diff --git a/sysdeps/unix/sysv/linux/loongarch/sysdep.h b/sysdeps/unix/sysv/linux/loongarch/sysdep.h
index eb0ba790daa6e27c..e2d853ae3e3c77fb 100644
--- a/sysdeps/unix/sysv/linux/loongarch/sysdep.h
+++ b/sysdeps/unix/sysv/linux/loongarch/sysdep.h
@@ -119,6 +119,7 @@
#define HAVE_CLOCK_GETTIME64_VSYSCALL "__vdso_clock_gettime"
#define HAVE_GETTIMEOFDAY_VSYSCALL "__vdso_gettimeofday"
#define HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
+#define HAVE_GETRANDOM_VSYSCALL "__vdso_getrandom"
#define HAVE_CLONE3_WRAPPER 1
diff --git a/sysdeps/unix/sysv/linux/not-cancel.h b/sysdeps/unix/sysv/linux/not-cancel.h
index 2a7585b73f2b23f7..12f26912d3f03640 100644
--- a/sysdeps/unix/sysv/linux/not-cancel.h
+++ b/sysdeps/unix/sysv/linux/not-cancel.h
@@ -27,6 +27,7 @@
#include <sys/syscall.h>
#include <sys/wait.h>
#include <time.h>
+#include <sys/random.h>
/* Non cancellable open syscall. */
__typeof (open) __open_nocancel;
@@ -84,15 +85,17 @@ __writev_nocancel_nostatus (int fd, const struct iovec *iov, int iovcnt)
}
static inline ssize_t
-__getrandom_nocancel (void *buf, size_t buflen, unsigned int flags)
+__getrandom_nocancel_direct (void *buf, size_t buflen, unsigned int flags)
{
return INLINE_SYSCALL_CALL (getrandom, buf, buflen, flags);
}
+__typeof (getrandom) __getrandom_nocancel attribute_hidden;
+
/* Non cancellable getrandom syscall that does not also set errno in case of
failure. */
static inline ssize_t
-__getrandom_nocancel_nostatus (void *buf, size_t buflen, unsigned int flags)
+__getrandom_nocancel_nostatus_direct (void *buf, size_t buflen, unsigned int flags)
{
return INTERNAL_SYSCALL_CALL (getrandom, buf, buflen, flags);
}
diff --git a/sysdeps/unix/sysv/linux/powerpc/sysdep.h b/sysdeps/unix/sysv/linux/powerpc/sysdep.h
index a69b7db33843d488..48f3d0d1b2c271cf 100644
--- a/sysdeps/unix/sysv/linux/powerpc/sysdep.h
+++ b/sysdeps/unix/sysv/linux/powerpc/sysdep.h
@@ -223,5 +223,6 @@
#define HAVE_TIME_VSYSCALL "__kernel_time"
#define HAVE_GETTIMEOFDAY_VSYSCALL "__kernel_gettimeofday"
#define HAVE_GET_TBFREQ "__kernel_get_tbfreq"
+#define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom"
#endif /* _LINUX_POWERPC_SYSDEP_H */
diff --git a/sysdeps/unix/sysv/linux/s390/sysdep.h b/sysdeps/unix/sysv/linux/s390/sysdep.h
index 9b3000ca62a0e00d..9698c57a03d19607 100644
--- a/sysdeps/unix/sysv/linux/s390/sysdep.h
+++ b/sysdeps/unix/sysv/linux/s390/sysdep.h
@@ -72,6 +72,7 @@
#ifdef __s390x__
#define HAVE_CLOCK_GETRES64_VSYSCALL "__kernel_clock_getres"
#define HAVE_CLOCK_GETTIME64_VSYSCALL "__kernel_clock_gettime"
+#define HAVE_GETRANDOM_VSYSCALL "__kernel_getrandom"
#else
#define HAVE_CLOCK_GETRES_VSYSCALL "__kernel_clock_getres"
#define HAVE_CLOCK_GETTIME_VSYSCALL "__kernel_clock_gettime"
diff --git a/sysdeps/unix/sysv/linux/x86_64/sysdep.h b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
index a2b021bd86f5d472..7dc072ae2da8f7c3 100644
--- a/sysdeps/unix/sysv/linux/x86_64/sysdep.h
+++ b/sysdeps/unix/sysv/linux/x86_64/sysdep.h
@@ -376,6 +376,7 @@
# define HAVE_TIME_VSYSCALL "__vdso_time"
# define HAVE_GETCPU_VSYSCALL "__vdso_getcpu"
# define HAVE_CLOCK_GETRES64_VSYSCALL "__vdso_clock_getres"
+# define HAVE_GETRANDOM_VSYSCALL "__vdso_getrandom"
# define HAVE_CLONE3_WRAPPER 1
commit 734e7f91e752f44984fe42c2384c23a0290b6e56
Author: Samuel Thibault <samuel.thibault@ens-lyon.org>
Date: Tue Aug 20 16:22:07 2024 +0200
Rules: Also build memcheck tests even when not running them
This will avoid in the future cases like a57cbbd85379 ("malloc: Link
threading tests with $(shared-thread-library") missing the memcheck
cases added in 251843e16fce ("malloc: Link threading tests with
$(shared-thread-library)")
diff --git a/Rules b/Rules
index 9010c5d5b269a805..27846abf82b65f60 100644
--- a/Rules
+++ b/Rules
@@ -145,7 +145,11 @@ others: $(py-const)
ifeq ($(run-built-tests),no)
tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
$(tests) $(tests-internal) \
- $(tests-container)) \
+ $(tests-container) \
+ $(tests-mcheck:%=%-mcheck) \
+ $(tests-malloc-check:%=%-malloc-check) \
+ $(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \
+ $(tests-malloc-hugetlb2:%=%-malloc-hugetlb2)) \
$(test-srcs)) $(tests-special) \
$(tests-printers-programs)
xtests: tests $(xtests-special)
commit d5a3ca4061f7adc59196fa58e34eacebbebcbcfe
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Sep 19 15:40:05 2024 +0200
Implement run-built-tests=no for make xcheck, always build xtests
Previously, the second occurrence of the xtests target
expected all xtests to run (as the result of specifying
$(xtests)), but these tests have not been run due to
the the first xtests target is set up for run-built-tests=no:
it only runs tests in $(xtests-special). Consequently,
xtests are reported as UNSUPPORTED with “make xcheck
run-built-tests=no”. The xtests were not built, either.
After this change always, xtests are built regardless
of the $(run-built-tests) variable (except for xtests listed
in $(tests-unsupported)). To fix the UNSUPPORTED issue,
introduce xtests-expected and use that manage test
expectations in the second xtests target.
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
diff --git a/Rules b/Rules
index 27846abf82b65f60..713c225d2ebf5506 100644
--- a/Rules
+++ b/Rules
@@ -143,8 +143,9 @@ endif
others: $(py-const)
ifeq ($(run-built-tests),no)
+# The $(xtests) dependency ensures that xtests are always built.
tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
- $(tests) $(tests-internal) \
+ $(tests) $(tests-internal) $(xtests) \
$(tests-container) \
$(tests-mcheck:%=%-mcheck) \
$(tests-malloc-check:%=%-malloc-check) \
@@ -153,8 +154,10 @@ tests: $(addprefix $(objpfx),$(filter-out $(tests-unsupported), \
$(test-srcs)) $(tests-special) \
$(tests-printers-programs)
xtests: tests $(xtests-special)
-else
+else # $(run-built-tests) != no
+# The $(xtests) dependency ensures that xtests are always built.
tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
+ $(addprefix $(objpfx),$(filter-out $(tests-unsupported), $(xtests))) \
$(tests-container:%=$(objpfx)%.out) \
$(tests-mcheck:%=$(objpfx)%-mcheck.out) \
$(tests-malloc-check:%=$(objpfx)%-malloc-check.out) \
@@ -162,26 +165,28 @@ tests: $(tests:%=$(objpfx)%.out) $(tests-internal:%=$(objpfx)%.out) \
$(tests-malloc-hugetlb2:%=$(objpfx)%-malloc-hugetlb2.out) \
$(tests-special) $(tests-printers-out)
xtests: tests $(xtests:%=$(objpfx)%.out) $(xtests-special)
-endif
+endif # $(run-built-tests) != no
tests-special-notdir = $(patsubst $(objpfx)%, %, $(tests-special))
xtests-special-notdir = $(patsubst $(objpfx)%, %, $(xtests-special))
ifeq ($(run-built-tests),no)
tests-expected =
-else
+xtests-expected =
+else # $(run-built-tests) != no
tests-expected = $(tests) $(tests-internal) $(tests-printers) \
$(tests-container) $(tests-malloc-check:%=%-malloc-check) \
$(tests-malloc-hugetlb1:%=%-malloc-hugetlb1) \
$(tests-malloc-hugetlb2:%=%-malloc-hugetlb2) \
$(tests-mcheck:%=%-mcheck)
-endif
+xtests-expected = $(xtests)
+endif # $(run-built-tests) != no
tests:
$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
$(sort $(tests-expected) $(tests-special-notdir:.out=)) \
> $(objpfx)subdir-tests.sum
xtests:
$(..)scripts/merge-test-results.sh -s $(objpfx) $(subdir) \
- $(sort $(xtests) $(xtests-special-notdir:.out=)) \
+ $(sort $(xtests-expected) $(xtests-special-notdir:.out=)) \
> $(objpfx)subdir-xtests.sum
ifeq ($(build-programs),yes)
commit 5a5eb72d8ee4783c28fead080143d53cac993e1d
Author: Florian Weimer <fweimer@redhat.com>
Date: Thu Aug 1 10:46:10 2024 +0200
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 ec119972cb2598c04ec7d4219e20506006836f64)
diff --git a/resolv/tst-resolv-short-response.c b/resolv/tst-resolv-short-response.c
index be354ae1c7f2a81a..9b06b0c1762f860c 100644
--- a/resolv/tst-resolv-short-response.c
+++ b/resolv/tst-resolv-short-response.c
@@ -33,8 +33,10 @@ response (const struct resolv_response_context *ctx,
{
case 0:
/* First server times out. */
- struct resolv_response_flags flags = {.rcode = rcode};
- resolv_response_init (b, flags);
+ {
+ struct resolv_response_flags flags = {.rcode = rcode};
+ resolv_response_init (b, flags);
+ }
break;
case 1:
/* Second server sends reply. */
commit afc15c2044cb9449ba506fe910fa8ab77394833c
Author: Andreas Schwab <schwab@suse.de>
Date: Mon Aug 5 10:55:51 2024 +0200
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 39ca997ab378990d5ac1aadbaa52aaf1db6d526f)
(redone from scratch because of many conflicts)
diff --git a/libio/bits/stdio2.h b/libio/bits/stdio2.h
index f9e8d37610d720aa..0dc4e87c652471f6 100644
--- a/libio/bits/stdio2.h
+++ b/libio/bits/stdio2.h
@@ -195,24 +195,24 @@ __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2)
__nonnull ((3)) 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 __nonnull ((4)) 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
@@ -220,12 +220,12 @@ __fortify_function __wur __fortified_attr_access (__write_only__, 1, 2)
__nonnull ((3)) 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
@@ -235,8 +235,8 @@ __fortify_function __wur __nonnull ((4)) 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)
@@ -261,9 +261,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
diff --git a/socket/bits/socket2.h b/socket/bits/socket2.h
index a88cb643703a4008..71f8d9c741049afd 100644
--- a/socket/bits/socket2.h
+++ b/socket/bits/socket2.h
@@ -33,12 +33,12 @@ extern ssize_t __REDIRECT (__recv_chk_warn,
__fortify_function ssize_t
recv (int __fd, void *__buf, size_t __n, int __flags)
{
- size_t sz = __glibc_objsize0 (__buf);
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+ size_t __sz = __glibc_objsize0 (__buf);
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
return __recv_alias (__fd, __buf, __n, __flags);
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
- return __recv_chk_warn (__fd, __buf, __n, sz, __flags);
- return __recv_chk (__fd, __buf, __n, sz, __flags);
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+ return __recv_chk_warn (__fd, __buf, __n, __sz, __flags);
+ return __recv_chk (__fd, __buf, __n, __sz, __flags);
}
extern ssize_t __recvfrom_chk (int __fd, void *__restrict __buf, size_t __n,
@@ -61,11 +61,11 @@ __fortify_function ssize_t
recvfrom (int __fd, void *__restrict __buf, size_t __n, int __flags,
__SOCKADDR_ARG __addr, socklen_t *__restrict __addr_len)
{
- size_t sz = __glibc_objsize0 (__buf);
- if (__glibc_safe_or_unknown_len (__n, sizeof (char), sz))
+ size_t __sz = __glibc_objsize0 (__buf);
+ if (__glibc_safe_or_unknown_len (__n, sizeof (char), __sz))
return __recvfrom_alias (__fd, __buf, __n, __flags, __addr, __addr_len);
- if (__glibc_unsafe_len (__n, sizeof (char), sz))
- return __recvfrom_chk_warn (__fd, __buf, __n, sz, __flags, __addr,
+ if (__glibc_unsafe_len (__n, sizeof (char), __sz))
+ return __recvfrom_chk_warn (__fd, __buf, __n, __sz, __flags, __addr,
__addr_len);
- return __recvfrom_chk (__fd, __buf, __n, sz, __flags, __addr, __addr_len);
+ return __recvfrom_chk (__fd, __buf, __n, __sz, __flags, __addr, __addr_len);
}
diff --git a/stdlib/bits/stdlib.h b/stdlib/bits/stdlib.h
index 1c7191ba574946ef..32f7ef5020eadc4c 100644
--- a/stdlib/bits/stdlib.h
+++ b/stdlib/bits/stdlib.h
@@ -36,16 +36,16 @@ extern char *__REDIRECT_NTH (__realpath_chk_warn,
__fortify_function __wur char *
__NTH (realpath (const char *__restrict __name, char *__restrict __resolved))
{
- size_t sz = __glibc_objsize (__resolved);
+ size_t __sz = __glibc_objsize (__resolved);
- if (sz == (size_t) -1)
+ if (__sz == (size_t) -1)
return __realpath_alias (__name, __resolved);
#if defined _LIBC_LIMITS_H_ && defined PATH_MAX
- if (__glibc_unsafe_len (PATH_MAX, sizeof (char), sz))
- return __realpath_chk_warn (__name, __resolved, sz);
+ if (__glibc_unsafe_len (PATH_MAX, sizeof (char), __sz))
+ return __realpath_chk_warn (__name, __resolved, __sz);
#endif
- return __realpath_chk (__name, __resolved, sz);
+ return __realpath_chk (__name, __resolved, __sz);
}
diff --git a/wcsmbs/bits/wchar2.h b/wcsmbs/bits/wchar2.h
index 49f19bca194fd601..c863b60ec203495e 100644
--- a/wcsmbs/bits/wchar2.h
+++ b/wcsmbs/bits/wchar2.h
@@ -59,18 +59,18 @@ __NTH (wmemset (wchar_t *__s, wchar_t __c, size_t __n))
__fortify_function wchar_t *
__NTH (wcscpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
{
- size_t sz = __glibc_objsize (__dest);
- if (sz != (size_t) -1)
- return __wcscpy_chk (__dest, __src, sz / sizeof (wchar_t));
+ size_t __sz = __glibc_objsize (__dest);
+ if (__sz != (size_t) -1)
+ return __wcscpy_chk (__dest, __src, __sz / sizeof (wchar_t));
return __wcscpy_alias (__dest, __src);
}
__fortify_function wchar_t *
__NTH (wcpcpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
{
- size_t sz = __glibc_objsize (__dest);
- if (sz != (size_t) -1)
- return __wcpcpy_chk (__dest, __src, sz / sizeof (wchar_t));
+ size_t __sz = __glibc_objsize (__dest);
+ if (__sz != (size_t) -1)
+ return __wcpcpy_chk (__dest, __src, __sz / sizeof (wchar_t));
return __wcpcpy_alias (__dest, __src);
}
@@ -95,9 +95,9 @@ __NTH (wcpncpy (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
__fortify_function wchar_t *
__NTH (wcscat (wchar_t *__restrict __dest, const wchar_t *__restrict __src))
{
- size_t sz = __glibc_objsize (__dest);
- if (sz != (size_t) -1)
- return __wcscat_chk (__dest, __src, sz / sizeof (wchar_t));
+ size_t __sz = __glibc_objsize (__dest);
+ if (__sz != (size_t) -1)
+ return __wcscat_chk (__dest, __src, __sz / sizeof (wchar_t));
return __wcscat_alias (__dest, __src);
}
@@ -105,9 +105,9 @@ __fortify_function wchar_t *
__NTH (wcsncat (wchar_t *__restrict __dest, const wchar_t *__restrict __src,
size_t __n))
{
- size_t sz = __glibc_objsize (__dest);
- if (sz != (size_t) -1)
- return __wcsncat_chk (__dest, __src, __n, sz / sizeof (wchar_t));
+ size_t __sz = __glibc_objsize (__dest);
+ if (__sz != (size_t) -1)
+ return __wcsncat_chk (__dest, __src, __n, __sz / sizeof (wchar_t));
return __wcsncat_alias (__dest, __src, __n);
}
@@ -144,10 +144,10 @@ __fortify_function int
__NTH (swprintf (wchar_t *__restrict __s, size_t __n,
const wchar_t *__restrict __fmt, ...))
{
- size_t sz = __glibc_objsize (__s);
- if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+ size_t __sz = __glibc_objsize (__s);
+ if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
return __swprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
- sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
+ __sz / sizeof (wchar_t), __fmt, __va_arg_pack ());
return __swprintf_alias (__s, __n, __fmt, __va_arg_pack ());
}
#elif !defined __cplusplus
@@ -163,10 +163,10 @@ __fortify_function int
__NTH (vswprintf (wchar_t *__restrict __s, size_t __n,
const wchar_t *__restrict __fmt, __gnuc_va_list __ap))
{
- size_t sz = __glibc_objsize (__s);
- if (sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
+ size_t __sz = __glibc_objsize (__s);
+ if (__sz != (size_t) -1 || __USE_FORTIFY_LEVEL > 1)
return __vswprintf_chk (__s, __n, __USE_FORTIFY_LEVEL - 1,
- sz / sizeof (wchar_t), __fmt, __ap);
+ __sz / sizeof (wchar_t), __fmt, __ap);
return __vswprintf_alias (__s, __n, __fmt, __ap);
}
@@ -210,25 +210,25 @@ vfwprintf (__FILE *__restrict __stream,
__fortify_function __wur wchar_t *
fgetws (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
{
- size_t sz = __glibc_objsize (__s);
- if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
+ size_t __sz = __glibc_objsize (__s);
+ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
return __fgetws_alias (__s, __n, __stream);
- if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
- return __fgetws_chk_warn (__s, sz / sizeof (wchar_t), __n, __stream);
- return __fgetws_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+ if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
+ return __fgetws_chk_warn (__s, __sz / sizeof (wchar_t), __n, __stream);
+ return __fgetws_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
}
#ifdef __USE_GNU
__fortify_function __wur wchar_t *
fgetws_unlocked (wchar_t *__restrict __s, int __n, __FILE *__restrict __stream)
{
- size_t sz = __glibc_objsize (__s);
- if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), sz))
+ size_t __sz = __glibc_objsize (__s);
+ if (__glibc_safe_or_unknown_len (__n, sizeof (wchar_t), __sz))
return __fgetws_unlocked_alias (__s, __n, __stream);
- if (__glibc_unsafe_len (__n, sizeof (wchar_t), sz))
- return __fgetws_unlocked_chk_warn (__s, sz / sizeof (wchar_t), __n,
+ if (__glibc_unsafe_len (__n, sizeof (wchar_t), __sz))
+ return __fgetws_unlocked_chk_warn (__s, __sz / sizeof (wchar_t), __n,
__stream);
- return __fgetws_unlocked_chk (__s, sz / sizeof (wchar_t), __n, __stream);
+ return __fgetws_unlocked_chk (__s, __sz / sizeof (wchar_t), __n, __stream);
}
#endif
commit 6eebc92cb290bed20dfb5726a88bafa02f6a2ba7
Author: Arjun Shankar <arjun@redhat.com>
Date: Tue Jul 30 11:37:57 2024 +0200
manual/stdio: Further clarify putc, putwc, getc, and getwc
This is a follow-up to 10de4a47ef3f481592e3c62eb07bcda23e9fde4d that
reworded the manual entries for putc and putwc and removed any
performance claims.
This commit further clarifies these entries and brings getc and getwc in
line with the descriptions of putc and putwc, removing any performance
claims from them as well.
Reviewed-by: Florian Weimer <fweimer@redhat.com>
(cherry picked from commit 942670c81dc8071dd75d6213e771daa5d2084cb6)
diff --git a/manual/stdio.texi b/manual/stdio.texi
index c11d37b363385531..0b31aeff958528c6 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -904,20 +904,16 @@ This function is a GNU extension.
@standards{ISO, stdio.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{} @aculock{}}}
This is just like @code{fputc}, except that it may be implemented as
-a macro, making it faster. One consequence is that it may evaluate the
-@var{stream} argument more than once, which is an exception to the
-general rule for macros. Therefore, @var{stream} should never be an
-expression with side-effects.
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun wint_t putwc (wchar_t @var{wc}, FILE *@var{stream})
@standards{ISO, wchar.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@acucorrupt{} @aculock{}}}
This is just like @code{fputwc}, except that it may be implemented as
-a macro, making it faster. One consequence is that it may evaluate the
-@var{stream} argument more than once, which is an exception to the
-general rule for macros. Therefore, @var{stream} should never be an
-expression with side-effects.
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun int putc_unlocked (int @var{c}, FILE *@var{stream})
@@ -1110,20 +1106,17 @@ This function is a GNU extension.
@deftypefun int getc (FILE *@var{stream})
@standards{ISO, stdio.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}}
-This is just like @code{fgetc}, except that it is permissible (and
-typical) for it to be implemented as a macro that evaluates the
-@var{stream} argument more than once. @code{getc} is often highly
-optimized, so it is usually the best function to use to read a single
-character.
+This is just like @code{fgetc}, except that it may be implemented as
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun wint_t getwc (FILE *@var{stream})
@standards{ISO, wchar.h}
@safety{@prelim{}@mtsafe{}@asunsafe{@asucorrupt{}}@acunsafe{@aculock{} @acucorrupt{}}}
-This is just like @code{fgetwc}, except that it is permissible for it to
-be implemented as a macro that evaluates the @var{stream} argument more
-than once. @code{getwc} can be highly optimized, so it is usually the
-best function to use to read a single wide character.
+This is just like @code{fgetwc}, except that it may be implemented as
+a macro and may evaluate the @var{stream} argument more than once.
+Therefore, @var{stream} should never be an expression with side-effects.
@end deftypefun
@deftypefun int getc_unlocked (FILE *@var{stream})
commit 1ab7faf86db2f6ebe76e6e077cc7899cd9edc518
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 9 17:01:17 2024 +0200
support: Add options list terminator to the test driver
This avoids crashes if a test is passed unknown options.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit c2a474f4617ede7a8bf56b7257acb37dc757b2d1)
diff --git a/support/test-driver.c b/support/test-driver.c
index f4c3e4d666918270..04ceebc08f320b8b 100644
--- a/support/test-driver.c
+++ b/support/test-driver.c
@@ -155,6 +155,7 @@ main (int argc, char **argv)
{
CMDLINE_OPTIONS
TEST_DEFAULT_OPTIONS
+ { 0, }
};
test_config.options = &options;
#endif
commit eeff407b196f2ffaadb5d41142688482e4a2a761
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Jul 22 17:47:21 2024 -0700
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 652c6cf26927352fc0e37e4e60c6fc98ddf6d3b4)
diff --git a/sysdeps/x86_64/dl-machine.h b/sysdeps/x86_64/dl-machine.h
index ff5d45f7cb7cd81d..899f56576f245a3f 100644
--- a/sysdeps/x86_64/dl-machine.h
+++ b/sysdeps/x86_64/dl-machine.h
@@ -139,37 +139,37 @@ elf_machine_runtime_setup (struct link_map *l, struct r_scope_elem *scope[],
.globl _start\n\
.globl _dl_start_user\n\
_start:\n\
- movq %rsp, %rdi\n\
+ mov %" RSP_LP ", %" RDI_LP "\n\
call _dl_start\n\
_dl_start_user:\n\
# Save the user entry point address in %r12.\n\
- movq %rax, %r12\n\
+ mov %" RAX_LP ", %" R12_LP "\n\
# Save %rsp value in %r13.\n\
- movq %rsp, %r13\n\
+ mov %" RSP_LP ", % " R13_LP "\n\
"\
RTLD_START_ENABLE_X86_FEATURES \
"\
# Read the original argument count.\n\
- movq (%rsp), %rdx\n\
+ mov (%rsp), %" RDX_LP "\n\
# Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
# argc -> rsi\n\
- movq %rdx, %rsi\n\
+ mov %" RDX_LP ", %" RSI_LP "\n\
# And align stack for the _dl_init call. \n\
- andq $-16, %rsp\n\
+ and $-16, %" RSP_LP "\n\
# _dl_loaded -> rdi\n\
- movq _rtld_local(%rip), %rdi\n\
+ mov _rtld_local(%rip), %" RDI_LP "\n\
# env -> rcx\n\
- leaq 16(%r13,%rdx,8), %rcx\n\
+ lea 2*" LP_SIZE "(%r13,%rdx," LP_SIZE "), %" RCX_LP "\n\
# argv -> rdx\n\
- leaq 8(%r13), %rdx\n\
+ lea " LP_SIZE "(%r13), %" RDX_LP "\n\
# Clear %rbp to mark outermost frame obviously even for constructors.\n\
xorl %ebp, %ebp\n\
# Call the function to run the initializers.\n\
call _dl_init\n\
# Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\
- leaq _dl_fini(%rip), %rdx\n\
+ lea _dl_fini(%rip), %" RDX_LP "\n\
# And make sure %rsp points to argc stored on the stack.\n\
- movq %r13, %rsp\n\
+ mov %" R13_LP ", %" RSP_LP "\n\
# Jump to the user's entry point.\n\
jmp *%r12\n\
.previous\n\
@@ -234,8 +234,13 @@ elf_machine_plt_value (struct link_map *map, const ElfW(Rela) *reloc,
/* Names of the architecture-specific auditing callback functions. */
+#ifdef __LP64__
#define ARCH_LA_PLTENTER x86_64_gnu_pltenter
#define ARCH_LA_PLTEXIT x86_64_gnu_pltexit
+#else
+#define ARCH_LA_PLTENTER x32_gnu_pltenter
+#define ARCH_LA_PLTEXIT x32_gnu_pltexit
+#endif
#endif /* !dl_machine_h */
diff --git a/sysdeps/x86_64/x32/dl-machine.h b/sysdeps/x86_64/x32/dl-machine.h
deleted file mode 100644
index c35cee92619923a2..0000000000000000
--- a/sysdeps/x86_64/x32/dl-machine.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/* Machine-dependent ELF dynamic relocation inline functions. x32 version.
- Copyright (C) 2012-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/>. */
-
-/* Must allow <sysdeps/x86_64/dl-machine.h> to be included more than once.
- See #ifdef RESOLVE_MAP in sysdeps/x86_64/dl-machine.h. */
-#include <sysdeps/x86_64/dl-machine.h>
-
-#ifndef _X32_DL_MACHINE_H
-#define _X32_DL_MACHINE_H
-
-#undef ARCH_LA_PLTENTER
-#undef ARCH_LA_PLTEXIT
-#undef RTLD_START
-
-/* Names of the architecture-specific auditing callback functions. */
-#define ARCH_LA_PLTENTER x32_gnu_pltenter
-#define ARCH_LA_PLTEXIT x32_gnu_pltexit
-
-/* Initial entry point code for the dynamic linker.
- The C function `_dl_start' is the real entry point;
- its return value is the user program's entry point. */
-#define RTLD_START asm ("\n\
-.text\n\
- .p2align 4\n\
-.globl _start\n\
-.globl _dl_start_user\n\
-_start:\n\
- movl %esp, %edi\n\
- call _dl_start\n\
-_dl_start_user:\n\
- # Save the user entry point address in %r12.\n\
- movl %eax, %r12d\n\
- # Read the original argument count.\n\
- movl (%rsp), %edx\n\
- # Call _dl_init (struct link_map *main_map, int argc, char **argv, char **env)\n\
- # argc -> rsi\n\
- movl %edx, %esi\n\
- # Save %rsp value in %r13.\n\
- movl %esp, %r13d\n\
- # And align stack for the _dl_init call.\n\
- and $-16, %esp\n\
- # _dl_loaded -> rdi\n\
- movl _rtld_local(%rip), %edi\n\
- # env -> rcx\n\
- lea 8(%r13,%rdx,4), %ecx\n\
- # argv -> rdx\n\
- lea 4(%r13), %edx\n\
- # Clear %rbp to mark outermost frame obviously even for constructors.\n\
- xorl %ebp, %ebp\n\
- # Call the function to run the initializers.\n\
- call _dl_init\n\
- # Pass our finalizer function to the user in %rdx, as per ELF ABI.\n\
- lea _dl_fini(%rip), %edx\n\
- # And make sure %rsp points to argc stored on the stack.\n\
- movl %r13d, %esp\n\
- # Jump to the user's entry point.\n\
- jmp *%r12\n\
-.previous\n\
-");
-
-#endif /* !_X32_DL_MACHINE_H */
commit 9fbbe86f7c6ab19356cfa7ca15b4b7c29b72e8cb
Author: H.J. Lu <hjl.tools@gmail.com>
Date: Mon Jul 22 17:47:22 2024 -0700
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 8344c1f5514b1b5b1c8c6e48f4b802653bd23b71)
diff --git a/sysdeps/unix/sysv/linux/x86_64/dl-cet.h b/sysdeps/unix/sysv/linux/x86_64/dl-cet.h
index 1fe313340611d9c5..b4f7e6c9cd7548a2 100644
--- a/sysdeps/unix/sysv/linux/x86_64/dl-cet.h
+++ b/sysdeps/unix/sysv/linux/x86_64/dl-cet.h
@@ -92,9 +92,9 @@ dl_cet_ibt_enabled (void)
# Pass GL(dl_x86_feature_1) to _dl_cet_setup_features.\n\
movl %edx, %edi\n\
# Align stack for the _dl_cet_setup_features call.\n\
- andq $-16, %rsp\n\
+ and $-16, %" RSP_LP "\n\
call _dl_cet_setup_features\n\
# Restore %rax and %rsp from %r12 and %r13.\n\
- movq %r12, %rax\n\
- movq %r13, %rsp\n\
+ mov %" R12_LP ", %" RAX_LP "\n\
+ mov %" R13_LP ", %" RSP_LP "\n\
"
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
index b9db8bc5be05eed8..645e85802f95a78c 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/arch-syscall.h
@@ -151,6 +151,7 @@
#define __NR_lsetxattr 1073742013
#define __NR_lstat 1073741830
#define __NR_madvise 1073741852
+#define __NR_map_shadow_stack 1073742277
#define __NR_mbind 1073742061
#define __NR_membarrier 1073742148
#define __NR_memfd_create 1073742143
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h
index 98124169e6035ea8..47fa8af4ce9af68e 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/fixup-asm-unistd.h
@@ -15,6 +15,10 @@
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
+#ifndef __NR_map_shadow_stack
+# define __NR_map_shadow_stack 1073742277
+#endif
+
/* X32 uses the same 64-bit syscall interface for set_thread_area. */
#ifndef __NR_set_thread_area
# define __NR_set_thread_area 1073742029
commit 81631a0dd1b76e6fe8e0ffcd9ee411676031b1bb
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Jul 19 15:57:46 2024 +0200
Adjust check-local-headers test for libaudit 4.0
The new version introduces /usr/include/audit_logging.h and
/usr/include/audit-records.h.
(cherry picked from commit 91eb62d63887a959e43aafb6fc022a87614dc7c9)
diff --git a/scripts/check-local-headers.sh b/scripts/check-local-headers.sh
index 5d3e61f8894b600e..ad23840333f7c7e5 100755
--- a/scripts/check-local-headers.sh
+++ b/scripts/check-local-headers.sh
@@ -33,7 +33,7 @@ exec ${AWK} -v includedir="$includedir" '
BEGIN {
status = 0
exclude = "^" includedir \
- "/(.*-.*-.*/|.*-.*/|)(asm[-/]|arch|linux/|selinux/|mach/|mach_debug/|device/|hurd/(((hurd|ioctl)_types|paths)\\.h|ioctls\\.defs|ihash\\.h|version\\.h)|gd|nss3/|nspr4?/|c\\+\\+/|sys/(capability|sdt(|-config))\\.h|libaudit\\.h)"
+ "/(.*-.*-.*/|.*-.*/|)(asm[-/]|arch|linux/|selinux/|mach/|mach_debug/|device/|hurd/(((hurd|ioctl)_types|paths)\\.h|ioctls\\.defs|ihash\\.h|version\\.h)|gd|nss3/|nspr4?/|c\\+\\+/|sys/(capability|sdt(|-config))\\.h|libaudit\\.h|audit(_logging|-records)\\.h)"
}
/^[^ ]/ && $1 ~ /.*:/ { obj = $1 }
{
commit 49953727d1768baeef2914f709f35cb4acad2d0b
Author: Noah Goldstein <goldstein.w.n@gmail.com>
Date: Tue Aug 13 23:29:14 2024 +0800
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 7da08862471dfec6fdae731c2a5f351ad485c71f)
diff --git a/string/test-strchr.c b/string/test-strchr.c
index c795eac6fa7b93b9..72b17af687f6ad0e 100644
--- a/string/test-strchr.c
+++ b/string/test-strchr.c
@@ -255,6 +255,69 @@ check1 (void)
check_result (impl, s, c, exp_result);
}
+static void
+check2 (void)
+{
+ CHAR *s = (CHAR *) (buf1 + getpagesize () - 4 * sizeof (CHAR));
+ CHAR *s_begin = (CHAR *) (buf1 + getpagesize () - 64);
+#ifndef USE_FOR_STRCHRNUL
+ CHAR *exp_result = NULL;
+#else
+ CHAR *exp_result = s + 1;
+#endif
+ CHAR val = 0x12;
+ for (; s_begin != s; ++s_begin)
+ *s_begin = val;
+
+ s[0] = val + 1;
+ s[1] = 0;
+ s[2] = val + 1;
+ s[3] = val + 1;
+
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+ s[3] = val;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+ exp_result = s;
+ s[0] = val;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+
+ s[3] = val + 1;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+
+ s[0] = val + 1;
+ s[1] = val + 1;
+ s[2] = val + 1;
+ s[3] = val + 1;
+ s[4] = val;
+ exp_result = s + 4;
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+ s[4] = 0;
+#ifndef USE_FOR_STRCHRNUL
+ exp_result = NULL;
+#else
+ exp_result = s + 4;
+#endif
+ {
+ FOR_EACH_IMPL (impl, 0)
+ check_result (impl, s, val, exp_result);
+ }
+}
+
int
test_main (void)
{
@@ -263,7 +326,7 @@ test_main (void)
test_init ();
check1 ();
-
+ check2 ();
printf ("%20s", "");
FOR_EACH_IMPL (impl, 0)
printf ("\t%s", impl->name);
diff --git a/sysdeps/x86_64/multiarch/strchr-evex-base.S b/sysdeps/x86_64/multiarch/strchr-evex-base.S
index 04e2c0e79e381691..3a0b7c9d6429fb20 100644
--- a/sysdeps/x86_64/multiarch/strchr-evex-base.S
+++ b/sysdeps/x86_64/multiarch/strchr-evex-base.S
@@ -124,13 +124,13 @@ L(page_cross):
VPCMPNE %VMM(1), %VMM(0), %k1
VPTEST %VMM(1), %VMM(1), %k0{%k1}
KMOV %k0, %VRAX
-# ifdef USE_AS_WCSCHR
+ sar %cl, %VRAX
+#ifdef USE_AS_WCSCHR
sub $VEC_MATCH_MASK, %VRAX
-# else
+#else
inc %VRAX
-# endif
+#endif
/* Ignore number of character for alignment adjustment. */
- shr %cl, %VRAX
jz L(align_more)
bsf %VRAX, %VRAX
commit 37c2aa4eaa0adc4193bc0e1f520b677ad30c9e4d
Author: Florian Weimer <fweimer@redhat.com>
Date: Fri Aug 9 16:17:14 2024 +0200
Define __libc_initial for the static libc
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit eb0e50e9a1cf80a2ba6f33f990a08ef37a3267fb)
diff --git a/include/libc-internal.h b/include/libc-internal.h
index 87ac591835637e4d..1ef43ffe673907a0 100644
--- a/include/libc-internal.h
+++ b/include/libc-internal.h
@@ -53,6 +53,9 @@ extern __typeof (__profile_frequency) __profile_frequency attribute_hidden;
is not for an audit module, not loaded via dlmopen, and not loaded
via static dlopen either). */
extern _Bool __libc_initial attribute_hidden;
+#else
+/* The static libc is always the initial namespace. */
+# define __libc_initial ((_Bool) 1)
#endif
#endif /* _LIBC_INTERNAL */
commit e73fd06b7f12d6ddaae4f91f9c5088a621a82ce4
Author: Florian Weimer <fweimer@redhat.com>
Date: Mon Aug 19 15:48:03 2024 +0200
string: strerror, strsignal cannot use buffer after dlmopen (bug 32026)
Secondary namespaces have a different malloc. Allocating the
buffer in one namespace and freeing it another results in
heap corruption. Fix this by using a static string (potentially
translated) in secondary namespaces. It would also be possible
to use the malloc from the initial namespace to manage the
buffer, but these functions would still not be safe to use in
auditors etc. because a call to strerror could still free a
buffer while it is used by the application. Another approach
could use proper initial-exec TLS, duplicated in secondary
namespaces, but that would need a callback interface for freeing
libc resources in namespaces on thread exit, which does not exist
today.
Reviewed-by: Adhemerval Zanella <adhemerval.zanella@linaro.org>
(cherry picked from commit 25a5eb4010df94b412c67db9e346029de316d06b)
diff --git a/string/strerror_l.c b/string/strerror_l.c
index 15cce261e6b406a7..70456e5bb45e5b52 100644
--- a/string/strerror_l.c
+++ b/string/strerror_l.c
@@ -20,7 +20,7 @@
#include <stdio.h>
#include <string.h>
#include <tls-internal.h>
-
+#include <libc-internal.h>
static const char *
translate (const char *str, locale_t loc)
@@ -31,6 +31,12 @@ translate (const char *str, locale_t loc)
return res;
}
+static char *
+unknown_error (locale_t loc)
+{
+ return (char *) translate ("Unknown error", loc);
+}
+
/* Return a string describing the errno code in ERRNUM. */
char *
@@ -40,18 +46,25 @@ __strerror_l (int errnum, locale_t loc)
char *err = (char *) __get_errlist (errnum);
if (__glibc_unlikely (err == NULL))
{
- struct tls_internal_t *tls_internal = __glibc_tls_internal ();
- free (tls_internal->strerror_l_buf);
- if (__asprintf (&tls_internal->strerror_l_buf, "%s%d",
- translate ("Unknown error ", loc), errnum) > 0)
- err = tls_internal->strerror_l_buf;
- else
+ if (__libc_initial)
{
- /* The memory was freed above. */
- tls_internal->strerror_l_buf = NULL;
- /* Provide a fallback translation. */
- err = (char *) translate ("Unknown error", loc);
+ struct tls_internal_t *tls_internal = __glibc_tls_internal ();
+ free (tls_internal->strerror_l_buf);
+ if (__asprintf (&tls_internal->strerror_l_buf, "%s%d",
+ translate ("Unknown error ", loc), errnum) > 0)
+ err = tls_internal->strerror_l_buf;
+ else
+ {
+ /* The memory was freed above. */
+ tls_internal->strerror_l_buf = NULL;
+ /* Provide a fallback translation. */
+ err = unknown_error (loc);
+ }
}
+ else
+ /* Secondary namespaces use a different malloc, so cannot
+ participate in the buffer management. */
+ err = unknown_error (loc);
}
else
err = (char *) translate (err, loc);
diff --git a/string/strsignal.c b/string/strsignal.c
index 31146015647c1d4a..d9b03654683a6805 100644
--- a/string/strsignal.c
+++ b/string/strsignal.c
@@ -21,6 +21,7 @@
#include <string.h>
#include <libintl.h>
#include <tls-internal.h>
+#include <libc-internal.h>
/* Return a string describing the meaning of the signal number SIGNUM. */
char *
@@ -30,21 +31,28 @@ strsignal (int signum)
if (desc != NULL)
return _(desc);
- struct tls_internal_t *tls_internal = __glibc_tls_internal ();
- free (tls_internal->strsignal_buf);
+ if (__libc_initial)
+ {
+ struct tls_internal_t *tls_internal = __glibc_tls_internal ();
+ free (tls_internal->strsignal_buf);
- int r;
+ int r;
#ifdef SIGRTMIN
- if (signum >= SIGRTMIN && signum <= SIGRTMAX)
- r = __asprintf (&tls_internal->strsignal_buf, _("Real-time signal %d"),
- signum - SIGRTMIN);
- else
+ if (signum >= SIGRTMIN && signum <= SIGRTMAX)
+ r = __asprintf (&tls_internal->strsignal_buf, _("Real-time signal %d"),
+ signum - SIGRTMIN);
+ else
#endif
- r = __asprintf (&tls_internal->strsignal_buf, _("Unknown signal %d"),
- signum);
-
- if (r == -1)
- tls_internal->strsignal_buf = NULL;
-
- return tls_internal->strsignal_buf;
+ r = __asprintf (&tls_internal->strsignal_buf, _("Unknown signal %d"),
+ signum);
+
+ if (r >= 0)
+ return tls_internal->strsignal_buf;
+ else
+ tls_internal->strsignal_buf = NULL;
+ }
+ /* Fall through on asprintf error, and for !__libc_initial:
+ secondary namespaces use a different malloc and cannot
+ participate in the buffer management. */
+ return _("Unknown signal");
}
commit 98de2f2baebeeac13748f064017b7bd2b94fafee
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Fri Jul 26 13:21:34 2024 +0100
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 1b97a9f23bf605ca608162089c94187573fb2a9e)
diff --git a/debug/tst-fortify-syslog.c b/debug/tst-fortify-syslog.c
index a7ddbf7c6b6d33c9..2712acf689ff5af2 100644
--- a/debug/tst-fortify-syslog.c
+++ b/debug/tst-fortify-syslog.c
@@ -22,7 +22,6 @@
#include <syslog.h>
#include <string.h>
#include <unistd.h>
-#include <stdio.h>
#include <support/check.h>
#include <support/support.h>
@@ -46,18 +45,13 @@ handler (int sig)
_exit (127);
}
-#define FAIL() \
- do { \
- printf ("Failure on line %d\n", __LINE__); \
- support_record_failure (); \
- } while (0)
#define CHK_FAIL_START \
chk_fail_ok = 1; \
if (! setjmp (chk_fail_buf)) \
{
#define CHK_FAIL_END \
chk_fail_ok = 0; \
- FAIL (); \
+ FAIL ("not supposed to reach here"); \
}
static void
diff --git a/localedata/tst-ctype.c b/localedata/tst-ctype.c
index 9de979a2d7592789..a23689719c173711 100644
--- a/localedata/tst-ctype.c
+++ b/localedata/tst-ctype.c
@@ -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;
}
diff --git a/math/test-tgmath2.c b/math/test-tgmath2.c
index 37afa8a08a5a4a9c..4aeb877b8e54c0a4 100644
--- a/math/test-tgmath2.c
+++ b/math/test-tgmath2.c
@@ -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
diff --git a/support/check.h b/support/check.h
index 711f34b83b95b594..7ea22c7a2cba5cfd 100644
--- a/support/check.h
+++ b/support/check.h
@@ -24,6 +24,11 @@
__BEGIN_DECLS
+/* Record a test failure, print the failure message to standard output
+ and pass the result of 1 through. */
+#define FAIL(...) \
+ support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)
+
/* Record a test failure, print the failure message to standard output
and return 1. */
#define FAIL_RET(...) \
commit 3c5f493d871c11de9d8358b8ac84c144a0d848fa
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Fri Jul 26 13:21:34 2024 +0100
stdio-common: Add test for vfscanf with matches longer than INT_MAX [BZ #27650]
Complement commit b03e4d7bd25b ("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 89cddc8a7096f3d9225868304d2bc0a1aaf07d63)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index e312565f3b671463..159dc472e4c76b9a 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -243,6 +243,7 @@ tests := \
tst-scanf-binary-c2x \
tst-scanf-binary-gnu11 \
tst-scanf-binary-gnu89 \
+ tst-scanf-bz27650 \
tst-scanf-intn \
tst-scanf-round \
tst-scanf-to_inpunct \
@@ -313,6 +314,7 @@ generated += \
tst-printf-fp-free.mtrace \
tst-printf-fp-leak-mem.out \
tst-printf-fp-leak.mtrace \
+ tst-scanf-bz27650.mtrace \
tst-vfprintf-width-prec-mem.out \
tst-vfprintf-width-prec.mtrace \
# generated
@@ -402,6 +404,9 @@ tst-printf-fp-free-ENV = \
tst-printf-fp-leak-ENV = \
MALLOC_TRACE=$(objpfx)tst-printf-fp-leak.mtrace \
LD_PRELOAD=$(common-objpfx)/malloc/libc_malloc_debug.so
+tst-scanf-bz27650-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-scanf-bz27650.c b/stdio-common/tst-scanf-bz27650.c
new file mode 100644
index 0000000000000000..3a742bc86556908c
--- /dev/null
+++ b/stdio-common/tst-scanf-bz27650.c
@@ -0,0 +1,108 @@
+/* Test for BZ #27650, formatted input matching beyond INT_MAX.
+ 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 <error.h>
+#include <errno.h>
+#include <limits.h>
+#include <mcheck.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/types.h>
+
+#include <support/check.h>
+#include <support/test-driver.h>
+
+/* Produce a stream of more than INT_MAX characters via buffer BUF of
+ size SIZE according to bookkeeping in COOKIE and then return EOF. */
+
+static ssize_t
+io_read (void *cookie, char *buf, size_t size)
+{
+ unsigned int *written = cookie;
+ unsigned int w = *written;
+
+ if (w > INT_MAX)
+ return 0;
+
+ memset (buf, 'a', size);
+ *written = w + size;
+ return size;
+}
+
+/* Consume a stream of more than INT_MAX characters from an artificial
+ input stream of which none is the new line character. The call to
+ fscanf is supposed to complete upon the EOF condition of input,
+ however in the presence of BZ #27650 it will terminate prematurely
+ with characters still outstanding in input. Diagnose the condition
+ and return status accordingly. */
+
+int
+do_test (void)
+{
+ static cookie_io_functions_t io_funcs = { .read = io_read };
+ unsigned int written = 0;
+ FILE *in;
+ int v;
+
+ mtrace ();
+
+ in = fopencookie (&written, "r", io_funcs);
+ if (in == NULL)
+ {
+ FAIL ("fopencookie: %m");
+ goto out;
+ }
+
+ v = fscanf (in, "%*[^\n]");
+ if (ferror (in))
+ {
+ FAIL ("fscanf: input failure, at %u: %m", written);
+ goto out_close;
+ }
+ else if (v == EOF)
+ {
+ FAIL ("fscanf: unexpected end of file, at %u", written);
+ goto out_close;
+ }
+
+ if (!feof (in))
+ {
+ v = fgetc (in);
+ if (ferror (in))
+ FAIL ("fgetc: input failure: %m");
+ else if (v == EOF)
+ FAIL ("fgetc: unexpected end of file after missing end of file");
+ else if (v == '\n')
+ FAIL ("unexpected new line character received");
+ else
+ FAIL ("character received after end of file expected: \\x%02x", v);
+ }
+
+out_close:
+ if (fclose (in) != 0)
+ FAIL ("fclose: %m");
+
+out:
+ return EXIT_SUCCESS;
+}
+
+#define TIMEOUT (DEFAULT_TIMEOUT * 8)
+#include <support/test-driver.c>
commit f0c308ab239340190f5ca9a226e43f3041d487f7
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Wed Aug 14 19:20:04 2024 -0400
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 3f7df7e757f4efec38e45d4068e5492efcac4856)
diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c
index 1344b2b591e3d6b1..5c808f073419f00b 100644
--- a/stdio-common/tst-ungetc.c
+++ b/stdio-common/tst-ungetc.c
@@ -1,70 +1,72 @@
-/* Test for ungetc bugs. */
+/* Test for ungetc bugs.
+ Copyright (C) 1996-2024 Free Software Foundation, Inc.
+ 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/>. */
#include <stdio.h>
#include <stdlib.h>
-#include <unistd.h>
-
-#undef assert
-#define assert(x) \
- if (!(x)) \
- { \
- fputs ("test failed: " #x "\n", stderr); \
- retval = 1; \
- goto the_end; \
- }
+#include <support/check.h>
+#include <support/support.h>
+#include <support/temp_file.h>
+#include <support/xstdio.h>
+#include <support/xunistd.h>
-int
-main (int argc, char *argv[])
+static int
+do_test (void)
{
- char name[] = "/tmp/tst-ungetc.XXXXXX";
+ char *name = NULL;
FILE *fp = NULL;
- int retval = 0;
int c;
char buffer[64];
- int fd = mkstemp (name);
+ int fd = create_temp_file ("tst-ungetc.", &name);
if (fd == -1)
- {
- printf ("mkstemp failed: %m\n");
- return 1;
- }
- close (fd);
- fp = fopen (name, "w");
- assert (fp != NULL)
- fputs ("bla", fp);
- fclose (fp);
- fp = NULL;
+ FAIL_EXIT1 ("cannot create temporary file: %m");
+ xclose (fd);
- fp = fopen (name, "r");
- assert (fp != NULL);
- assert (ungetc ('z', fp) == 'z');
- assert (getc (fp) == 'z');
- assert (getc (fp) == 'b');
- assert (getc (fp) == 'l');
- assert (ungetc ('m', fp) == 'm');
- assert (getc (fp) == 'm');
- assert ((c = getc (fp)) == 'a');
- assert (getc (fp) == EOF);
- assert (ungetc (c, fp) == c);
- assert (feof (fp) == 0);
- assert (getc (fp) == c);
- assert (getc (fp) == EOF);
- fclose (fp);
- fp = NULL;
+ fp = xfopen (name, "w");
+ fputs ("bla", fp);
+ xfclose (fp);
- fp = fopen (name, "r");
- assert (fp != NULL);
- assert (getc (fp) == 'b');
- assert (getc (fp) == 'l');
- assert (ungetc ('b', fp) == 'b');
- assert (fread (buffer, 1, 64, fp) == 2);
- assert (buffer[0] == 'b');
- assert (buffer[1] == 'a');
+ fp = xfopen (name, "r");
+ TEST_VERIFY_EXIT (ungetc ('z', fp) == 'z');
+ TEST_VERIFY_EXIT (getc (fp) == 'z');
+ TEST_VERIFY_EXIT (getc (fp) == 'b');
+ TEST_VERIFY_EXIT (getc (fp) == 'l');
+ TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm');
+ TEST_VERIFY_EXIT (getc (fp) == 'm');
+ TEST_VERIFY_EXIT ((c = getc (fp)) == 'a');
+ TEST_VERIFY_EXIT (getc (fp) == EOF);
+ TEST_VERIFY_EXIT (ungetc (c, fp) == c);
+ TEST_VERIFY_EXIT (feof (fp) == 0);
+ TEST_VERIFY_EXIT (getc (fp) == c);
+ TEST_VERIFY_EXIT (getc (fp) == EOF);
+ xfclose (fp);
-the_end:
- if (fp != NULL)
- fclose (fp);
- unlink (name);
+ fp = xfopen (name, "r");
+ TEST_VERIFY_EXIT (getc (fp) == 'b');
+ TEST_VERIFY_EXIT (getc (fp) == 'l');
+ TEST_VERIFY_EXIT (ungetc ('b', fp) == 'b');
+ TEST_VERIFY_EXIT (fread (buffer, 1, 64, fp) == 2);
+ TEST_VERIFY_EXIT (buffer[0] == 'b');
+ TEST_VERIFY_EXIT (buffer[1] == 'a');
+ xfclose (fp);
- return retval;
+ return 0;
}
+
+#include <support/test-driver.c>
commit 70939528c67507f12d6d41423b7fac25153a6dce
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue Aug 13 21:00:06 2024 -0400
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 cdf0f88f97b0aaceb894cc02b21159d148d7065c)
diff --git a/libio/genops.c b/libio/genops.c
index bc45e60a09437ae5..4f5c6136f3ef1b88 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -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--;
diff --git a/manual/stdio.texi b/manual/stdio.texi
index 0b31aeff958528c6..393ed9c665792609 100644
--- a/manual/stdio.texi
+++ b/manual/stdio.texi
@@ -1467,11 +1467,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
diff --git a/stdio-common/tst-ungetc.c b/stdio-common/tst-ungetc.c
index 5c808f073419f00b..388b202493ddd586 100644
--- a/stdio-common/tst-ungetc.c
+++ b/stdio-common/tst-ungetc.c
@@ -48,6 +48,8 @@ do_test (void)
TEST_VERIFY_EXIT (getc (fp) == 'b');
TEST_VERIFY_EXIT (getc (fp) == 'l');
TEST_VERIFY_EXIT (ungetc ('m', fp) == 'm');
+ TEST_VERIFY_EXIT (ungetc ('n', fp) == 'n');
+ TEST_VERIFY_EXIT (getc (fp) == 'n');
TEST_VERIFY_EXIT (getc (fp) == 'm');
TEST_VERIFY_EXIT ((c = getc (fp)) == 'a');
TEST_VERIFY_EXIT (getc (fp) == EOF);
commit a500b48bd2a6401de442c00f433079d24331dbb6
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date: Tue Aug 13 21:08:49 2024 -0400
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 3e1d8d1d1dca24ae90df2ea826a8916896fc7e77)
diff --git a/libio/genops.c b/libio/genops.c
index 4f5c6136f3ef1b88..bb1d9594ebb60375 100644
--- a/libio/genops.c
+++ b/libio/genops.c
@@ -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 (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))
diff --git a/libio/libioP.h b/libio/libioP.h
index 1af287b19f30fa2a..616253fcd00f04db 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -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)
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 159dc472e4c76b9a..b9c38ce6b3b2f43a 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -257,6 +257,7 @@ tests := \
tst-swscanf \
tst-tmpnam \
tst-ungetc \
+ tst-ungetc-leak \
tst-unlockedio \
tst-vfprintf-mbs-prec \
tst-vfprintf-user-type \
@@ -301,6 +302,7 @@ tests-special += \
$(objpfx)tst-printfsz-islongdouble.out \
$(objpfx)tst-setvbuf1-cmp.out \
$(objpfx)tst-unbputc.out \
+ $(objpfx)tst-ungetc-leak-mem.out \
$(objpfx)tst-vfprintf-width-prec-mem.out \
# tests-special
@@ -315,6 +317,8 @@ generated += \
tst-printf-fp-leak-mem.out \
tst-printf-fp-leak.mtrace \
tst-scanf-bz27650.mtrace \
+ tst-ungetc-leak-mem.out \
+ tst-ungetc-leak.mtrace \
tst-vfprintf-width-prec-mem.out \
tst-vfprintf-width-prec.mtrace \
# generated
@@ -407,6 +411,9 @@ tst-printf-fp-leak-ENV = \
tst-scanf-bz27650-ENV = \
MALLOC_TRACE=$(objpfx)tst-scanf-bz27650.mtrace \
LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
+tst-ungetc-leak-ENV = \
+ MALLOC_TRACE=$(objpfx)tst-ungetc-leak.mtrace \
+ LD_PRELOAD=$(common-objpfx)malloc/libc_malloc_debug.so
$(objpfx)tst-unbputc.out: tst-unbputc.sh $(objpfx)tst-unbputc
$(SHELL) $< $(common-objpfx) '$(test-program-prefix)'; \
diff --git a/stdio-common/tst-ungetc-leak.c b/stdio-common/tst-ungetc-leak.c
new file mode 100644
index 0000000000000000..6c5152b43f80b217
--- /dev/null
+++ b/stdio-common/tst-ungetc-leak.c
@@ -0,0 +1,32 @@
+/* Test for memory leak with ungetc when stream is unused.
+ 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/>. */
+
+#include <stdio.h>
+#include <mcheck.h>
+#include <support/check.h>
+#include <support/support.h>
+
+static int
+do_test (void)
+{
+ mtrace ();
+ TEST_COMPARE (ungetc('y', stdin), 'y');
+ return 0;
+}
+
+#include <support/test-driver.c>
commit cae418638e83bcac4e65d612036edbd58f6e9364
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Fri Jul 26 13:21:34 2024 +0100
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 fe47595504a55e7bb992f8928533df154b510383)
diff --git a/posix/tst-truncate-common.c b/posix/tst-truncate-common.c
index b774fa46b80412b4..b8c561ffdb2b2903 100644
--- a/posix/tst-truncate-common.c
+++ b/posix/tst-truncate-common.c
@@ -21,6 +21,8 @@
#include <sys/stat.h>
#include <unistd.h>
+#include <support/check.h>
+
static void do_prepare (void);
#define PREPARE(argc, argv) do_prepare ()
static int do_test (void);
@@ -42,9 +44,6 @@ do_prepare (void)
}
}
-#define FAIL(str) \
- do { printf ("error: %s (line %d)\n", str, __LINE__); return 1; } while (0)
-
static int
do_test_with_offset (off_t offset)
{
@@ -54,35 +53,35 @@ do_test_with_offset (off_t offset)
memset (buf, 0xcf, sizeof (buf));
if (pwrite (temp_fd, buf, sizeof (buf), offset) != sizeof (buf))
- FAIL ("write failed");
+ FAIL_RET ("write failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + sizeof (buf)))
- FAIL ("initial size wrong");
+ FAIL_RET ("initial size wrong");
if (ftruncate (temp_fd, offset + 800) < 0)
- FAIL ("size reduction with ftruncate failed");
+ FAIL_RET ("size reduction with ftruncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
- FAIL ("size after reduction with ftruncate is incorrect");
+ FAIL_RET ("size after reduction with ftruncate is incorrect");
/* The following test covers more than POSIX. POSIX does not require
that ftruncate() can increase the file size. But we are testing
Unix systems. */
if (ftruncate (temp_fd, offset + 1200) < 0)
- FAIL ("size increate with ftruncate failed");
+ FAIL_RET ("size increate with ftruncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
- FAIL ("size after increase is incorrect");
+ FAIL_RET ("size after increase is incorrect");
if (truncate (temp_filename, offset + 800) < 0)
- FAIL ("size reduction with truncate failed");
+ FAIL_RET ("size reduction with truncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 800))
- FAIL ("size after reduction with truncate incorrect");
+ FAIL_RET ("size after reduction with truncate incorrect");
/* The following test covers more than POSIX. POSIX does not require
that truncate() can increase the file size. But we are testing
Unix systems. */
if (truncate (temp_filename, (offset + 1200)) < 0)
- FAIL ("size increase with truncate failed");
+ FAIL_RET ("size increase with truncate failed");
if (fstat (temp_fd, &st) < 0 || st.st_size != (offset + 1200))
- FAIL ("size increase with truncate is incorrect");
+ FAIL_RET ("size increase with truncate is incorrect");
return 0;
}
commit 5ff30b2f75681e1f752eeaad9d48ad249dabe71c
Author: Maciej W. Rozycki <macro@redhat.com>
Date: Fri Jul 26 13:21:34 2024 +0100
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 8c98195af6e6f1ce21743fc26c723e0f7e45bcf2)
diff --git a/sysdeps/pthread/tst-setuid3.c b/sysdeps/pthread/tst-setuid3.c
index 83f42a0ae5b06df5..3845ab03d306cf0f 100644
--- a/sysdeps/pthread/tst-setuid3.c
+++ b/sysdeps/pthread/tst-setuid3.c
@@ -15,24 +15,19 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
-#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <stdbool.h>
#include <unistd.h>
+#include <support/check.h>
+
/* The test must run under a non-privileged user ID. */
static const uid_t test_uid = 1;
static pthread_barrier_t barrier1;
static pthread_barrier_t barrier2;
-#define FAIL(fmt, ...) \
- do { printf ("FAIL: " fmt "\n", __VA_ARGS__); _exit (1); } while (0)
-
-#define FAIL_ERR(fmt, ...) \
- do { printf ("FAIL: " fmt ": %m\n", __VA_ARGS__); _exit (1); } while (0)
-
/* True if x is not a successful return code from pthread_barrier_wait. */
static inline bool
is_invalid_barrier_ret (int x)
@@ -45,10 +40,10 @@ thread_func (void *ctx __attribute__ ((unused)))
{
int ret = pthread_barrier_wait (&barrier1);
if (is_invalid_barrier_ret (ret))
- FAIL ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier1) (on thread): %d", ret);
ret = pthread_barrier_wait (&barrier2);
if (is_invalid_barrier_ret (ret))
- FAIL ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier2) (on thread): %d", ret);
return NULL;
}
@@ -59,13 +54,13 @@ setuid_failure (int phase)
switch (ret)
{
case 0:
- FAIL ("setuid succeeded unexpectedly in phase %d", phase);
+ FAIL_EXIT1 ("setuid succeeded unexpectedly in phase %d", phase);
case -1:
if (errno != EPERM)
- FAIL_ERR ("setuid phase %d", phase);
+ FAIL_EXIT1 ("setuid phase %d: %m", phase);
break;
default:
- FAIL ("invalid setuid return value in phase %d: %d", phase, ret);
+ FAIL_EXIT1 ("invalid setuid return value in phase %d: %d", phase, ret);
}
}
@@ -74,42 +69,42 @@ do_test (void)
{
if (getuid () == 0)
if (setuid (test_uid) != 0)
- FAIL_ERR ("setuid (%u)", (unsigned) test_uid);
+ FAIL_EXIT1 ("setuid (%u): %m", (unsigned) test_uid);
if (setuid (getuid ()))
- FAIL_ERR ("setuid (%s)", "getuid ()");
+ FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
setuid_failure (1);
int ret = pthread_barrier_init (&barrier1, NULL, 2);
if (ret != 0)
- FAIL ("pthread_barrier_init (barrier1): %d", ret);
+ FAIL_EXIT1 ("pthread_barrier_init (barrier1): %d", ret);
ret = pthread_barrier_init (&barrier2, NULL, 2);
if (ret != 0)
- FAIL ("pthread_barrier_init (barrier2): %d", ret);
+ FAIL_EXIT1 ("pthread_barrier_init (barrier2): %d", ret);
pthread_t thread;
ret = pthread_create (&thread, NULL, thread_func, NULL);
if (ret != 0)
- FAIL ("pthread_create: %d", ret);
+ FAIL_EXIT1 ("pthread_create: %d", ret);
/* Ensure that the thread is running properly. */
ret = pthread_barrier_wait (&barrier1);
if (is_invalid_barrier_ret (ret))
- FAIL ("pthread_barrier_wait (barrier1): %d", ret);
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier1): %d", ret);
setuid_failure (2);
/* Check success case. */
if (setuid (getuid ()) != 0)
- FAIL_ERR ("setuid (%s)", "getuid ()");
+ FAIL_EXIT1 ("setuid (%s): %m", "getuid ()");
/* Shutdown. */
ret = pthread_barrier_wait (&barrier2);
if (is_invalid_barrier_ret (ret))
- FAIL ("pthread_barrier_wait (barrier2): %d", ret);
+ FAIL_EXIT1 ("pthread_barrier_wait (barrier2): %d", ret);
ret = pthread_join (thread, NULL);
if (ret != 0)
- FAIL ("pthread_join: %d", ret);
+ FAIL_EXIT1 ("pthread_join: %d", ret);
return 0;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment