From nobody Mon Feb 9 07:59:21 2026 Received: from mail.zytor.com (terminus.zytor.com [198.137.202.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6629724EA81; Mon, 9 Jun 2025 08:44:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.137.202.136 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749458690; cv=none; b=N81Ko7j2F6PVRJ7pdOPPJIlBRWBjdvJb/NHRT5fKGP8xRmoLKOQUqOqxamwKRcHFnJ7P+S1NZsV4DQhMM0uXbCMCweiLvhUUwAoRX2meV8xf+4iiI8SpJEUnM5oz1NYPZtTuC2fDySvWHV5FBdT5g0snVGqkZUWNuWreCN0H7zs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749458690; c=relaxed/simple; bh=/4ntWDGVEqdM6hvIE/8soqmoRgUpmSGCncYbw6lnA74=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=LNUnqA3PpkLqx3/0bo+GdyBi7BBTUHT1DsQzL3Owf49zAVBPGa2ZwnI632HS0gs9pBgsVoDtpx7xjq79liTVXJjpMWHZpXIvIaO6C/tY/fRjhIBvms19LPwwJ7hoYZ0G1RVi6DhBhhkQK8jv9JwlybY0BZAofwdqHemB+sjtv/g= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zytor.com; spf=pass smtp.mailfrom=zytor.com; dkim=pass (2048-bit key) header.d=zytor.com header.i=@zytor.com header.b=r02gkbkW; arc=none smtp.client-ip=198.137.202.136 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zytor.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zytor.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=zytor.com header.i=@zytor.com header.b="r02gkbkW" Received: from terminus.zytor.com (terminus.zytor.com [IPv6:2607:7c80:54:3:0:0:0:136]) (authenticated bits=0) by mail.zytor.com (8.18.1/8.17.1) with ESMTPSA id 5598etjX2083203 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Mon, 9 Jun 2025 01:40:59 -0700 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.zytor.com 5598etjX2083203 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zytor.com; s=2025052101; t=1749458460; bh=6Ht1A8Hjh+GgjfuSQd4GiSvEvDAMxvRo+MyQbhgjQBY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=r02gkbkWbfJjED1AU4IuyZAvobeagHU/vJHRevqnje6mxyIfWzKf4tzwbUAXwe7sp SSqPK89WkwZk9hm7s8Mc6Kf6qri1QR4p/+BU05BRi2zS5SD4kV9fbUMzrxZdsHiXCv EzA0m1fsaT+q+OhL2edKeco7zvtJm7W6G6faNsyLx+T5q0cerozfPzFuJWZOdoZbxG wOpwOFHJGBiuNq6Hb9Txtltp974Tfk5JcsFrKZh16/JpB9bRHmnI4WJt2OPpaxfhqr 3T0JgxnnlfgGQa9RgylNlqI3WynV8lRuTGQeUMqr3BVpc60cQsRABkCK1+WQzl9T5g VJitlDKLquY+g== From: "Xin Li (Intel)" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com, shuah@kernel.org, andrew.cooper3@citrix.com, sohil.mehta@intel.com, stable@vger.kernel.org Subject: [PATCH v6 1/2] x86/fred/signal: Prevent immediate repeat of single step trap on return from SIGTRAP handler Date: Mon, 9 Jun 2025 01:40:53 -0700 Message-ID: <20250609084054.2083189-2-xin@zytor.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609084054.2083189-1-xin@zytor.com> References: <20250609084054.2083189-1-xin@zytor.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Clear the software event flag in the augmented SS to prevent immediate repeat of single step trap on return from SIGTRAP handler if the trap flag (TF) is set without an external debugger attached. Following is a typical single-stepping flow for a user process: 1) The user process is prepared for single-stepping by setting RFLAGS.TF =3D 1. 2) When any instruction in user space completes, a #DB is triggered. 3) The kernel handles the #DB and returns to user space, invoking the SIGTRAP handler with RFLAGS.TF =3D 0. 4) After the SIGTRAP handler finishes, the user process performs a sigreturn syscall, restoring the original state, including RFLAGS.TF =3D 1. 5) Goto step 2. According to the FRED specification: A) Bit 17 in the augmented SS is designated as the software event flag, which is set to 1 for FRED event delivery of SYSCALL, SYSENTER, or INT n. B) If bit 17 of the augmented SS is 1 and ERETU would result in RFLAGS.TF =3D 1, a single-step trap will be pending upon completion of ERETU. In step 4) above, the software event flag is set upon the sigreturn syscall, and its corresponding ERETU would restore RFLAGS.TF =3D 1. This combination causes a pending single-step trap upon completion of ERETU. Therefore, another #DB is triggered before any user space instruction is executed, which leads to an infinite loop in which the SIGTRAP handler keeps being invoked on the same user space IP. Suggested-by: H. Peter Anvin (Intel) Tested-by: Sohil Mehta Signed-off-by: Xin Li (Intel) Cc: stable@vger.kernel.org Reviewed-by: Sohil Mehta --- Change in v6: *) Add TB from Sohil. Change in v5: *) Accurately rephrase the shortlog (hpa). Change in v4: *) Add a selftest to the patch set (Dave Hansen). Change in v3: *) Use "#ifdef CONFIG_X86_FRED" instead of IS_ENABLED(CONFIG_X86_FRED) (Intel LKP). Change in v2: *) Remove the check cpu_feature_enabled(X86_FEATURE_FRED), because regs->fred_ss.swevent will always be 0 otherwise (hpa). --- arch/x86/include/asm/sighandling.h | 22 ++++++++++++++++++++++ arch/x86/kernel/signal_32.c | 4 ++++ arch/x86/kernel/signal_64.c | 4 ++++ 3 files changed, 30 insertions(+) diff --git a/arch/x86/include/asm/sighandling.h b/arch/x86/include/asm/sigh= andling.h index e770c4fc47f4..8727c7e21dd1 100644 --- a/arch/x86/include/asm/sighandling.h +++ b/arch/x86/include/asm/sighandling.h @@ -24,4 +24,26 @@ int ia32_setup_rt_frame(struct ksignal *ksig, struct pt_= regs *regs); int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs); int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs); =20 +/* + * To prevent immediate repeat of single step trap on return from SIGTRAP + * handler if the trap flag (TF) is set without an external debugger attac= hed, + * clear the software event flag in the augmented SS, ensuring no single-s= tep + * trap is pending upon ERETU completion. + * + * Note, this function should be called in sigreturn() before the original + * state is restored to make sure the TF is read from the entry frame. + */ +static __always_inline void prevent_single_step_upon_eretu(struct pt_regs = *regs) +{ + /* + * If the trap flag (TF) is set, i.e., the sigreturn() SYSCALL instruction + * is being single-stepped, do not clear the software event flag in the + * augmented SS, thus a debugger won't skip over the following instructio= n. + */ +#ifdef CONFIG_X86_FRED + if (!(regs->flags & X86_EFLAGS_TF)) + regs->fred_ss.swevent =3D 0; +#endif +} + #endif /* _ASM_X86_SIGHANDLING_H */ diff --git a/arch/x86/kernel/signal_32.c b/arch/x86/kernel/signal_32.c index 98123ff10506..42bbc42bd350 100644 --- a/arch/x86/kernel/signal_32.c +++ b/arch/x86/kernel/signal_32.c @@ -152,6 +152,8 @@ SYSCALL32_DEFINE0(sigreturn) struct sigframe_ia32 __user *frame =3D (struct sigframe_ia32 __user *)(re= gs->sp-8); sigset_t set; =20 + prevent_single_step_upon_eretu(regs); + if (!access_ok(frame, sizeof(*frame))) goto badframe; if (__get_user(set.sig[0], &frame->sc.oldmask) @@ -175,6 +177,8 @@ SYSCALL32_DEFINE0(rt_sigreturn) struct rt_sigframe_ia32 __user *frame; sigset_t set; =20 + prevent_single_step_upon_eretu(regs); + frame =3D (struct rt_sigframe_ia32 __user *)(regs->sp - 4); =20 if (!access_ok(frame, sizeof(*frame))) diff --git a/arch/x86/kernel/signal_64.c b/arch/x86/kernel/signal_64.c index ee9453891901..d483b585c6c6 100644 --- a/arch/x86/kernel/signal_64.c +++ b/arch/x86/kernel/signal_64.c @@ -250,6 +250,8 @@ SYSCALL_DEFINE0(rt_sigreturn) sigset_t set; unsigned long uc_flags; =20 + prevent_single_step_upon_eretu(regs); + frame =3D (struct rt_sigframe __user *)(regs->sp - sizeof(long)); if (!access_ok(frame, sizeof(*frame))) goto badframe; @@ -366,6 +368,8 @@ COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn) sigset_t set; unsigned long uc_flags; =20 + prevent_single_step_upon_eretu(regs); + frame =3D (struct rt_sigframe_x32 __user *)(regs->sp - 8); =20 if (!access_ok(frame, sizeof(*frame))) --=20 2.49.0 From nobody Mon Feb 9 07:59:21 2026 Received: from terminus.zytor.com (terminus.zytor.com [198.137.202.136]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6EB0D1E832A; Mon, 9 Jun 2025 08:44:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.137.202.136 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749458687; cv=none; b=kyL1kaXSy/ewiuCDRPMwstPVz0IFzzCtHD9jVIfMHuNo6VLhQhDEGcdOeFGxASDCW/iKW8qtvo5mcD5iGzNX84cJbkoR2H77SZS8saFubeOpzwXOFAoQ/RgJp8kTGf0mYVfNbgHUJ32Iou7UjnPotuUnN7BE8H1uBDAMOCNGAAc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749458687; c=relaxed/simple; bh=CByUBOS0MBmmNMegB/+6lX7pJRvkfT954wBkluc+45o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=X1epkVEDsLpnZ/rzbAd3qF9GNOLEemsIItTSP7YzkLSLixcPIcms+y7X3F9LUbUqK65l7VLaj1Wt8qgu9SzT/6O4qbw8dCH4sGgog78lfGUwrBEnjZj78ZPoCQQBQ2ssOSg7QZOnWk5DUeoAIIJro8As7s0J6mNmpCZgcEzoRC8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zytor.com; spf=pass smtp.mailfrom=zytor.com; dkim=pass (2048-bit key) header.d=zytor.com header.i=@zytor.com header.b=AbzWx8Fv; arc=none smtp.client-ip=198.137.202.136 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=zytor.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=zytor.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=zytor.com header.i=@zytor.com header.b="AbzWx8Fv" Received: from terminus.zytor.com (terminus.zytor.com [IPv6:2607:7c80:54:3:0:0:0:136]) (authenticated bits=0) by mail.zytor.com (8.18.1/8.17.1) with ESMTPSA id 5598etjY2083203 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Mon, 9 Jun 2025 01:41:00 -0700 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.zytor.com 5598etjY2083203 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zytor.com; s=2025052101; t=1749458461; bh=6/ZBNndjXX8DFqqBm4MVFtkldgTvHA01dVD0CKp8O6U=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=AbzWx8FvOp8tj7jZxacME/ujTLvaMAf8hpft+jbUjQh+FjSUsziLpf/ds7KBnf1FG Mc8xahmuus64jiuJ+CPIyyqAAKPfc5V7HjSYtPxYgXH0SQoRn4F4hYkvRVbMpGy59o qLdyhtEC1QZ2UAEHv7mpauqgaE41Cf/XQ3s3Mbb9/T488d1T4ytcLmynF7j2EQDpRv qKipgUnx8EraMr+2paPYXIu0fkfYeK9RKZlqAyV54oET1RBInGNWdyu1lafq57/Kyz SDisfqGYv9J8VaqVOTnCUB3moQdg7u7yfHNbvMMniowqdtqqQtmZABzfgdKkz10KT4 JANRLWOiOyGog== From: "Xin Li (Intel)" To: linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Cc: tglx@linutronix.de, mingo@redhat.com, bp@alien8.de, dave.hansen@linux.intel.com, x86@kernel.org, hpa@zytor.com, shuah@kernel.org, andrew.cooper3@citrix.com, sohil.mehta@intel.com, stable@vger.kernel.org Subject: [PATCH v6 2/2] selftests/x86: Add a test to detect infinite SIGTRAP handler loop Date: Mon, 9 Jun 2025 01:40:54 -0700 Message-ID: <20250609084054.2083189-3-xin@zytor.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250609084054.2083189-1-xin@zytor.com> References: <20250609084054.2083189-1-xin@zytor.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable 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=E2=80=94verifying whether the k= ernel 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. Tested-by: Sohil Mehta Signed-off-by: Xin Li (Intel) Cc: stable@vger.kernel.org Reviewed-by: Sohil Mehta --- Changes in v6: *) Replace a "sub $128, %rsp" with "add $-128, %rsp" (hpa). *) Declared loop_count_on_same_ip inside sigtrap() (Sohil). *) s/sigtrap/SIGTRAP (Sohil). Changes in v5: *) Do "sub $-128, %rsp" rather than "add $128, %rsp", which is more efficient in code size (hpa). *) Add TB from Sohil. *) Add Cc: stable@vger.kernel.org. Changes in v4: *) merge this selftest with its bug fix patch set (Dave Hansen). *) Address review comments from Sohil. --- tools/testing/selftests/x86/Makefile | 2 +- tools/testing/selftests/x86/sigtrap_loop.c | 101 +++++++++++++++++++++ 2 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/x86/sigtrap_loop.c diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests= /x86/Makefile index f703fcfe9f7c..83148875a12c 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile @@ -12,7 +12,7 @@ CAN_BUILD_WITH_NOPIE :=3D $(shell ./check_cc.sh "$(CC)" t= rivial_program.c -no-pie) =20 TARGETS_C_BOTHBITS :=3D single_step_syscall sysret_ss_attrs syscall_nt tes= t_mremap_vdso \ check_initial_reg_state sigreturn iopl ioperm \ - test_vsyscall mov_ss_trap \ + test_vsyscall mov_ss_trap sigtrap_loop \ syscall_arg_fault fsgsbase_restore sigaltstack TARGETS_C_BOTHBITS +=3D nx_stack TARGETS_C_32BIT_ONLY :=3D entry_from_vm86 test_syscall_vdso unwind_vdso \ diff --git a/tools/testing/selftests/x86/sigtrap_loop.c b/tools/testing/sel= ftests/x86/sigtrap_loop.c new file mode 100644 index 000000000000..9d065479e89f --- /dev/null +++ b/tools/testing/selftests/x86/sigtrap_loop.c @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2025 Intel Corporation + */ +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include + +#ifdef __x86_64__ +# define REG_IP REG_RIP +#else +# define REG_IP REG_EIP +#endif + +static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),= int flags) +{ + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction =3D handler; + sa.sa_flags =3D SA_SIGINFO | flags; + sigemptyset(&sa.sa_mask); + + if (sigaction(sig, &sa, 0)) + err(1, "sigaction"); + + return; +} + +static void sigtrap(int sig, siginfo_t *info, void *ctx_void) +{ + ucontext_t *ctx =3D (ucontext_t *)ctx_void; + static unsigned int loop_count_on_same_ip; + static unsigned long last_trap_ip; + + if (last_trap_ip =3D=3D ctx->uc_mcontext.gregs[REG_IP]) { + printf("\tTrapped at %016lx\n", last_trap_ip); + + /* + * If the same IP is hit more than 10 times in a row, it is + * _considered_ an infinite loop. + */ + if (++loop_count_on_same_ip > 10) { + printf("[FAIL]\tDetected SIGTRAP infinite loop\n"); + exit(1); + } + + return; + } + + loop_count_on_same_ip =3D 0; + last_trap_ip =3D ctx->uc_mcontext.gregs[REG_IP]; + printf("\tTrapped at %016lx\n", last_trap_ip); +} + +int main(int argc, char *argv[]) +{ + sethandler(SIGTRAP, sigtrap, 0); + + /* + * Set the Trap Flag (TF) to single-step the test code, therefore to + * trigger a SIGTRAP signal after each instruction until the TF is + * cleared. + * + * Because the arithmetic flags are not significant here, the TF is + * set by pushing 0x302 onto the stack and then popping it into the + * flags register. + * + * Four instructions in the following asm code are executed with the + * TF set, thus the SIGTRAP handler is expected to run four times. + */ + printf("[RUN]\tSIGTRAP infinite loop detection\n"); + asm volatile( +#ifdef __x86_64__ + /* + * Avoid clobbering the redzone + * + * Equivalent to "sub $128, %rsp", however -128 can be encoded + * in a single byte immediate while 128 uses 4 bytes. + */ + "add $-128, %rsp\n\t" +#endif + "push $0x302\n\t" + "popf\n\t" + "nop\n\t" + "nop\n\t" + "push $0x202\n\t" + "popf\n\t" +#ifdef __x86_64__ + "sub $-128, %rsp\n\t" +#endif + ); + + printf("[OK]\tNo SIGTRAP infinite loop detected\n"); + return 0; +} --=20 2.49.0