Skip to content

Commit 22d9231

Browse files
xinli-intelpopcornmix
authored andcommitted
selftests/x86: Add a test to detect infinite SIGTRAP handler loop
commit f287822 upstream. When FRED is enabled, if the Trap Flag (TF) is set without an external debugger attached, it can lead to an infinite loop in the SIGTRAP handler. To avoid this, the software event flag in the augmented SS must be cleared, ensuring that no single-step trap remains pending when ERETU completes. This test checks for that specific scenario—verifying whether the kernel correctly prevents an infinite SIGTRAP loop in this edge case when FRED is enabled. The test should _always_ pass with IDT event delivery, thus no need to disable the test even when FRED is not enabled. Signed-off-by: Xin Li (Intel) <xin@zytor.com> Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com> Tested-by: Sohil Mehta <sohil.mehta@intel.com> Cc:stable@vger.kernel.org Link: https://lore.kernel.org/all/20250609084054.2083189-3-xin%40zytor.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent c2cbae6 commit 22d9231

File tree

2 files changed

+102
-1
lines changed

2 files changed

+102
-1
lines changed

tools/testing/selftests/x86/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ CAN_BUILD_WITH_NOPIE := $(shell ./check_cc.sh "$(CC)" trivial_program.c -no-pie)
1212

1313
TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt test_mremap_vdso \
1414
check_initial_reg_state sigreturn iopl ioperm \
15-
test_vsyscall mov_ss_trap \
15+
test_vsyscall mov_ss_trap sigtrap_loop \
1616
syscall_arg_fault fsgsbase_restore sigaltstack
1717
TARGETS_C_BOTHBITS += nx_stack
1818
TARGETS_C_32BIT_ONLY := entry_from_vm86 test_syscall_vdso unwind_vdso \
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2025 Intel Corporation
4+
*/
5+
#define _GNU_SOURCE
6+
7+
#include <err.h>
8+
#include <signal.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <string.h>
12+
#include <sys/ucontext.h>
13+
14+
#ifdef __x86_64__
15+
# define REG_IP REG_RIP
16+
#else
17+
# define REG_IP REG_EIP
18+
#endif
19+
20+
static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), int flags)
21+
{
22+
struct sigaction sa;
23+
24+
memset(&sa, 0, sizeof(sa));
25+
sa.sa_sigaction = handler;
26+
sa.sa_flags = SA_SIGINFO | flags;
27+
sigemptyset(&sa.sa_mask);
28+
29+
if (sigaction(sig, &sa, 0))
30+
err(1, "sigaction");
31+
32+
return;
33+
}
34+
35+
static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
36+
{
37+
ucontext_t *ctx = (ucontext_t *)ctx_void;
38+
static unsigned int loop_count_on_same_ip;
39+
static unsigned long last_trap_ip;
40+
41+
if (last_trap_ip == ctx->uc_mcontext.gregs[REG_IP]) {
42+
printf("\tTrapped at %016lx\n", last_trap_ip);
43+
44+
/*
45+
* If the same IP is hit more than 10 times in a row, it is
46+
* _considered_ an infinite loop.
47+
*/
48+
if (++loop_count_on_same_ip > 10) {
49+
printf("[FAIL]\tDetected SIGTRAP infinite loop\n");
50+
exit(1);
51+
}
52+
53+
return;
54+
}
55+
56+
loop_count_on_same_ip = 0;
57+
last_trap_ip = ctx->uc_mcontext.gregs[REG_IP];
58+
printf("\tTrapped at %016lx\n", last_trap_ip);
59+
}
60+
61+
int main(int argc, char *argv[])
62+
{
63+
sethandler(SIGTRAP, sigtrap, 0);
64+
65+
/*
66+
* Set the Trap Flag (TF) to single-step the test code, therefore to
67+
* trigger a SIGTRAP signal after each instruction until the TF is
68+
* cleared.
69+
*
70+
* Because the arithmetic flags are not significant here, the TF is
71+
* set by pushing 0x302 onto the stack and then popping it into the
72+
* flags register.
73+
*
74+
* Four instructions in the following asm code are executed with the
75+
* TF set, thus the SIGTRAP handler is expected to run four times.
76+
*/
77+
printf("[RUN]\tSIGTRAP infinite loop detection\n");
78+
asm volatile(
79+
#ifdef __x86_64__
80+
/*
81+
* Avoid clobbering the redzone
82+
*
83+
* Equivalent to "sub $128, %rsp", however -128 can be encoded
84+
* in a single byte immediate while 128 uses 4 bytes.
85+
*/
86+
"add $-128, %rsp\n\t"
87+
#endif
88+
"push $0x302\n\t"
89+
"popf\n\t"
90+
"nop\n\t"
91+
"nop\n\t"
92+
"push $0x202\n\t"
93+
"popf\n\t"
94+
#ifdef __x86_64__
95+
"sub $-128, %rsp\n\t"
96+
#endif
97+
);
98+
99+
printf("[OK]\tNo SIGTRAP infinite loop detected\n");
100+
return 0;
101+
}

0 commit comments

Comments
 (0)