From: Marcos Del Sol Vives <marcos@orca.pet>
To: linux-kernel@vger.kernel.org
Cc: marcos@orca.pet, Thomas Gleixner <tglx@linutronix.de>,
Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
Dave Hansen <dave.hansen@linux.intel.com>,
x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>,
Brian Gerst <brgerst@gmail.com>, Uros Bizjak <ubizjak@gmail.com>,
Ard Biesheuvel <ardb@kernel.org>,
David Kaplan <david.kaplan@amd.com>,
"Ahmed S. Darwish" <darwi@linutronix.de>,
Kees Cook <kees@kernel.org>,
"Peter Zijlstra (Intel)" <peterz@infradead.org>,
Andrew Cooper <andrew.cooper3@citrix.com>,
Oleg Nesterov <oleg@redhat.com>, "Xin Li (Intel)" <xin@zytor.com>,
Sabyrzhan Tasbolatov <snovitoll@gmail.com>
Subject: [PATCH] x86: add hintable NOPs emulation
Date: Wed, 20 Aug 2025 03:34:46 +0200 [thread overview]
Message-ID: <20250820013452.495481-1-marcos@orca.pet> (raw)
Hintable NOPs are a series of instructions introduced by Intel with the
Pentium Pro (i686), and described in US patent US5701442A.
These instructions were reserved to allow backwards-compatible changes
in the instruction set possible, by having old processors treat them as
variable-length NOPs, while having other semantics in modern processors.
Some modern uses are:
- Multi-byte/long NOPs
- Indirect Branch Tracking (ENDBR32)
- Shadow Stack (part of CET)
Some processors advertising i686 compatibility lack full support for
them, which may cause #UD to be incorrectly triggered, crashing software
that uses then with an unexpected SIGILL.
One such software is sudo in Debian bookworm, which is compiled with
GCC -fcf-protection=branch and contains ENDBR32 instructions. It crashes
on my Vortex86DX3 processor and VIA C3 Nehalem processors [1].
This patch is a much simplified version of my previous patch for x86
instruction emulation [2], that only emulates hintable NOPs.
When #UD is raised, it checks if the opcode corresponds to a hintable NOP
in user space. If true, it warns the user via the dmesg and advances the
instruction pointer, thus emulating its expected NOP behaviour.
[1]: https://lists.debian.org/debian-devel/2023/10/msg00118.html
[2]: https://lore.kernel.org/all/20210626130313.1283485-1-marcos@orca.pet/
Signed-off-by: Marcos Del Sol Vives <marcos@orca.pet>
---
arch/x86/Kconfig | 29 +++++++++++++++++++++++++
arch/x86/include/asm/processor.h | 4 ++++
arch/x86/kernel/process.c | 3 +++
arch/x86/kernel/traps.c | 36 ++++++++++++++++++++++++++++++++
4 files changed, 72 insertions(+)
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 58d890fe2100..a6daebdc2573 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1286,6 +1286,35 @@ config X86_IOPL_IOPERM
ability to disable interrupts from user space which would be
granted if the hardware IOPL mechanism would be used.
+config X86_HNOP_EMU
+ bool "Hintable NOPs emulation"
+ depends on X86_32
+ default y
+ help
+ Hintable NOPs are a series of instructions introduced by Intel with
+ the Pentium Pro (i686), and described in US patent US5701442A.
+
+ These instructions were reserved to allow backwards-compatible
+ changes in the instruction set possible, by having old processors
+ treat them as variable-length NOPs, while having other semantics in
+ modern processors.
+
+ Some modern uses are:
+ - Multi-byte/long NOPs
+ - Indirect Branch Tracking (ENDBR32)
+ - Shadow Stack (part of CET)
+
+ Some processors advertising i686 compatibility (such as Cyrix MII,
+ VIA C3 Nehalem or DM&P Vortex86DX3) lack full support for them,
+ which may cause SIGILL to be incorrectly raised in user space when
+ a hintable NOP is encountered.
+
+ Say Y here if you want the kernel to emulate them, allowing programs
+ that make use of them to run transparently on such processors.
+
+ This emulation has no performance penalty for processors that
+ properly support them, so if unsure, enable it.
+
config TOSHIBA
tristate "Toshiba Laptop support"
depends on X86_32
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index bde58f6510ac..c34fb678c4de 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -499,6 +499,10 @@ struct thread_struct {
unsigned int iopl_warn:1;
+#ifdef CONFIG_X86_HNOP_EMU
+ unsigned int hnop_warn:1;
+#endif
+
/*
* Protection Keys Register for Userspace. Loaded immediately on
* context switch. Store it in thread_struct to avoid a lookup in
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 1b7960cf6eb0..6ec8021638d0 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -178,6 +178,9 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
p->thread.io_bitmap = NULL;
clear_tsk_thread_flag(p, TIF_IO_BITMAP);
p->thread.iopl_warn = 0;
+#ifdef CONFIG_X86_HNOP_EMU
+ p->thread.hnop_warn = 0;
+#endif
memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));
#ifdef CONFIG_X86_64
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 36354b470590..2dcb7d7edf8a 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -295,12 +295,48 @@ DEFINE_IDTENTRY(exc_overflow)
do_error_trap(regs, 0, "overflow", X86_TRAP_OF, SIGSEGV, 0, NULL);
}
+#ifdef CONFIG_X86_HNOP_EMU
+static bool handle_hnop(struct pt_regs *regs)
+{
+ struct thread_struct *t = ¤t->thread;
+ unsigned char buf[MAX_INSN_SIZE];
+ unsigned long nr_copied;
+ struct insn insn;
+
+ nr_copied = insn_fetch_from_user(regs, buf);
+ if (nr_copied <= 0)
+ return false;
+
+ if (!insn_decode_from_regs(&insn, regs, buf, nr_copied))
+ return false;
+
+ /* Hintable NOPs cover 0F 18 to 0F 1F */
+ if (insn.opcode.bytes[0] != 0x0F ||
+ insn.opcode.bytes[1] < 0x18 || insn.opcode.bytes[1] > 0x1F)
+ return false;
+
+ if (!t->hnop_warn) {
+ pr_warn_ratelimited("%s[%d] emulating hintable NOP, ip:%lx\n",
+ current->comm, task_pid_nr(current), regs->ip);
+ t->hnop_warn = 1;
+ }
+
+ regs->ip += insn.length;
+ return true;
+}
+#endif
+
#ifdef CONFIG_X86_F00F_BUG
void handle_invalid_op(struct pt_regs *regs)
#else
static inline void handle_invalid_op(struct pt_regs *regs)
#endif
{
+#ifdef CONFIG_X86_HNOP_EMU
+ if (user_mode(regs) && handle_hnop(regs))
+ return;
+#endif
+
do_error_trap(regs, 0, "invalid opcode", X86_TRAP_UD, SIGILL,
ILL_ILLOPN, error_get_trap_addr(regs));
}
--
2.34.1
next reply other threads:[~2025-08-20 1:35 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-08-20 1:34 Marcos Del Sol Vives [this message]
2025-08-20 9:07 ` [PATCH] x86: add hintable NOPs emulation Peter Zijlstra
2025-08-21 12:28 ` David Laight
2025-08-21 12:46 ` Peter Zijlstra
2025-08-21 18:40 ` David Laight
2025-08-21 19:46 ` Marcos Del Sol Vives
2025-08-21 15:11 ` Marcos Del Sol Vives
2025-08-20 9:14 ` Ahmed S. Darwish
2025-08-20 9:33 ` Marcos Del Sol Vives
2025-08-20 9:43 ` Borislav Petkov
2025-08-20 9:51 ` Marcos Del Sol Vives
2025-08-20 9:55 ` Borislav Petkov
2025-08-20 10:01 ` Marcos Del Sol Vives
2025-08-20 10:08 ` Borislav Petkov
2025-08-20 10:21 ` Marcos Del Sol Vives
2025-08-20 10:30 ` Borislav Petkov
2025-08-21 2:00 ` Kees Cook
2025-08-20 10:11 ` Ahmed S. Darwish
2025-08-20 10:30 ` Ahmed S. Darwish
2025-08-21 1:43 ` H. Peter Anvin
2025-08-21 9:35 ` Marcos Del Sol Vives
2025-08-21 5:02 ` H. Peter Anvin
2025-08-21 12:26 ` David Laight
2025-08-21 12:48 ` Marcos Del Sol Vives
2025-08-21 12:48 ` Peter Zijlstra
2025-08-21 13:45 ` Marcos Del Sol Vives
2025-08-21 13:59 ` Peter Zijlstra
2025-08-22 22:12 ` H. Peter Anvin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250820013452.495481-1-marcos@orca.pet \
--to=marcos@orca.pet \
--cc=andrew.cooper3@citrix.com \
--cc=ardb@kernel.org \
--cc=bp@alien8.de \
--cc=brgerst@gmail.com \
--cc=darwi@linutronix.de \
--cc=dave.hansen@linux.intel.com \
--cc=david.kaplan@amd.com \
--cc=hpa@zytor.com \
--cc=kees@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@redhat.com \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=snovitoll@gmail.com \
--cc=tglx@linutronix.de \
--cc=ubizjak@gmail.com \
--cc=x86@kernel.org \
--cc=xin@zytor.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.