* 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®