aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/unix/sysv/linux
diff options
context:
space:
mode:
authorFlorian Weimer <fweimer@redhat.com>2024-07-08 21:14:00 +0200
committerFlorian Weimer <fweimer@redhat.com>2024-07-09 19:33:37 +0200
commit2e456ccf0c34a056e3ccafac4a0c7effef14d918 (patch)
treef8850016fc638b37f5edb32a729bb023d8084fa6 /sysdeps/unix/sysv/linux
parent7e7f35278cf5980f6eb1ddd384217a04a5293bc8 (diff)
downloadglibc-2e456ccf0c34a056e3ccafac4a0c7effef14d918.zip
glibc-2e456ccf0c34a056e3ccafac4a0c7effef14d918.tar.gz
glibc-2e456ccf0c34a056e3ccafac4a0c7effef14d918.tar.bz2
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>
Diffstat (limited to 'sysdeps/unix/sysv/linux')
-rw-r--r--sysdeps/unix/sysv/linux/rseq-internal.h23
-rw-r--r--sysdeps/unix/sysv/linux/tst-rseq.c10
2 files changed, 30 insertions, 3 deletions
diff --git a/sysdeps/unix/sysv/linux/rseq-internal.h b/sysdeps/unix/sysv/linux/rseq-internal.h
index 48eebc1..7ea935b 100644
--- a/sysdeps/unix/sysv/linux/rseq-internal.h
+++ b/sysdeps/unix/sysv/linux/rseq-internal.h
@@ -25,15 +25,34 @@
#include <stdio.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
static inline bool
rseq_register_current_thread (struct pthread *self, bool 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,
- sizeof (self->rseq_area),
- 0, RSEQ_SIG);
+ size, 0, RSEQ_SIG);
if (!INTERNAL_SYSCALL_ERROR_P (ret))
return true;
}
diff --git a/sysdeps/unix/sysv/linux/tst-rseq.c b/sysdeps/unix/sysv/linux/tst-rseq.c
index 2c90409..08a9533 100644
--- a/sysdeps/unix/sysv/linux/tst-rseq.c
+++ b/sysdeps/unix/sysv/linux/tst-rseq.c
@@ -29,6 +29,7 @@
# include <stdlib.h>
# include <string.h>
# include <syscall.h>
+# include <sys/auxv.h>
# include <thread_pointer.h>
# include <tls.h>
# include "tst-rseq.h"
@@ -42,7 +43,8 @@ do_rseq_main_test (void)
TEST_COMPARE (__rseq_flags, 0);
TEST_VERIFY ((char *) __thread_pointer () + __rseq_offset
== (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
@@ -52,6 +54,12 @@ do_rseq_test (void)
{
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 ();
}
#else /* RSEQ_SIG */