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. When the do_syscall() function is called for the first time, it will memorize the behavior, either (A) or (B). Then, the next do_syscall() call will verify that the 'syscall' behavior is the same. Test them with trivial system calls like __NR_getppid and friends, which are highly likely to return with SYSRET on an IDT system. The purposes of this test are: - Ensure that the syscall behavior is consistent. It must always be (A) or always be (B). Not a mix of them. - Ensure that the kernel doesn't leak its internal data when returning to userspace. Cc: Xin Li <xin3.li@xxxxxxxxx> 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 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/tools/testing/selftests/x86/sysret_rip.c b/tools/testing/selftests/x86/sysret_rip.c index 300104900192d396..1531593b50d02150 100644 --- a/tools/testing/selftests/x86/sysret_rip.c +++ b/tools/testing/selftests/x86/sysret_rip.c @@ -266,8 +266,21 @@ static void test_syscall_fallthrough_to(unsigned long ip) printf("[OK]\tWe survived\n"); } +/* See the comment in do_syscall(). */ +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 @@ -275,7 +288,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); @@ -286,7 +299,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