[PATCH v2] x86/bug: Handle __WARN_printf() trap in early_fixup_exception()

Hou Wenlong posted 1 patch 4 weeks, 1 day ago
arch/x86/include/asm/traps.h | 2 ++
arch/x86/kernel/traps.c      | 2 +-
arch/x86/mm/extable.c        | 7 ++-----
3 files changed, 5 insertions(+), 6 deletions(-)
[PATCH v2] x86/bug: Handle __WARN_printf() trap in early_fixup_exception()
Posted by Hou Wenlong 4 weeks, 1 day ago
The commit 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
implemented __WARN_printf(), which changed the mechanism to use UD1
instead of UD2. However, it only handles the trap in the runtime IDT
handler, while the early booting IDT handler lacks this handling. As a
result, the usage of WARN() before the runtime IDT setup can lead to
kernel crashes. Since KMSAN is enabled after the runtime IDT setup, it
is safe to use handle_bug() directly in early_fixup_exception() to
address this issue.

Fixes: 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
---
 arch/x86/include/asm/traps.h | 2 ++
 arch/x86/kernel/traps.c      | 2 +-
 arch/x86/mm/extable.c        | 7 ++-----
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
index 869b88061801..3f24cc472ce9 100644
--- a/arch/x86/include/asm/traps.h
+++ b/arch/x86/include/asm/traps.h
@@ -25,6 +25,8 @@ extern int ibt_selftest_noendbr(void);
 void handle_invalid_op(struct pt_regs *regs);
 #endif
 
+noinstr bool handle_bug(struct pt_regs *regs);
+
 static inline int get_si_code(unsigned long condition)
 {
 	if (condition & DR_STEP)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index bcf1dedc1d00..aca1eca5daff 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -397,7 +397,7 @@ static inline void handle_invalid_op(struct pt_regs *regs)
 		      ILL_ILLOPN, error_get_trap_addr(regs));
 }
 
-static noinstr bool handle_bug(struct pt_regs *regs)
+noinstr bool handle_bug(struct pt_regs *regs)
 {
 	unsigned long addr = regs->ip;
 	bool handled = false;
diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index 2fdc1f1f5adb..6b9ff1c6cafa 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -411,14 +411,11 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
 		return;
 
 	if (trapnr == X86_TRAP_UD) {
-		if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
-			/* Skip the ud2. */
-			regs->ip += LEN_UD2;
+		if (handle_bug(regs))
 			return;
-		}
 
 		/*
-		 * If this was a BUG and report_bug returns or if this
+		 * If this was a BUG and handle_bug returns or if this
 		 * was just a normal #UD, we want to continue onward and
 		 * crash.
 		 */

base-commit: b7dccac786071bba98b0d834c517fd44a22c50f9
-- 
2.31.1
Re: [PATCH v2] x86/bug: Handle __WARN_printf() trap in early_fixup_exception()
Posted by Peter Zijlstra 3 weeks, 6 days ago
On Sat, Jan 10, 2026 at 11:47:37AM +0800, Hou Wenlong wrote:
> The commit 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
> implemented __WARN_printf(), which changed the mechanism to use UD1
> instead of UD2. However, it only handles the trap in the runtime IDT
> handler, while the early booting IDT handler lacks this handling. As a
> result, the usage of WARN() before the runtime IDT setup can lead to
> kernel crashes. 

Urgh, indeed. Clearly I don't see many early WARNs :/

> Since KMSAN is enabled after the runtime IDT setup, it
> is safe to use handle_bug() directly in early_fixup_exception() to
> address this issue.

I'm not sure I understand this. Should it not be that KMSAN is enabled
*before* early IDT to make this a non-issue?

> Fixes: 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
> Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> ---
>  arch/x86/include/asm/traps.h | 2 ++
>  arch/x86/kernel/traps.c      | 2 +-
>  arch/x86/mm/extable.c        | 7 ++-----
>  3 files changed, 5 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
> index 869b88061801..3f24cc472ce9 100644
> --- a/arch/x86/include/asm/traps.h
> +++ b/arch/x86/include/asm/traps.h
> @@ -25,6 +25,8 @@ extern int ibt_selftest_noendbr(void);
>  void handle_invalid_op(struct pt_regs *regs);
>  #endif
>  
> +noinstr bool handle_bug(struct pt_regs *regs);
> +
>  static inline int get_si_code(unsigned long condition)
>  {
>  	if (condition & DR_STEP)
> diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
> index bcf1dedc1d00..aca1eca5daff 100644
> --- a/arch/x86/kernel/traps.c
> +++ b/arch/x86/kernel/traps.c
> @@ -397,7 +397,7 @@ static inline void handle_invalid_op(struct pt_regs *regs)
>  		      ILL_ILLOPN, error_get_trap_addr(regs));
>  }
>  
> -static noinstr bool handle_bug(struct pt_regs *regs)
> +noinstr bool handle_bug(struct pt_regs *regs)
>  {
>  	unsigned long addr = regs->ip;
>  	bool handled = false;
> diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> index 2fdc1f1f5adb..6b9ff1c6cafa 100644
> --- a/arch/x86/mm/extable.c
> +++ b/arch/x86/mm/extable.c
> @@ -411,14 +411,11 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
>  		return;
>  
>  	if (trapnr == X86_TRAP_UD) {
> -		if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
> -			/* Skip the ud2. */
> -			regs->ip += LEN_UD2;
> +		if (handle_bug(regs))
>  			return;
> -		}
>  
>  		/*
> -		 * If this was a BUG and report_bug returns or if this
> +		 * If this was a BUG and handle_bug returns or if this
>  		 * was just a normal #UD, we want to continue onward and
>  		 * crash.
>  		 */
> 
> base-commit: b7dccac786071bba98b0d834c517fd44a22c50f9
> -- 
> 2.31.1
>
Re: [PATCH v2] x86/bug: Handle __WARN_printf() trap in early_fixup_exception()
Posted by Hou Wenlong 2 weeks, 6 days ago
On Mon, Jan 12, 2026 at 08:44:28AM +0100, Peter Zijlstra wrote:
> On Sat, Jan 10, 2026 at 11:47:37AM +0800, Hou Wenlong wrote:
> > The commit 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
> > implemented __WARN_printf(), which changed the mechanism to use UD1
> > instead of UD2. However, it only handles the trap in the runtime IDT
> > handler, while the early booting IDT handler lacks this handling. As a
> > result, the usage of WARN() before the runtime IDT setup can lead to
> > kernel crashes. 
> 
> Urgh, indeed. Clearly I don't see many early WARNs :/
> 
> > Since KMSAN is enabled after the runtime IDT setup, it
> > is safe to use handle_bug() directly in early_fixup_exception() to
> > address this issue.
> 
> I'm not sure I understand this. Should it not be that KMSAN is enabled
> *before* early IDT to make this a non-issue?
> 
> > Fixes: 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
> > Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> > ---
> >  arch/x86/include/asm/traps.h | 2 ++
> >  arch/x86/kernel/traps.c      | 2 +-
> >  arch/x86/mm/extable.c        | 7 ++-----
> >  3 files changed, 5 insertions(+), 6 deletions(-)
> > 
> > diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
> > index 869b88061801..3f24cc472ce9 100644
> > --- a/arch/x86/include/asm/traps.h
> > +++ b/arch/x86/include/asm/traps.h
> > @@ -25,6 +25,8 @@ extern int ibt_selftest_noendbr(void);
> >  void handle_invalid_op(struct pt_regs *regs);
> >  #endif
> >  
> > +noinstr bool handle_bug(struct pt_regs *regs);
> > +
> >  static inline int get_si_code(unsigned long condition)
> >  {
> >  	if (condition & DR_STEP)
> > diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
> > index bcf1dedc1d00..aca1eca5daff 100644
> > --- a/arch/x86/kernel/traps.c
> > +++ b/arch/x86/kernel/traps.c
> > @@ -397,7 +397,7 @@ static inline void handle_invalid_op(struct pt_regs *regs)
> >  		      ILL_ILLOPN, error_get_trap_addr(regs));
> >  }
> >  
> > -static noinstr bool handle_bug(struct pt_regs *regs)
> > +noinstr bool handle_bug(struct pt_regs *regs)
> >  {
> >  	unsigned long addr = regs->ip;
> >  	bool handled = false;
> > diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> > index 2fdc1f1f5adb..6b9ff1c6cafa 100644
> > --- a/arch/x86/mm/extable.c
> > +++ b/arch/x86/mm/extable.c
> > @@ -411,14 +411,11 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
> >  		return;
> >  
> >  	if (trapnr == X86_TRAP_UD) {
> > -		if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
> > -			/* Skip the ud2. */
> > -			regs->ip += LEN_UD2;
> > +		if (handle_bug(regs))
> >  			return;
> > -		}
> >  
> >  		/*
> > -		 * If this was a BUG and report_bug returns or if this
> > +		 * If this was a BUG and handle_bug returns or if this
> >  		 * was just a normal #UD, we want to continue onward and
> >  		 * crash.
> >  		 */
> > 
> > base-commit: b7dccac786071bba98b0d834c517fd44a22c50f9
> > -- 
> > 2.31.1
> > 
Hi, Peter.

I received a kernel test robot build failure message regarding this
patch, but I noticed that you queued the v1 version instead of the v2
version in your queue tree[0]. I ran the test config file with the v2
version, and it should be fine.

[0]: https://git.kernel.org/pub/scm/linux/kernel/git/peterz/queue.git/commit/?h=x86/urgent&id=695d896472d6543523de43110b0016b8b4469643

Thanks!
Re: [PATCH v2] x86/bug: Handle __WARN_printf() trap in early_fixup_exception()
Posted by Hou Wenlong 3 weeks, 6 days ago
On Mon, Jan 12, 2026 at 08:44:28AM +0100, Peter Zijlstra wrote:
> On Sat, Jan 10, 2026 at 11:47:37AM +0800, Hou Wenlong wrote:
> > The commit 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
> > implemented __WARN_printf(), which changed the mechanism to use UD1
> > instead of UD2. However, it only handles the trap in the runtime IDT
> > handler, while the early booting IDT handler lacks this handling. As a
> > result, the usage of WARN() before the runtime IDT setup can lead to
> > kernel crashes. 
> 
> Urgh, indeed. Clearly I don't see many early WARNs :/
>
Uh, I found this accidentally while I was trying to clean up the
early_ioremap debug printing, where it uses WARN() for dumpstack.

> > Since KMSAN is enabled after the runtime IDT setup, it
> > is safe to use handle_bug() directly in early_fixup_exception() to
> > address this issue.
> 
> I'm not sure I understand this. Should it not be that KMSAN is enabled
> *before* early IDT to make this a non-issue?
>
I see that handle_bug() would call kmsan_unpoison_entry_regs(), and I
assume that it should be a NOP before kmsan_init_runtime(). Therefore, I
think it's safe to use handle_bug() directly in early_fixup_exception().
Additionally, I note that kmsan_init_runtime() is called after
trap_init(), which is why I described the commit message this way.

Thanks!

> > Fixes: 5b472b6e5bd9 ("x86_64/bug: Implement __WARN_printf()")
> > Signed-off-by: Hou Wenlong <houwenlong.hwl@antgroup.com>
> > ---
> >  arch/x86/include/asm/traps.h | 2 ++
> >  arch/x86/kernel/traps.c      | 2 +-
> >  arch/x86/mm/extable.c        | 7 ++-----
> >  3 files changed, 5 insertions(+), 6 deletions(-)
> > 
> > diff --git a/arch/x86/include/asm/traps.h b/arch/x86/include/asm/traps.h
> > index 869b88061801..3f24cc472ce9 100644
> > --- a/arch/x86/include/asm/traps.h
> > +++ b/arch/x86/include/asm/traps.h
> > @@ -25,6 +25,8 @@ extern int ibt_selftest_noendbr(void);
> >  void handle_invalid_op(struct pt_regs *regs);
> >  #endif
> >  
> > +noinstr bool handle_bug(struct pt_regs *regs);
> > +
> >  static inline int get_si_code(unsigned long condition)
> >  {
> >  	if (condition & DR_STEP)
> > diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
> > index bcf1dedc1d00..aca1eca5daff 100644
> > --- a/arch/x86/kernel/traps.c
> > +++ b/arch/x86/kernel/traps.c
> > @@ -397,7 +397,7 @@ static inline void handle_invalid_op(struct pt_regs *regs)
> >  		      ILL_ILLOPN, error_get_trap_addr(regs));
> >  }
> >  
> > -static noinstr bool handle_bug(struct pt_regs *regs)
> > +noinstr bool handle_bug(struct pt_regs *regs)
> >  {
> >  	unsigned long addr = regs->ip;
> >  	bool handled = false;
> > diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> > index 2fdc1f1f5adb..6b9ff1c6cafa 100644
> > --- a/arch/x86/mm/extable.c
> > +++ b/arch/x86/mm/extable.c
> > @@ -411,14 +411,11 @@ void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
> >  		return;
> >  
> >  	if (trapnr == X86_TRAP_UD) {
> > -		if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
> > -			/* Skip the ud2. */
> > -			regs->ip += LEN_UD2;
> > +		if (handle_bug(regs))
> >  			return;
> > -		}
> >  
> >  		/*
> > -		 * If this was a BUG and report_bug returns or if this
> > +		 * If this was a BUG and handle_bug returns or if this
> >  		 * was just a normal #UD, we want to continue onward and
> >  		 * crash.
> >  		 */
> > 
> > base-commit: b7dccac786071bba98b0d834c517fd44a22c50f9
> > -- 
> > 2.31.1
> >