From: Ammar Faizi <ammarfaizi2@xxxxxxxxxxx> 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 must 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@xxxxxxxxx Co-developed-by: H. Peter Anvin (Intel) <hpa@xxxxxxxxx> Signed-off-by: H. Peter Anvin (Intel) <hpa@xxxxxxxxx> Signed-off-by: Ammar Faizi <ammarfaizi2@xxxxxxxxxxx> --- 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 ef3f492d95f6f2a1..d688cb9d5ac919eb 100644 --- a/tools/testing/selftests/x86/sysret_rip.c +++ b/tools/testing/selftests/x86/sysret_rip.c @@ -258,8 +258,24 @@ static void test_syscall_fallthrough_to(unsigned long ip) printf("[OK]\tWe survived\n"); } +/* + * Ensure that various system calls are consistent. + * We must 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 @@ -267,7 +283,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); @@ -278,7 +294,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); } -- Ammar Faizi