* [PATCH] media: airspy: Guard stop_streaming() against disconnected device
@ 2026-05-13 5:26 Valery Borovsky
2026-05-20 6:57 ` Hans Verkuil
0 siblings, 1 reply; 3+ messages in thread
From: Valery Borovsky @ 2026-05-13 5:26 UTC (permalink / raw)
To: linux-media, mchehab; +Cc: stable, linux-kernel, linux-usb, Valery Borovsky
airspy_disconnect() clears s->udev under v4l2_lock, but
airspy_stop_streaming() unconditionally calls airspy_ctrl_msg() and
airspy_free_stream_bufs() afterwards. If a streaming user closes the
device after disconnect, stop_streaming() runs and dereferences the
NULL s->udev:
airspy_stop_streaming()
airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0)
usb_sndctrlpipe(s->udev, 0) /* NULL deref */
airspy_free_stream_bufs(s)
usb_free_coherent(s->udev, ...) /* NULL deref */
Mirror the precedent set by sibling SDR drivers msi2500 and pwc, which
already guard their hardware teardown block with an "if (udev)" check.
The queued-buffer drain via airspy_cleanup_queued_bufs() must still
run unconditionally so vb2 sees its buffers returned.
Issue identified by automated review of the INV-003 series at
https://sashiko.dev/
Fixes: 634fe5033951 ("[media] airspy: AirSpy SDR driver")
Cc: stable@vger.kernel.org
Signed-off-by: Valery Borovsky <vebohr@gmail.com>
---
drivers/media/usb/airspy/airspy.c | 12 +++++++-----
1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 8f6b721ba107..50db02d35213 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -584,12 +584,14 @@ static void airspy_stop_streaming(struct vb2_queue *vq)
mutex_lock(&s->v4l2_lock);
- /* stop hardware streaming */
- airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0);
+ if (s->udev) {
+ /* stop hardware streaming */
+ airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0);
- airspy_kill_urbs(s);
- airspy_free_urbs(s);
- airspy_free_stream_bufs(s);
+ airspy_kill_urbs(s);
+ airspy_free_urbs(s);
+ airspy_free_stream_bufs(s);
+ }
airspy_cleanup_queued_bufs(s);
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] media: airspy: Guard stop_streaming() against disconnected device
2026-05-13 5:26 [PATCH] media: airspy: Guard stop_streaming() against disconnected device Valery Borovsky
@ 2026-05-20 6:57 ` Hans Verkuil
2026-05-23 16:53 ` [PATCH v2] media: airspy: use vb2_video_unregister_device() on disconnect to fix NULL deref Valery Borovsky
0 siblings, 1 reply; 3+ messages in thread
From: Hans Verkuil @ 2026-05-20 6:57 UTC (permalink / raw)
To: Valery Borovsky, linux-media, mchehab; +Cc: stable, linux-kernel, linux-usb
On 13/05/2026 07:26, Valery Borovsky wrote:
> airspy_disconnect() clears s->udev under v4l2_lock, but
> airspy_stop_streaming() unconditionally calls airspy_ctrl_msg() and
> airspy_free_stream_bufs() afterwards. If a streaming user closes the
> device after disconnect, stop_streaming() runs and dereferences the
> NULL s->udev:
>
> airspy_stop_streaming()
> airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0)
> usb_sndctrlpipe(s->udev, 0) /* NULL deref */
> airspy_free_stream_bufs(s)
> usb_free_coherent(s->udev, ...) /* NULL deref */
>
> Mirror the precedent set by sibling SDR drivers msi2500 and pwc, which
> already guard their hardware teardown block with an "if (udev)" check.
> The queued-buffer drain via airspy_cleanup_queued_bufs() must still
> run unconditionally so vb2 sees its buffers returned.
>
> Issue identified by automated review of the INV-003 series at
> https://sashiko.dev/
>
> Fixes: 634fe5033951 ("[media] airspy: AirSpy SDR driver")
> Cc: stable@vger.kernel.org
> Signed-off-by: Valery Borovsky <vebohr@gmail.com>
> ---
> drivers/media/usb/airspy/airspy.c | 12 +++++++-----
> 1 file changed, 7 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
> index 8f6b721ba107..50db02d35213 100644
> --- a/drivers/media/usb/airspy/airspy.c
> +++ b/drivers/media/usb/airspy/airspy.c
> @@ -584,12 +584,14 @@ static void airspy_stop_streaming(struct vb2_queue *vq)
>
> mutex_lock(&s->v4l2_lock);
>
> - /* stop hardware streaming */
> - airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0);
> + if (s->udev) {
> + /* stop hardware streaming */
> + airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0);
>
> - airspy_kill_urbs(s);
> - airspy_free_urbs(s);
> - airspy_free_stream_bufs(s);
> + airspy_kill_urbs(s);
> + airspy_free_urbs(s);
> + airspy_free_stream_bufs(s);
> + }
>
> airspy_cleanup_queued_bufs(s);
>
Here too it is better to replace video_unregister_device(&dev->vdev);
by vb2_video_unregister_device(&dev->vdev);
Similar to what I suggested for rtl2832_sdr.
Regards,
Hans
^ permalink raw reply [flat|nested] 3+ messages in thread* [PATCH v2] media: airspy: use vb2_video_unregister_device() on disconnect to fix NULL deref
2026-05-20 6:57 ` Hans Verkuil
@ 2026-05-23 16:53 ` Valery Borovsky
0 siblings, 0 replies; 3+ messages in thread
From: Valery Borovsky @ 2026-05-23 16:53 UTC (permalink / raw)
To: mchehab; +Cc: hverkuil+cisco, linux-media, stable, linux-kernel, linux-usb
airspy_disconnect() clears s->udev under v4l2_lock, but
airspy_stop_streaming() unconditionally calls airspy_ctrl_msg() and
airspy_free_stream_bufs() afterwards. If a streaming user closes the
device after disconnect, stop_streaming() runs and dereferences the
NULL s->udev:
airspy_stop_streaming()
airspy_ctrl_msg(s, CMD_RECEIVER_MODE, 0, 0, NULL, 0)
usb_sndctrlpipe(s->udev, 0) /* NULL deref */
airspy_free_stream_bufs(s)
usb_free_coherent(s->udev, ...) /* NULL deref */
The airspy driver uses vb2_fop_release() in its file_operations, so
replace video_unregister_device(&s->vdev) with
vb2_video_unregister_device(&s->vdev) and move it before clearing
s->udev. vb2_video_unregister_device() releases the vb2 queue, which
synchronously runs airspy_stop_streaming() if streaming is active, so
the URBs, coherent DMA stream buffers and the hardware stop control
message all execute while s->udev is still valid.
vb2_video_unregister_device() locks vdev->queue->lock (vb_queue_lock)
internally, and stop_streaming() locks v4l2_lock, so the previous outer
mutex_lock(&s->vb_queue_lock) / mutex_lock(&s->v4l2_lock) pair around
the unregister sequence would self-deadlock and has been removed. A
short v4l2_lock critical section around s->udev = NULL remains so any
ioctl path that still holds the file descriptor sees coherent state.
Issue identified by automated review of the INV-003 series at
https://sashiko.dev/
Fixes: 634fe5033951 ("[media] airspy: AirSpy SDR driver")
Cc: stable@vger.kernel.org
Suggested-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Signed-off-by: Valery Borovsky <vebohr@gmail.com>
---
Changes since v1
(https://lore.kernel.org/linux-media/20260513052617.140688-1-vebohr@gmail.com/):
- Rewritten per Hans Verkuil's review
(https://lore.kernel.org/linux-media/f202c8ae-554f-49de-a9d1-add337e28515@kernel.org/):
fix the root cause in airspy_disconnect() by replacing
video_unregister_device() with vb2_video_unregister_device() and
moving it before clearing s->udev, instead of guarding the hardware
teardown in airspy_stop_streaming() with "if (s->udev)".
vb2_video_unregister_device() releases the queue, which synchronously
calls stop_streaming() while s->udev is still valid, so the guard is
no longer needed; airspy_stop_streaming() is unchanged.
- Dropped the outer mutex_lock(&s->vb_queue_lock) /
mutex_lock(&s->v4l2_lock) around the unregister sequence:
vb2_video_unregister_device() acquires vb_queue_lock internally and
stop_streaming() acquires v4l2_lock, so holding either of those
while calling the unregister helper self-deadlocks.
- Rebased on media-committers/next.
drivers/media/usb/airspy/airspy.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index 57edb42463e8..358a66ab8e48 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -464,14 +464,21 @@ static void airspy_disconnect(struct usb_interface *intf)
dev_dbg(s->dev, "\n");
- mutex_lock(&s->vb_queue_lock);
+ /*
+ * vb2_video_unregister_device() releases the vb2 queue, which
+ * triggers airspy_stop_streaming() if streaming is active.
+ * stop_streaming() dereferences s->udev via airspy_ctrl_msg() and
+ * airspy_free_stream_bufs(), so it must run before s->udev is
+ * cleared. vb2_video_unregister_device() locks vb_queue_lock
+ * internally and stop_streaming() locks v4l2_lock, so neither may
+ * be held by the caller.
+ */
+ v4l2_device_disconnect(&s->v4l2_dev);
+ vb2_video_unregister_device(&s->vdev);
+
mutex_lock(&s->v4l2_lock);
- /* No need to keep the urbs around after disconnection */
s->udev = NULL;
- v4l2_device_disconnect(&s->v4l2_dev);
- video_unregister_device(&s->vdev);
mutex_unlock(&s->v4l2_lock);
- mutex_unlock(&s->vb_queue_lock);
v4l2_device_put(&s->v4l2_dev);
}
--
2.51.0
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-23 16:53 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-13 5:26 [PATCH] media: airspy: Guard stop_streaming() against disconnected device Valery Borovsky
2026-05-20 6:57 ` Hans Verkuil
2026-05-23 16:53 ` [PATCH v2] media: airspy: use vb2_video_unregister_device() on disconnect to fix NULL deref Valery Borovsky
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox