Test that:
- REGS_SAVED: "syscall" in a FRED system doesn't clobber %rcx and %r11.
- REGS_SYSRET: "syscall" in a non-FRED system sets %rcx=%rip and %r11=%rflags.
Test them out with trivial system calls like __NR_getppid and friends which are extremely likely to return with SYSRET on an IDT system.
Goals of this test:
- Ensure that the syscall behavior is consistent. It should be either always REGS_SAVED or always REGS_SYSRET. Not a mix of them.
- The kernel doesn't leak its internal data when returning to userspace.
Link: https://lore.kernel.org/lkml/25b96960-a07e-a952-5c23-786b55054126@zytor.com Co-developed-by: H. Peter Anvin (Intel) hpa@zytor.com Signed-off-by: H. Peter Anvin (Intel) hpa@zytor.com Signed-off-by: Ammar Faizi ammarfaizi2@gnuweeb.org --- tools/testing/selftests/x86/sysret_rip.c | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-)
diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c index 100f55981d77a29b..d45b7f0147cd25ad 100644 --- a/tools/testing/selftests/x86/sysret_rip.c +++ b/tools/testing/selftests/x86/sysret_rip.c @@ -264,8 +264,24 @@ static void test_syscall_fallthrough_to(unsigned long ip) printf("[OK]\tWe survived\n"); }
+/* + * Ensure that various system calls are consistent. + * We should not get a mix of REGS_SAVED and REGS_SYSRET. + */ +static void test_syscall_rcx_r11_consistent(void) +{ + do_syscall(__NR_getpid, 0, 0, 0, 0, 0, 0); + do_syscall(__NR_gettid, 0, 0, 0, 0, 0, 0); + do_syscall(__NR_getppid, 0, 0, 0, 0, 0, 0); +} + int main() { + int i; + + for (i = 0; i < 32; i++) + test_syscall_rcx_r11_consistent(); + /* * When the kernel returns from a slow-path syscall, it will * detect whether SYSRET is appropriate. If it incorrectly @@ -273,7 +289,7 @@ int main() * it'll crash on Intel CPUs. */ sethandler(SIGUSR1, sigusr1, 0); - for (int i = 47; i < 64; i++) + for (i = 47; i < 64; i++) test_sigreturn_to(1UL<<i);
clearhandler(SIGUSR1); @@ -284,7 +300,7 @@ int main() test_syscall_fallthrough_to((1UL << 47) - 2*PAGE_SIZE);
/* These are the interesting cases. */ - for (int i = 47; i < 64; i++) { + for (i = 47; i < 64; i++) { test_syscall_fallthrough_to((1UL<<i) - PAGE_SIZE); test_syscall_fallthrough_to(1UL<<i); }