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

Hou Wenlong posted 1 patch 4 weeks, 1 day ago
arch/x86/include/asm/bug.h | 1 +
arch/x86/kernel/traps.c    | 2 +-
arch/x86/mm/extable.c      | 7 ++-----
3 files changed, 4 insertions(+), 6 deletions(-)
[PATCH] x86_64/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/bug.h | 1 +
 arch/x86/kernel/traps.c    | 2 +-
 arch/x86/mm/extable.c      | 7 ++-----
 3 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h
index 9b4e04690e1a..23e4b235461d 100644
--- a/arch/x86/include/asm/bug.h
+++ b/arch/x86/include/asm/bug.h
@@ -153,6 +153,7 @@ struct arch_va_list {
 	struct sysv_va_list args;
 };
 extern void *__warn_args(struct arch_va_list *args, struct pt_regs *regs);
+extern noinstr bool handle_bug(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 
 #define __WARN_bug_entry(flags, format) ({				\
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.
 		 */
-- 
2.31.1
Re: [PATCH] x86_64/bug: Handle __WARN_printf() trap in early_fixup_exception()
Posted by kernel test robot 4 weeks, 1 day ago
Hi Hou,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v6.19-rc4 next-20260109]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Hou-Wenlong/x86_64-bug-Handle-__WARN_printf-trap-in-early_fixup_exception/20260109-204012
base:   linus/master
patch link:    https://lore.kernel.org/r/97dd5c5b5e92d48ffbc95fb1357dfbbbf0d12a1e.1767960698.git.houwenlong.hwl%40antgroup.com
patch subject: [PATCH] x86_64/bug: Handle __WARN_printf() trap in early_fixup_exception()
config: i386-allnoconfig-bpf (https://download.01.org/0day-ci/archive/20260110/202601100329.ndS6mKRm-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260110/202601100329.ndS6mKRm-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202601100329.ndS6mKRm-lkp@intel.com/

All errors (new ones prefixed by >>):

>> arch/x86/mm/extable.c:414:7: error: call to undeclared function 'handle_bug'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
     414 |                 if (handle_bug(regs))
         |                     ^
   1 error generated.


vim +/handle_bug +414 arch/x86/mm/extable.c

   376	
   377	/* Restricted version used during very early boot */
   378	void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
   379	{
   380		/* Ignore early NMIs. */
   381		if (trapnr == X86_TRAP_NMI)
   382			return;
   383	
   384		if (early_recursion_flag > 2)
   385			goto halt_loop;
   386	
   387		/*
   388		 * Old CPUs leave the high bits of CS on the stack
   389		 * undefined.  I'm not sure which CPUs do this, but at least
   390		 * the 486 DX works this way.
   391		 * Xen pv domains are not using the default __KERNEL_CS.
   392		 */
   393		if (!xen_pv_domain() && regs->cs != __KERNEL_CS)
   394			goto fail;
   395	
   396		/*
   397		 * The full exception fixup machinery is available as soon as
   398		 * the early IDT is loaded.  This means that it is the
   399		 * responsibility of extable users to either function correctly
   400		 * when handlers are invoked early or to simply avoid causing
   401		 * exceptions before they're ready to handle them.
   402		 *
   403		 * This is better than filtering which handlers can be used,
   404		 * because refusing to call a handler here is guaranteed to
   405		 * result in a hard-to-debug panic.
   406		 *
   407		 * Keep in mind that not all vectors actually get here.  Early
   408		 * page faults, for example, are special.
   409		 */
   410		if (fixup_exception(regs, trapnr, regs->orig_ax, 0))
   411			return;
   412	
   413		if (trapnr == X86_TRAP_UD) {
 > 414			if (handle_bug(regs))

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
[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, 5 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, 5 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, 5 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
> >