mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v1 0/2] Input: sur40 - fix UAF/hang on closing the video node after unplug
@ 2026-09-20 11:39 Nguyen Ngoc Thang
  2026-09-20 11:39 ` [PATCH v1 1/2] Input: sur40 - don't wait for buffers nothing will complete Nguyen Ngoc Thang
  2026-09-20 11:39 ` [PATCH v1 2/2] Input: sur40 - keep device state alive until the video node is released Nguyen Ngoc Thang
  0 siblings, 2 replies; 5+ messages in thread
From: Nguyen Ngoc Thang @ 2026-09-20 11:39 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: floe, linux-input, linux-media, linux-kernel, Nguyen Ngoc Thang

Hi,

syzbot reported a slab-use-after-free in vb2_core_queue_release() [1]:
closing /dev/v4l-touch* after the SUR40 was unplugged reads freed memory.

Cause: sur40_disconnect() kfree()s struct sur40_state, which embeds the
video_device, v4l2_device and vb2_queue, even though a video node can
still be open. v4l2_release() and vb2_fop_release() then dereference
freed memory. Patch 2 fixes this by giving the v4l2_device a release()
callback that frees the state, and dropping the disconnect path's
reference with v4l2_device_put(), so the last close does the freeing.
The probe error paths never expose the node and still free directly.

Patch 1 is needed first: once the state outlives disconnect, closing a
node that is still streaming hangs forever, because
sur40_stop_streaming() waits (vb2_wait_for_all_buffers) for buffers
that only the input poll callback completes, and that is gone after
unplug. Returning the queued buffers before the wait fixes it. This was
masked by the UAF above.

Testing: no hardware, so I emulated a SUR40 (045e:0775) with raw-gadget
on dummy_hcd in QEMU with KASAN. The reproducer enumerates the device,
starts a non-blocking read() on the video node (making the fd the queue
owner), disconnects the gadget, then close()s the fd.
  - before: KASAN: slab-use-after-free in v4l2_release(), allocated in
    sur40_probe(), freed in sur40_disconnect() (same alloc/free stacks
    as the syzbot report)
  - patch 1 only: no KASAN, but close() blocks in
    vb2_wait_for_all_buffers()  [only meaningful with patch 2 applied]
  - both patches: 5 consecutive enumerate/disconnect/close cycles, no
    KASAN, no hang.
(The dma_map_sg WARNING during read() in the log comes from dummy_hcd
having no DMA mask; it is unrelated.)

Nguyen Ngoc Thang (2):
  Input: sur40 - don't wait for buffers nothing will complete
  Input: sur40 - keep device state alive until the video node is
    released

 drivers/input/touchscreen/sur40.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v1 1/2] Input: sur40 - don't wait for buffers nothing will complete
  2026-09-20 11:39 [PATCH v1 0/2] Input: sur40 - fix UAF/hang on closing the video node after unplug Nguyen Ngoc Thang
@ 2026-09-20 11:39 ` Nguyen Ngoc Thang
  2026-09-30  8:04   ` Hans Verkuil
  2026-09-20 11:39 ` [PATCH v1 2/2] Input: sur40 - keep device state alive until the video node is released Nguyen Ngoc Thang
  1 sibling, 1 reply; 5+ messages in thread
From: Nguyen Ngoc Thang @ 2026-09-20 11:39 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: floe, linux-input, linux-media, linux-kernel, Nguyen Ngoc Thang, stable

sur40_stop_streaming() calls vb2_wait_for_all_buffers() before handing
the queued buffers back. Those buffers are only completed from the input
poll callback, which is gone once the device is unplugged. Closing a
video node that is still streaming after a disconnect then sleeps
forever in vb2_wait_for_all_buffers():

  vb2_wait_for_all_buffers+0x20f/0x330
  sur40_stop_streaming+0x45/0x310
  __vb2_queue_cancel+0xc5/0xf70
  vb2_core_streamoff+0x5d/0x180
  __vb2_cleanup_fileio+0x6e/0x190
  vb2_core_queue_release+0x1f/0x190
  _vb2_fop_release+0xe8/0x280
  v4l2_release+0x280/0x430

It has not been noticed so far because sur40_disconnect() frees the
device state under the open file, and the close then crashes earlier.

Return the queued buffers first. A buffer that sur40_process_video()
has already taken off the list still completes by itself, so the wait
afterwards only covers that one.

Fixes: 6a8588156657 ("[media] sur40: fix occasional oopses on device close")
Cc: stable@vger.kernel.org
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
---
 drivers/input/touchscreen/sur40.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 09d8c5f8d09f..7020bcf9b81a 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -929,11 +929,11 @@ static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count)
 static void sur40_stop_streaming(struct vb2_queue *vq)
 {
 	struct sur40_state *sur40 = vb2_get_drv_priv(vq);
-	vb2_wait_for_all_buffers(vq);
-	sur40->sequence = -1;
 
-	/* Release all active buffers */
+	/* Release queued buffers first: nothing completes them after unplug */
 	return_all_buffers(sur40, VB2_BUF_STATE_ERROR);
+	vb2_wait_for_all_buffers(vq);
+	sur40->sequence = -1;
 }
 
 /* V4L ioctl */
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v1 2/2] Input: sur40 - keep device state alive until the video node is released
  2026-09-20 11:39 [PATCH v1 0/2] Input: sur40 - fix UAF/hang on closing the video node after unplug Nguyen Ngoc Thang
  2026-09-20 11:39 ` [PATCH v1 1/2] Input: sur40 - don't wait for buffers nothing will complete Nguyen Ngoc Thang
@ 2026-09-20 11:39 ` Nguyen Ngoc Thang
  2026-09-30  8:05   ` Hans Verkuil
  1 sibling, 1 reply; 5+ messages in thread
From: Nguyen Ngoc Thang @ 2026-09-20 11:39 UTC (permalink / raw)
  To: dmitry.torokhov
  Cc: floe, linux-input, linux-media, linux-kernel, Nguyen Ngoc Thang,
	syzbot+eb4706daf505f9c4b547, stable

sur40_disconnect() frees the sur40_state, which embeds the video_device,
the v4l2_device and the vb2_queue, while a video node may still be open.
Closing that file afterwards touches freed memory:

  BUG: KASAN: slab-use-after-free in vb2_core_queue_release+0x12d/0x150
  Read of size 4 at addr ffff888066fa8aa8 by task v4l_id/28733
   vb2_core_queue_release+0x12d/0x150
   vb2_fop_release+0x16e/0x200
   v4l2_release+0x22c/0x350
   __fput+0x418/0xa50
  Freed by task 16811:
   kfree+0x1c5/0x650
   sur40_disconnect+0xaf/0x140

Give the v4l2_device a release callback that frees the bulk buffer and
the state, and drop the disconnect path's own reference with
v4l2_device_put(). The last closer of the node then does the freeing.
The probe error paths never open the node and keep freeing directly.

Reported-by: syzbot+eb4706daf505f9c4b547@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=eb4706daf505f9c4b547
Fixes: e831cd251fb9 ("[media] add raw video stream support for Samsung SUR40")
Cc: stable@vger.kernel.org
Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
---
 drivers/input/touchscreen/sur40.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
index 7020bcf9b81a..efd4fe557cef 100644
--- a/drivers/input/touchscreen/sur40.c
+++ b/drivers/input/touchscreen/sur40.c
@@ -648,6 +648,15 @@ static int sur40_input_setup_events(struct input_dev *input_dev)
 }
 
 /* Check candidate USB interface. */
+/* Runs once the last video node reference is gone. */
+static void sur40_release(struct v4l2_device *v4l2)
+{
+	struct sur40_state *sur40 = container_of(v4l2, struct sur40_state, v4l2);
+
+	kfree(sur40->bulk_in_buffer);
+	kfree(sur40);
+}
+
 static int sur40_probe(struct usb_interface *interface,
 		       const struct usb_device_id *id)
 {
@@ -733,6 +742,7 @@ static int sur40_probe(struct usb_interface *interface,
 			"Unable to register video master device.");
 		goto err_free_buffer;
 	}
+	sur40->v4l2.release = sur40_release;
 
 	/* initialize the lock and subdevice */
 	sur40->queue = sur40_queue;
@@ -831,11 +841,10 @@ static void sur40_disconnect(struct usb_interface *interface)
 	video_unregister_device(&sur40->vdev);
 	v4l2_device_unregister(&sur40->v4l2);
 
-	kfree(sur40->bulk_in_buffer);
-	kfree(sur40);
-
 	usb_set_intfdata(interface, NULL);
 	dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC);
+
+	v4l2_device_put(&sur40->v4l2);
 }
 
 /*
-- 
2.43.0


^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1 1/2] Input: sur40 - don't wait for buffers nothing will complete
  2026-09-20 11:39 ` [PATCH v1 1/2] Input: sur40 - don't wait for buffers nothing will complete Nguyen Ngoc Thang
@ 2026-09-30  8:04   ` Hans Verkuil
  0 siblings, 0 replies; 5+ messages in thread
From: Hans Verkuil @ 2026-09-30  8:04 UTC (permalink / raw)
  To: Nguyen Ngoc Thang, dmitry.torokhov
  Cc: floe, linux-input, linux-media, linux-kernel, stable

On 20/09/2026 13:39, Nguyen Ngoc Thang wrote:
> sur40_stop_streaming() calls vb2_wait_for_all_buffers() before handing
> the queued buffers back. Those buffers are only completed from the input
> poll callback, which is gone once the device is unplugged. Closing a
> video node that is still streaming after a disconnect then sleeps
> forever in vb2_wait_for_all_buffers():
> 
>   vb2_wait_for_all_buffers+0x20f/0x330
>   sur40_stop_streaming+0x45/0x310
>   __vb2_queue_cancel+0xc5/0xf70
>   vb2_core_streamoff+0x5d/0x180
>   __vb2_cleanup_fileio+0x6e/0x190
>   vb2_core_queue_release+0x1f/0x190
>   _vb2_fop_release+0xe8/0x280
>   v4l2_release+0x280/0x430
> 
> It has not been noticed so far because sur40_disconnect() frees the
> device state under the open file, and the close then crashes earlier.
> 
> Return the queued buffers first. A buffer that sur40_process_video()
> has already taken off the list still completes by itself, so the wait
> afterwards only covers that one.
> 
> Fixes: 6a8588156657 ("[media] sur40: fix occasional oopses on device close")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>
> ---
>  drivers/input/touchscreen/sur40.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
> index 09d8c5f8d09f..7020bcf9b81a 100644
> --- a/drivers/input/touchscreen/sur40.c
> +++ b/drivers/input/touchscreen/sur40.c
> @@ -929,11 +929,11 @@ static int sur40_start_streaming(struct vb2_queue *vq, unsigned int count)
>  static void sur40_stop_streaming(struct vb2_queue *vq)
>  {
>  	struct sur40_state *sur40 = vb2_get_drv_priv(vq);
> -	vb2_wait_for_all_buffers(vq);
> -	sur40->sequence = -1;
>  
> -	/* Release all active buffers */
> +	/* Release queued buffers first: nothing completes them after unplug */
>  	return_all_buffers(sur40, VB2_BUF_STATE_ERROR);
> +	vb2_wait_for_all_buffers(vq);
> +	sur40->sequence = -1;
>  }
>  
>  /* V4L ioctl */

I think you should make one more change: replace the video_unregister_device calls by
vb2_video_unregister_device(). This ensures that at unregister time all streaming is
canceled and stop_streaming is called.

Having streaming continue after unregistering a device is in general not a good idea,
which is why we added that vb2_video_unregister_device call.

I think you still need to have that change in stop_streaming for this specific driver,
but it might be worth testing without it.

Regards,

	Hans

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v1 2/2] Input: sur40 - keep device state alive until the video node is released
  2026-09-20 11:39 ` [PATCH v1 2/2] Input: sur40 - keep device state alive until the video node is released Nguyen Ngoc Thang
@ 2026-09-30  8:05   ` Hans Verkuil
  0 siblings, 0 replies; 5+ messages in thread
From: Hans Verkuil @ 2026-09-30  8:05 UTC (permalink / raw)
  To: Nguyen Ngoc Thang, dmitry.torokhov
  Cc: floe, linux-input, linux-media, linux-kernel,
	syzbot+eb4706daf505f9c4b547, stable

On 20/09/2026 13:39, Nguyen Ngoc Thang wrote:
> sur40_disconnect() frees the sur40_state, which embeds the video_device,
> the v4l2_device and the vb2_queue, while a video node may still be open.
> Closing that file afterwards touches freed memory:
> 
>   BUG: KASAN: slab-use-after-free in vb2_core_queue_release+0x12d/0x150
>   Read of size 4 at addr ffff888066fa8aa8 by task v4l_id/28733
>    vb2_core_queue_release+0x12d/0x150
>    vb2_fop_release+0x16e/0x200
>    v4l2_release+0x22c/0x350
>    __fput+0x418/0xa50
>   Freed by task 16811:
>    kfree+0x1c5/0x650
>    sur40_disconnect+0xaf/0x140
> 
> Give the v4l2_device a release callback that frees the bulk buffer and
> the state, and drop the disconnect path's own reference with
> v4l2_device_put(). The last closer of the node then does the freeing.
> The probe error paths never open the node and keep freeing directly.
> 
> Reported-by: syzbot+eb4706daf505f9c4b547@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=eb4706daf505f9c4b547
> Fixes: e831cd251fb9 ("[media] add raw video stream support for Samsung SUR40")
> Cc: stable@vger.kernel.org
> Signed-off-by: Nguyen Ngoc Thang <ngocthang2710.1999@gmail.com>

Reviewed-by: Hans Verkuil <hverkuil+cisco@kernel.org>

Regards,

	Hans

> ---
>  drivers/input/touchscreen/sur40.c | 15 ++++++++++++---
>  1 file changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/input/touchscreen/sur40.c b/drivers/input/touchscreen/sur40.c
> index 7020bcf9b81a..efd4fe557cef 100644
> --- a/drivers/input/touchscreen/sur40.c
> +++ b/drivers/input/touchscreen/sur40.c
> @@ -648,6 +648,15 @@ static int sur40_input_setup_events(struct input_dev *input_dev)
>  }
>  
>  /* Check candidate USB interface. */
> +/* Runs once the last video node reference is gone. */
> +static void sur40_release(struct v4l2_device *v4l2)
> +{
> +	struct sur40_state *sur40 = container_of(v4l2, struct sur40_state, v4l2);
> +
> +	kfree(sur40->bulk_in_buffer);
> +	kfree(sur40);
> +}
> +
>  static int sur40_probe(struct usb_interface *interface,
>  		       const struct usb_device_id *id)
>  {
> @@ -733,6 +742,7 @@ static int sur40_probe(struct usb_interface *interface,
>  			"Unable to register video master device.");
>  		goto err_free_buffer;
>  	}
> +	sur40->v4l2.release = sur40_release;
>  
>  	/* initialize the lock and subdevice */
>  	sur40->queue = sur40_queue;
> @@ -831,11 +841,10 @@ static void sur40_disconnect(struct usb_interface *interface)
>  	video_unregister_device(&sur40->vdev);
>  	v4l2_device_unregister(&sur40->v4l2);
>  
> -	kfree(sur40->bulk_in_buffer);
> -	kfree(sur40);
> -
>  	usb_set_intfdata(interface, NULL);
>  	dev_dbg(&interface->dev, "%s is now disconnected\n", DRIVER_DESC);
> +
> +	v4l2_device_put(&sur40->v4l2);
>  }
>  
>  /*


^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-30  8:05 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-20 11:39 [PATCH v1 0/2] Input: sur40 - fix UAF/hang on closing the video node after unplug Nguyen Ngoc Thang
2026-09-20 11:39 ` [PATCH v1 1/2] Input: sur40 - don't wait for buffers nothing will complete Nguyen Ngoc Thang
2026-09-30  8:04   ` Hans Verkuil
2026-09-20 11:39 ` [PATCH v1 2/2] Input: sur40 - keep device state alive until the video node is released Nguyen Ngoc Thang
2026-09-30  8:05   ` Hans Verkuil

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®