* [PATCH 0/2] HID: hyperv: bound initial device info descriptor
@ 2026-07-10 2:28 Michael Bommarito
2026-07-10 2:28 ` [PATCH 1/2] HID: hyperv: validate initial device info bounds Michael Bommarito
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Michael Bommarito @ 2026-07-10 2:28 UTC (permalink / raw)
To: Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu
Cc: Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable
A malicious Hyper-V host or backend can crash a guest with a short
SYNTH_HID_INITIAL_DEVICE_INFO message. mousevsc_on_receive_device_info()
trusts the HID descriptor bLength and wDescriptorLength without checking
that the received VMBus packet actually contains both byte ranges, so a
truncated packet with an oversized report-descriptor length makes the
guest read past the received packet while copying the descriptor. This
matters most for a confidential guest, where the host is outside the trust
boundary.
Patch 1 passes the received initial-device-info size into the parser and
rejects descriptor lengths that exceed the packet. Patch 2 adds
same-translation-unit KUnit coverage: a well-formed message that must
still parse and the truncated/oversized message that must now be rejected.
Reproduced with the KUnit/KASAN test: stock reads past the packet on the
short message after the benign control passes; patched rejects it and both
cases pass.
Cc: stable@vger.kernel.org
Michael Bommarito (2):
HID: hyperv: validate initial device info bounds
HID: hyperv: add KUnit coverage for device info bounds
drivers/hid/Kconfig | 10 +++
drivers/hid/hid-hyperv.c | 144 ++++++++++++++++++++++++++++++++++++---
2 files changed, 144 insertions(+), 10 deletions(-)
--
2.53.0
^ permalink raw reply [flat|nested] 8+ messages in thread* [PATCH 1/2] HID: hyperv: validate initial device info bounds 2026-07-10 2:28 [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Bommarito @ 2026-07-10 2:28 ` Michael Bommarito 2026-07-10 2:28 ` [PATCH 2/2] HID: hyperv: add KUnit coverage for " Michael Bommarito ` (2 subsequent siblings) 3 siblings, 0 replies; 8+ messages in thread From: Michael Bommarito @ 2026-07-10 2:28 UTC (permalink / raw) To: Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu Cc: Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable 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: stable@vger.kernel.org Assisted-by: Codex:gpt-5-5-xhigh Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> --- 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 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH 2/2] HID: hyperv: add KUnit coverage for device info bounds 2026-07-10 2:28 [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Bommarito 2026-07-10 2:28 ` [PATCH 1/2] HID: hyperv: validate initial device info bounds Michael Bommarito @ 2026-07-10 2:28 ` Michael Bommarito 2026-08-31 12:40 ` David Laight 2026-08-31 16:41 ` Nico Pache (Red Hat) 2026-07-11 18:06 ` [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Kelley 2026-08-03 19:10 ` Jiri Kosina 3 siblings, 2 replies; 8+ messages in thread From: Michael Bommarito @ 2026-07-10 2:28 UTC (permalink / raw) To: Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu Cc: Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable Add KUnit coverage for Hyper-V synthetic HID initial device-info parsing. The tests cover zero bLength, a valid descriptor plus report descriptor, and a malformed report descriptor length that exceeds the received message. The same-translation-unit test uses a KUnit-only ACK bypass so parser coverage does not require a live VMBus channel. Assisted-by: Codex:gpt-5-5-xhigh Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> --- drivers/hid/Kconfig | 10 ++++ drivers/hid/hid-hyperv.c | 117 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 120 insertions(+), 7 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index c1d9f7c6a5f23..41ca48d9adc9e 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1183,6 +1183,16 @@ config HID_HYPERV_MOUSE help Select this option to enable the Hyper-V mouse driver. +config HID_HYPERV_MOUSE_KUNIT_TEST + bool "KUnit tests for Hyper-V mouse driver" if !KUNIT_ALL_TESTS + depends on KUNIT && HID_HYPERV_MOUSE + default KUNIT_ALL_TESTS + help + Builds unit tests for the Hyper-V synthetic HID driver. + These tests exercise the initial device-info parser with + malformed host-provided HID descriptors and are only useful + for kernel developers running KUnit. + config HID_SMARTJOYPLUS tristate "SmartJoy PLUS PS2/USB adapter support" help diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index fd90196430e29..6579bd19da13a 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -13,6 +13,9 @@ #include <linux/hiddev.h> #include <linux/hyperv.h> +#if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) +#include <kunit/test.h> +#endif struct hv_input_dev_info { unsigned int size; @@ -240,13 +243,18 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, ack.ack.header.size = 1; ack.ack.reserved = 0; - ret = vmbus_sendpacket(input_device->device->channel, - &ack, - sizeof(struct pipe_prt_msg) + - sizeof(struct synthhid_device_info_ack), - (unsigned long)&ack, - VM_PKT_DATA_INBAND, - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + if (IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) && + !input_device->device) { + ret = 0; + } else { + ret = vmbus_sendpacket(input_device->device->channel, + &ack, + sizeof(struct pipe_prt_msg) + + sizeof(struct synthhid_device_info_ack), + (unsigned long)&ack, + VM_PKT_DATA_INBAND, + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); + } if (!ret) input_device->dev_info_status = 0; @@ -635,5 +643,100 @@ static void __exit mousevsc_exit(void) MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver"); +#if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) +static struct mousevsc_dev *mousevsc_kunit_alloc_dev(struct kunit *test) +{ + struct mousevsc_dev *input_dev; + + input_dev = kunit_kzalloc(test, sizeof(*input_dev), GFP_KERNEL); + if (!input_dev) + return NULL; + + init_completion(&input_dev->wait_event); + + return input_dev; +} + +static void mousevsc_device_info_zero_blength(struct kunit *test) +{ + struct synthhid_device_info *info; + struct mousevsc_dev *input_dev; + + input_dev = mousevsc_kunit_alloc_dev(test); + KUNIT_ASSERT_NOT_NULL(test, input_dev); + info = kunit_kzalloc(test, sizeof(*info), GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, info); + + info->hid_descriptor.bLength = 0; + + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info)); + + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -ENOMEM); +} + +static void mousevsc_device_info_valid_descriptor(struct kunit *test) +{ + struct synthhid_device_info *info; + struct mousevsc_dev *input_dev; + u8 *report; + + input_dev = mousevsc_kunit_alloc_dev(test); + KUNIT_ASSERT_NOT_NULL(test, input_dev); + info = kunit_kzalloc(test, sizeof(*info) + 4, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, info); + + info->hid_descriptor.bLength = sizeof(struct hid_descriptor); + info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(4); + report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength; + memset(report, 0x42, 4); + + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 4); + + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, 0); + KUNIT_EXPECT_EQ(test, input_dev->report_desc_size, 4); + KUNIT_EXPECT_MEMEQ(test, input_dev->report_desc, report, 4); + + kfree(input_dev->hid_desc); + kfree(input_dev->report_desc); +} + +static void mousevsc_device_info_report_desc_oob(struct kunit *test) +{ + struct synthhid_device_info *info; + struct mousevsc_dev *input_dev; + u8 *report; + + input_dev = mousevsc_kunit_alloc_dev(test); + KUNIT_ASSERT_NOT_NULL(test, input_dev); + info = kunit_kzalloc(test, sizeof(*info) + 8, GFP_KERNEL); + KUNIT_ASSERT_NOT_NULL(test, info); + + info->hid_descriptor.bLength = sizeof(struct hid_descriptor); + info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(64); + report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength; + memset(report, 0x42, 8); + + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 8); + + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -EINVAL); + + kfree(input_dev->hid_desc); +} + +static struct kunit_case mousevsc_test_cases[] = { + KUNIT_CASE(mousevsc_device_info_zero_blength), + KUNIT_CASE(mousevsc_device_info_valid_descriptor), + KUNIT_CASE(mousevsc_device_info_report_desc_oob), + {} +}; + +static struct kunit_suite mousevsc_test_suite = { + .name = "hid_hyperv_mouse", + .test_cases = mousevsc_test_cases, +}; + +kunit_test_suite(mousevsc_test_suite); +#endif + module_init(mousevsc_init); module_exit(mousevsc_exit); -- 2.53.0 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] HID: hyperv: add KUnit coverage for device info bounds 2026-07-10 2:28 ` [PATCH 2/2] HID: hyperv: add KUnit coverage for " Michael Bommarito @ 2026-08-31 12:40 ` David Laight 2026-08-31 15:25 ` Michael Bommarito 2026-08-31 16:41 ` Nico Pache (Red Hat) 1 sibling, 1 reply; 8+ messages in thread From: David Laight @ 2026-08-31 12:40 UTC (permalink / raw) To: Michael Bommarito Cc: Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable On Thu, 9 Jul 2026 22:28:54 -0400 Michael Bommarito <michael.bommarito@gmail.com> wrote: > Add KUnit coverage for Hyper-V synthetic HID initial device-info parsing. > The tests cover zero bLength, a valid descriptor plus report descriptor, > and a malformed report descriptor length that exceeds the received > message. > > The same-translation-unit test uses a KUnit-only ACK bypass so parser > coverage does not require a live VMBus channel. Breaks build - see below. > > Assisted-by: Codex:gpt-5-5-xhigh > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> > --- > drivers/hid/Kconfig | 10 ++++ > drivers/hid/hid-hyperv.c | 117 ++++++++++++++++++++++++++++++++++++--- > 2 files changed, 120 insertions(+), 7 deletions(-) > > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index c1d9f7c6a5f23..41ca48d9adc9e 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -1183,6 +1183,16 @@ config HID_HYPERV_MOUSE > help > Select this option to enable the Hyper-V mouse driver. > > +config HID_HYPERV_MOUSE_KUNIT_TEST > + bool "KUnit tests for Hyper-V mouse driver" if !KUNIT_ALL_TESTS > + depends on KUNIT && HID_HYPERV_MOUSE > + default KUNIT_ALL_TESTS > + help > + Builds unit tests for the Hyper-V synthetic HID driver. > + These tests exercise the initial device-info parser with > + malformed host-provided HID descriptors and are only useful > + for kernel developers running KUnit. > + > config HID_SMARTJOYPLUS > tristate "SmartJoy PLUS PS2/USB adapter support" > help > diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c > index fd90196430e29..6579bd19da13a 100644 > --- a/drivers/hid/hid-hyperv.c > +++ b/drivers/hid/hid-hyperv.c > @@ -13,6 +13,9 @@ > #include <linux/hiddev.h> > #include <linux/hyperv.h> > > +#if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) > +#include <kunit/test.h> > +#endif > > struct hv_input_dev_info { > unsigned int size; > @@ -240,13 +243,18 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, > ack.ack.header.size = 1; > ack.ack.reserved = 0; > > - ret = vmbus_sendpacket(input_device->device->channel, > - &ack, > - sizeof(struct pipe_prt_msg) + > - sizeof(struct synthhid_device_info_ack), > - (unsigned long)&ack, > - VM_PKT_DATA_INBAND, > - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); > + if (IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) && > + !input_device->device) { > + ret = 0; > + } else { > + ret = vmbus_sendpacket(input_device->device->channel, > + &ack, > + sizeof(struct pipe_prt_msg) + > + sizeof(struct synthhid_device_info_ack), > + (unsigned long)&ack, > + VM_PKT_DATA_INBAND, > + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); > + } > > if (!ret) > input_device->dev_info_status = 0; > @@ -635,5 +643,100 @@ static void __exit mousevsc_exit(void) > MODULE_LICENSE("GPL"); > MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver"); > > +#if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) > +static struct mousevsc_dev *mousevsc_kunit_alloc_dev(struct kunit *test) > +{ > + struct mousevsc_dev *input_dev; > + > + input_dev = kunit_kzalloc(test, sizeof(*input_dev), GFP_KERNEL); > + if (!input_dev) > + return NULL; > + > + init_completion(&input_dev->wait_event); > + > + return input_dev; > +} > + > +static void mousevsc_device_info_zero_blength(struct kunit *test) > +{ > + struct synthhid_device_info *info; > + struct mousevsc_dev *input_dev; > + > + input_dev = mousevsc_kunit_alloc_dev(test); > + KUNIT_ASSERT_NOT_NULL(test, input_dev); > + info = kunit_kzalloc(test, sizeof(*info), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, info); > + > + info->hid_descriptor.bLength = 0; > + > + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info)); > + > + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -ENOMEM); > +} > + > +static void mousevsc_device_info_valid_descriptor(struct kunit *test) > +{ > + struct synthhid_device_info *info; > + struct mousevsc_dev *input_dev; > + u8 *report; > + > + input_dev = mousevsc_kunit_alloc_dev(test); > + KUNIT_ASSERT_NOT_NULL(test, input_dev); > + info = kunit_kzalloc(test, sizeof(*info) + 4, GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, info); > + > + info->hid_descriptor.bLength = sizeof(struct hid_descriptor); > + info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(4); > + report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength; > + memset(report, 0x42, 4); This has landed in rc1 and fails to build (with gcc 12.2) because the tests in fortify-string.h detect that is it writing beyond the end of the structure. > + > + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 4); > + > + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, 0); > + KUNIT_EXPECT_EQ(test, input_dev->report_desc_size, 4); > + KUNIT_EXPECT_MEMEQ(test, input_dev->report_desc, report, 4); > + > + kfree(input_dev->hid_desc); > + kfree(input_dev->report_desc); > +} > + > +static void mousevsc_device_info_report_desc_oob(struct kunit *test) > +{ > + struct synthhid_device_info *info; > + struct mousevsc_dev *input_dev; > + u8 *report; > + > + input_dev = mousevsc_kunit_alloc_dev(test); > + KUNIT_ASSERT_NOT_NULL(test, input_dev); > + info = kunit_kzalloc(test, sizeof(*info) + 8, GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, info); > + > + info->hid_descriptor.bLength = sizeof(struct hid_descriptor); > + info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(64); > + report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength; > + memset(report, 0x42, 8); Same here. David > + > + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 8); > + > + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -EINVAL); > + > + kfree(input_dev->hid_desc); > +} > + > +static struct kunit_case mousevsc_test_cases[] = { > + KUNIT_CASE(mousevsc_device_info_zero_blength), > + KUNIT_CASE(mousevsc_device_info_valid_descriptor), > + KUNIT_CASE(mousevsc_device_info_report_desc_oob), > + {} > +}; > + > +static struct kunit_suite mousevsc_test_suite = { > + .name = "hid_hyperv_mouse", > + .test_cases = mousevsc_test_cases, > +}; > + > +kunit_test_suite(mousevsc_test_suite); > +#endif > + > module_init(mousevsc_init); > module_exit(mousevsc_exit); ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] HID: hyperv: add KUnit coverage for device info bounds 2026-08-31 12:40 ` David Laight @ 2026-08-31 15:25 ` Michael Bommarito 0 siblings, 0 replies; 8+ messages in thread From: Michael Bommarito @ 2026-08-31 15:25 UTC (permalink / raw) To: David Laight Cc: Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable On Mon, Aug 31, 2026 at 8:40 AM David Laight <david.laight.linux@gmail.com> wrote: > This has landed in rc1 and fails to build (with gcc 12.2) because the tests > in fortify-string.h detect that is it writing beyond the end of the > structure. > module_exit(mousevsc_exit); I think Juergen and Jiri already found and fixed this, but it probably needs to get bumped up to for-linus sooner. Sorry again for missing this on the original series. Thanks, Mike ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 2/2] HID: hyperv: add KUnit coverage for device info bounds 2026-07-10 2:28 ` [PATCH 2/2] HID: hyperv: add KUnit coverage for " Michael Bommarito 2026-08-31 12:40 ` David Laight @ 2026-08-31 16:41 ` Nico Pache (Red Hat) 1 sibling, 0 replies; 8+ messages in thread From: Nico Pache (Red Hat) @ 2026-08-31 16:41 UTC (permalink / raw) To: Michael Bommarito, Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu Cc: Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable On 7/9/26 8:28 PM, Michael Bommarito wrote: > Add KUnit coverage for Hyper-V synthetic HID initial device-info parsing. > The tests cover zero bLength, a valid descriptor plus report descriptor, > and a malformed report descriptor length that exceeds the received > message. > > The same-translation-unit test uses a KUnit-only ACK bypass so parser > coverage does not require a live VMBus channel. > > Assisted-by: Codex:gpt-5-5-xhigh > Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com> > --- Hi this is breaking builds when compiling the kunit framework as modules. See below. > drivers/hid/Kconfig | 10 ++++ > drivers/hid/hid-hyperv.c | 117 ++++++++++++++++++++++++++++++++++++--- > 2 files changed, 120 insertions(+), 7 deletions(-) > > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index c1d9f7c6a5f23..41ca48d9adc9e 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -1183,6 +1183,16 @@ config HID_HYPERV_MOUSE > help > Select this option to enable the Hyper-V mouse driver. > > +config HID_HYPERV_MOUSE_KUNIT_TEST > + bool "KUnit tests for Hyper-V mouse driver" if !KUNIT_ALL_TESTS This should either be tristate (instead of bool) or... > + depends on KUNIT && HID_HYPERV_MOUSE ... this should be 'KUNIT=y' Im not familar with this test so I cant judge what is right. Can this test run as a module or does it have to be builtin? Cheers, -- Nico > + default KUNIT_ALL_TESTS > + help > + Builds unit tests for the Hyper-V synthetic HID driver. > + These tests exercise the initial device-info parser with > + malformed host-provided HID descriptors and are only useful > + for kernel developers running KUnit. > + > config HID_SMARTJOYPLUS > tristate "SmartJoy PLUS PS2/USB adapter support" > help > diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c > index fd90196430e29..6579bd19da13a 100644 > --- a/drivers/hid/hid-hyperv.c > +++ b/drivers/hid/hid-hyperv.c > @@ -13,6 +13,9 @@ > #include <linux/hiddev.h> > #include <linux/hyperv.h> > > +#if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) > +#include <kunit/test.h> > +#endif > > struct hv_input_dev_info { > unsigned int size; > @@ -240,13 +243,18 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device, > ack.ack.header.size = 1; > ack.ack.reserved = 0; > > - ret = vmbus_sendpacket(input_device->device->channel, > - &ack, > - sizeof(struct pipe_prt_msg) + > - sizeof(struct synthhid_device_info_ack), > - (unsigned long)&ack, > - VM_PKT_DATA_INBAND, > - VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); > + if (IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) && > + !input_device->device) { > + ret = 0; > + } else { > + ret = vmbus_sendpacket(input_device->device->channel, > + &ack, > + sizeof(struct pipe_prt_msg) + > + sizeof(struct synthhid_device_info_ack), > + (unsigned long)&ack, > + VM_PKT_DATA_INBAND, > + VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED); > + } > > if (!ret) > input_device->dev_info_status = 0; > @@ -635,5 +643,100 @@ static void __exit mousevsc_exit(void) > MODULE_LICENSE("GPL"); > MODULE_DESCRIPTION("Microsoft Hyper-V Synthetic HID Driver"); > > +#if IS_ENABLED(CONFIG_HID_HYPERV_MOUSE_KUNIT_TEST) > +static struct mousevsc_dev *mousevsc_kunit_alloc_dev(struct kunit *test) > +{ > + struct mousevsc_dev *input_dev; > + > + input_dev = kunit_kzalloc(test, sizeof(*input_dev), GFP_KERNEL); > + if (!input_dev) > + return NULL; > + > + init_completion(&input_dev->wait_event); > + > + return input_dev; > +} > + > +static void mousevsc_device_info_zero_blength(struct kunit *test) > +{ > + struct synthhid_device_info *info; > + struct mousevsc_dev *input_dev; > + > + input_dev = mousevsc_kunit_alloc_dev(test); > + KUNIT_ASSERT_NOT_NULL(test, input_dev); > + info = kunit_kzalloc(test, sizeof(*info), GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, info); > + > + info->hid_descriptor.bLength = 0; > + > + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info)); > + > + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -ENOMEM); > +} > + > +static void mousevsc_device_info_valid_descriptor(struct kunit *test) > +{ > + struct synthhid_device_info *info; > + struct mousevsc_dev *input_dev; > + u8 *report; > + > + input_dev = mousevsc_kunit_alloc_dev(test); > + KUNIT_ASSERT_NOT_NULL(test, input_dev); > + info = kunit_kzalloc(test, sizeof(*info) + 4, GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, info); > + > + info->hid_descriptor.bLength = sizeof(struct hid_descriptor); > + info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(4); > + report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength; > + memset(report, 0x42, 4); > + > + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 4); > + > + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, 0); > + KUNIT_EXPECT_EQ(test, input_dev->report_desc_size, 4); > + KUNIT_EXPECT_MEMEQ(test, input_dev->report_desc, report, 4); > + > + kfree(input_dev->hid_desc); > + kfree(input_dev->report_desc); > +} > + > +static void mousevsc_device_info_report_desc_oob(struct kunit *test) > +{ > + struct synthhid_device_info *info; > + struct mousevsc_dev *input_dev; > + u8 *report; > + > + input_dev = mousevsc_kunit_alloc_dev(test); > + KUNIT_ASSERT_NOT_NULL(test, input_dev); > + info = kunit_kzalloc(test, sizeof(*info) + 8, GFP_KERNEL); > + KUNIT_ASSERT_NOT_NULL(test, info); > + > + info->hid_descriptor.bLength = sizeof(struct hid_descriptor); > + info->hid_descriptor.rpt_desc.wDescriptorLength = cpu_to_le16(64); > + report = ((u8 *)&info->hid_descriptor) + info->hid_descriptor.bLength; > + memset(report, 0x42, 8); > + > + mousevsc_on_receive_device_info(input_dev, info, sizeof(*info) + 8); > + > + KUNIT_EXPECT_EQ(test, input_dev->dev_info_status, -EINVAL); > + > + kfree(input_dev->hid_desc); > +} > + > +static struct kunit_case mousevsc_test_cases[] = { > + KUNIT_CASE(mousevsc_device_info_zero_blength), > + KUNIT_CASE(mousevsc_device_info_valid_descriptor), > + KUNIT_CASE(mousevsc_device_info_report_desc_oob), > + {} > +}; > + > +static struct kunit_suite mousevsc_test_suite = { > + .name = "hid_hyperv_mouse", > + .test_cases = mousevsc_test_cases, > +}; > + > +kunit_test_suite(mousevsc_test_suite); > +#endif > + > module_init(mousevsc_init); > module_exit(mousevsc_exit); ^ permalink raw reply [flat|nested] 8+ messages in thread
* RE: [PATCH 0/2] HID: hyperv: bound initial device info descriptor 2026-07-10 2:28 [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Bommarito 2026-07-10 2:28 ` [PATCH 1/2] HID: hyperv: validate initial device info bounds Michael Bommarito 2026-07-10 2:28 ` [PATCH 2/2] HID: hyperv: add KUnit coverage for " Michael Bommarito @ 2026-07-11 18:06 ` Michael Kelley 2026-08-03 19:10 ` Jiri Kosina 3 siblings, 0 replies; 8+ messages in thread From: Michael Kelley @ 2026-07-11 18:06 UTC (permalink / raw) To: Michael Bommarito, Jiri Kosina, Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu Cc: Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable From: Michael Bommarito <michael.bommarito@gmail.com> Sent: Thursday, July 9, 2026 7:29 PM > > A malicious Hyper-V host or backend can crash a guest with a short > SYNTH_HID_INITIAL_DEVICE_INFO message. mousevsc_on_receive_device_info() > trusts the HID descriptor bLength and wDescriptorLength without checking > that the received VMBus packet actually contains both byte ranges, so a > truncated packet with an oversized report-descriptor length makes the > guest read past the received packet while copying the descriptor. This > matters most for a confidential guest, where the host is outside the trust > boundary. For some additional background on the assumed threat model that underlies this kind of validation (and lack thereof), see [1]. This Hyper-V mouse driver has .allowed_in_isolated set to "false", so it is never loaded in a CoCo VM. In normal VMs, the threat model says that we trust the Hyper-V host not to provide bad values. But as I said in [1], I'm good with taking additional validations. But Wei Liu as the maintainer for the Hyper-V drivers is the person who should decide whether we want to take additional validations. If we take these additional validations, there's a separate question of whether to backport them to stable kernels. I'm inclined to *not* backport to avoid introducing churn (and the risk of breaking something) when it isn't fixing an observed or likely-to-happen problem. But Wei Liu should probably weigh in on that as well. [1] https://lore.kernel.org/linux-hyperv/SN6PR02MB4157D595B990A321BFA85B40D4002@SN6PR02MB4157.namprd02.prod.outlook.com/ Michael > > Patch 1 passes the received initial-device-info size into the parser and > rejects descriptor lengths that exceed the packet. Patch 2 adds > same-translation-unit KUnit coverage: a well-formed message that must > still parse and the truncated/oversized message that must now be rejected. > > Reproduced with the KUnit/KASAN test: stock reads past the packet on the > short message after the benign control passes; patched rejects it and both > cases pass. > > Cc: stable@vger.kernel.org > > Michael Bommarito (2): > HID: hyperv: validate initial device info bounds > HID: hyperv: add KUnit coverage for device info bounds > > drivers/hid/Kconfig | 10 +++ > drivers/hid/hid-hyperv.c | 144 ++++++++++++++++++++++++++++++++++++--- > 2 files changed, 144 insertions(+), 10 deletions(-) > > -- > 2.53.0 ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH 0/2] HID: hyperv: bound initial device info descriptor 2026-07-10 2:28 [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Bommarito ` (2 preceding siblings ...) 2026-07-11 18:06 ` [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Kelley @ 2026-08-03 19:10 ` Jiri Kosina 3 siblings, 0 replies; 8+ messages in thread From: Jiri Kosina @ 2026-08-03 19:10 UTC (permalink / raw) To: Michael Bommarito Cc: Benjamin Tissoires, kys, Haiyang Zhang, Wei Liu, Dexuan Cui, Long Li, linux-input, linux-hyperv, linux-kernel, stable On Thu, 9 Jul 2026, Michael Bommarito wrote: > A malicious Hyper-V host or backend can crash a guest with a short > SYNTH_HID_INITIAL_DEVICE_INFO message. mousevsc_on_receive_device_info() > trusts the HID descriptor bLength and wDescriptorLength without checking > that the received VMBus packet actually contains both byte ranges, so a > truncated packet with an oversized report-descriptor length makes the > guest read past the received packet while copying the descriptor. This > matters most for a confidential guest, where the host is outside the trust > boundary. Well, untrusted host can crash the (confidential) guest in various other ways. Anyway, the sanitization is good, so I've now applied it. Thanks, -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2026-08-31 16:42 UTC | newest] Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-07-10 2:28 [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Bommarito 2026-07-10 2:28 ` [PATCH 1/2] HID: hyperv: validate initial device info bounds Michael Bommarito 2026-07-10 2:28 ` [PATCH 2/2] HID: hyperv: add KUnit coverage for " Michael Bommarito 2026-08-31 12:40 ` David Laight 2026-08-31 15:25 ` Michael Bommarito 2026-08-31 16:41 ` Nico Pache (Red Hat) 2026-07-11 18:06 ` [PATCH 0/2] HID: hyperv: bound initial device info descriptor Michael Kelley 2026-08-03 19:10 ` Jiri Kosina
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®