50 lines
1.9 KiB
Diff
50 lines
1.9 KiB
Diff
From 51660aba34b41c08d892bda6528abe992a5687e7 Mon Sep 17 00:00:00 2001
|
|
From: Adrian Reber <areber@redhat.com>
|
|
Date: Tue, 19 May 2026 17:11:35 +0000
|
|
Subject: [PATCH] zdtm: unregister rseq before zeroing the rseq area
|
|
|
|
Starting with Linux 7.1, the kernel enforces strict read-only field
|
|
protection for the rseq V2 ABI. Userspace is no longer allowed to
|
|
modify kernel-managed fields (cpu_id_start, cpu_id, node_id, mm_cid)
|
|
while rseq is registered. Violations are detected on the next context
|
|
switch and the offending process is killed with SIGSEGV.
|
|
|
|
The rseq01 test was zeroing the entire glibc-registered rseq area
|
|
with memset() before calling test_init(), which internally calls
|
|
fork(). This corrupted the read-only fields while the glibc rseq
|
|
registration was still active, causing the kernel to send SIGSEGV
|
|
during the fork.
|
|
|
|
Fix this by calling unregister_old_rseq() before the memset in both
|
|
main() and thread_routine(), so the kernel is no longer monitoring
|
|
those fields when they are zeroed. The subsequent register_thread()
|
|
call re-registers rseq with the clean area.
|
|
|
|
Link: https://github.com/torvalds/linux/commit/7f0023215262221ca08d56be2203e8a4770be033
|
|
|
|
Assisted-by: Claude Code (https://claude.ai/code):claude-opus-4-6
|
|
Signed-off-by: Adrian Reber <areber@redhat.com>
|
|
---
|
|
test/zdtm/transition/rseq01.c | 2 ++
|
|
1 file changed, 2 insertions(+)
|
|
|
|
diff --git a/test/zdtm/transition/rseq01.c b/test/zdtm/transition/rseq01.c
|
|
index 9c5925bc45..0d5485e162 100644
|
|
--- a/test/zdtm/transition/rseq01.c
|
|
+++ b/test/zdtm/transition/rseq01.c
|
|
@@ -252,6 +252,7 @@ void *thread_routine(void *args)
|
|
int cpu;
|
|
|
|
rseq_ptr = rseq_area();
|
|
+ unregister_old_rseq();
|
|
memset((void *)rseq_ptr, 0, rseq_reg_size());
|
|
register_thread();
|
|
task_waiter_complete(&waiter, 1);
|
|
@@ -277,6 +278,7 @@ int main(int argc, char *argv[])
|
|
pthread_t thread;
|
|
|
|
rseq_ptr = rseq_area();
|
|
+ unregister_old_rseq();
|
|
memset((void *)rseq_ptr, 0, rseq_reg_size());
|
|
|
|
test_init(argc, argv);
|