Skip to content

Commit 826b78e

Browse files
nixprimegvisor-bot
authored andcommitted
test: fix rseq test bugs
- Unregister stack-allocated rseq before returning from test cases. - Add compiler barrier in RseqTest.InvalidAbortClearsCS. PiperOrigin-RevId: 853431610
1 parent 65762f8 commit 826b78e

File tree

2 files changed

+78
-33
lines changed

2 files changed

+78
-33
lines changed

test/syscalls/linux/rseq/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ genrule(
3434
"-static " +
3535
"-nostdlib " +
3636
"-ffreestanding " +
37+
"-fno-exceptions " +
3738
"-o " +
3839
"$(location rseq) " +
3940
select_arch(

test/syscalls/linux/rseq/rseq.cc

Lines changed: 77 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,45 @@ int sys_rseq(struct rseq* rseq, uint32_t rseq_len, int flags, uint32_t sig) {
5353
return raw_syscall(kRseqSyscall, rseq, rseq_len, flags, sig);
5454
}
5555

56+
// RSeqRegistration represents a registered struct rseq, which is unregistered
57+
// when the RSeqRegistration is destroyed.
58+
class RSeqRegistration {
59+
public:
60+
~RSeqRegistration() {
61+
if (rseq_) {
62+
sys_rseq(rseq_, rseq_len_, kRseqFlagUnregister, sig_);
63+
}
64+
}
65+
66+
RSeqRegistration(const RSeqRegistration&) = delete;
67+
RSeqRegistration& operator=(const RSeqRegistration&) = delete;
68+
RSeqRegistration(RSeqRegistration&&) = delete;
69+
RSeqRegistration& operator=(RSeqRegistration&&) = delete;
70+
71+
int errno() const { return errno_; }
72+
73+
private:
74+
RSeqRegistration(struct rseq* rseq, uint32_t rseq_len, uint32_t sig,
75+
int errno)
76+
: rseq_(rseq), rseq_len_(rseq_len), sig_(sig), errno_(errno) {}
77+
78+
struct rseq* rseq_;
79+
uint32_t rseq_len_;
80+
uint32_t sig_;
81+
int errno_;
82+
83+
friend RSeqRegistration RSeqRegister(struct rseq*, uint32_t, int, uint32_t);
84+
};
85+
86+
RSeqRegistration RSeqRegister(struct rseq* rseq, uint32_t rseq_len, int flags,
87+
uint32_t sig) {
88+
int ret = sys_rseq(rseq, rseq_len, flags, sig);
89+
if (int errno = sys_errno(ret); errno != 0) {
90+
return RSeqRegistration(nullptr, 0, 0, errno);
91+
}
92+
return RSeqRegistration(rseq, rseq_len, sig, 0);
93+
}
94+
5695
// Test that rseq must be aligned.
5796
int TestUnaligned() {
5897
constexpr uintptr_t kRequiredAlignment = alignof(rseq);
@@ -64,8 +103,8 @@ int TestUnaligned() {
64103
ptr++;
65104
}
66105

67-
int ret = sys_rseq(reinterpret_cast<rseq*>(ptr), sizeof(rseq), 0, 0);
68-
if (sys_errno(ret) != EINVAL) {
106+
auto reg = RSeqRegister(reinterpret_cast<rseq*>(ptr), sizeof(rseq), 0, 0);
107+
if (reg.errno() != EINVAL) {
69108
return 1;
70109
}
71110
return 0;
@@ -74,8 +113,8 @@ int TestUnaligned() {
74113
// Sanity test that registration works.
75114
int TestRegister() {
76115
struct rseq r = {};
77-
int ret = sys_rseq(&r, sizeof(r), 0, 0);
78-
if (sys_errno(ret) != 0) {
116+
auto reg = RSeqRegister(&r, sizeof(r), 0, 0);
117+
if (reg.errno() != 0) {
79118
return 1;
80119
}
81120
return 0;
@@ -84,13 +123,13 @@ int TestRegister() {
84123
// Registration can't be done twice.
85124
int TestDoubleRegister() {
86125
struct rseq r = {};
87-
int ret = sys_rseq(&r, sizeof(r), 0, 0);
88-
if (sys_errno(ret) != 0) {
126+
auto reg1 = RSeqRegister(&r, sizeof(r), 0, 0);
127+
if (reg1.errno() != 0) {
89128
return 1;
90129
}
91130

92-
ret = sys_rseq(&r, sizeof(r), 0, 0);
93-
if (sys_errno(ret) != EBUSY) {
131+
auto reg2 = RSeqRegister(&r, sizeof(r), 0, 0);
132+
if (reg2.errno() != EBUSY) {
94133
return 1;
95134
}
96135

@@ -111,8 +150,8 @@ int TestRegisterUnregister() {
111150
return 1;
112151
}
113152

114-
ret = sys_rseq(&r, sizeof(r), 0, 0);
115-
if (sys_errno(ret) != 0) {
153+
auto reg = RSeqRegister(&r, sizeof(r), 0, 0);
154+
if (reg.errno() != 0) {
116155
return 1;
117156
}
118157

@@ -123,14 +162,14 @@ int TestRegisterUnregister() {
123162
int TestUnregisterDifferentPtr() {
124163
struct rseq r = {};
125164

126-
int ret = sys_rseq(&r, sizeof(r), 0, 0);
127-
if (sys_errno(ret) != 0) {
165+
auto reg = RSeqRegister(&r, sizeof(r), 0, 0);
166+
if (reg.errno() != 0) {
128167
return 1;
129168
}
130169

131170
struct rseq r2 = {};
132171

133-
ret = sys_rseq(&r2, sizeof(r2), kRseqFlagUnregister, 0);
172+
int ret = sys_rseq(&r2, sizeof(r2), kRseqFlagUnregister, 0);
134173
if (sys_errno(ret) != EINVAL) {
135174
return 1;
136175
}
@@ -143,12 +182,12 @@ int TestUnregisterDifferentSignature() {
143182
constexpr int kSignature = 0;
144183

145184
struct rseq r = {};
146-
int ret = sys_rseq(&r, sizeof(r), 0, kSignature);
147-
if (sys_errno(ret) != 0) {
185+
auto reg = RSeqRegister(&r, sizeof(r), 0, kSignature);
186+
if (reg.errno() != 0) {
148187
return 1;
149188
}
150189

151-
ret = sys_rseq(&r, sizeof(r), kRseqFlagUnregister, kSignature + 1);
190+
int ret = sys_rseq(&r, sizeof(r), kRseqFlagUnregister, kSignature + 1);
152191
if (sys_errno(ret) != EPERM) {
153192
return 1;
154193
}
@@ -161,8 +200,8 @@ int TestCPU() {
161200
struct rseq r = {};
162201
r.cpu_id = kRseqCPUIDUninitialized;
163202

164-
int ret = sys_rseq(&r, sizeof(r), 0, 0);
165-
if (sys_errno(ret) != 0) {
203+
auto reg = RSeqRegister(&r, sizeof(r), 0, 0);
204+
if (reg.errno() != 0) {
166205
return 1;
167206
}
168207

@@ -179,8 +218,8 @@ int TestCPU() {
179218
// Critical section is eventually aborted.
180219
int TestAbort() {
181220
struct rseq r = {};
182-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature);
183-
if (sys_errno(ret) != 0) {
221+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature);
222+
if (reg.errno() != 0) {
184223
return 1;
185224
}
186225

@@ -201,8 +240,8 @@ int TestAbort() {
201240
// Abort may be before the critical section.
202241
int TestAbortBefore() {
203242
struct rseq r = {};
204-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature);
205-
if (sys_errno(ret) != 0) {
243+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature);
244+
if (reg.errno() != 0) {
206245
return 1;
207246
}
208247

@@ -223,8 +262,8 @@ int TestAbortBefore() {
223262
// Signature must match.
224263
int TestAbortSignature() {
225264
struct rseq r = {};
226-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature + 1);
227-
if (sys_errno(ret) != 0) {
265+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature + 1);
266+
if (reg.errno() != 0) {
228267
return 1;
229268
}
230269

@@ -245,8 +284,8 @@ int TestAbortSignature() {
245284
// Abort must not be in the critical section.
246285
int TestAbortPreCommit() {
247286
struct rseq r = {};
248-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature + 1);
249-
if (sys_errno(ret) != 0) {
287+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature + 1);
288+
if (reg.errno() != 0) {
250289
return 1;
251290
}
252291

@@ -267,8 +306,8 @@ int TestAbortPreCommit() {
267306
// rseq.rseq_cs is cleared on abort.
268307
int TestAbortClearsCS() {
269308
struct rseq r = {};
270-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature);
271-
if (sys_errno(ret) != 0) {
309+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature);
310+
if (reg.errno() != 0) {
272311
return 1;
273312
}
274313

@@ -293,8 +332,8 @@ int TestAbortClearsCS() {
293332
// rseq.rseq_cs is cleared on abort outside of critical section.
294333
int TestInvalidAbortClearsCS() {
295334
struct rseq r = {};
296-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature);
297-
if (sys_errno(ret) != 0) {
335+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature);
336+
if (reg.errno() != 0) {
298337
return 1;
299338
}
300339

@@ -306,6 +345,11 @@ int TestInvalidAbortClearsCS() {
306345
reinterpret_cast<uint64_t>(&rseq_loop_start);
307346
cs.abort_ip = reinterpret_cast<uint64_t>(&rseq_loop_abort);
308347

348+
// Ensure that the kernel, running on this CPU, will observe the preceding
349+
// stores to cs before the following store to r.rseq_cs. This is a compiler
350+
// barrier, equivalent to std::atomic_signal_fence() but without stdlib.
351+
asm volatile("" ::: "memory");
352+
309353
__atomic_store_n(&r.rseq_cs, &cs, __ATOMIC_RELAXED);
310354

311355
// When the next abort condition occurs, the kernel will clear cs once it
@@ -322,11 +366,11 @@ int TestInvalidAbortClearsCS() {
322366
// rseq.cpu_id_start is overwritten by RSEQ fence.
323367
int TestMembarrierResetsCpuIdStart() {
324368
struct rseq r = {};
325-
int ret = sys_rseq(&r, sizeof(r), 0, kRseqSignature);
326-
if (sys_errno(ret) != 0) {
369+
auto reg = RSeqRegister(&r, sizeof(r), 0, kRseqSignature);
370+
if (reg.errno() != 0) {
327371
return 1;
328372
}
329-
ret = sys_membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0);
373+
int ret = sys_membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ, 0);
330374
if (sys_errno(ret) != 0) {
331375
return 1;
332376
}

0 commit comments

Comments
 (0)