From patchwork Fri Jun 6 17:45:27 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Xin Li X-Patchwork-Id: 894601 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 B184928A1CA; Fri, 6 Jun 2025 17:46:06 +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=1749231971; cv=none; b=WZSd1hwkAt8az8xiCzWOdtQg63XPMgj+82IsHFuhYghy9dGfG131CbbxmGg2UmXHgjEVSHd7L8KpNh9djsQuDopHMYaN8GbOgSA5kxHuidDhcB5Wx3ZXYghIQ1dZl/ySYH0p08DmvWuPBMIiJEXX3KRe1ItRvdTcMcu/4YejPsg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749231971; c=relaxed/simple; bh=CczLoW2dlYcx5sPWpp7uNqve7lenu2UjeLRtcexDZbI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=qZlMTsH4urQkKRO/H7bLUBlMAoPImNCTvzGR7ptK1+8RN26vuO9zz/ehaFZKFXkzYKC45jX/1GxYnJhpIxrOUWAZm7/kvUnhrbd7nlZ8sQfzD/nJv4A7c/Egxj1ct4z8GRWy0RJxbtUkWB8RvpoMdStUWiPr2cFxucgdc/Z0Rx0= 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=w3p1A4Ju; 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="w3p1A4Ju" 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 556HjTFq1004770 (version=TLSv1.3 cipher=TLS_AES_256_GCM_SHA384 bits=256 verify=NO); Fri, 6 Jun 2025 10:45:34 -0700 DKIM-Filter: OpenDKIM Filter v2.11.0 mail.zytor.com 556HjTFq1004770 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=zytor.com; s=2025052101; t=1749231934; bh=VEJNnQ7PpoyqgGIxpsAno3Mvap5meMu5RIbn9OvGm2w=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=w3p1A4Jux/rDT62s2GKh6qUlI6qBFzatbw2Sacf3A/hC358YoG11kaybczMTlFn18 DL5NJDLNG7rchEmKQhmzCTnDuQrgY8EG3kGk+1wGniJ0EFKFgZvWLPKioCxOUoLVSG vO0qXKTvjMSwTuI1+872JoIqE/YypXy41WoXSTMBYSekitqucbNZIybfJ/NQQ+bw4Y 4ukFEVycTnY7SR8Ev2o7JuJRMyuGZyMUOnG9EQODvLBHWhLm5tLgm4Ftj+EpcnrT42 TkTK2dY0dh14aimAFTfHjJ6m2Qbwo2K8g//orUqDFWzSyDy90Iw/CmBls4Du8+jnMe a7vLfwHROpQrw== 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 v5 1/2] x86/fred/signal: Prevent immediate repeat of single step trap on return from SIGTRAP handler Date: Fri, 6 Jun 2025 10:45:27 -0700 Message-ID: <20250606174528.1004756-2-xin@zytor.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250606174528.1004756-1-xin@zytor.com> References: <20250606174528.1004756-1-xin@zytor.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 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 = 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 = 0. 4) After the SIGTRAP handler finishes, the user process performs a sigreturn syscall, restoring the original state, including RFLAGS.TF = 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 = 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 = 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) Signed-off-by: Xin Li (Intel) Cc: stable@vger.kernel.org --- 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/sighandling.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); +/* + * 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, + * clear the software event flag in the augmented SS, ensuring no single-step + * 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 instruction. + */ +#ifdef CONFIG_X86_FRED + if (!(regs->flags & X86_EFLAGS_TF)) + regs->fred_ss.swevent = 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 = (struct sigframe_ia32 __user *)(regs->sp-8); sigset_t set; + 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; + prevent_single_step_upon_eretu(regs); + frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4); 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; + prevent_single_step_upon_eretu(regs); + frame = (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; + prevent_single_step_upon_eretu(regs); + frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8); if (!access_ok(frame, sizeof(*frame)))