lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<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

Powered by Openwall GNU/*/Linux Powered by OpenVZ