The Hyper-V synthetic HID host supplies SYNTH_HID_INITIAL_DEVICE_INFO
messages that contain a HID descriptor followed by the report descriptor
bytes. mousevsc_on_receive_device_info() trusts bLength and
wDescriptorLength without checking that the received packet contains both
byte ranges.

A malformed host or backend message can therefore make the guest read
past the received VMBus packet while copying the report descriptor. Pass
the received initial-device-info size into the parser and reject
descriptor lengths that exceed the packet.

Impact: A malicious Hyper-V host or backend can crash a guest by sending
a short initial device-info message with an oversized HID report
descriptor length.

Fixes: b95f5bcb811e ("HID: Move the hid-hyperv driver out of staging")
Cc: [email protected]
Assisted-by: Codex:gpt-5-5-xhigh
Signed-off-by: Michael Bommarito <[email protected]>
---
 drivers/hid/hid-hyperv.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 7d2b0063df151..fd90196430e29 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -171,18 +171,32 @@ static void mousevsc_free_device(struct mousevsc_dev 
*device)
 }
 
 static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
-                               struct synthhid_device_info *device_info)
+                                           struct synthhid_device_info 
*device_info,
+                                           u32 device_info_size)
 {
        int ret = 0;
        struct hid_descriptor *desc;
        struct mousevsc_prt_msg ack;
+       size_t desc_offset;
+       size_t desc_size;
 
        input_device->dev_info_status = -ENOMEM;
 
+       if (device_info_size < sizeof(*device_info)) {
+               input_device->dev_info_status = -EINVAL;
+               goto cleanup;
+       }
+
        input_device->hid_dev_info = device_info->hid_dev_info;
        desc = &device_info->hid_descriptor;
+       desc_offset = offsetof(struct synthhid_device_info, hid_descriptor);
+       desc_size = device_info_size - desc_offset;
        if (desc->bLength == 0)
                goto cleanup;
+       if (desc->bLength < sizeof(*desc) || desc->bLength > desc_size) {
+               input_device->dev_info_status = -EINVAL;
+               goto cleanup;
+       }
 
        /* The pointer is not NULL when we resume from hibernation */
        kfree(input_device->hid_desc);
@@ -197,6 +211,10 @@ static void mousevsc_on_receive_device_info(struct 
mousevsc_dev *input_device,
                input_device->dev_info_status = -EINVAL;
                goto cleanup;
        }
+       if (input_device->report_desc_size > desc_size - desc->bLength) {
+               input_device->dev_info_status = -EINVAL;
+               goto cleanup;
+       }
 
        /* The pointer is not NULL when we resume from hibernation */
        kfree(input_device->report_desc);
@@ -273,14 +291,17 @@ static void mousevsc_on_receive(struct hv_device *device,
                break;
 
        case SYNTH_HID_INITIAL_DEVICE_INFO:
-               WARN_ON(pipe_msg->size < sizeof(struct hv_input_dev_info));
+               if (WARN_ON_ONCE(pipe_msg->size <
+                                sizeof(struct synthhid_device_info)))
+                       break;
 
                /*
                 * Parse out the device info into device attr,
                 * hid desc and report desc
                 */
                mousevsc_on_receive_device_info(input_dev,
-                       (struct synthhid_device_info *)pipe_msg->data);
+                                               (struct synthhid_device_info 
*)pipe_msg->data,
+                                               pipe_msg->size);
                break;
        case SYNTH_HID_INPUT_REPORT:
                input_report =
-- 
2.53.0

Reply via email to