Skip to content

Commit 336d02b

Browse files
compudjshuahkh
authored andcommitted
selftests/rseq: Fix handling of glibc without rseq support
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>
1 parent d6d35d0 commit 336d02b

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

tools/testing/selftests/rseq/rseq.c

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ unsigned int rseq_size = -1U;
6161
unsigned int rseq_flags;
6262

6363
static int rseq_ownership;
64-
static int rseq_reg_success; /* At least one rseq registration has succeded. */
6564

6665
/* Allocate a large area for the TLS. */
6766
#define RSEQ_THREAD_AREA_ALLOC_SIZE 1024
@@ -152,14 +151,27 @@ int rseq_register_current_thread(void)
152151
}
153152
rc = sys_rseq(&__rseq_abi, get_rseq_min_alloc_size(), 0, RSEQ_SIG);
154153
if (rc) {
155-
if (RSEQ_READ_ONCE(rseq_reg_success)) {
154+
/*
155+
* After at least one thread has registered successfully
156+
* (rseq_size > 0), the registration of other threads should
157+
* never fail.
158+
*/
159+
if (RSEQ_READ_ONCE(rseq_size) > 0) {
156160
/* Incoherent success/failure within process. */
157161
abort();
158162
}
159163
return -1;
160164
}
161165
assert(rseq_current_cpu_raw() >= 0);
162-
RSEQ_WRITE_ONCE(rseq_reg_success, 1);
166+
167+
/*
168+
* The first thread to register sets the rseq_size to mimic the libc
169+
* behavior.
170+
*/
171+
if (RSEQ_READ_ONCE(rseq_size) == 0) {
172+
RSEQ_WRITE_ONCE(rseq_size, get_rseq_kernel_feature_size());
173+
}
174+
163175
return 0;
164176
}
165177

@@ -235,12 +247,18 @@ void rseq_init(void)
235247
return;
236248
}
237249
rseq_ownership = 1;
238-
if (!rseq_available()) {
239-
rseq_size = 0;
240-
return;
241-
}
250+
251+
/* Calculate the offset of the rseq area from the thread pointer. */
242252
rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
253+
254+
/* rseq flags are deprecated, always set to 0. */
243255
rseq_flags = 0;
256+
257+
/*
258+
* Set the size to 0 until at least one thread registers to mimic the
259+
* libc behavior.
260+
*/
261+
rseq_size = 0;
244262
}
245263

246264
static __attribute__((destructor))

tools/testing/selftests/rseq/rseq.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,14 @@
6060
extern ptrdiff_t rseq_offset;
6161

6262
/*
63-
* Size of the registered rseq area. 0 if the registration was
63+
* The rseq ABI is composed of extensible feature fields. The extensions
64+
* are done by appending additional fields at the end of the structure.
65+
* The rseq_size defines the size of the active feature set which can be
66+
* used by the application for the current rseq registration. Features
67+
* starting at offset >= rseq_size are inactive and should not be used.
68+
*
69+
* The rseq_size is the intersection between the available allocation
70+
* size for the rseq area and the feature size supported by the kernel.
6471
* unsuccessful.
6572
*/
6673
extern unsigned int rseq_size;

0 commit comments

Comments
 (0)