[<prev] [next>] [day] [month] [year] [list]
Message-ID: <bed73c01aba29fe651c9e23a9820a21e88ad13e7.1769048488.git.jpoimboe@kernel.org>
Date: Wed, 21 Jan 2026 19:18:51 -0800
From: Josh Poimboeuf <jpoimboe@...nel.org>
To: x86@...nel.org
Cc: linux-kernel@...r.kernel.org,
Ajay Kaher <ajay.kaher@...adcom.com>,
Alexey Makhalov <alexey.makhalov@...adcom.com>,
bcm-kernel-feedback-list@...adcom.com,
Peter Zijlstra <peterz@...radead.org>,
Justin Forbes <jforbes@...oraproject.org>
Subject: [PATCH] x86/vmware: Fix hypercall clobbers
Fedora QA reported the following panic:
BUG: unable to handle page fault for address: 0000000040003e54
#PF: supervisor write access in kernel mode
#PF: error_code(0x0002) - not-present page
PGD 1082ec067 P4D 0
Oops: Oops: 0002 [#1] SMP NOPTI
CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Not tainted 6.19.0-0.rc4.260108gf0b9d8eb98df.34.fc43.x86_64 #1 PREEMPT(lazy)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS edk2-20251119-3.fc43 11/19/2025
RIP: 0010:vmware_hypercall4.constprop.0+0x52/0x90
Code: 48 83 c4 20 5b e9 69 f0 fc fe 8b 05 a0 c1 b2 01 85 c0 74 23 b8 68 58 4d 56 b9 27 00 00 00 31 d2 bb 04 00 00 00 66 ba 58 56 ed <89> 1f 89 0e 41 89 10 5b e9 3c f0 fc fe 6a 00 49 89 f9 45 31 c0 31
RSP: 0018:ff5eeb3240003e40 EFLAGS: 00010046
RAX: 0000000000000000 RBX: 000000000000ffca RCX: 000000000000ffac
RDX: 0000000000000000 RSI: 0000000040003e58 RDI: 0000000040003e54
RBP: ff1e05f3c1204800 R08: ff5eeb3240003e5c R09: 000000009d899c41
R10: 000000000000003d R11: ff5eeb3240003ff8 R12: 0000000000000000
R13: 00000000000000ff R14: ff1e05f3c02f9e00 R15: 000000000000000c
FS: 0000000000000000(0000) GS:ff1e05f489e40000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000040003e54 CR3: 000000010841d002 CR4: 0000000000771ef0
PKRU: 55555554
Call Trace:
<IRQ>
vmmouse_report_events+0x13e/0x1b0
psmouse_handle_byte+0x15/0x60
ps2_interrupt+0x8a/0xd0
...
The panic was triggered by dereferencing a bad pointer (in RDI)
immediately after a VMware hypercall:
ffffffff82135070 <vmware_hypercall4.constprop.0>:
...
ffffffff821350ac: b8 68 58 4d 56 mov $0x564d5868,%eax
ffffffff821350b1: b9 27 00 00 00 mov $0x27,%ecx
ffffffff821350b6: 31 d2 xor %edx,%edx
ffffffff821350b8: bb 04 00 00 00 mov $0x4,%ebx
ffffffff821350bd: 66 ba 58 56 mov $0x5658,%dx
ffffffff821350c1: ed in (%dx),%eax <-- hypercall
ffffffff821350c2: 89 1f mov %ebx,(%rdi) <-- crash
Reading the disassembly shows that RDI should contain the value of a
valid kernel stack address here (0xff5eeb3240003e54). Instead it
contains 0x40003e54, suggesting the hypervisor cleared the upper 32
bits.
This issue was bisected to commit aca282ab7e75 ("x86/asm: Annotate
special section entries"), which added annotations to the ALTERNATIVE()
macro. Despite the use of asm_inline, that commit caused the compiler
to un-inline and const-propagate vmware_hypercall4().
That made RDI live across the hypercall, making the hypervisor's
register clobbering visible and exposing this latent bug.
The open-vm-tools reference implementation treats all six registers as
clobbered for all hypercalls. Match that behavior here.
Fixes: 34bf25e820ae ("x86/vmware: Introduce VMware hypercall API")
Fixes: aca282ab7e75 ("x86/asm: Annotate special section entries")
Reported-by: Justin Forbes <jforbes@...oraproject.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@...nel.org>
---
arch/x86/include/asm/vmware.h | 72 +++++++++++++++++------------------
1 file changed, 34 insertions(+), 38 deletions(-)
diff --git a/arch/x86/include/asm/vmware.h b/arch/x86/include/asm/vmware.h
index c9cf43d5ef23..372173d4ea27 100644
--- a/arch/x86/include/asm/vmware.h
+++ b/arch/x86/include/asm/vmware.h
@@ -98,7 +98,7 @@ extern unsigned long vmware_tdx_hypercall(unsigned long cmd,
static inline
unsigned long vmware_hypercall1(unsigned long cmd, unsigned long in1)
{
- unsigned long out0;
+ unsigned long out0, tmp = 0;
if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
@@ -109,13 +109,11 @@ unsigned long vmware_hypercall1(unsigned long cmd, unsigned long in1)
NULL, NULL, NULL, NULL, NULL);
asm_inline volatile (VMWARE_HYPERCALL
- : "=a" (out0)
+ : "=a" (out0), "+b" (in1), "+c" (cmd), "+d" (tmp)
: [port] "i" (VMWARE_HYPERVISOR_PORT),
- "a" (VMWARE_HYPERVISOR_MAGIC),
- "b" (in1),
- "c" (cmd),
- "d" (0)
- : "cc", "memory");
+ "a" (VMWARE_HYPERVISOR_MAGIC)
+ : "di", "si", "cc", "memory");
+
return out0;
}
@@ -123,7 +121,7 @@ static inline
unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
u32 *out1, u32 *out2)
{
- unsigned long out0;
+ unsigned long out0, tmp = 0;
if (cpu_feature_enabled(X86_FEATURE_TDX_GUEST))
return vmware_tdx_hypercall(cmd, in1, 0, 0, 0,
@@ -134,13 +132,13 @@ unsigned long vmware_hypercall3(unsigned long cmd, unsigned long in1,
out1, out2, NULL, NULL, NULL);
asm_inline volatile (VMWARE_HYPERCALL
- : "=a" (out0), "=b" (*out1), "=c" (*out2)
+ : "=a" (out0), "=b" (*out1), "=c" (*out2), "+d" (tmp)
: [port] "i" (VMWARE_HYPERVISOR_PORT),
"a" (VMWARE_HYPERVISOR_MAGIC),
"b" (in1),
- "c" (cmd),
- "d" (0)
- : "cc", "memory");
+ "c" (cmd)
+ : "di", "si", "cc", "memory");
+
return out0;
}
@@ -165,7 +163,8 @@ unsigned long vmware_hypercall4(unsigned long cmd, unsigned long in1,
"b" (in1),
"c" (cmd),
"d" (0)
- : "cc", "memory");
+ : "di", "si", "cc", "memory");
+
return out0;
}
@@ -185,15 +184,13 @@ unsigned long vmware_hypercall5(unsigned long cmd, unsigned long in1,
NULL, out2, NULL, NULL, NULL);
asm_inline volatile (VMWARE_HYPERCALL
- : "=a" (out0), "=c" (*out2)
+ : "=a" (out0), "+b" (in1), "=c" (*out2), "+d" (in3),
+ "+S" (in4), "+D" (in5)
: [port] "i" (VMWARE_HYPERVISOR_PORT),
"a" (VMWARE_HYPERVISOR_MAGIC),
- "b" (in1),
- "c" (cmd),
- "d" (in3),
- "S" (in4),
- "D" (in5)
+ "c" (cmd)
: "cc", "memory");
+
return out0;
}
@@ -213,14 +210,14 @@ unsigned long vmware_hypercall6(unsigned long cmd, unsigned long in1,
NULL, out2, out3, out4, out5);
asm_inline volatile (VMWARE_HYPERCALL
- : "=a" (out0), "=c" (*out2), "=d" (*out3), "=S" (*out4),
- "=D" (*out5)
+ : "=a" (out0), "+b" (in1), "=c" (*out2), "=d" (*out3),
+ "=S" (*out4), "=D" (*out5)
: [port] "i" (VMWARE_HYPERVISOR_PORT),
"a" (VMWARE_HYPERVISOR_MAGIC),
- "b" (in1),
"c" (cmd),
"d" (in3)
: "cc", "memory");
+
return out0;
}
@@ -241,15 +238,15 @@ unsigned long vmware_hypercall7(unsigned long cmd, unsigned long in1,
out1, out2, out3, NULL, NULL);
asm_inline volatile (VMWARE_HYPERCALL
- : "=a" (out0), "=b" (*out1), "=c" (*out2), "=d" (*out3)
+ : "=a" (out0), "=b" (*out1), "=c" (*out2), "=d" (*out3),
+ "+S" (in4), "+D" (in5)
: [port] "i" (VMWARE_HYPERVISOR_PORT),
"a" (VMWARE_HYPERVISOR_MAGIC),
"b" (in1),
"c" (cmd),
- "d" (in3),
- "S" (in4),
- "D" (in5)
+ "d" (in3)
: "cc", "memory");
+
return out0;
}
@@ -272,7 +269,9 @@ unsigned long vmware_hypercall_hb_out(unsigned long cmd, unsigned long in2,
unsigned long in5, unsigned long in6,
u32 *out1)
{
- unsigned long out0;
+ unsigned long out0, port;
+
+ port = in3 | VMWARE_HYPERVISOR_PORT_HB;
asm_inline volatile (
UNWIND_HINT_SAVE
@@ -282,15 +281,13 @@ unsigned long vmware_hypercall_hb_out(unsigned long cmd, unsigned long in2,
"rep outsb\n\t"
"pop %%" _ASM_BP "\n\t"
UNWIND_HINT_RESTORE
- : "=a" (out0), "=b" (*out1)
+ : "=a" (out0), "=b" (*out1), "+c" (in2), "+d" (port),
+ "+S" (in4), "+D" (in5)
: "a" (VMWARE_HYPERVISOR_MAGIC),
"b" (cmd),
- "c" (in2),
- "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
- "S" (in4),
- "D" (in5),
[in6] VMW_BP_CONSTRAINT (in6)
: "cc", "memory");
+
return out0;
}
@@ -300,7 +297,9 @@ unsigned long vmware_hypercall_hb_in(unsigned long cmd, unsigned long in2,
unsigned long in5, unsigned long in6,
u32 *out1)
{
- unsigned long out0;
+ unsigned long out0, port;
+
+ port = in3 | VMWARE_HYPERVISOR_PORT_HB;
asm_inline volatile (
UNWIND_HINT_SAVE
@@ -310,13 +309,10 @@ unsigned long vmware_hypercall_hb_in(unsigned long cmd, unsigned long in2,
"rep insb\n\t"
"pop %%" _ASM_BP "\n\t"
UNWIND_HINT_RESTORE
- : "=a" (out0), "=b" (*out1)
+ : "=a" (out0), "=b" (*out1), "+c" (in2), "+d" (port),
+ "+S" (in4), "+D" (in5)
: "a" (VMWARE_HYPERVISOR_MAGIC),
"b" (cmd),
- "c" (in2),
- "d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
- "S" (in4),
- "D" (in5),
[in6] VMW_BP_CONSTRAINT (in6)
: "cc", "memory");
return out0;
--
2.52.0
Powered by blists - more mailing lists