[PATCH] hw/i386/vmmouse: Fix hypercall clobbers

Josh Poimboeuf posted 1 patch 2 days, 12 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/ae0b8f2c574abe8053e742260c794adcaeda975a.1769110562.git.jpoimboe@kernel.org
Maintainers: "Michael S. Tsirkin" <mst@redhat.com>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, Paolo Bonzini <pbonzini@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, Eduardo Habkost <eduardo@habkost.net>
hw/i386/vmmouse.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
[PATCH] hw/i386/vmmouse: Fix hypercall clobbers
Posted by Josh Poimboeuf 2 days, 12 hours ago
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 (RDI) immediately
after a VMware hypercall for VMWARE_CMD_ABSPOINTER_DATA in the vmmouse
driver:

  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.

And indeed, Alexey discovered that QEMU's vmmouse_get_data() and
vmmouse_set_data() are only saving/restoring the lower 32 bits, while
clearing the upper 32.  Fix that by changing the type of the saved data
array from uint32_t to target_ulong.

Fixes: 548df2acc6fc ("VMMouse Emulation, by Anthony Liguori.")
Reported-by: Justin Forbes <jforbes@fedoraproject.org>
Debugged-by: Alexey Makhalov <alexey.makhalov@broadcom.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 hw/i386/vmmouse.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
index 2ae7f3a242..3bba221d5f 100644
--- a/hw/i386/vmmouse.c
+++ b/hw/i386/vmmouse.c
@@ -72,7 +72,7 @@ struct VMMouseState {
     ISAKBDState *i8042;
 };
 
-static void vmmouse_get_data(uint32_t *data)
+static void vmmouse_get_data(target_ulong *data)
 {
     X86CPU *cpu = X86_CPU(current_cpu);
     CPUX86State *env = &cpu->env;
@@ -82,7 +82,7 @@ static void vmmouse_get_data(uint32_t *data)
     data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
 }
 
-static void vmmouse_set_data(const uint32_t *data)
+static void vmmouse_set_data(const target_ulong *data)
 {
     X86CPU *cpu = X86_CPU(current_cpu);
     CPUX86State *env = &cpu->env;
@@ -197,7 +197,7 @@ static void vmmouse_disable(VMMouseState *s)
     vmmouse_remove_handler(s);
 }
 
-static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
+static void vmmouse_data(VMMouseState *s, target_ulong *data, uint32_t size)
 {
     int i;
 
@@ -221,7 +221,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
 static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
 {
     VMMouseState *s = opaque;
-    uint32_t data[6];
+    target_ulong data[6];
     uint16_t command;
 
     vmmouse_get_data(data);
@@ -247,7 +247,7 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
             vmmouse_request_absolute(s);
             break;
         default:
-            printf("vmmouse: unknown command %x\n", data[1]);
+            printf("vmmouse: unknown command " TARGET_FMT_lx "\n", data[1]);
             break;
         }
         break;
-- 
2.52.0
Re: [PATCH] hw/i386/vmmouse: Fix hypercall clobbers
Posted by Alexey Makhalov 2 days, 11 hours ago
Thanks Josh for a quick fix.

Acked-by: Alexey Makhalov <alexey.makhalov@broadcom.com>

On 1/22/26 11:36 AM, Josh Poimboeuf wrote:
> 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 (RDI) immediately
> after a VMware hypercall for VMWARE_CMD_ABSPOINTER_DATA in the vmmouse
> driver:
> 
>    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.
> 
> And indeed, Alexey discovered that QEMU's vmmouse_get_data() and
> vmmouse_set_data() are only saving/restoring the lower 32 bits, while
> clearing the upper 32.  Fix that by changing the type of the saved data
> array from uint32_t to target_ulong.
> 
> Fixes: 548df2acc6fc ("VMMouse Emulation, by Anthony Liguori.")
> Reported-by: Justin Forbes <jforbes@fedoraproject.org>
> Debugged-by: Alexey Makhalov <alexey.makhalov@broadcom.com>
> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
> ---
>   hw/i386/vmmouse.c | 10 +++++-----
>   1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/hw/i386/vmmouse.c b/hw/i386/vmmouse.c
> index 2ae7f3a242..3bba221d5f 100644
> --- a/hw/i386/vmmouse.c
> +++ b/hw/i386/vmmouse.c
> @@ -72,7 +72,7 @@ struct VMMouseState {
>       ISAKBDState *i8042;
>   };
>   
> -static void vmmouse_get_data(uint32_t *data)
> +static void vmmouse_get_data(target_ulong *data)
>   {
>       X86CPU *cpu = X86_CPU(current_cpu);
>       CPUX86State *env = &cpu->env;
> @@ -82,7 +82,7 @@ static void vmmouse_get_data(uint32_t *data)
>       data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
>   }
>   
> -static void vmmouse_set_data(const uint32_t *data)
> +static void vmmouse_set_data(const target_ulong *data)
>   {
>       X86CPU *cpu = X86_CPU(current_cpu);
>       CPUX86State *env = &cpu->env;
> @@ -197,7 +197,7 @@ static void vmmouse_disable(VMMouseState *s)
>       vmmouse_remove_handler(s);
>   }
>   
> -static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
> +static void vmmouse_data(VMMouseState *s, target_ulong *data, uint32_t size)
>   {
>       int i;
>   
> @@ -221,7 +221,7 @@ static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
>   static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
>   {
>       VMMouseState *s = opaque;
> -    uint32_t data[6];
> +    target_ulong data[6];
>       uint16_t command;
>   
>       vmmouse_get_data(data);
> @@ -247,7 +247,7 @@ static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
>               vmmouse_request_absolute(s);
>               break;
>           default:
> -            printf("vmmouse: unknown command %x\n", data[1]);
> +            printf("vmmouse: unknown command " TARGET_FMT_lx "\n", data[1]);
>               break;
>           }
>           break;