mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
       [not found] <CANd6bgL=v+uReoQznRGKunZQApwV5ESHAQn2_MOt-J-=cPkm9g@mail.gmail.com>
@ 2026-08-11 11:50 ` Jürgen Groß
  2026-08-12  9:22   ` 李则良
  0 siblings, 1 reply; 12+ messages in thread
From: Jürgen Groß @ 2026-08-11 11:50 UTC (permalink / raw)
  To: 李则良,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86
  Cc: H. Peter Anvin, Peter Zijlstra, Kees Cook, Nathan Chancellor,
	Josh Poimboeuf, linux-kernel


[-- Attachment #1.1.1: Type: text/plain, Size: 2462 bytes --]

On 11.08.26 13:41, 李则良 wrote:
>  From cd58bd112a6178593c6bc9c0f9b307d6897ae3d0 Mon Sep 17 00:00:00 2001
> From: Zeliang Li <lizeliang.linux@gmail.com <mailto:lizeliang.linux@gmail.com>>
> Date: Tue, 11 Aug 2026 19:09:09 +0800
> Subject: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call
>   instructions
> 
> When the kernel is compiled at a non-default optimization level
> (e.g., KCFLAGS=-O1), the compiler may emit call instruction
> patterns that differ from the expected 6-byte sequence
> (opcodes 0xff 0x15 followed by a 32-bit displacement) checked
> by alt_replace_call().
> 
> Currently this triggers a BUG() in apply_alternatives(), causing
> an immediate kernel panic during early boot:
> 
>    kernel BUG at arch/x86/kernel/alternative.c:558!
> 
> Instead of crashing, print a warning (once per boot) and preserve
> the original call instruction verbatim. The call will execute as
> compiled, without any alternatives patching applied. This is a
> graceful degradation: the indirect call remains indirect, which is
> functionally correct albeit slower than the direct-call patching
> that was skipped.
> 
> No change to normal -O2 builds, where call instructions continue
> to match the expected pattern.
> 
> Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com 
> <mailto:lizeliang.linux@gmail.com>>

Please don't send patches as HTML mails!

> ---
>   arch/x86/kernel/alternative.c | 11 +++++++++--
>   1 file changed, 9 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> index 62936a3bde19..0e3903e76b55 100644
> --- a/arch/x86/kernel/alternative.c
> +++ b/arch/x86/kernel/alternative.c
> @@ -554,8 +554,15 @@ static unsigned int alt_replace_call(u8 *instr, u8 
> *insn_buff, struct alt_instr
>    if (a->instrlen != 6 ||
>       instr[0] != CALL_RIP_REL_OPCODE ||
>       instr[1] != CALL_RIP_REL_MODRM) {
> - pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
> - BUG();
> + static bool warned;
> +
> + if (!warned) {
> + warned = true;
> + pr_warn("%s: skipping unrecognized indirect call (instrlen=%d)\n",
> + __func__, a->instrlen);
> + }

You are open coding pr_warn_once() here.

> + memcpy(insn_buff, instr, a->instrlen);
> + return a->instrlen;

And now you are letting an indirect call survive which is not subject to
any cpu bug mitigations.


Juergen


[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-11 11:50 ` [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions Jürgen Groß
@ 2026-08-12  9:22   ` 李则良
  2026-08-12 11:00     ` Peter Zijlstra
  0 siblings, 1 reply; 12+ messages in thread
From: 李则良 @ 2026-08-12  9:22 UTC (permalink / raw)
  To: Jürgen Groß
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Peter Zijlstra, Kees Cook, Nathan Chancellor,
	Josh Poimboeuf, linux-kernel

From cd58bd112a6178593c6bc9c0f9b307d6897ae3d0 Mon Sep 17 00:00:00 2001
From: Zeliang Li <lizeliang.linux@gmail.com>
Date: Tue, 11 Aug 2026 19:09:09 +0800
Subject: [PATCH v2] x86/alternative: WARN and skip unrecognized indirect call
 only for non-O2 builds

When the kernel is compiled at a non-default optimization level
(e.g., KCFLAGS=-O1 or -O0), the compiler may emit call instruction
patterns that differ from the expected 6-byte sequence
(opcodes 0xff 0x15 followed by a 32-bit displacement) checked
by alt_replace_call().

Currently this triggers a BUG() in apply_alternatives(), causing
an immediate kernel panic during early boot.

For official -O2 builds, the BUG() is appropriate and should be
retained, as the kernel only guarantees correct operation at this
optimization level[reference:0].

For non-standard optimization levels used for debugging purposes,
crashing the kernel is too severe. Instead, issue a WARN_ONCE()
and skip patching for this particular site, preserving the original
indirect call.

This approach balances safety for production builds with usability
for developers using non-standard optimization levels.

Signed-off-by: Zeliang Li <zeliang.li@linux@gmail.com>
---
 arch/x86/kernel/alternative.c | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
index 62936a3bde19..b8c9d0e1f2a3 100644
--- a/arch/x86/kernel/alternative.c
+++ b/arch/x86/kernel/alternative.c
@@ -554,8 +554,21 @@ static unsigned int alt_replace_call(u8 *instr,
u8 *insn_buff, struct alt_instr
  if (a->instrlen != 6 ||
     instr[0] != CALL_RIP_REL_OPCODE ||
     instr[1] != CALL_RIP_REL_MODRM) {
- pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
- BUG();
+ /*
+ * Unrecognized indirect call pattern. For -O2 builds this is a
+ * fatal error - the kernel only guarantees correct operation at
+ * this optimization level. For non-O2 builds (debugging), skip
+ * patching to avoid a boot-time crash.
+ */
+#ifdef __OPTIMIZE__
+#if __OPTIMIZE__ == 2
+ BUG();
+#endif
+#endif
+ WARN_ONCE(1,
+  "ALT_FLAG_DIRECT_CALL: unrecognized indirect call at %pS (instrlen=%d)\n",
+  instr, a->instrlen);
+ memcpy(insn_buff, instr, a->instrlen);
+ return a->instrlen;
  }

Jürgen Groß <jgross@suse.com> 于2026年8月11日周二 19:50写道:
>
> On 11.08.26 13:41, 李则良 wrote:
> >  From cd58bd112a6178593c6bc9c0f9b307d6897ae3d0 Mon Sep 17 00:00:00 2001
> > From: Zeliang Li <lizeliang.linux@gmail.com <mailto:lizeliang.linux@gmail.com>>
> > Date: Tue, 11 Aug 2026 19:09:09 +0800
> > Subject: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call
> >   instructions
> >
> > When the kernel is compiled at a non-default optimization level
> > (e.g., KCFLAGS=-O1), the compiler may emit call instruction
> > patterns that differ from the expected 6-byte sequence
> > (opcodes 0xff 0x15 followed by a 32-bit displacement) checked
> > by alt_replace_call().
> >
> > Currently this triggers a BUG() in apply_alternatives(), causing
> > an immediate kernel panic during early boot:
> >
> >    kernel BUG at arch/x86/kernel/alternative.c:558!
> >
> > Instead of crashing, print a warning (once per boot) and preserve
> > the original call instruction verbatim. The call will execute as
> > compiled, without any alternatives patching applied. This is a
> > graceful degradation: the indirect call remains indirect, which is
> > functionally correct albeit slower than the direct-call patching
> > that was skipped.
> >
> > No change to normal -O2 builds, where call instructions continue
> > to match the expected pattern.
> >
> > Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com
> > <mailto:lizeliang.linux@gmail.com>>
>
> Please don't send patches as HTML mails!

My apologies.  I have now configured my Gmail to send plain text by default.
Thank you for pointing this out.
>
> > ---
> >   arch/x86/kernel/alternative.c | 11 +++++++++--
> >   1 file changed, 9 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c
> > index 62936a3bde19..0e3903e76b55 100644
> > --- a/arch/x86/kernel/alternative.c
> > +++ b/arch/x86/kernel/alternative.c
> > @@ -554,8 +554,15 @@ static unsigned int alt_replace_call(u8 *instr, u8
> > *insn_buff, struct alt_instr
> >    if (a->instrlen != 6 ||
> >       instr[0] != CALL_RIP_REL_OPCODE ||
> >       instr[1] != CALL_RIP_REL_MODRM) {
> > - pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
> > - BUG();
> > + static bool warned;
> > +
> > + if (!warned) {
> > + warned = true;
> > + pr_warn("%s: skipping unrecognized indirect call (instrlen=%d)\n",
> > + __func__, a->instrlen);
> > + }
>
> You are open coding pr_warn_once() here.
>
> > + memcpy(insn_buff, instr, a->instrlen);
> > + return a->instrlen;
>
> And now you are letting an indirect call survive which is not subject to
> any cpu bug mitigations.

You are absolutely right – this was a serious oversight in my original
patch. Simply preserving the indirect call would bypass retpoline and
other CPU mitigations, which is unacceptable for production kernels.

To address this, I have revised the patch to distinguish between
optimization levels:

- For -O2 builds (the officially supported configuration), the existing
  BUG() is retained, as the kernel only guarantees correct operation at
  this level.

- For non-standard -O1/-O0 builds (typically used for debugging), we
  issue a WARN_ONCE() and skip patching. This avoids a boot-time crash
  for developers, while keeping the production (-O2) path fully secure.

This way, the security impact is limited to non-standard builds, which
are outside the official support scope and are already considered
"developer‑only".

>
>
> Juergen
>


-- 
KISS == Keep it simple,stupid~:-)
http://lizeliang.org

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12  9:22   ` 李则良
@ 2026-08-12 11:00     ` Peter Zijlstra
  2026-08-12 11:24       ` H. Peter Anvin
  2026-08-12 17:14       ` 李则良
  0 siblings, 2 replies; 12+ messages in thread
From: Peter Zijlstra @ 2026-08-12 11:00 UTC (permalink / raw)
  To: 李则良
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Kees Cook, Nathan Chancellor, Josh Poimboeuf,
	linux-kernel

On Wed, Aug 12, 2026 at 05:22:14PM +0800, 李则良 wrote:
> From cd58bd112a6178593c6bc9c0f9b307d6897ae3d0 Mon Sep 17 00:00:00 2001
> From: Zeliang Li <lizeliang.linux@gmail.com>
> Date: Tue, 11 Aug 2026 19:09:09 +0800
> Subject: [PATCH v2] x86/alternative: WARN and skip unrecognized indirect call
>  only for non-O2 builds
> 
> When the kernel is compiled at a non-default optimization level
> (e.g., KCFLAGS=-O1 or -O0), the compiler may emit call instruction
> patterns that differ from the expected 6-byte sequence
> (opcodes 0xff 0x15 followed by a 32-bit displacement) checked
> by alt_replace_call().

I don't think we want to cater for this. But what actual instruction
sequences is it emitting?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12 11:00     ` Peter Zijlstra
@ 2026-08-12 11:24       ` H. Peter Anvin
  2026-08-12 15:30         ` Borislav Petkov
  2026-08-12 17:14       ` 李则良
  1 sibling, 1 reply; 12+ messages in thread
From: H. Peter Anvin @ 2026-08-12 11:24 UTC (permalink / raw)
  To: Peter Zijlstra, 李则良
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Kees Cook, Nathan Chancellor, Josh Poimboeuf, linux-kernel

On August 12, 2026 4:00:23 AM PDT, Peter Zijlstra <peterz@infradead.org> wrote:
>On Wed, Aug 12, 2026 at 05:22:14PM +0800, 李则良 wrote:
>> From cd58bd112a6178593c6bc9c0f9b307d6897ae3d0 Mon Sep 17 00:00:00 2001
>> From: Zeliang Li <lizeliang.linux@gmail.com>
>> Date: Tue, 11 Aug 2026 19:09:09 +0800
>> Subject: [PATCH v2] x86/alternative: WARN and skip unrecognized indirect call
>>  only for non-O2 builds
>> 
>> When the kernel is compiled at a non-default optimization level
>> (e.g., KCFLAGS=-O1 or -O0), the compiler may emit call instruction
>> patterns that differ from the expected 6-byte sequence
>> (opcodes 0xff 0x15 followed by a 32-bit displacement) checked
>> by alt_replace_call().
>
>I don't think we want to cater for this. But what actual instruction
>sequences is it emitting?

I'm kind of surprised the kernel compiles with -O0 at all; it certainly didn't used to. -Og was created for a reason. 

That being said, if it helps someone debug a problem as long as the kernel also screams "bloody murder don't use me in production" it might be useful. 

Honestly, thinking about it, an "unsafe_debug=..." or similar kernel command line option might be justified for things like this; by requiring an active user step to enable the unsafe behavior it should make it much harder for something to sneak into production.

   -hpa


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12 11:24       ` H. Peter Anvin
@ 2026-08-12 15:30         ` Borislav Petkov
  0 siblings, 0 replies; 12+ messages in thread
From: Borislav Petkov @ 2026-08-12 15:30 UTC (permalink / raw)
  To: H. Peter Anvin
  Cc: Peter Zijlstra, 李则良, Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Dave Hansen, x86, Kees Cook,
	Nathan Chancellor, Josh Poimboeuf, linux-kernel

On Wed, Aug 12, 2026 at 04:24:37AM -0700, H. Peter Anvin wrote:
> >I don't think we want to cater for this. But what actual instruction
> >sequences is it emitting?
> 
> I'm kind of surprised the kernel compiles with -O0 at all; it certainly didn't used to. -Og was created for a reason. 

I'm with PeterZ on this. If you hack the tree to modify KCFLAGS, then you get
to keep the pieces too.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12 11:00     ` Peter Zijlstra
  2026-08-12 11:24       ` H. Peter Anvin
@ 2026-08-12 17:14       ` 李则良
  2026-08-12 19:01         ` H. Peter Anvin
                           ` (2 more replies)
  1 sibling, 3 replies; 12+ messages in thread
From: 李则良 @ 2026-08-12 17:14 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Kees Cook, Nathan Chancellor, Josh Poimboeuf,
	linux-kernel

>
> I don't think we want to cater for this. But what actual instruction
> sequences is it emitting?

This is the scene that triggers the bug, which can be perfectly
reproduced when KCFLAGS=-O1.

[    0.111827] SMP alternatives: ALT_FLAG_DIRECT_CALL set for
unrecognized indirect call
[    0.112083] ------------[ cut here ]------------
[    0.112417] kernel BUG at arch/x86/kernel/alternative.c:558!
[    0.113080] Oops: invalid opcode: 0000 [#1] SMP NOPTI
[    0.113424] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted
7.2.0-rc7-00016-g3d6d817622b0-dirty #2 PREEMPT(lazy)
[    0.114077] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009),
BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
[    0.114077] RIP: 0010:apply_alternatives+0x3a6/0x540
[    0.114077] Code: 8d 04 80 89 95 d1 fe ff ff e9 dd fe ff ff 48 c7
c7 f8 88 9d 82 e8 ea 94 0d 00 90 0f 0b 48 c7 c7 50 89 9d 82 e8 db 94
0d 00 90 <0f> 0b 80 7d ce 00 75 0d 41 80 7e 0d 00 0f 84 14 ff ff ff eb
62 48
[    0.114077] RSP: 0000:ffffffff82c03d60 EFLAGS: 00010246
[    0.114077] RAX: 0000000000000049 RBX: ffffffff831dae1c RCX: 0000000000000003
[    0.114077] RDX: 0000000000000000 RSI: ffffffff82d3cd08 RDI: 0000000000000001
[    0.114077] RBP: ffffffff82c03ea8 R08: 0000000000000000 R09: 205d373238313131
[    0.114077] R10: 7265746c6120504d R11: 65746c6120504d53 R12: ffffffff831e116c
[    0.114077] R13: ffffffff82ee2880 R14: ffffffff831dae0e R15: ffffffff831e1f58
[    0.114077] FS:  0000000000000000(0000) GS:ffff8882f4a18000(0000)
knlGS:0000000000000000
[    0.114077] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.114077] CR2: ffff88827ffff000 CR3: 0000000002c30001 CR4: 0000000000770ef0
[    0.114077] PKRU: 55555554
[    0.114077] Call Trace:
[    0.114077]  <TASK>
[    0.114077]  ? insn_get_sib+0x21/0x80
[    0.114077]  ? early_fixup_exception+0x85/0xa0
[    0.114077]  alternative_instructions+0x76/0x110
[    0.114077]  arch_cpu_finalize_init+0x113/0x170
[    0.114077]  start_kernel+0x794/0x820
[    0.114077]  x86_64_start_reservations+0x28/0x30
[    0.114077]  x86_64_start_kernel+0xdc/0xe0
[    0.114077]  common_startup_64+0x13e/0x158
[    0.114077] RIP: 1f0f:0x2e66000000000084
[    0.114077] Code: Unable to access opcode bytes at 0x2e6600000000005a.
[    0.114077] RSP: 0000:00841f0f2e660000 EFLAGS: 841f0f2e66 ORIG_RAX:
1f0f2e6600000000
[    0.114077] RAX: 1f0f2e6600000000 RBX: 1f0f2e6600000000 RCX: 2e66000000000084
[    0.114077] RDX: 0000000000841f0f RSI: 000000841f0f2e66 RDI: 00841f0f2e660000
[    0.114077] RBP: 00841f0f2e660000 R08: 00841f0f2e660000 R09: 000000841f0f2e66
[    0.114077] R10: 0000000000841f0f R11: 2e66000000000084 R12: 000000841f0f2e66
[    0.114077] R13: 0000000000841f0f R14: 2e66000000000084 R15: 1f0f2e6600000000
[    0.114077]  </TASK>
[    0.114077] Modules linked in:
[    0.114078] ---[ end trace 0000000000000000 ]---
[    0.114405] RIP: 0010:apply_alternatives+0x3a6/0x540
[    0.115078] Code: 8d 04 80 89 95 d1 fe ff ff e9 dd fe ff ff 48 c7
c7 f8 88 9d 82 e8 ea 94 0d 00 90 0f 0b 48 c7 c7 50 89 9d 82 e8 db 94
0d 00 90 <0f> 0b 80 7d ce 00 75 0d 41 80 7e 0d 00 0f 84 14 ff ff ff eb
62 48
[    0.116078] RSP: 0000:ffffffff82c03d60 EFLAGS: 00010246
[    0.116456] RAX: 0000000000000049 RBX: ffffffff831dae1c RCX: 0000000000000003
[    0.117077] RDX: 0000000000000000 RSI: ffffffff82d3cd08 RDI: 0000000000000001
[    0.117589] RBP: ffffffff82c03ea8 R08: 0000000000000000 R09: 205d373238313131
[    0.118077] R10: 7265746c6120504d R11: 65746c6120504d53 R12: ffffffff831e116c
[    0.118585] R13: ffffffff82ee2880 R14: ffffffff831dae0e R15: ffffffff831e1f58
[    0.119077] FS:  0000000000000000(0000) GS:ffff8882f4a18000(0000)
knlGS:0000000000000000
[    0.119642] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[    0.120077] CR2: ffff88827ffff000 CR3: 0000000002c30001 CR4: 0000000000770ef0
[    0.120537] PKRU: 55555554
[    0.121078] Kernel panic - not syncing: Attempted to kill the idle task!
[    0.121545] ---[ end Kernel panic - not syncing: Attempted to kill
the idle task! ]---

-- 
KISS == Keep it simple,stupid~:-)
http://lizeliang.org

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12 17:14       ` 李则良
@ 2026-08-12 19:01         ` H. Peter Anvin
  2026-08-12 19:02         ` H. Peter Anvin
  2026-08-13  9:51         ` Peter Zijlstra
  2 siblings, 0 replies; 12+ messages in thread
From: H. Peter Anvin @ 2026-08-12 19:01 UTC (permalink / raw)
  To: 李则良, Peter Zijlstra
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Kees Cook, Nathan Chancellor, Josh Poimboeuf, linux-kernel

On August 12, 2026 10:14:41 AM PDT, "李则良" <lizeliang.linux@gmail.com> wrote:
>>
>> I don't think we want to cater for this. But what actual instruction
>> sequences is it emitting?
>
>This is the scene that triggers the bug, which can be perfectly
>reproduced when KCFLAGS=-O1.
>
>[    0.111827] SMP alternatives: ALT_FLAG_DIRECT_CALL set for
>unrecognized indirect call
>[    0.112083] ------------[ cut here ]------------
>[    0.112417] kernel BUG at arch/x86/kernel/alternative.c:558!
>[    0.113080] Oops: invalid opcode: 0000 [#1] SMP NOPTI
>[    0.113424] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted
>7.2.0-rc7-00016-g3d6d817622b0-dirty #2 PREEMPT(lazy)
>[    0.114077] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009),
>BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
>[    0.114077] RIP: 0010:apply_alternatives+0x3a6/0x540
>[    0.114077] Code: 8d 04 80 89 95 d1 fe ff ff e9 dd fe ff ff 48 c7
>c7 f8 88 9d 82 e8 ea 94 0d 00 90 0f 0b 48 c7 c7 50 89 9d 82 e8 db 94
>0d 00 90 <0f> 0b 80 7d ce 00 75 0d 41 80 7e 0d 00 0f 84 14 ff ff ff eb
>62 48
>[    0.114077] RSP: 0000:ffffffff82c03d60 EFLAGS: 00010246
>[    0.114077] RAX: 0000000000000049 RBX: ffffffff831dae1c RCX: 0000000000000003
>[    0.114077] RDX: 0000000000000000 RSI: ffffffff82d3cd08 RDI: 0000000000000001
>[    0.114077] RBP: ffffffff82c03ea8 R08: 0000000000000000 R09: 205d373238313131
>[    0.114077] R10: 7265746c6120504d R11: 65746c6120504d53 R12: ffffffff831e116c
>[    0.114077] R13: ffffffff82ee2880 R14: ffffffff831dae0e R15: ffffffff831e1f58
>[    0.114077] FS:  0000000000000000(0000) GS:ffff8882f4a18000(0000)
>knlGS:0000000000000000
>[    0.114077] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[    0.114077] CR2: ffff88827ffff000 CR3: 0000000002c30001 CR4: 0000000000770ef0
>[    0.114077] PKRU: 55555554
>[    0.114077] Call Trace:
>[    0.114077]  <TASK>
>[    0.114077]  ? insn_get_sib+0x21/0x80
>[    0.114077]  ? early_fixup_exception+0x85/0xa0
>[    0.114077]  alternative_instructions+0x76/0x110
>[    0.114077]  arch_cpu_finalize_init+0x113/0x170
>[    0.114077]  start_kernel+0x794/0x820
>[    0.114077]  x86_64_start_reservations+0x28/0x30
>[    0.114077]  x86_64_start_kernel+0xdc/0xe0
>[    0.114077]  common_startup_64+0x13e/0x158
>[    0.114077] RIP: 1f0f:0x2e66000000000084
>[    0.114077] Code: Unable to access opcode bytes at 0x2e6600000000005a.
>[    0.114077] RSP: 0000:00841f0f2e660000 EFLAGS: 841f0f2e66 ORIG_RAX:
>1f0f2e6600000000
>[    0.114077] RAX: 1f0f2e6600000000 RBX: 1f0f2e6600000000 RCX: 2e66000000000084
>[    0.114077] RDX: 0000000000841f0f RSI: 000000841f0f2e66 RDI: 00841f0f2e660000
>[    0.114077] RBP: 00841f0f2e660000 R08: 00841f0f2e660000 R09: 000000841f0f2e66
>[    0.114077] R10: 0000000000841f0f R11: 2e66000000000084 R12: 000000841f0f2e66
>[    0.114077] R13: 0000000000841f0f R14: 2e66000000000084 R15: 1f0f2e6600000000
>[    0.114077]  </TASK>
>[    0.114077] Modules linked in:
>[    0.114078] ---[ end trace 0000000000000000 ]---
>[    0.114405] RIP: 0010:apply_alternatives+0x3a6/0x540
>[    0.115078] Code: 8d 04 80 89 95 d1 fe ff ff e9 dd fe ff ff 48 c7
>c7 f8 88 9d 82 e8 ea 94 0d 00 90 0f 0b 48 c7 c7 50 89 9d 82 e8 db 94
>0d 00 90 <0f> 0b 80 7d ce 00 75 0d 41 80 7e 0d 00 0f 84 14 ff ff ff eb
>62 48
>[    0.116078] RSP: 0000:ffffffff82c03d60 EFLAGS: 00010246
>[    0.116456] RAX: 0000000000000049 RBX: ffffffff831dae1c RCX: 0000000000000003
>[    0.117077] RDX: 0000000000000000 RSI: ffffffff82d3cd08 RDI: 0000000000000001
>[    0.117589] RBP: ffffffff82c03ea8 R08: 0000000000000000 R09: 205d373238313131
>[    0.118077] R10: 7265746c6120504d R11: 65746c6120504d53 R12: ffffffff831e116c
>[    0.118585] R13: ffffffff82ee2880 R14: ffffffff831dae0e R15: ffffffff831e1f58
>[    0.119077] FS:  0000000000000000(0000) GS:ffff8882f4a18000(0000)
>knlGS:0000000000000000
>[    0.119642] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[    0.120077] CR2: ffff88827ffff000 CR3: 0000000002c30001 CR4: 0000000000770ef0
>[    0.120537] PKRU: 55555554
>[    0.121078] Kernel panic - not syncing: Attempted to kill the idle task!
>[    0.121545] ---[ end Kernel panic - not syncing: Attempted to kill
>the idle task! ]---
>

Well, what about -Og?

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12 17:14       ` 李则良
  2026-08-12 19:01         ` H. Peter Anvin
@ 2026-08-12 19:02         ` H. Peter Anvin
  2026-08-13  9:51         ` Peter Zijlstra
  2 siblings, 0 replies; 12+ messages in thread
From: H. Peter Anvin @ 2026-08-12 19:02 UTC (permalink / raw)
  To: 李则良, Peter Zijlstra
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	Kees Cook, Nathan Chancellor, Josh Poimboeuf, linux-kernel

On August 12, 2026 10:14:41 AM PDT, "李则良" <lizeliang.linux@gmail.com> wrote:
>>
>> I don't think we want to cater for this. But what actual instruction
>> sequences is it emitting?
>
>This is the scene that triggers the bug, which can be perfectly
>reproduced when KCFLAGS=-O1.
>
>[    0.111827] SMP alternatives: ALT_FLAG_DIRECT_CALL set for
>unrecognized indirect call
>[    0.112083] ------------[ cut here ]------------
>[    0.112417] kernel BUG at arch/x86/kernel/alternative.c:558!
>[    0.113080] Oops: invalid opcode: 0000 [#1] SMP NOPTI
>[    0.113424] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted
>7.2.0-rc7-00016-g3d6d817622b0-dirty #2 PREEMPT(lazy)
>[    0.114077] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009),
>BIOS 1.17.0-debian-1.17.0-1ubuntu1 04/01/2014
>[    0.114077] RIP: 0010:apply_alternatives+0x3a6/0x540
>[    0.114077] Code: 8d 04 80 89 95 d1 fe ff ff e9 dd fe ff ff 48 c7
>c7 f8 88 9d 82 e8 ea 94 0d 00 90 0f 0b 48 c7 c7 50 89 9d 82 e8 db 94
>0d 00 90 <0f> 0b 80 7d ce 00 75 0d 41 80 7e 0d 00 0f 84 14 ff ff ff eb
>62 48
>[    0.114077] RSP: 0000:ffffffff82c03d60 EFLAGS: 00010246
>[    0.114077] RAX: 0000000000000049 RBX: ffffffff831dae1c RCX: 0000000000000003
>[    0.114077] RDX: 0000000000000000 RSI: ffffffff82d3cd08 RDI: 0000000000000001
>[    0.114077] RBP: ffffffff82c03ea8 R08: 0000000000000000 R09: 205d373238313131
>[    0.114077] R10: 7265746c6120504d R11: 65746c6120504d53 R12: ffffffff831e116c
>[    0.114077] R13: ffffffff82ee2880 R14: ffffffff831dae0e R15: ffffffff831e1f58
>[    0.114077] FS:  0000000000000000(0000) GS:ffff8882f4a18000(0000)
>knlGS:0000000000000000
>[    0.114077] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[    0.114077] CR2: ffff88827ffff000 CR3: 0000000002c30001 CR4: 0000000000770ef0
>[    0.114077] PKRU: 55555554
>[    0.114077] Call Trace:
>[    0.114077]  <TASK>
>[    0.114077]  ? insn_get_sib+0x21/0x80
>[    0.114077]  ? early_fixup_exception+0x85/0xa0
>[    0.114077]  alternative_instructions+0x76/0x110
>[    0.114077]  arch_cpu_finalize_init+0x113/0x170
>[    0.114077]  start_kernel+0x794/0x820
>[    0.114077]  x86_64_start_reservations+0x28/0x30
>[    0.114077]  x86_64_start_kernel+0xdc/0xe0
>[    0.114077]  common_startup_64+0x13e/0x158
>[    0.114077] RIP: 1f0f:0x2e66000000000084
>[    0.114077] Code: Unable to access opcode bytes at 0x2e6600000000005a.
>[    0.114077] RSP: 0000:00841f0f2e660000 EFLAGS: 841f0f2e66 ORIG_RAX:
>1f0f2e6600000000
>[    0.114077] RAX: 1f0f2e6600000000 RBX: 1f0f2e6600000000 RCX: 2e66000000000084
>[    0.114077] RDX: 0000000000841f0f RSI: 000000841f0f2e66 RDI: 00841f0f2e660000
>[    0.114077] RBP: 00841f0f2e660000 R08: 00841f0f2e660000 R09: 000000841f0f2e66
>[    0.114077] R10: 0000000000841f0f R11: 2e66000000000084 R12: 000000841f0f2e66
>[    0.114077] R13: 0000000000841f0f R14: 2e66000000000084 R15: 1f0f2e6600000000
>[    0.114077]  </TASK>
>[    0.114077] Modules linked in:
>[    0.114078] ---[ end trace 0000000000000000 ]---
>[    0.114405] RIP: 0010:apply_alternatives+0x3a6/0x540
>[    0.115078] Code: 8d 04 80 89 95 d1 fe ff ff e9 dd fe ff ff 48 c7
>c7 f8 88 9d 82 e8 ea 94 0d 00 90 0f 0b 48 c7 c7 50 89 9d 82 e8 db 94
>0d 00 90 <0f> 0b 80 7d ce 00 75 0d 41 80 7e 0d 00 0f 84 14 ff ff ff eb
>62 48
>[    0.116078] RSP: 0000:ffffffff82c03d60 EFLAGS: 00010246
>[    0.116456] RAX: 0000000000000049 RBX: ffffffff831dae1c RCX: 0000000000000003
>[    0.117077] RDX: 0000000000000000 RSI: ffffffff82d3cd08 RDI: 0000000000000001
>[    0.117589] RBP: ffffffff82c03ea8 R08: 0000000000000000 R09: 205d373238313131
>[    0.118077] R10: 7265746c6120504d R11: 65746c6120504d53 R12: ffffffff831e116c
>[    0.118585] R13: ffffffff82ee2880 R14: ffffffff831dae0e R15: ffffffff831e1f58
>[    0.119077] FS:  0000000000000000(0000) GS:ffff8882f4a18000(0000)
>knlGS:0000000000000000
>[    0.119642] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
>[    0.120077] CR2: ffff88827ffff000 CR3: 0000000002c30001 CR4: 0000000000770ef0
>[    0.120537] PKRU: 55555554
>[    0.121078] Kernel panic - not syncing: Attempted to kill the idle task!
>[    0.121545] ---[ end Kernel panic - not syncing: Attempted to kill
>the idle task! ]---
>

That a UD2 opcode...

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-12 17:14       ` 李则良
  2026-08-12 19:01         ` H. Peter Anvin
  2026-08-12 19:02         ` H. Peter Anvin
@ 2026-08-13  9:51         ` Peter Zijlstra
  2026-08-13 19:35           ` 李则良
  2 siblings, 1 reply; 12+ messages in thread
From: Peter Zijlstra @ 2026-08-13  9:51 UTC (permalink / raw)
  To: 李则良
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Kees Cook, Nathan Chancellor, Josh Poimboeuf,
	linux-kernel

On Thu, Aug 13, 2026 at 01:14:41AM +0800, 李则良 wrote:
> >
> > I don't think we want to cater for this. But what actual instruction
> > sequences is it emitting?
> 
> This is the scene that triggers the bug, which can be perfectly
> reproduced when KCFLAGS=-O1.
> 

That's not what I asked, now was it. I asked what opcodes it does
generate. Disassemble an affected function and show the difference
between the normal -O2 and your -O1 build that causes the failure.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-13  9:51         ` Peter Zijlstra
@ 2026-08-13 19:35           ` 李则良
  2026-08-13 19:57             ` 李则良
  0 siblings, 1 reply; 12+ messages in thread
From: 李则良 @ 2026-08-13 19:35 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Kees Cook, Nathan Chancellor, Josh Poimboeuf,
	linux-kernel

[-- Attachment #1: Type: text/plain, Size: 3290 bytes --]

>
> That's not what I asked, now was it. I asked what opcodes it does
> generate. Disassemble an affected function and show the difference
> between the normal -O2 and your -O1 build that causes the failure.
on vmlinux-O1:
(gdb) until arch/x86/kernel/alternative.c:557
alt_replace_call (instr=0xffffffff82f447e5 <early_fixup_exception+133>
"\377S\b\220\220\353\371[A\\]\303\314\314\314\314\303\314\314\314\314f\017\037D",
insn_buff=0xffffffff82c03d78 <init_thread_union+15736>
"\350\263\177\020\377",
    a=0xffffffff831dae0e) at arch/x86/kernel/alternative.c:557
557 pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
vmlinux-O1:
  0xffffffff82f447e5 <+133>: ff 53 08           call   QWORD PTR [rbx+0x8]
   0xffffffff82f447e8 <+136>: 90                 nop
   0xffffffff82f447e9 <+137>: 90                 nop
   0xffffffff82f447ea <+138>: eb f9               jmp
0xffffffff82f447e5 <early_fixup_exception+133>
   0xffffffff82f447ec <+140>: 5b                 pop    rbx
   0xffffffff82f447ed <+141>: 41 5c               pop    r12

vmlinux-O2:
  0xffffffff82f3bf4b <+123>: 74 b0               je
0xffffffff82f3befd <early_fixup_exception+45>
   0xffffffff82f3bf4d <+125>: eb 08               jmp
0xffffffff82f3bf57 <early_fixup_exception+135>
   0xffffffff82f3bf4f <+127>: ff 15 33 32 d0 ff   call   QWORD PTR
[rip+0xffffffffffd03233]        # 0xffffffff82c3f188 <pv_ops+8>
   0xffffffff82f3bf55 <+133>: eb f8               jmp
0xffffffff82f3bf4f <early_fixup_exception+127>
   0xffffffff82f3bf57 <+135>: 5b                 pop    rbx
   0xffffffff82f3bf58 <+136>: 41 5c               pop    r12
   0xffffffff82f3bf5a <+138>: 5d                 pop    rbp

I use the patch below to bypass the problem while keeping all logic of
alt_replace_call intact.

From 2538684697e537298aa9082b582bc7dddd29b278 Mon Sep 17 00:00:00 2001
From: Zeliang Li <lizeliang.linux@gmail.com>
Date: Fri, 14 Aug 2026 02:32:19 +0800
Subject: [PATCH] x86/mm: force O2 optimization for early_fixup_exception

When the kernel is compiled with non-standard optimization flags
(e.g., KCFLAGS=-O1), the function early_fixup_exception may be
compiled to an indirect call instruction that is not recognized
by alt_replace_call() (e.g., "call *0x8(%rbx)"). This triggers a
BUG() during early boot, as seen in:

  ALT_FLAG_DIRECT_CALL: original instruction is not a 6-byte ...
  instruction at early_fixup_exception+0x85/0xa0, length=5
  instruction bytes: ff 53 08 90 90

Force this function to be compiled with -O2 optimization level,
which guarantees the standard 6-byte `ff 15 <disp32>` form used
by alternatives patching.

Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com>
---
 arch/x86/mm/extable.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
index ceb8d03191ab..5d5c7510a817 100644
--- a/arch/x86/mm/extable.c
+++ b/arch/x86/mm/extable.c
@@ -375,6 +375,7 @@ int fixup_exception(struct pt_regs *regs, int
trapnr, unsigned long error_code,
 extern unsigned int early_recursion_flag;

 /* Restricted version used during very early boot */
+__attribute__((optimize("O2")))
 void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
 {
  /* Ignore early NMIs. */
-- 
2.53.0

-- 
KISS == Keep it simple,stupid~:-)
http://lizeliang.org

[-- Attachment #2: O2-gdb --]
[-- Type: application/octet-stream, Size: 3595 bytes --]

(gdb) set disassembly-flavor intel
(gdb) disassemble /r early_fixup_exception
Dump of assembler code for function early_fixup_exception:
   0xffffffff82f3bed0 <+0>:	f3 0f 1e fa        	endbr64
   0xffffffff82f3bed4 <+4>:	83 fe 02           	cmp    esi,0x2
   0xffffffff82f3bed7 <+7>:	0f 84 83 00 00 00  	je     0xffffffff82f3bf60 <early_fixup_exception+144>
   0xffffffff82f3bedd <+13>:	55                 	push   rbp
   0xffffffff82f3bede <+14>:	48 89 e5           	mov    rbp,rsp
   0xffffffff82f3bee1 <+17>:	41 54              	push   r12
   0xffffffff82f3bee3 <+19>:	53                 	push   rbx
   0xffffffff82f3bee4 <+20>:	83 3d 15 61 0a 00 02	cmp    DWORD PTR [rip+0xa6115],0x2        # 0xffffffff82fe2000 <early_recursion_flag>
   0xffffffff82f3beeb <+27>:	77 62              	ja     0xffffffff82f3bf4f <early_fixup_exception+127>
   0xffffffff82f3beed <+29>:	41 89 f4           	mov    r12d,esi
   0xffffffff82f3bef0 <+32>:	48 89 fb           	mov    rbx,rdi
   0xffffffff82f3bef3 <+35>:	66 83 bf 88 00 00 00 10	cmp    WORD PTR [rdi+0x88],0x10
   0xffffffff82f3befb <+43>:	74 2f              	je     0xffffffff82f3bf2c <early_fixup_exception+92>
   0xffffffff82f3befd <+45>:	41 0f 20 d1        	mov    r9,cr2
   0xffffffff82f3bf01 <+49>:	48 8b 8b 80 00 00 00	mov    rcx,QWORD PTR [rbx+0x80]
   0xffffffff82f3bf08 <+56>:	4c 8b 43 78        	mov    r8,QWORD PTR [rbx+0x78]
   0xffffffff82f3bf0c <+60>:	44 89 e6           	mov    esi,r12d
   0xffffffff82f3bf0f <+63>:	48 c7 c7 2c 5a 83 82	mov    rdi,0xffffffff82835a2c
   0xffffffff82f3bf16 <+70>:	0f b7 93 88 00 00 00	movzx  edx,WORD PTR [rbx+0x88]
   0xffffffff82f3bf1d <+77>:	e8 ae fa 3c fe     	call   0xffffffff8130b9d0 <early_printk>
   0xffffffff82f3bf22 <+82>:	48 89 df           	mov    rdi,rbx
   0xffffffff82f3bf25 <+85>:	e8 86 c9 30 fe     	call   0xffffffff812488b0 <show_regs>
   0xffffffff82f3bf2a <+90>:	eb 23              	jmp    0xffffffff82f3bf4f <early_fixup_exception+127>
   0xffffffff82f3bf2c <+92>:	48 8b 57 78        	mov    rdx,QWORD PTR [rdi+0x78]
   0xffffffff82f3bf30 <+96>:	31 c9              	xor    ecx,ecx
   0xffffffff82f3bf32 <+98>:	e8 39 c9 34 fe     	call   0xffffffff81288870 <fixup_exception>
   0xffffffff82f3bf37 <+103>:	85 c0              	test   eax,eax
   0xffffffff82f3bf39 <+105>:	75 1c              	jne    0xffffffff82f3bf57 <early_fixup_exception+135>
   0xffffffff82f3bf3b <+107>:	41 83 fc 06        	cmp    r12d,0x6
   0xffffffff82f3bf3f <+111>:	75 bc              	jne    0xffffffff82f3befd <early_fixup_exception+45>
   0xffffffff82f3bf41 <+113>:	48 89 df           	mov    rdi,rbx
   0xffffffff82f3bf44 <+116>:	e8 97 93 10 ff     	call   0xffffffff820452e0 <handle_bug>
   0xffffffff82f3bf49 <+121>:	84 c0              	test   al,al
   0xffffffff82f3bf4b <+123>:	74 b0              	je     0xffffffff82f3befd <early_fixup_exception+45>
   0xffffffff82f3bf4d <+125>:	eb 08              	jmp    0xffffffff82f3bf57 <early_fixup_exception+135>
   0xffffffff82f3bf4f <+127>:	ff 15 33 32 d0 ff  	call   QWORD PTR [rip+0xffffffffffd03233]        # 0xffffffff82c3f188 <pv_ops+8>
   0xffffffff82f3bf55 <+133>:	eb f8              	jmp    0xffffffff82f3bf4f <early_fixup_exception+127>
   0xffffffff82f3bf57 <+135>:	5b                 	pop    rbx
   0xffffffff82f3bf58 <+136>:	41 5c              	pop    r12
   0xffffffff82f3bf5a <+138>:	5d                 	pop    rbp
   0xffffffff82f3bf5b <+139>:	e9 50 75 11 ff     	jmp    0xffffffff820534b0 <__x86_return_thunk>
   0xffffffff82f3bf60 <+144>:	e9 4b 75 11 ff     	jmp    0xffffffff820534b0 <__x86_return_thunk>
End of assembler dump.
(gdb) 


[-- Attachment #3: O1-gdb --]
[-- Type: application/octet-stream, Size: 4327 bytes --]

(gdb) until arch/x86/kernel/alternative.c:557
alt_replace_call (instr=0xffffffff82f447e5 <early_fixup_exception+133> "\377S\b\220\220\353\371[A\\]\303\314\314\314\314\303\314\314\314\314f\017\037D", insn_buff=0xffffffff82c03d78 <init_thread_union+15736> "\350\263\177\020\377", 
    a=0xffffffff831dae0e) at arch/x86/kernel/alternative.c:557
557			pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
(gdb) set disassembly-flavor intel
(gdb) disassemble /r early_fixup_exception
Dump of assembler code for function early_fixup_exception:
   0xffffffff82f44760 <+0>:	f3 0f 1e fa        	endbr64
   0xffffffff82f44764 <+4>:	83 fe 02           	cmp    esi,0x2
   0xffffffff82f44767 <+7>:	0f 84 88 00 00 00  	je     0xffffffff82f447f5 <early_fixup_exception+149>
   0xffffffff82f4476d <+13>:	55                 	push   rbp
   0xffffffff82f4476e <+14>:	48 89 e5           	mov    rbp,rsp
   0xffffffff82f44771 <+17>:	41 54              	push   r12
   0xffffffff82f44773 <+19>:	53                 	push   rbx
   0xffffffff82f44774 <+20>:	48 89 fb           	mov    rbx,rdi
   0xffffffff82f44777 <+23>:	41 89 f4           	mov    r12d,esi
   0xffffffff82f4477a <+26>:	83 3d 7f b8 0a 00 02	cmp    DWORD PTR [rip+0xab87f],0x2        # 0xffffffff82ff0000 <early_recursion_flag>
   0xffffffff82f44781 <+33>:	77 5b              	ja     0xffffffff82f447de <early_fixup_exception+126>
   0xffffffff82f44783 <+35>:	66 83 bf 88 00 00 00 10	cmp    WORD PTR [rdi+0x88],0x10
   0xffffffff82f4478b <+43>:	75 24              	jne    0xffffffff82f447b1 <early_fixup_exception+81>
   0xffffffff82f4478d <+45>:	48 8b 57 78        	mov    rdx,QWORD PTR [rdi+0x78]
   0xffffffff82f44791 <+49>:	b9 00 00 00 00     	mov    ecx,0x0
   0xffffffff82f44796 <+54>:	e8 35 0d 34 fe     	call   0xffffffff812854d0 <fixup_exception>
   0xffffffff82f4479b <+59>:	85 c0              	test   eax,eax
   0xffffffff82f4479d <+61>:	75 4d              	jne    0xffffffff82f447ec <early_fixup_exception+140>
   0xffffffff82f4479f <+63>:	41 83 fc 06        	cmp    r12d,0x6
   0xffffffff82f447a3 <+67>:	75 0c              	jne    0xffffffff82f447b1 <early_fixup_exception+81>
   0xffffffff82f447a5 <+69>:	48 89 df           	mov    rdi,rbx
   0xffffffff82f447a8 <+72>:	e8 d3 3d 3a ff     	call   0xffffffff822e8580 <handle_bug>
   0xffffffff82f447ad <+77>:	84 c0              	test   al,al
   0xffffffff82f447af <+79>:	75 3b              	jne    0xffffffff82f447ec <early_fixup_exception+140>
   0xffffffff82f447b1 <+81>:	41 0f 20 d1        	mov    r9,cr2
   0xffffffff82f447b5 <+85>:	48 8b 8b 80 00 00 00	mov    rcx,QWORD PTR [rbx+0x80]
   0xffffffff82f447bc <+92>:	0f b7 93 88 00 00 00	movzx  edx,WORD PTR [rbx+0x88]
   0xffffffff82f447c3 <+99>:	4c 8b 43 78        	mov    r8,QWORD PTR [rbx+0x78]
   0xffffffff82f447c7 <+103>:	44 89 e6           	mov    esi,r12d
   0xffffffff82f447ca <+106>:	48 c7 c7 08 32 9e 82	mov    rdi,0xffffffff829e3208
   0xffffffff82f447d1 <+113>:	e8 ba a0 3d fe     	call   0xffffffff8131e890 <early_printk>
   0xffffffff82f447d6 <+118>:	48 89 df           	mov    rdi,rbx
   0xffffffff82f447d9 <+121>:	e8 82 73 2f fe     	call   0xffffffff8123bb60 <show_regs>
   0xffffffff82f447de <+126>:	48 c7 c3 80 f1 c3 82	mov    rbx,0xffffffff82c3f180
   0xffffffff82f447e5 <+133>:	ff 53 08           	call   QWORD PTR [rbx+0x8]
   0xffffffff82f447e8 <+136>:	90                 	nop
   0xffffffff82f447e9 <+137>:	90                 	nop
   0xffffffff82f447ea <+138>:	eb f9              	jmp    0xffffffff82f447e5 <early_fixup_exception+133>
   0xffffffff82f447ec <+140>:	5b                 	pop    rbx
   0xffffffff82f447ed <+141>:	41 5c              	pop    r12
   0xffffffff82f447ef <+143>:	5d                 	pop    rbp
   0xffffffff82f447f0 <+144>:	c3                 	ret
   0xffffffff82f447f1 <+145>:	cc                 	int3
   0xffffffff82f447f2 <+146>:	cc                 	int3
--Type <RET> for more, q to quit, c to continue without paging--
   0xffffffff82f447f3 <+147>:	cc                 	int3
   0xffffffff82f447f4 <+148>:	cc                 	int3
   0xffffffff82f447f5 <+149>:	c3                 	ret
   0xffffffff82f447f6 <+150>:	cc                 	int3
   0xffffffff82f447f7 <+151>:	cc                 	int3
   0xffffffff82f447f8 <+152>:	cc                 	int3
   0xffffffff82f447f9 <+153>:	cc                 	int3


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-13 19:35           ` 李则良
@ 2026-08-13 19:57             ` 李则良
  2026-08-14 10:15               ` Jürgen Groß
  0 siblings, 1 reply; 12+ messages in thread
From: 李则良 @ 2026-08-13 19:57 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Jürgen Groß,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Kees Cook, Nathan Chancellor, Josh Poimboeuf,
	linux-kernel

I am currently testing the more general approach shown below. Your
review is also appreciated.

on vmlinux-O1:

   0xffffffff82f447de <+126>: ff 15 a4 a9 cf ff   call   QWORD PTR
[rip+0xffffffffffcfa9a4]        # 0xffffffff82c3f188 <pv_ops+8>
   0xffffffff82f447e4 <+132>: eb f8               jmp
0xffffffff82f447de <early_fixup_exception+126>
   0xffffffff82f447e6 <+134>: 5b                 pop    rbx
   0xffffffff82f447e7 <+135>: 41 5c               pop    r12
   0xffffffff82f447e9 <+137>: 5d                 pop    rbp

on vmlinux-O2:

   0xffffffff82f3bf4f <+127>: ff 15 33 32 d0 ff   call   QWORD PTR
[rip+0xffffffffffd03233]        # 0xffffffff82c3f188 <pv_ops+8>
   0xffffffff82f3bf55 <+133>: eb f8               jmp
0xffffffff82f3bf4f <early_fixup_exception+127>
   0xffffffff82f3bf57 <+135>: 5b                 pop    rbx
   0xffffffff82f3bf58 <+136>: 41 5c               pop    r12
   0xffffffff82f3bf5a <+138>: 5d                 pop    rbp

This is an early draft – please review. Thanks in advance.

From 5989dcf448e4d23ea4f3a0f91fec34f3dd25d26c Mon Sep 17 00:00:00 2001
From: Zeliang Li <lizeliang.linux@gmail.com>
Date: Fri, 14 Aug 2026 03:17:38 +0800
Subject: [PATCH] x86/paravirt: Force RIP-relative paravirt calls under low
 optimization levels

When compiling the kernel with non-standard lower optimization levels like
-O1 (e.g., during specific debugging or framework testing setups) using
newer toolchains like GCC 15.2.0, the compiler exhibits passive register
hoisting. In complex code paths like early_fixup_exception(), it caches the
base address of the global 'pv_ops' structure into a general-purpose register
instead of issuing direct RIP-relative memory loads, producing:

    mov $0xffffffff82c3f180, %rbx
    call *0x8(%rbx)

While this behavior is bypassed under aggressive -O2 optimizations, under -O1
it leaves a register-relative indirect call. This violates the strict format
assertion in the x86 alternative text-patching engine (alt_replace_call),
which expects an 'ALT_FLAG_DIRECT_CALL' site to be a standard 6-byte
RIP-relative indirect call (ff 15), leading to a boot-time kernel BUG.

Fix this by changing the x86_64 paravirt inline assembly to use an "i"
(immediate) constraint for the function pointer address, and explicitly
reference it via (%rip) in the assembly template. This removes the
toolchain's ability to select any other addressing mode, guaranteeing the
emission of compliant 'call *pv_ops+offset(%rip)' sequences on x86_64
regardless of the active compiler -O flag.

For i386, the original "m" constraint is retained since RIP-relative
addressing does not exist on 32-bit x86.

Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com>
---
 arch/x86/include/asm/paravirt_types.h | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/x86/include/asm/paravirt_types.h
b/arch/x86/include/asm/paravirt_types.h
index b4c4a23e77a1..e8047bdbed3a 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -184,8 +184,6 @@ struct paravirt_patch_template {

 extern struct paravirt_patch_template pv_ops;

-#define paravirt_ptr(array, op) [paravirt_opptr] "m" (array.op)
-
 /*
  * This generates an indirect call based on the operation type number.
  *
@@ -197,9 +195,20 @@ extern struct paravirt_patch_template pv_ops;
  * OTOH since this is effectively a __nocfi indirect call, the paravirt stubs
  * don't need to bother with CFI prefixes.
  */
+#ifdef CONFIG_X86_64
+
+#define paravirt_ptr(array, op) [paravirt_opptr] "i" (&(array.op))
 #define PARAVIRT_CALL \
  ANNOTATE_RETPOLINE_SAFE "\n\t" \
- "call *%[paravirt_opptr]"
+        "call *%c[paravirt_opptr](%%rip);"
+#else /* CONFIG_X86_32 */
+
+#define paravirt_ptr(array, op) [paravirt_opptr] "m" (array.op)
+#define PARAVIRT_CALL \
+    ANNOTATE_RETPOLINE_SAFE "\n\t" \
+        "call *%[paravirt_opptr];"
+
+#endif /* CONFIG_X86_64 */

 /*
  * These macros are intended to wrap calls through one of the paravirt
-- 
2.53.0

李则良 <lizeliang.linux@gmail.com> 于2026年8月14日周五 03:35写道:
>
> >
> > That's not what I asked, now was it. I asked what opcodes it does
> > generate. Disassemble an affected function and show the difference
> > between the normal -O2 and your -O1 build that causes the failure.
> on vmlinux-O1:
> (gdb) until arch/x86/kernel/alternative.c:557
> alt_replace_call (instr=0xffffffff82f447e5 <early_fixup_exception+133>
> "\377S\b\220\220\353\371[A\\]\303\314\314\314\314\303\314\314\314\314f\017\037D",
> insn_buff=0xffffffff82c03d78 <init_thread_union+15736>
> "\350\263\177\020\377",
>     a=0xffffffff831dae0e) at arch/x86/kernel/alternative.c:557
> 557 pr_err("ALT_FLAG_DIRECT_CALL set for unrecognized indirect call\n");
> vmlinux-O1:
>   0xffffffff82f447e5 <+133>: ff 53 08           call   QWORD PTR [rbx+0x8]
>    0xffffffff82f447e8 <+136>: 90                 nop
>    0xffffffff82f447e9 <+137>: 90                 nop
>    0xffffffff82f447ea <+138>: eb f9               jmp
> 0xffffffff82f447e5 <early_fixup_exception+133>
>    0xffffffff82f447ec <+140>: 5b                 pop    rbx
>    0xffffffff82f447ed <+141>: 41 5c               pop    r12
>
> vmlinux-O2:
>   0xffffffff82f3bf4b <+123>: 74 b0               je
> 0xffffffff82f3befd <early_fixup_exception+45>
>    0xffffffff82f3bf4d <+125>: eb 08               jmp
> 0xffffffff82f3bf57 <early_fixup_exception+135>
>    0xffffffff82f3bf4f <+127>: ff 15 33 32 d0 ff   call   QWORD PTR
> [rip+0xffffffffffd03233]        # 0xffffffff82c3f188 <pv_ops+8>
>    0xffffffff82f3bf55 <+133>: eb f8               jmp
> 0xffffffff82f3bf4f <early_fixup_exception+127>
>    0xffffffff82f3bf57 <+135>: 5b                 pop    rbx
>    0xffffffff82f3bf58 <+136>: 41 5c               pop    r12
>    0xffffffff82f3bf5a <+138>: 5d                 pop    rbp
>
> I use the patch below to bypass the problem while keeping all logic of
> alt_replace_call intact.
>
> From 2538684697e537298aa9082b582bc7dddd29b278 Mon Sep 17 00:00:00 2001
> From: Zeliang Li <lizeliang.linux@gmail.com>
> Date: Fri, 14 Aug 2026 02:32:19 +0800
> Subject: [PATCH] x86/mm: force O2 optimization for early_fixup_exception
>
> When the kernel is compiled with non-standard optimization flags
> (e.g., KCFLAGS=-O1), the function early_fixup_exception may be
> compiled to an indirect call instruction that is not recognized
> by alt_replace_call() (e.g., "call *0x8(%rbx)"). This triggers a
> BUG() during early boot, as seen in:
>
>   ALT_FLAG_DIRECT_CALL: original instruction is not a 6-byte ...
>   instruction at early_fixup_exception+0x85/0xa0, length=5
>   instruction bytes: ff 53 08 90 90
>
> Force this function to be compiled with -O2 optimization level,
> which guarantees the standard 6-byte `ff 15 <disp32>` form used
> by alternatives patching.
>
> Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com>
> ---
>  arch/x86/mm/extable.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/arch/x86/mm/extable.c b/arch/x86/mm/extable.c
> index ceb8d03191ab..5d5c7510a817 100644
> --- a/arch/x86/mm/extable.c
> +++ b/arch/x86/mm/extable.c
> @@ -375,6 +375,7 @@ int fixup_exception(struct pt_regs *regs, int
> trapnr, unsigned long error_code,
>  extern unsigned int early_recursion_flag;
>
>  /* Restricted version used during very early boot */
> +__attribute__((optimize("O2")))
>  void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
>  {
>   /* Ignore early NMIs. */
> --
> 2.53.0
>
> --
> KISS == Keep it simple,stupid~:-)
> http://lizeliang.org



-- 
KISS == Keep it simple,stupid~:-)
http://lizeliang.org

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions
  2026-08-13 19:57             ` 李则良
@ 2026-08-14 10:15               ` Jürgen Groß
  0 siblings, 0 replies; 12+ messages in thread
From: Jürgen Groß @ 2026-08-14 10:15 UTC (permalink / raw)
  To: 李则良, Peter Zijlstra
  Cc: Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Kees Cook, Nathan Chancellor, Josh Poimboeuf,
	linux-kernel


[-- Attachment #1.1.1: Type: text/plain, Size: 4614 bytes --]

On 13.08.26 21:57, 李则良 wrote:
> I am currently testing the more general approach shown below. Your
> review is also appreciated.
> 
> on vmlinux-O1:
> 
>     0xffffffff82f447de <+126>: ff 15 a4 a9 cf ff   call   QWORD PTR
> [rip+0xffffffffffcfa9a4]        # 0xffffffff82c3f188 <pv_ops+8>
>     0xffffffff82f447e4 <+132>: eb f8               jmp
> 0xffffffff82f447de <early_fixup_exception+126>
>     0xffffffff82f447e6 <+134>: 5b                 pop    rbx
>     0xffffffff82f447e7 <+135>: 41 5c               pop    r12
>     0xffffffff82f447e9 <+137>: 5d                 pop    rbp
> 
> on vmlinux-O2:
> 
>     0xffffffff82f3bf4f <+127>: ff 15 33 32 d0 ff   call   QWORD PTR
> [rip+0xffffffffffd03233]        # 0xffffffff82c3f188 <pv_ops+8>
>     0xffffffff82f3bf55 <+133>: eb f8               jmp
> 0xffffffff82f3bf4f <early_fixup_exception+127>
>     0xffffffff82f3bf57 <+135>: 5b                 pop    rbx
>     0xffffffff82f3bf58 <+136>: 41 5c               pop    r12
>     0xffffffff82f3bf5a <+138>: 5d                 pop    rbp
> 
> This is an early draft – please review. Thanks in advance.
> 
>  From 5989dcf448e4d23ea4f3a0f91fec34f3dd25d26c Mon Sep 17 00:00:00 2001
> From: Zeliang Li <lizeliang.linux@gmail.com>
> Date: Fri, 14 Aug 2026 03:17:38 +0800
> Subject: [PATCH] x86/paravirt: Force RIP-relative paravirt calls under low
>   optimization levels
> 
> When compiling the kernel with non-standard lower optimization levels like
> -O1 (e.g., during specific debugging or framework testing setups) using
> newer toolchains like GCC 15.2.0, the compiler exhibits passive register
> hoisting. In complex code paths like early_fixup_exception(), it caches the
> base address of the global 'pv_ops' structure into a general-purpose register
> instead of issuing direct RIP-relative memory loads, producing:
> 
>      mov $0xffffffff82c3f180, %rbx
>      call *0x8(%rbx)
> 
> While this behavior is bypassed under aggressive -O2 optimizations, under -O1
> it leaves a register-relative indirect call. This violates the strict format
> assertion in the x86 alternative text-patching engine (alt_replace_call),
> which expects an 'ALT_FLAG_DIRECT_CALL' site to be a standard 6-byte
> RIP-relative indirect call (ff 15), leading to a boot-time kernel BUG.
> 
> Fix this by changing the x86_64 paravirt inline assembly to use an "i"
> (immediate) constraint for the function pointer address, and explicitly
> reference it via (%rip) in the assembly template. This removes the
> toolchain's ability to select any other addressing mode, guaranteeing the
> emission of compliant 'call *pv_ops+offset(%rip)' sequences on x86_64
> regardless of the active compiler -O flag.
> 
> For i386, the original "m" constraint is retained since RIP-relative
> addressing does not exist on 32-bit x86.
> 
> Signed-off-by: Zeliang Li <lizeliang.linux@gmail.com>
> ---
>   arch/x86/include/asm/paravirt_types.h | 15 ++++++++++++---
>   1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/x86/include/asm/paravirt_types.h
> b/arch/x86/include/asm/paravirt_types.h
> index b4c4a23e77a1..e8047bdbed3a 100644
> --- a/arch/x86/include/asm/paravirt_types.h
> +++ b/arch/x86/include/asm/paravirt_types.h
> @@ -184,8 +184,6 @@ struct paravirt_patch_template {
> 
>   extern struct paravirt_patch_template pv_ops;
> 
> -#define paravirt_ptr(array, op) [paravirt_opptr] "m" (array.op)
> -
>   /*
>    * This generates an indirect call based on the operation type number.
>    *
> @@ -197,9 +195,20 @@ extern struct paravirt_patch_template pv_ops;
>    * OTOH since this is effectively a __nocfi indirect call, the paravirt stubs
>    * don't need to bother with CFI prefixes.
>    */
> +#ifdef CONFIG_X86_64
> +
> +#define paravirt_ptr(array, op) [paravirt_opptr] "i" (&(array.op))
>   #define PARAVIRT_CALL \
>    ANNOTATE_RETPOLINE_SAFE "\n\t" \
> - "call *%[paravirt_opptr]"
> +        "call *%c[paravirt_opptr](%%rip);"
> +#else /* CONFIG_X86_32 */
> +
> +#define paravirt_ptr(array, op) [paravirt_opptr] "m" (array.op)
> +#define PARAVIRT_CALL \
> +    ANNOTATE_RETPOLINE_SAFE "\n\t" \
> +        "call *%[paravirt_opptr];"
> +
> +#endif /* CONFIG_X86_64 */
> 
>   /*
>    * These macros are intended to wrap calls through one of the paravirt

Thanks for this solution. I like it much more, especially as it will avoid
any nasty compiler optimizations as the one you have observed.

When sending this as a proper patch you can add my:

Reviewed-by: Juergen Gross <jgross@suse.com>


Juergen

[-- Attachment #1.1.2: OpenPGP public key --]
[-- Type: application/pgp-keys, Size: 3743 bytes --]

[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 495 bytes --]

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2026-08-14 10:15 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <CANd6bgL=v+uReoQznRGKunZQApwV5ESHAQn2_MOt-J-=cPkm9g@mail.gmail.com>
2026-08-11 11:50 ` [PATCH] x86/alternatives: gracefully skip unrecognized indirect call instructions Jürgen Groß
2026-08-12  9:22   ` 李则良
2026-08-12 11:00     ` Peter Zijlstra
2026-08-12 11:24       ` H. Peter Anvin
2026-08-12 15:30         ` Borislav Petkov
2026-08-12 17:14       ` 李则良
2026-08-12 19:01         ` H. Peter Anvin
2026-08-12 19:02         ` H. Peter Anvin
2026-08-13  9:51         ` Peter Zijlstra
2026-08-13 19:35           ` 李则良
2026-08-13 19:57             ` 李则良
2026-08-14 10:15               ` Jürgen Groß

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®