* [PATCH 1/4] virtio-mem: validate device-reported block size
2026-07-15 14:22 [PATCH 0/4] virtio: validate device-reported values across drivers Hari Mishal
@ 2026-07-15 14:22 ` Hari Mishal
2026-07-15 15:57 ` Michael S. Tsirkin
2026-07-15 16:41 ` [PATCH v2 " Hari Mishal
2026-07-15 14:22 ` [PATCH 2/4] virtio_input: validate device-reported multitouch slot count Hari Mishal
` (2 subsequent siblings)
3 siblings, 2 replies; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 14:22 UTC (permalink / raw)
To: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Michael S . Tsirkin, Jason Wang, David Hildenbrand,
Henrik Rydberg
Cc: Xuan Zhuo, Eugenio Pérez, virtualization, linux-kernel,
linux-input, Hari Mishal
The device_block_size read from the virtio-mem config space is used
as a divisor and also in ALIGN_DOWN() further down the code path in
the driver without further validation. A zero value leads to a division
by zero, and a non-power-of-two value corrupts the ALIGN_DOWN() bitmask
arithmetic leading to a misreporting of guest usable guest ram, post
crash. Reject both at init time instead of trusting the device.
Assisted-by: gkh_clanker:t1000
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
drivers/virtio/virtio_mem.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
index 11c441501582..43d12ec7c323 100644
--- a/drivers/virtio/virtio_mem.c
+++ b/drivers/virtio/virtio_mem.c
@@ -2847,6 +2847,13 @@ static int virtio_mem_init(struct virtio_mem *vm)
&vm->plugged_size);
virtio_cread_le(vm->vdev, struct virtio_mem_config, block_size,
&vm->device_block_size);
+ if (!vm->device_block_size ||
+ !is_power_of_2(vm->device_block_size)) {
+ dev_err(&vm->vdev->dev,
+ "invalid device block size: 0x%llx\n",
+ (unsigned long long)vm->device_block_size);
+ return -EINVAL;
+ }
virtio_cread_le(vm->vdev, struct virtio_mem_config, node_id,
&node_id);
vm->nid = virtio_mem_translate_node_id(vm, node_id);
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 1/4] virtio-mem: validate device-reported block size
2026-07-15 14:22 ` [PATCH 1/4] virtio-mem: validate device-reported block size Hari Mishal
@ 2026-07-15 15:57 ` Michael S. Tsirkin
2026-07-15 16:41 ` [PATCH v2 " Hari Mishal
1 sibling, 0 replies; 16+ messages in thread
From: Michael S. Tsirkin @ 2026-07-15 15:57 UTC (permalink / raw)
To: Hari Mishal
Cc: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Jason Wang, David Hildenbrand, Henrik Rydberg, Xuan Zhuo,
Eugenio Pérez, virtualization, linux-kernel, linux-input
On Wed, Jul 15, 2026 at 04:22:40PM +0200, Hari Mishal wrote:
> The device_block_size read from the virtio-mem config space is used
> as a divisor and also in ALIGN_DOWN() further down the code path in
> the driver without further validation. A zero value leads to a division
> by zero, and a non-power-of-two value corrupts the ALIGN_DOWN() bitmask
> arithmetic leading to a misreporting of guest usable guest ram, post
> crash. Reject both at init time instead of trusting the device.
>
> Assisted-by: gkh_clanker:t1000
> Signed-off-by: Hari Mishal <harimishal1@gmail.com>
> ---
> drivers/virtio/virtio_mem.c | 7 +++++++
> 1 file changed, 7 insertions(+)
>
> diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
> index 11c441501582..43d12ec7c323 100644
> --- a/drivers/virtio/virtio_mem.c
> +++ b/drivers/virtio/virtio_mem.c
> @@ -2847,6 +2847,13 @@ static int virtio_mem_init(struct virtio_mem *vm)
> &vm->plugged_size);
> virtio_cread_le(vm->vdev, struct virtio_mem_config, block_size,
> &vm->device_block_size);
> + if (!vm->device_block_size ||
> + !is_power_of_2(vm->device_block_size)) {
0 is not a power of 2, why do we need to check twice?
> + dev_err(&vm->vdev->dev,
> + "invalid device block size: 0x%llx\n",
> + (unsigned long long)vm->device_block_size);
> + return -EINVAL;
> + }
> virtio_cread_le(vm->vdev, struct virtio_mem_config, node_id,
> &node_id);
> vm->nid = virtio_mem_translate_node_id(vm, node_id);
> --
> 2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread* [PATCH v2 1/4] virtio-mem: validate device-reported block size
2026-07-15 14:22 ` [PATCH 1/4] virtio-mem: validate device-reported block size Hari Mishal
2026-07-15 15:57 ` Michael S. Tsirkin
@ 2026-07-15 16:41 ` Hari Mishal
2026-07-16 8:55 ` David Hildenbrand (Arm)
1 sibling, 1 reply; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 16:41 UTC (permalink / raw)
To: David Hildenbrand, Michael S . Tsirkin, Jason Wang
Cc: Greg Kroah-Hartman, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel, Hari Mishal
The device_block_size read from the virtio-mem config space is used as a
divisor and also in ALIGN_DOWN() further down the code path in the
driver without further validation. A zero value leads to a division by
zero, and a non-power-of-two value corrupts the ALIGN_DOWN() bitmask
arithmetic leading to a misreporting of guest-usable ram, post crash.
Reject both at init time instead of trusting the device.
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
v2: dropped the redundant explicit zero check, since
is_power_of_2(0) already returns false.
drivers/virtio/virtio_mem.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
index 11c441501582..0e04fec458af 100644
--- a/drivers/virtio/virtio_mem.c
+++ b/drivers/virtio/virtio_mem.c
@@ -2847,6 +2847,12 @@ static int virtio_mem_init(struct virtio_mem *vm)
&vm->plugged_size);
virtio_cread_le(vm->vdev, struct virtio_mem_config, block_size,
&vm->device_block_size);
+ if (!is_power_of_2(vm->device_block_size)) {
+ dev_err(&vm->vdev->dev,
+ "invalid device block size: 0x%llx\n",
+ (unsigned long long)vm->device_block_size);
+ return -EINVAL;
+ }
virtio_cread_le(vm->vdev, struct virtio_mem_config, node_id,
&node_id);
vm->nid = virtio_mem_translate_node_id(vm, node_id);
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/4] virtio-mem: validate device-reported block size
2026-07-15 16:41 ` [PATCH v2 " Hari Mishal
@ 2026-07-16 8:55 ` David Hildenbrand (Arm)
2026-07-16 14:18 ` Greg Kroah-Hartman
0 siblings, 1 reply; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-07-16 8:55 UTC (permalink / raw)
To: Hari Mishal, Michael S . Tsirkin, Jason Wang
Cc: Greg Kroah-Hartman, Xuan Zhuo, Eugenio Pérez, virtualization,
linux-kernel
On 7/15/26 18:41, Hari Mishal wrote:
> The device_block_size read from the virtio-mem config space is used as a
> divisor and also in ALIGN_DOWN() further down the code path in the
> driver without further validation. A zero value leads to a division by
> zero, and a non-power-of-two value corrupts the ALIGN_DOWN() bitmask
> arithmetic leading to a misreporting of guest-usable ram, post crash.
>
> Reject both at init time instead of trusting the device.
>
> Signed-off-by: Hari Mishal <harimishal1@gmail.com>
> ---
> v2: dropped the redundant explicit zero check, since
> is_power_of_2(0) already returns false.
>
> drivers/virtio/virtio_mem.c | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
> index 11c441501582..0e04fec458af 100644
> --- a/drivers/virtio/virtio_mem.c
> +++ b/drivers/virtio/virtio_mem.c
> @@ -2847,6 +2847,12 @@ static int virtio_mem_init(struct virtio_mem *vm)
> &vm->plugged_size);
> virtio_cread_le(vm->vdev, struct virtio_mem_config, block_size,
> &vm->device_block_size);
> + if (!is_power_of_2(vm->device_block_size)) {
> + dev_err(&vm->vdev->dev,
> + "invalid device block size: 0x%llx\n",
> + (unsigned long long)vm->device_block_size);
> + return -EINVAL;
> + }
The spec states "The device MUST set block_size to a power of two."
I'm missing the point here.
--
Cheers,
David
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/4] virtio-mem: validate device-reported block size
2026-07-16 8:55 ` David Hildenbrand (Arm)
@ 2026-07-16 14:18 ` Greg Kroah-Hartman
2026-07-16 15:59 ` David Hildenbrand (Arm)
0 siblings, 1 reply; 16+ messages in thread
From: Greg Kroah-Hartman @ 2026-07-16 14:18 UTC (permalink / raw)
To: David Hildenbrand (Arm)
Cc: Hari Mishal, Michael S . Tsirkin, Jason Wang, Xuan Zhuo,
Eugenio Pérez, virtualization, linux-kernel
On Thu, Jul 16, 2026 at 10:55:42AM +0200, David Hildenbrand (Arm) wrote:
> On 7/15/26 18:41, Hari Mishal wrote:
> > The device_block_size read from the virtio-mem config space is used as a
> > divisor and also in ALIGN_DOWN() further down the code path in the
> > driver without further validation. A zero value leads to a division by
> > zero, and a non-power-of-two value corrupts the ALIGN_DOWN() bitmask
> > arithmetic leading to a misreporting of guest-usable ram, post crash.
> >
> > Reject both at init time instead of trusting the device.
> >
> > Signed-off-by: Hari Mishal <harimishal1@gmail.com>
> > ---
> > v2: dropped the redundant explicit zero check, since
> > is_power_of_2(0) already returns false.
> >
> > drivers/virtio/virtio_mem.c | 6 ++++++
> > 1 file changed, 6 insertions(+)
> >
> > diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
> > index 11c441501582..0e04fec458af 100644
> > --- a/drivers/virtio/virtio_mem.c
> > +++ b/drivers/virtio/virtio_mem.c
> > @@ -2847,6 +2847,12 @@ static int virtio_mem_init(struct virtio_mem *vm)
> > &vm->plugged_size);
> > virtio_cread_le(vm->vdev, struct virtio_mem_config, block_size,
> > &vm->device_block_size);
> > + if (!is_power_of_2(vm->device_block_size)) {
> > + dev_err(&vm->vdev->dev,
> > + "invalid device block size: 0x%llx\n",
> > + (unsigned long long)vm->device_block_size);
> > + return -EINVAL;
> > + }
>
> The spec states "The device MUST set block_size to a power of two."
>
> I'm missing the point here.
So what happens if we have a non-spec-compliant device? Shouldn't we be
attempting to verify this before doing something with the data?
Or do we just always trust virtio mem devices explicitly?
thanks,
greg k-h
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH v2 1/4] virtio-mem: validate device-reported block size
2026-07-16 14:18 ` Greg Kroah-Hartman
@ 2026-07-16 15:59 ` David Hildenbrand (Arm)
0 siblings, 0 replies; 16+ messages in thread
From: David Hildenbrand (Arm) @ 2026-07-16 15:59 UTC (permalink / raw)
To: Greg Kroah-Hartman
Cc: Hari Mishal, Michael S . Tsirkin, Jason Wang, Xuan Zhuo,
Eugenio Pérez, virtualization, linux-kernel
On 7/16/26 16:18, Greg Kroah-Hartman wrote:
> On Thu, Jul 16, 2026 at 10:55:42AM +0200, David Hildenbrand (Arm) wrote:
>> On 7/15/26 18:41, Hari Mishal wrote:
>>> The device_block_size read from the virtio-mem config space is used as a
>>> divisor and also in ALIGN_DOWN() further down the code path in the
>>> driver without further validation. A zero value leads to a division by
>>> zero, and a non-power-of-two value corrupts the ALIGN_DOWN() bitmask
>>> arithmetic leading to a misreporting of guest-usable ram, post crash.
>>>
>>> Reject both at init time instead of trusting the device.
>>>
>>> Signed-off-by: Hari Mishal <harimishal1@gmail.com>
>>> ---
>>> v2: dropped the redundant explicit zero check, since
>>> is_power_of_2(0) already returns false.
>>>
>>> drivers/virtio/virtio_mem.c | 6 ++++++
>>> 1 file changed, 6 insertions(+)
>>>
>>> diff --git a/drivers/virtio/virtio_mem.c b/drivers/virtio/virtio_mem.c
>>> index 11c441501582..0e04fec458af 100644
>>> --- a/drivers/virtio/virtio_mem.c
>>> +++ b/drivers/virtio/virtio_mem.c
>>> @@ -2847,6 +2847,12 @@ static int virtio_mem_init(struct virtio_mem *vm)
>>> &vm->plugged_size);
>>> virtio_cread_le(vm->vdev, struct virtio_mem_config, block_size,
>>> &vm->device_block_size);
>>> + if (!is_power_of_2(vm->device_block_size)) {
>>> + dev_err(&vm->vdev->dev,
>>> + "invalid device block size: 0x%llx\n",
>>> + (unsigned long long)vm->device_block_size);
>>> + return -EINVAL;
>>> + }
>>
>> The spec states "The device MUST set block_size to a power of two."
>>
>> I'm missing the point here.
>
> So what happens if we have a non-spec-compliant device? Shouldn't we be
> attempting to verify this before doing something with the data?
The problem I see is that there are plenty of other devices where a
non-compliant device might cause problems.
Like, we request to hotplug some memory block and our device ACKs it, but it
simply didn't do that.
Or we request to hotunplug a memory block and instead it hotplugs some random
other memory block.
Or we sense whether a memory block is plugged and the device lies to us.
>
> Or do we just always trust virtio mem devices explicitly?
It's hard for me to understand where we draw the line, really.
But maybe MST can clarify what we care about in virtio world where the
hypervisor is fully in charge of the device,
--
Cheers,
David
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH 2/4] virtio_input: validate device-reported multitouch slot count
2026-07-15 14:22 [PATCH 0/4] virtio: validate device-reported values across drivers Hari Mishal
2026-07-15 14:22 ` [PATCH 1/4] virtio-mem: validate device-reported block size Hari Mishal
@ 2026-07-15 14:22 ` Hari Mishal
2026-07-15 15:50 ` Michael S. Tsirkin
2026-07-15 16:41 ` [PATCH v2 " Hari Mishal
2026-07-15 14:22 ` [PATCH 3/4] virtio_console: avoid NULL portdev dereference in in_intr() Hari Mishal
2026-07-15 14:22 ` [PATCH 4/4] virtio_console: take a kref in find_port_by_vq() to fix port UAF Hari Mishal
3 siblings, 2 replies; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 14:22 UTC (permalink / raw)
To: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Michael S . Tsirkin, Jason Wang, David Hildenbrand,
Henrik Rydberg
Cc: Xuan Zhuo, Eugenio Pérez, virtualization, linux-kernel,
linux-input, Hari Mishal
nslots is derived from the ABS_MT_SLOT maximum reported by the
virtio device. A device could report a bogus maximum (e.g. -1)
making nslots = 0, which input_mt_init_slots() does not reject;
it returns success without allocating any slot storage, silently
leaving the device registered as multitouch capable with no
backing state. Reject non-positive slot counts before calling
input_mt_init_slots().
Assisted-by: gkh_clanker:t1000
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
drivers/virtio/virtio_input.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
index deec24e8e682..2cc19782cdd3 100644
--- a/drivers/virtio/virtio_input.c
+++ b/drivers/virtio/virtio_input.c
@@ -312,6 +312,10 @@ static int virtinput_probe(struct virtio_device *vdev)
if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) {
nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1;
+ if (nslots <= 0) {
+ err = -EINVAL;
+ goto err_mt_init_slots;
+ }
err = input_mt_init_slots(vi->idev, nslots, 0);
if (err)
goto err_mt_init_slots;
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* Re: [PATCH 2/4] virtio_input: validate device-reported multitouch slot count
2026-07-15 14:22 ` [PATCH 2/4] virtio_input: validate device-reported multitouch slot count Hari Mishal
@ 2026-07-15 15:50 ` Michael S. Tsirkin
2026-07-15 16:07 ` Hari Mishal
2026-07-15 16:41 ` [PATCH v2 " Hari Mishal
1 sibling, 1 reply; 16+ messages in thread
From: Michael S. Tsirkin @ 2026-07-15 15:50 UTC (permalink / raw)
To: Hari Mishal
Cc: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Jason Wang, David Hildenbrand, Henrik Rydberg, Xuan Zhuo,
Eugenio Pérez, virtualization, linux-kernel, linux-input
On Wed, Jul 15, 2026 at 04:22:41PM +0200, Hari Mishal wrote:
> nslots is derived from the ABS_MT_SLOT maximum reported by the
> virtio device. A device could report a bogus maximum (e.g. -1)
> making nslots = 0, which input_mt_init_slots() does not reject;
> it returns success without allocating any slot storage, silently
> leaving the device registered as multitouch capable with no
> backing state.
So let's disable multitouch instead?
> Reject non-positive slot counts before calling
> input_mt_init_slots().
>
> Assisted-by: gkh_clanker:t1000
> Signed-off-by: Hari Mishal <harimishal1@gmail.com>
> ---
> drivers/virtio/virtio_input.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
> index deec24e8e682..2cc19782cdd3 100644
> --- a/drivers/virtio/virtio_input.c
> +++ b/drivers/virtio/virtio_input.c
> @@ -312,6 +312,10 @@ static int virtinput_probe(struct virtio_device *vdev)
>
> if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) {
> nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1;
> + if (nslots <= 0) {
> + err = -EINVAL;
> + goto err_mt_init_slots;
> + }
> err = input_mt_init_slots(vi->idev, nslots, 0);
> if (err)
> goto err_mt_init_slots;
> --
> 2.43.0
^ permalink raw reply [flat|nested] 16+ messages in thread* Re: [PATCH 2/4] virtio_input: validate device-reported multitouch slot count
2026-07-15 15:50 ` Michael S. Tsirkin
@ 2026-07-15 16:07 ` Hari Mishal
2026-07-15 16:11 ` Michael S. Tsirkin
0 siblings, 1 reply; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 16:07 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Jason Wang, David Hildenbrand, Henrik Rydberg, Xuan Zhuo,
Eugenio Pérez, virtualization, linux-kernel, linux-input
On Wed, Jul 15, 2026 at 5:50 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Wed, Jul 15, 2026 at 04:22:41PM +0200, Hari Mishal wrote:
> > nslots is derived from the ABS_MT_SLOT maximum reported by the
> > virtio device. A device could report a bogus maximum (e.g. -1)
> > making nslots = 0, which input_mt_init_slots() does not reject;
> > it returns success without allocating any slot storage, silently
> > leaving the device registered as multitouch capable with no
> > backing state.
>
> So let's disable multitouch instead?
>
So rather than failing the whole probe, just warn and clear
ABS_MT_SLOT from absbit in that case, so the rest of the device
still registers? I took my lead from input_mt_init_slots(), which
has its own internal cap and returns -EINVAL when the device
reports more than 1024 slots.
Shall I modify that case to get the same "warn and disable
multitouch" for consistency, or is a hard failure better there since
it's a different type of bad device data?
Happy to fix it either way! Just want to confirm before sending V2.
Cheers,
Hari
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/4] virtio_input: validate device-reported multitouch slot count
2026-07-15 16:07 ` Hari Mishal
@ 2026-07-15 16:11 ` Michael S. Tsirkin
2026-07-15 18:25 ` Dmitry Torokhov
0 siblings, 1 reply; 16+ messages in thread
From: Michael S. Tsirkin @ 2026-07-15 16:11 UTC (permalink / raw)
To: Hari Mishal
Cc: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Jason Wang, David Hildenbrand, Henrik Rydberg, Xuan Zhuo,
Eugenio Pérez, virtualization, linux-kernel, linux-input
On Wed, Jul 15, 2026 at 06:07:56PM +0200, Hari Mishal wrote:
> On Wed, Jul 15, 2026 at 5:50 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > On Wed, Jul 15, 2026 at 04:22:41PM +0200, Hari Mishal wrote:
> > > nslots is derived from the ABS_MT_SLOT maximum reported by the
> > > virtio device. A device could report a bogus maximum (e.g. -1)
> > > making nslots = 0, which input_mt_init_slots() does not reject;
> > > it returns success without allocating any slot storage, silently
> > > leaving the device registered as multitouch capable with no
> > > backing state.
> >
> > So let's disable multitouch instead?
> >
>
> So rather than failing the whole probe, just warn and clear
> ABS_MT_SLOT from absbit in that case, so the rest of the device
> still registers? I took my lead from input_mt_init_slots(), which
> has its own internal cap and returns -EINVAL when the device
> reports more than 1024 slots.
> Shall I modify that case to get the same "warn and disable
> multitouch" for consistency, or is a hard failure better there since
> it's a different type of bad device data?
I don't really know enough for sure but generally if the device can
kinda work it's better than not working, and adding
a capability to a device that driver can't use should
generally just ignore the capability, not fail probe.
> Happy to fix it either way! Just want to confirm before sending V2.
>
> Cheers,
> Hari
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH 2/4] virtio_input: validate device-reported multitouch slot count
2026-07-15 16:11 ` Michael S. Tsirkin
@ 2026-07-15 18:25 ` Dmitry Torokhov
0 siblings, 0 replies; 16+ messages in thread
From: Dmitry Torokhov @ 2026-07-15 18:25 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: Hari Mishal, Amit Shah, Arnd Bergmann, Greg Kroah-Hartman,
Gerd Hoffmann, Jason Wang, David Hildenbrand, Henrik Rydberg,
Xuan Zhuo, Eugenio Pérez, virtualization, linux-kernel,
linux-input
On Wed, Jul 15, 2026 at 12:11:12PM -0400, Michael S. Tsirkin wrote:
> On Wed, Jul 15, 2026 at 06:07:56PM +0200, Hari Mishal wrote:
> > On Wed, Jul 15, 2026 at 5:50 PM Michael S. Tsirkin <mst@redhat.com> wrote:
> > >
> > > On Wed, Jul 15, 2026 at 04:22:41PM +0200, Hari Mishal wrote:
> > > > nslots is derived from the ABS_MT_SLOT maximum reported by the
> > > > virtio device. A device could report a bogus maximum (e.g. -1)
> > > > making nslots = 0, which input_mt_init_slots() does not reject;
> > > > it returns success without allocating any slot storage, silently
> > > > leaving the device registered as multitouch capable with no
> > > > backing state.
> > >
> > > So let's disable multitouch instead?
> > >
> >
> > So rather than failing the whole probe, just warn and clear
> > ABS_MT_SLOT from absbit in that case, so the rest of the device
> > still registers? I took my lead from input_mt_init_slots(), which
> > has its own internal cap and returns -EINVAL when the device
> > reports more than 1024 slots.
> > Shall I modify that case to get the same "warn and disable
> > multitouch" for consistency, or is a hard failure better there since
> > it's a different type of bad device data?
>
> I don't really know enough for sure but generally if the device can
> kinda work it's better than not working, and adding
> a capability to a device that driver can't use should
> generally just ignore the capability, not fail probe.
What is the failure mode if we keep the ABS_MT_SLOT capability? Does the
kernel crash? And if this can cause crash then we should fix
input_mt_init_slots() to reject requests for 0 slots with -EINVAL.
Thanks.
--
Dmitry
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 2/4] virtio_input: validate device-reported multitouch slot count
2026-07-15 14:22 ` [PATCH 2/4] virtio_input: validate device-reported multitouch slot count Hari Mishal
2026-07-15 15:50 ` Michael S. Tsirkin
@ 2026-07-15 16:41 ` Hari Mishal
1 sibling, 0 replies; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 16:41 UTC (permalink / raw)
To: Gerd Hoffmann, Michael S . Tsirkin, Jason Wang
Cc: Greg Kroah-Hartman, Xuan Zhuo, Eugenio Pérez, Henrik Rydberg,
virtualization, linux-kernel, linux-input, Hari Mishal
nslots is derived from the ABS_MT_SLOT maximum reported by the virtio
device. A device could report a bogus maximum (e.g. -1) making nslots <=
0, and input_mt_init_slots() can independently fail too (e.g. it rejects
slot counts over 1024). Neither case was handled here, and
input_mt_init_slots() failing took down the whole probe, losing the rest
of the input device over a problem isolated to multitouch.
Instead of failing the probe, warn and disable the ABS_MT_SLOT
capability in either case, and let the rest of the device register
normally. This recovery assumes input_mt_init_slots() is called with
flags == 0: with nonzero flags it can fail after already mutating the
input_dev (e.g. via input_set_abs_params()), which this recovery does
not account for.
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
v2: per review, disable multitouch instead of failing the whole
probe when the reported slot count is invalid or
input_mt_init_slots() otherwise fails.
drivers/virtio/virtio_input.c | 23 +++++++++++++++++++----
1 file changed, 19 insertions(+), 4 deletions(-)
diff --git a/drivers/virtio/virtio_input.c b/drivers/virtio/virtio_input.c
index deec24e8e682..786f5150724f 100644
--- a/drivers/virtio/virtio_input.c
+++ b/drivers/virtio/virtio_input.c
@@ -312,9 +312,25 @@ static int virtinput_probe(struct virtio_device *vdev)
if (test_bit(ABS_MT_SLOT, vi->idev->absbit)) {
nslots = input_abs_get_max(vi->idev, ABS_MT_SLOT) + 1;
- err = input_mt_init_slots(vi->idev, nslots, 0);
- if (err)
- goto err_mt_init_slots;
+ if (nslots <= 0) {
+ dev_warn(&vdev->dev,
+ "invalid multitouch slot count %d, disabling multitouch\n",
+ nslots);
+ __clear_bit(ABS_MT_SLOT, vi->idev->absbit);
+ } else {
+ /*
+ * flags is 0: input_mt_init_slots() can only fail
+ * before touching *idev, so the recovery below is
+ * a full rollback.
+ */
+ err = input_mt_init_slots(vi->idev, nslots, 0);
+ if (err) {
+ dev_warn(&vdev->dev,
+ "failed to init %d multitouch slots (%d), disabling multitouch\n",
+ nslots, err);
+ __clear_bit(ABS_MT_SLOT, vi->idev->absbit);
+ }
+ }
}
}
@@ -331,7 +347,6 @@ static int virtinput_probe(struct virtio_device *vdev)
spin_lock_irqsave(&vi->lock, flags);
vi->ready = false;
spin_unlock_irqrestore(&vi->lock, flags);
-err_mt_init_slots:
input_free_device(vi->idev);
err_input_alloc:
vdev->config->del_vqs(vdev);
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH 3/4] virtio_console: avoid NULL portdev dereference in in_intr()
2026-07-15 14:22 [PATCH 0/4] virtio: validate device-reported values across drivers Hari Mishal
2026-07-15 14:22 ` [PATCH 1/4] virtio-mem: validate device-reported block size Hari Mishal
2026-07-15 14:22 ` [PATCH 2/4] virtio_input: validate device-reported multitouch slot count Hari Mishal
@ 2026-07-15 14:22 ` Hari Mishal
2026-07-15 14:22 ` [PATCH 4/4] virtio_console: take a kref in find_port_by_vq() to fix port UAF Hari Mishal
3 siblings, 0 replies; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 14:22 UTC (permalink / raw)
To: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Michael S . Tsirkin, Jason Wang, David Hildenbrand,
Henrik Rydberg
Cc: Xuan Zhuo, Eugenio Pérez, virtualization, linux-kernel,
linux-input, Hari Mishal
A port's virtqueue is not torn down immediately if the port itself is
hot-unplugged (unplug_port() only nulls port->portdev; the vq
callback stays registered until the whole device is removed).
If in_intr() fires for a port in that window it dereferences
port->portdev->vdev via is_rproc_serial(), crashing on the NULL
portdev.
Bail out early when portdev has already been cleared.
Assisted-by: gkh_clanker:t1000
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
drivers/char/virtio_console.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index 198b97314168..faef362dae85 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1720,6 +1720,11 @@ static void in_intr(struct virtqueue *vq)
}
spin_lock_irqsave(&port->inbuf_lock, flags);
+ if (!port->portdev) {
+ /* Port is being unplugged, ignore further data. */
+ spin_unlock_irqrestore(&port->inbuf_lock, flags);
+ return;
+ }
port->inbuf = get_inbuf(port);
/*
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH 4/4] virtio_console: take a kref in find_port_by_vq() to fix port UAF
2026-07-15 14:22 [PATCH 0/4] virtio: validate device-reported values across drivers Hari Mishal
` (2 preceding siblings ...)
2026-07-15 14:22 ` [PATCH 3/4] virtio_console: avoid NULL portdev dereference in in_intr() Hari Mishal
@ 2026-07-15 14:22 ` Hari Mishal
2026-07-15 14:42 ` [PATCH v2 " Hari Mishal
3 siblings, 1 reply; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 14:22 UTC (permalink / raw)
To: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman, Gerd Hoffmann,
Michael S . Tsirkin, Jason Wang, David Hildenbrand,
Henrik Rydberg
Cc: Xuan Zhuo, Eugenio Pérez, virtualization, linux-kernel,
linux-input, Hari Mishal
find_port_by_vq() returns a raw struct port pointer without taking a
reference on it, unlike find_port_by_devt_in_portdev() which does.
find_port_by_vq()'s only two callers, in_intr() and out_intr(), run
as virtqueue interrupt callbacks, entirely independent of and
possibly concurrently with unplug_port(), which itself runs from a
workqueue when the host sends a VIRTIO_CONSOLE_PORT_REMOVE control
message.
unplug_port() removes the port from portdev->ports under ports_lock,
then later drops its last reference with kref_put(), freeing it via
remove_port(). find_port_by_vq() also walks portdev->ports under
ports_lock, so if it finds the port still on the list, the list
removal, and therefore the eventual kref_put(), has not happened yet,
and taking a reference at that point is always safe. Without doing
so, in_intr()/out_intr() can be left holding a pointer to a port that
unplug_port() frees on another core before they are done using it.
Both triggers are host-controlled as the host decides when to send the
PORT_REMOVE control message and when to kick the port's data vq. So a
malicious backend could race the two on purpose, without any guest side
cooperation. The freed object is a generic kmalloc allocation containing
a wait_queue_head_t, which in_intr()/out_intr() pass to
wake_up_interruptible() after touching the stale pointer.
wake_up_interruptible() invokes a function pointer read out of the
wait queue's entries. If the freed slab slot is reclaimed with
attacker influenced content before that call, then this is an arbitrary
function call primitive rather than just undefined behaviour.
Take a reference in find_port_by_vq() while still holding ports_lock,
matching find_port_by_devt_in_portdev(), and release it in in_intr()
and out_intr() once they are done with the port.
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
drivers/char/virtio_console.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index faef362dae85..1b7593684ed9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -304,6 +304,11 @@ static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
return port;
}
+/*
+ * The port object's reference is incremented now and
+ * it is the caller's responsibility to decrement it
+ */
+
static struct port *find_port_by_vq(struct ports_device *portdev,
struct virtqueue *vq)
{
@@ -312,8 +317,10 @@ static struct port *find_port_by_vq(struct ports_device *portdev,
spin_lock_irqsave(&portdev->ports_lock, flags);
list_for_each_entry(port, &portdev->ports, list)
- if (port->in_vq == vq || port->out_vq == vq)
+ if (port->in_vq == vq || port->out_vq == vq) {
+ kref_get(&port->kref);
goto out;
+ }
port = NULL;
out:
spin_unlock_irqrestore(&portdev->ports_lock, flags);
@@ -1706,6 +1713,7 @@ static void out_intr(struct virtqueue *vq)
}
wake_up_interruptible(&port->waitqueue);
+ kref_put(&port->kref, remove_port);
}
static void in_intr(struct virtqueue *vq)
@@ -1723,6 +1731,7 @@ static void in_intr(struct virtqueue *vq)
if (!port->portdev) {
/* Port is being unplugged, ignore further data. */
spin_unlock_irqrestore(&port->inbuf_lock, flags);
+ kref_put(&port->kref, remove_port);
return;
}
port->inbuf = get_inbuf(port);
@@ -1756,6 +1765,8 @@ static void in_intr(struct virtqueue *vq)
if (is_console_port(port) && hvc_poll(port->cons.hvc))
hvc_kick();
+
+ kref_put(&port->kref, remove_port);
}
static void control_intr(struct virtqueue *vq)
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread* [PATCH v2 4/4] virtio_console: take a kref in find_port_by_vq() to fix port UAF
2026-07-15 14:22 ` [PATCH 4/4] virtio_console: take a kref in find_port_by_vq() to fix port UAF Hari Mishal
@ 2026-07-15 14:42 ` Hari Mishal
0 siblings, 0 replies; 16+ messages in thread
From: Hari Mishal @ 2026-07-15 14:42 UTC (permalink / raw)
To: Amit Shah, Arnd Bergmann, Greg Kroah-Hartman
Cc: virtualization, linux-kernel, Hari Mishal
find_port_by_vq() returns a raw struct port pointer without taking a
reference on it, unlike find_port_by_devt_in_portdev() which does.
find_port_by_vq()'s only two callers, in_intr() and out_intr(), run as
virtqueue interrupt callbacks, entirely independent of and possibly
concurrently with unplug_port(), which itself runs from a workqueue when
the host sends a VIRTIO_CONSOLE_PORT_REMOVE control message.
unplug_port() removes the port from portdev->ports under ports_lock,
then later drops its last reference with kref_put(), freeing it via
remove_port(). find_port_by_vq() also walks portdev->ports under
ports_lock, so if it finds the port still on the list, the list removal,
and therefore the eventual kref_put(), has not happened yet, and taking
a reference at that point is always safe. Without doing so,
in_intr()/out_intr() can be left holding a pointer to a port that
unplug_port() frees on another core before they are done using it.
Both triggers are host-controlled as the host decides when to send the
PORT_REMOVE control message and when to kick the port's data vq. So a
malicious backend could race the two on purpose, without any guest side
cooperation. The freed object is a generic kmalloc allocation containing
a wait_queue_head_t, which in_intr()/out_intr() pass to
wake_up_interruptible() after touching the stale pointer.
wake_up_interruptible() invokes a function pointer read out of the wait
queue's entries. If the freed slab slot is reclaimed with attacker
influenced content before that call, then this is an arbitrary function
call primitive rather than just undefined behaviour.
Take a reference in find_port_by_vq() while still holding ports_lock,
matching find_port_by_devt_in_portdev(), and release it in in_intr() and
out_intr() once they are done with the port.
Signed-off-by: Hari Mishal <harimishal1@gmail.com>
---
v2: reworded the comment above find_port_by_vq() for clarity, no
functional change since v1.
drivers/char/virtio_console.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index faef362dae85..1b63afe24e29 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -304,6 +304,12 @@ static struct port *find_port_by_id(struct ports_device *portdev, u32 id)
return port;
}
+/*
+ * Finds a port by the virtqueue and returns a pointer to struct port
+ * with the reference count incremented.
+ *
+ * Callers MUST decrement it when finished.
+ */
static struct port *find_port_by_vq(struct ports_device *portdev,
struct virtqueue *vq)
{
@@ -312,8 +318,10 @@ static struct port *find_port_by_vq(struct ports_device *portdev,
spin_lock_irqsave(&portdev->ports_lock, flags);
list_for_each_entry(port, &portdev->ports, list)
- if (port->in_vq == vq || port->out_vq == vq)
+ if (port->in_vq == vq || port->out_vq == vq) {
+ kref_get(&port->kref);
goto out;
+ }
port = NULL;
out:
spin_unlock_irqrestore(&portdev->ports_lock, flags);
@@ -1706,6 +1714,7 @@ static void out_intr(struct virtqueue *vq)
}
wake_up_interruptible(&port->waitqueue);
+ kref_put(&port->kref, remove_port);
}
static void in_intr(struct virtqueue *vq)
@@ -1723,6 +1732,7 @@ static void in_intr(struct virtqueue *vq)
if (!port->portdev) {
/* Port is being unplugged, ignore further data. */
spin_unlock_irqrestore(&port->inbuf_lock, flags);
+ kref_put(&port->kref, remove_port);
return;
}
port->inbuf = get_inbuf(port);
@@ -1756,6 +1766,8 @@ static void in_intr(struct virtqueue *vq)
if (is_console_port(port) && hvc_poll(port->cons.hvc))
hvc_kick();
+
+ kref_put(&port->kref, remove_port);
}
static void control_intr(struct virtqueue *vq)
--
2.43.0
^ permalink raw reply related [flat|nested] 16+ messages in thread