Skip to content

Commit

Permalink
selftests/rseq: Fix handling of glibc without rseq support
Browse files Browse the repository at this point in the history
When porting librseq commit:

commit c7b45750fa85 ("Adapt to glibc __rseq_size feature detection")

from librseq to the kernel selftests, the following line was missed
at the end of rseq_init():

  rseq_size = get_rseq_kernel_feature_size();

which effectively leaves rseq_size initialized to -1U when glibc does not
have rseq support. glibc supports rseq from version 2.35 onwards.

In a following librseq commit

commit c67d198627c2 ("Only set 'rseq_size' on first thread registration")

to mimic the libc behavior, a new approach is taken: don't set the
feature size in 'rseq_size' until at least one thread has successfully
registered. This allows using 'rseq_size' in fast-paths to test for both
registration status and available features. The caveat is that on libc
either all threads are registered or none are, while with bare librseq
it is the responsability of the user to register all threads using rseq.

This combines the changes from the following librseq git commits:

commit c7b45750fa85 ("Adapt to glibc __rseq_size feature detection")
commit c67d198627c2 ("Only set 'rseq_size' on first thread registration")

Fixes: a0cc649 ("selftests/rseq: Fix mm_cid test failure")
Reported-by: Raghavendra Rao Ananta <rananta@google.com>
Signed-off-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Raghavendra Rao Ananta <rananta@google.com>
Cc: Shuah Khan <skhan@linuxfoundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: "Paul E. McKenney" <paulmck@kernel.org>
Cc: Carlos O'Donell <carlos@redhat.com>
Cc: Florian Weimer <fweimer@redhat.com>
Cc: Michael Jeanson <mjeanson@efficios.com>
Cc: linux-kselftest@vger.kernel.org
Cc: stable@vger.kernel.org
Signed-off-by: Shuah Khan <skhan@linuxfoundation.org>
  • Loading branch information
Mathieu Desnoyers authored and Shuah Khan committed Jan 15, 2025
1 parent d6d35d0 commit 336d02b
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 8 deletions.
32 changes: 25 additions & 7 deletions tools/testing/selftests/rseq/rseq.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ unsigned int rseq_size = -1U;
unsigned int rseq_flags;

static int rseq_ownership;
static int rseq_reg_success; /* At least one rseq registration has succeded. */

/* Allocate a large area for the TLS. */
#define RSEQ_THREAD_AREA_ALLOC_SIZE 1024
Expand Down Expand Up @@ -152,14 +151,27 @@ int rseq_register_current_thread(void)
}
rc = sys_rseq(&__rseq_abi, get_rseq_min_alloc_size(), 0, RSEQ_SIG);
if (rc) {
if (RSEQ_READ_ONCE(rseq_reg_success)) {
/*
* After at least one thread has registered successfully
* (rseq_size > 0), the registration of other threads should
* never fail.
*/
if (RSEQ_READ_ONCE(rseq_size) > 0) {
/* Incoherent success/failure within process. */
abort();
}
return -1;
}
assert(rseq_current_cpu_raw() >= 0);
RSEQ_WRITE_ONCE(rseq_reg_success, 1);

/*
* The first thread to register sets the rseq_size to mimic the libc
* behavior.
*/
if (RSEQ_READ_ONCE(rseq_size) == 0) {
RSEQ_WRITE_ONCE(rseq_size, get_rseq_kernel_feature_size());
}

return 0;
}

Expand Down Expand Up @@ -235,12 +247,18 @@ void rseq_init(void)
return;
}
rseq_ownership = 1;
if (!rseq_available()) {
rseq_size = 0;
return;
}

/* Calculate the offset of the rseq area from the thread pointer. */
rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();

/* rseq flags are deprecated, always set to 0. */
rseq_flags = 0;

/*
* Set the size to 0 until at least one thread registers to mimic the
* libc behavior.
*/
rseq_size = 0;
}

static __attribute__((destructor))
Expand Down
9 changes: 8 additions & 1 deletion tools/testing/selftests/rseq/rseq.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,14 @@
extern ptrdiff_t rseq_offset;

/*
* Size of the registered rseq area. 0 if the registration was
* The rseq ABI is composed of extensible feature fields. The extensions
* are done by appending additional fields at the end of the structure.
* The rseq_size defines the size of the active feature set which can be
* used by the application for the current rseq registration. Features
* starting at offset >= rseq_size are inactive and should not be used.
*
* The rseq_size is the intersection between the available allocation
* size for the rseq area and the feature size supported by the kernel.
* unsuccessful.
*/
extern unsigned int rseq_size;
Expand Down

0 comments on commit 336d02b

Please sign in to comment.