1
0
mirror of https://sourceware.org/git/glibc.git synced 2025-08-08 17:42:12 +03:00

Linux: Make __rseq_size useful for feature detection (bug 31965)

The __rseq_size value is now the active area of struct rseq
(so 20 initially), not the full struct size including padding
at the end (32 initially).

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

Reviewed-by: Michael Jeanson <mjeanson@efficios.com>
Reviewed-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
This commit is contained in:
Florian Weimer
2024-07-08 21:14:00 +02:00
parent 7e7f35278c
commit 2e456ccf0c
5 changed files with 40 additions and 12 deletions

3
NEWS
View File

@@ -49,6 +49,9 @@ Deprecated and removed features, and other changes affecting compatibility:
<utmpx.h> (except for login_tty) due to locking and session management <utmpx.h> (except for login_tty) due to locking and session management
problems. problems.
* __rseq_size now denotes the size of the active rseq area (20 bytes
initially), not the size of struct rseq (32 bytes initially).
Changes to build and runtime requirements: Changes to build and runtime requirements:
[Add changes to build and runtime requirements here] [Add changes to build and runtime requirements here]

View File

@@ -1007,8 +1007,12 @@ This variable is either zero (if restartable sequence registration
failed or has been disabled) or the size of the restartable sequence failed or has been disabled) or the size of the restartable sequence
registration. This can be different from the size of @code{struct rseq} registration. This can be different from the size of @code{struct rseq}
if the kernel has extended the size of the registration. If if the kernel has extended the size of the registration. If
registration is successful, @code{__rseq_size} is at least 32 (the registration is successful, @code{__rseq_size} is at least 20 (the
initial size of @code{struct rseq}). initially active size of @code{struct rseq}).
Previous versions of @theglibc{} set this to 32 even if the kernel only
supported the initial area of 20 bytes because the value included unused
padding at the end of the restartable sequence area.
@end deftypevar @end deftypevar
@deftypevar {unsigned int} __rseq_flags @deftypevar {unsigned int} __rseq_flags

View File

@@ -46,10 +46,6 @@ rtld_mutex_dummy (pthread_mutex_t *lock)
const unsigned int __rseq_flags; const unsigned int __rseq_flags;
/* The variables are in .data.relro but are not yet write-protected. */
extern unsigned int _rseq_size attribute_hidden;
extern ptrdiff_t _rseq_offset attribute_hidden;
void void
__tls_pre_init_tp (void) __tls_pre_init_tp (void)
{ {
@@ -106,9 +102,7 @@ __tls_init_tp (void)
bool do_rseq = true; bool do_rseq = true;
do_rseq = TUNABLE_GET (rseq, int, NULL); do_rseq = TUNABLE_GET (rseq, int, NULL);
if (rseq_register_current_thread (pd, do_rseq)) if (rseq_register_current_thread (pd, do_rseq))
{ _rseq_size = RSEQ_AREA_SIZE_INITIAL_USED;
_rseq_size = sizeof (pd->rseq_area);
}
#ifdef RSEQ_SIG #ifdef RSEQ_SIG
/* This should be a compile-time constant, but the current /* This should be a compile-time constant, but the current

View File

@@ -25,15 +25,34 @@
#include <stdio.h> #include <stdio.h>
#include <sys/rseq.h> #include <sys/rseq.h>
/* 32 is the initially required value for the area size. The
actually used rseq size may be less (20 bytes initially). */
#define RSEQ_AREA_SIZE_INITIAL 32
#define RSEQ_AREA_SIZE_INITIAL_USED 20
/* The variables are in .data.relro but are not yet write-protected. */
extern unsigned int _rseq_size attribute_hidden;
extern ptrdiff_t _rseq_offset attribute_hidden;
#ifdef RSEQ_SIG #ifdef RSEQ_SIG
static inline bool static inline bool
rseq_register_current_thread (struct pthread *self, bool do_rseq) rseq_register_current_thread (struct pthread *self, bool do_rseq)
{ {
if (do_rseq) if (do_rseq)
{ {
unsigned int size;
#if IS_IN (rtld)
/* Use the hidden symbol in ld.so. */
size = _rseq_size;
#else
size = __rseq_size;
#endif
if (size < RSEQ_AREA_SIZE_INITIAL)
/* The initial implementation used only 20 bytes out of 32,
but still expected size 32. */
size = RSEQ_AREA_SIZE_INITIAL;
int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area, int ret = INTERNAL_SYSCALL_CALL (rseq, &self->rseq_area,
sizeof (self->rseq_area), size, 0, RSEQ_SIG);
0, RSEQ_SIG);
if (!INTERNAL_SYSCALL_ERROR_P (ret)) if (!INTERNAL_SYSCALL_ERROR_P (ret))
return true; return true;
} }

View File

@@ -29,6 +29,7 @@
# include <stdlib.h> # include <stdlib.h>
# include <string.h> # include <string.h>
# include <syscall.h> # include <syscall.h>
# include <sys/auxv.h>
# include <thread_pointer.h> # include <thread_pointer.h>
# include <tls.h> # include <tls.h>
# include "tst-rseq.h" # include "tst-rseq.h"
@@ -42,7 +43,8 @@ do_rseq_main_test (void)
TEST_COMPARE (__rseq_flags, 0); TEST_COMPARE (__rseq_flags, 0);
TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset
== (char *) &pd->rseq_area); == (char *) &pd->rseq_area);
TEST_COMPARE (__rseq_size, sizeof (pd->rseq_area)); /* The current implementation only supports the initial size. */
TEST_COMPARE (__rseq_size, 20);
} }
static void static void
@@ -52,6 +54,12 @@ do_rseq_test (void)
{ {
FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test"); FAIL_UNSUPPORTED ("kernel does not support rseq, skipping test");
} }
printf ("info: __rseq_size: %u\n", __rseq_size);
printf ("info: __rseq_offset: %td\n", __rseq_offset);
printf ("info: __rseq_flags: %u\n", __rseq_flags);
printf ("info: getauxval (AT_RSEQ_FEATURE_SIZE): %ld\n",
getauxval (AT_RSEQ_FEATURE_SIZE));
printf ("info: getauxval (AT_RSEQ_ALIGN): %ld\n", getauxval (AT_RSEQ_ALIGN));
do_rseq_main_test (); do_rseq_main_test ();
} }
#else /* RSEQ_SIG */ #else /* RSEQ_SIG */