Skip to content

Commit a0cc649

Browse files
compudjshuahkh
authored andcommitted
selftests/rseq: Fix mm_cid test failure
Adapt the rseq.c/rseq.h code to follow GNU C library changes introduced by: glibc commit 2e456ccf0c34 ("Linux: Make __rseq_size useful for feature detection (bug 31965)") Without this fix, rseq selftests for mm_cid fail: ./run_param_test.sh Default parameters Running test spinlock Running compare-twice test spinlock Running mm_cid test spinlock Error: cpu id getter unavailable Fixes: 18c2355 ("selftests/rseq: Implement rseq mm_cid field support") Signed-off-by: Mathieu Desnoyers <[email protected]> Cc: Peter Zijlstra <[email protected]> CC: Boqun Feng <[email protected]> CC: "Paul E. McKenney" <[email protected]> Cc: Shuah Khan <[email protected]> CC: Carlos O'Donell <[email protected]> CC: Florian Weimer <[email protected]> CC: [email protected] CC: [email protected] Signed-off-by: Shuah Khan <[email protected]>
1 parent 34d5b60 commit a0cc649

File tree

2 files changed

+77
-43
lines changed

2 files changed

+77
-43
lines changed

tools/testing/selftests/rseq/rseq.c

Lines changed: 75 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,6 @@ unsigned int rseq_size = -1U;
6060
/* Flags used during rseq registration. */
6161
unsigned int rseq_flags;
6262

63-
/*
64-
* rseq feature size supported by the kernel. 0 if the registration was
65-
* unsuccessful.
66-
*/
67-
unsigned int rseq_feature_size = -1U;
68-
6963
static int rseq_ownership;
7064
static int rseq_reg_success; /* At least one rseq registration has succeded. */
7165

@@ -111,6 +105,43 @@ int rseq_available(void)
111105
}
112106
}
113107

108+
/* The rseq areas need to be at least 32 bytes. */
109+
static
110+
unsigned int get_rseq_min_alloc_size(void)
111+
{
112+
unsigned int alloc_size = rseq_size;
113+
114+
if (alloc_size < ORIG_RSEQ_ALLOC_SIZE)
115+
alloc_size = ORIG_RSEQ_ALLOC_SIZE;
116+
return alloc_size;
117+
}
118+
119+
/*
120+
* Return the feature size supported by the kernel.
121+
*
122+
* Depending on the value returned by getauxval(AT_RSEQ_FEATURE_SIZE):
123+
*
124+
* 0: Return ORIG_RSEQ_FEATURE_SIZE (20)
125+
* > 0: Return the value from getauxval(AT_RSEQ_FEATURE_SIZE).
126+
*
127+
* It should never return a value below ORIG_RSEQ_FEATURE_SIZE.
128+
*/
129+
static
130+
unsigned int get_rseq_kernel_feature_size(void)
131+
{
132+
unsigned long auxv_rseq_feature_size, auxv_rseq_align;
133+
134+
auxv_rseq_align = getauxval(AT_RSEQ_ALIGN);
135+
assert(!auxv_rseq_align || auxv_rseq_align <= RSEQ_THREAD_AREA_ALLOC_SIZE);
136+
137+
auxv_rseq_feature_size = getauxval(AT_RSEQ_FEATURE_SIZE);
138+
assert(!auxv_rseq_feature_size || auxv_rseq_feature_size <= RSEQ_THREAD_AREA_ALLOC_SIZE);
139+
if (auxv_rseq_feature_size)
140+
return auxv_rseq_feature_size;
141+
else
142+
return ORIG_RSEQ_FEATURE_SIZE;
143+
}
144+
114145
int rseq_register_current_thread(void)
115146
{
116147
int rc;
@@ -119,7 +150,7 @@ int rseq_register_current_thread(void)
119150
/* Treat libc's ownership as a successful registration. */
120151
return 0;
121152
}
122-
rc = sys_rseq(&__rseq_abi, rseq_size, 0, RSEQ_SIG);
153+
rc = sys_rseq(&__rseq_abi, get_rseq_min_alloc_size(), 0, RSEQ_SIG);
123154
if (rc) {
124155
if (RSEQ_READ_ONCE(rseq_reg_success)) {
125156
/* Incoherent success/failure within process. */
@@ -140,28 +171,12 @@ int rseq_unregister_current_thread(void)
140171
/* Treat libc's ownership as a successful unregistration. */
141172
return 0;
142173
}
143-
rc = sys_rseq(&__rseq_abi, rseq_size, RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
174+
rc = sys_rseq(&__rseq_abi, get_rseq_min_alloc_size(), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
144175
if (rc)
145176
return -1;
146177
return 0;
147178
}
148179

149-
static
150-
unsigned int get_rseq_feature_size(void)
151-
{
152-
unsigned long auxv_rseq_feature_size, auxv_rseq_align;
153-
154-
auxv_rseq_align = getauxval(AT_RSEQ_ALIGN);
155-
assert(!auxv_rseq_align || auxv_rseq_align <= RSEQ_THREAD_AREA_ALLOC_SIZE);
156-
157-
auxv_rseq_feature_size = getauxval(AT_RSEQ_FEATURE_SIZE);
158-
assert(!auxv_rseq_feature_size || auxv_rseq_feature_size <= RSEQ_THREAD_AREA_ALLOC_SIZE);
159-
if (auxv_rseq_feature_size)
160-
return auxv_rseq_feature_size;
161-
else
162-
return ORIG_RSEQ_FEATURE_SIZE;
163-
}
164-
165180
static __attribute__((constructor))
166181
void rseq_init(void)
167182
{
@@ -178,28 +193,54 @@ void rseq_init(void)
178193
}
179194
if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p &&
180195
*libc_rseq_size_p != 0) {
196+
unsigned int libc_rseq_size;
197+
181198
/* rseq registration owned by glibc */
182199
rseq_offset = *libc_rseq_offset_p;
183-
rseq_size = *libc_rseq_size_p;
200+
libc_rseq_size = *libc_rseq_size_p;
184201
rseq_flags = *libc_rseq_flags_p;
185-
rseq_feature_size = get_rseq_feature_size();
186-
if (rseq_feature_size > rseq_size)
187-
rseq_feature_size = rseq_size;
202+
203+
/*
204+
* Previous versions of glibc expose the value
205+
* 32 even though the kernel only supported 20
206+
* bytes initially. Therefore treat 32 as a
207+
* special-case. glibc 2.40 exposes a 20 bytes
208+
* __rseq_size without using getauxval(3) to
209+
* query the supported size, while still allocating a 32
210+
* bytes area. Also treat 20 as a special-case.
211+
*
212+
* Special-cases are handled by using the following
213+
* value as active feature set size:
214+
*
215+
* rseq_size = min(32, get_rseq_kernel_feature_size())
216+
*/
217+
switch (libc_rseq_size) {
218+
case ORIG_RSEQ_FEATURE_SIZE:
219+
fallthrough;
220+
case ORIG_RSEQ_ALLOC_SIZE:
221+
{
222+
unsigned int rseq_kernel_feature_size = get_rseq_kernel_feature_size();
223+
224+
if (rseq_kernel_feature_size < ORIG_RSEQ_ALLOC_SIZE)
225+
rseq_size = rseq_kernel_feature_size;
226+
else
227+
rseq_size = ORIG_RSEQ_ALLOC_SIZE;
228+
break;
229+
}
230+
default:
231+
/* Otherwise just use the __rseq_size from libc as rseq_size. */
232+
rseq_size = libc_rseq_size;
233+
break;
234+
}
188235
return;
189236
}
190237
rseq_ownership = 1;
191238
if (!rseq_available()) {
192239
rseq_size = 0;
193-
rseq_feature_size = 0;
194240
return;
195241
}
196242
rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
197243
rseq_flags = 0;
198-
rseq_feature_size = get_rseq_feature_size();
199-
if (rseq_feature_size == ORIG_RSEQ_FEATURE_SIZE)
200-
rseq_size = ORIG_RSEQ_ALLOC_SIZE;
201-
else
202-
rseq_size = RSEQ_THREAD_AREA_ALLOC_SIZE;
203244
}
204245

205246
static __attribute__((destructor))
@@ -209,7 +250,6 @@ void rseq_exit(void)
209250
return;
210251
rseq_offset = 0;
211252
rseq_size = -1U;
212-
rseq_feature_size = -1U;
213253
rseq_ownership = 0;
214254
}
215255

tools/testing/selftests/rseq/rseq.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,12 +68,6 @@ extern unsigned int rseq_size;
6868
/* Flags used during rseq registration. */
6969
extern unsigned int rseq_flags;
7070

71-
/*
72-
* rseq feature size supported by the kernel. 0 if the registration was
73-
* unsuccessful.
74-
*/
75-
extern unsigned int rseq_feature_size;
76-
7771
enum rseq_mo {
7872
RSEQ_MO_RELAXED = 0,
7973
RSEQ_MO_CONSUME = 1, /* Unused */
@@ -193,7 +187,7 @@ static inline uint32_t rseq_current_cpu(void)
193187

194188
static inline bool rseq_node_id_available(void)
195189
{
196-
return (int) rseq_feature_size >= rseq_offsetofend(struct rseq_abi, node_id);
190+
return (int) rseq_size >= rseq_offsetofend(struct rseq_abi, node_id);
197191
}
198192

199193
/*
@@ -207,7 +201,7 @@ static inline uint32_t rseq_current_node_id(void)
207201

208202
static inline bool rseq_mm_cid_available(void)
209203
{
210-
return (int) rseq_feature_size >= rseq_offsetofend(struct rseq_abi, mm_cid);
204+
return (int) rseq_size >= rseq_offsetofend(struct rseq_abi, mm_cid);
211205
}
212206

213207
static inline uint32_t rseq_current_mm_cid(void)

0 commit comments

Comments
 (0)