]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
a2109d8e95eeb812810d198d2fc4929c9e64f338
[thirdparty/kernel/stable-queue.git] /
1 From e34dbbc85d64af59176fe59fad7b4122f4330fe2 Mon Sep 17 00:00:00 2001
2 From: "Xin Li (Intel)" <xin@zytor.com>
3 Date: Mon, 9 Jun 2025 01:40:53 -0700
4 Subject: x86/fred/signal: Prevent immediate repeat of single step trap on return from SIGTRAP handler
5
6 From: Xin Li (Intel) <xin@zytor.com>
7
8 commit e34dbbc85d64af59176fe59fad7b4122f4330fe2 upstream.
9
10 Clear the software event flag in the augmented SS to prevent immediate
11 repeat of single step trap on return from SIGTRAP handler if the trap
12 flag (TF) is set without an external debugger attached.
13
14 Following is a typical single-stepping flow for a user process:
15
16 1) The user process is prepared for single-stepping by setting
17 RFLAGS.TF = 1.
18 2) When any instruction in user space completes, a #DB is triggered.
19 3) The kernel handles the #DB and returns to user space, invoking the
20 SIGTRAP handler with RFLAGS.TF = 0.
21 4) After the SIGTRAP handler finishes, the user process performs a
22 sigreturn syscall, restoring the original state, including
23 RFLAGS.TF = 1.
24 5) Goto step 2.
25
26 According to the FRED specification:
27
28 A) Bit 17 in the augmented SS is designated as the software event
29 flag, which is set to 1 for FRED event delivery of SYSCALL,
30 SYSENTER, or INT n.
31 B) If bit 17 of the augmented SS is 1 and ERETU would result in
32 RFLAGS.TF = 1, a single-step trap will be pending upon completion
33 of ERETU.
34
35 In step 4) above, the software event flag is set upon the sigreturn
36 syscall, and its corresponding ERETU would restore RFLAGS.TF = 1.
37 This combination causes a pending single-step trap upon completion of
38 ERETU. Therefore, another #DB is triggered before any user space
39 instruction is executed, which leads to an infinite loop in which the
40 SIGTRAP handler keeps being invoked on the same user space IP.
41
42 Fixes: 14619d912b65 ("x86/fred: FRED entry/exit and dispatch code")
43 Suggested-by: H. Peter Anvin (Intel) <hpa@zytor.com>
44 Signed-off-by: Xin Li (Intel) <xin@zytor.com>
45 Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
46 Tested-by: Sohil Mehta <sohil.mehta@intel.com>
47 Cc:stable@vger.kernel.org
48 Link: https://lore.kernel.org/all/20250609084054.2083189-2-xin%40zytor.com
49 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
50 ---
51 arch/x86/include/asm/sighandling.h | 22 ++++++++++++++++++++++
52 arch/x86/kernel/signal_32.c | 4 ++++
53 arch/x86/kernel/signal_64.c | 4 ++++
54 3 files changed, 30 insertions(+)
55
56 --- a/arch/x86/include/asm/sighandling.h
57 +++ b/arch/x86/include/asm/sighandling.h
58 @@ -24,4 +24,26 @@ int ia32_setup_rt_frame(struct ksignal *
59 int x64_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
60 int x32_setup_rt_frame(struct ksignal *ksig, struct pt_regs *regs);
61
62 +/*
63 + * To prevent immediate repeat of single step trap on return from SIGTRAP
64 + * handler if the trap flag (TF) is set without an external debugger attached,
65 + * clear the software event flag in the augmented SS, ensuring no single-step
66 + * trap is pending upon ERETU completion.
67 + *
68 + * Note, this function should be called in sigreturn() before the original
69 + * state is restored to make sure the TF is read from the entry frame.
70 + */
71 +static __always_inline void prevent_single_step_upon_eretu(struct pt_regs *regs)
72 +{
73 + /*
74 + * If the trap flag (TF) is set, i.e., the sigreturn() SYSCALL instruction
75 + * is being single-stepped, do not clear the software event flag in the
76 + * augmented SS, thus a debugger won't skip over the following instruction.
77 + */
78 +#ifdef CONFIG_X86_FRED
79 + if (!(regs->flags & X86_EFLAGS_TF))
80 + regs->fred_ss.swevent = 0;
81 +#endif
82 +}
83 +
84 #endif /* _ASM_X86_SIGHANDLING_H */
85 --- a/arch/x86/kernel/signal_32.c
86 +++ b/arch/x86/kernel/signal_32.c
87 @@ -152,6 +152,8 @@ SYSCALL32_DEFINE0(sigreturn)
88 struct sigframe_ia32 __user *frame = (struct sigframe_ia32 __user *)(regs->sp-8);
89 sigset_t set;
90
91 + prevent_single_step_upon_eretu(regs);
92 +
93 if (!access_ok(frame, sizeof(*frame)))
94 goto badframe;
95 if (__get_user(set.sig[0], &frame->sc.oldmask)
96 @@ -175,6 +177,8 @@ SYSCALL32_DEFINE0(rt_sigreturn)
97 struct rt_sigframe_ia32 __user *frame;
98 sigset_t set;
99
100 + prevent_single_step_upon_eretu(regs);
101 +
102 frame = (struct rt_sigframe_ia32 __user *)(regs->sp - 4);
103
104 if (!access_ok(frame, sizeof(*frame)))
105 --- a/arch/x86/kernel/signal_64.c
106 +++ b/arch/x86/kernel/signal_64.c
107 @@ -250,6 +250,8 @@ SYSCALL_DEFINE0(rt_sigreturn)
108 sigset_t set;
109 unsigned long uc_flags;
110
111 + prevent_single_step_upon_eretu(regs);
112 +
113 frame = (struct rt_sigframe __user *)(regs->sp - sizeof(long));
114 if (!access_ok(frame, sizeof(*frame)))
115 goto badframe;
116 @@ -366,6 +368,8 @@ COMPAT_SYSCALL_DEFINE0(x32_rt_sigreturn)
117 sigset_t set;
118 unsigned long uc_flags;
119
120 + prevent_single_step_upon_eretu(regs);
121 +
122 frame = (struct rt_sigframe_x32 __user *)(regs->sp - 8);
123
124 if (!access_ok(frame, sizeof(*frame)))