The current test_sigreturn_to() goes to the slow-path syscall with IRET due to non-canonical addresses. It uses the SIGUSR1 signal to perform the test.
Add a similar test that goes to the SYSRET path instead of IRET using the SIGUSR2 signal. There are two cases:
A) 'syscall' in a FRED system preserves %rcx and %r11.
B) 'syscall' in a non-FRED system sets %rcx=%rip and %r11=%rflags.
The __raise(SIGUSR2) call verifies the 'syscall' behavior consistency when dealing with a signal handler. It must always be (A) or always be (B). Not a mix of them.
Cc: Xin Li xin3.li@intel.com Link: https://lore.kernel.org/lkml/8770815f-0f23-d0c5-e56a-d401827842c9@zytor.com Suggested-by: H. Peter Anvin (Intel) hpa@zytor.com Signed-off-by: Ammar Faizi ammarfaizi2@gnuweeb.org --- tools/testing/selftests/x86/sysret_rip.c | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c index 1531593b50d02150..746801675fe77e9c 100644 --- a/tools/testing/selftests/x86/sysret_rip.c +++ b/tools/testing/selftests/x86/sysret_rip.c @@ -274,6 +274,28 @@ static void test_syscall_rcx_r11_consistent(void) do_syscall(__NR_getppid, 0, 0, 0, 0, 0, 0); }
+static unsigned long usr2_rcx; +static unsigned long usr2_r11; + +static void sigusr2(int sig, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx = (ucontext_t*)ctx_void; + + usr2_r11 = ctx->uc_mcontext.gregs[REG_R11]; + usr2_rcx = ctx->uc_mcontext.gregs[REG_RCX]; + + check_regs_result(ctx->uc_mcontext.gregs[REG_R11], + ctx->uc_mcontext.gregs[REG_RCX], + ctx->uc_mcontext.gregs[REG_RBX]); +} + +static void test_sysret_consistent(void) +{ + printf("[RUN]\ttest_sysret_consistent\n"); + __raise(SIGUSR2); + printf("[OK]\tRCX = %#lx; R11 = %#lx\n", usr2_rcx, usr2_r11); +} + int main() { int i; @@ -291,6 +313,14 @@ int main() for (i = 47; i < 64; i++) test_sigreturn_to(1UL<<i);
+ /* + * test_sigreturn_to() above will test the IRET path. Now test + * the SYSRET path. + */ + sethandler(SIGUSR2, sigusr2, 0); + for (i = 0; i < 32; i++) + test_sysret_consistent(); + clearhandler(SIGUSR1);
sethandler(SIGSEGV, sigsegv_for_fallthrough, 0);