[PATCH] media: hackrf: fix use-after-free in hackrf_probe() error path

Morduan Zang posted 1 patch 3 days, 2 hours ago
drivers/media/usb/hackrf/hackrf.c | 8 ++++++++
1 file changed, 8 insertions(+)
[PATCH] media: hackrf: fix use-after-free in hackrf_probe() error path
Posted by Morduan Zang 3 days, 2 hours ago
From: Zhan Jun <zhanjun@uniontech.com>

When hackrf_probe() registers the RX video device successfully but the
subsequent TX video device registration fails, the error path falls
through to kfree(dev), immediately freeing the entire hackrf_dev struct.

Since the RX video device is already visible to userspace at this point,
a process such as v4l_id may have opened /dev/swradioN and still hold a
file descriptor. When that fd is closed, v4l2_fh_release() calls
v4l2_fh_del() which tries to acquire the spinlock vdev->fh_lock — but
that lock lives inside the already-freed hackrf_dev, causing a
slab-use-after-free detected by KASAN:

  BUG: KASAN: slab-use-after-free in _raw_spin_lock_irqsave+0x40/0x60
  Call Trace:
   v4l2_fh_del drivers/media/v4l2-core/v4l2-fh.c:74 [inline]
   v4l2_fh_release+0x78/0x290 drivers/media/v4l2-core/v4l2-fh.c:99
   v4l2_release+0x250/0x370 drivers/media/v4l2-core/v4l2-dev.c:471

The root cause is that the probe error path directly frees the struct
instead of deferring cleanup via the v4l2_device refcount, unlike
hackrf_disconnect() which correctly calls v4l2_device_put() and lets
hackrf_video_release() handle the final kfree() when all references
are dropped.

Fix this by returning early from err_video_unregister_device_rx after
calling v4l2_device_put(), mirroring the disconnect path. This ensures
the hackrf_dev struct remains valid until all open file descriptors are
closed.

Fixes: 8bc4a9ed8504 ("[media] hackrf: add support for transmitter")
Reported-by: syzbot+4a824e616e58ca2b3d25@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=4a824e616e58ca2b3d25

Signed-off-by: Zhan Jun <zhanjun@uniontech.com>
---
 drivers/media/usb/hackrf/hackrf.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 94d356fba612..ec4ac1b77d0b 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -1513,6 +1513,14 @@ static int hackrf_probe(struct usb_interface *intf,
 	return 0;
 err_video_unregister_device_rx:
 	video_unregister_device(&dev->rx_vdev);
+	/* v4l2_device refcount was incremented by video_register_device().
+	 * Use v4l2_device_put() to let hackrf_video_release() handle cleanup
+	 * when the last reference is dropped, avoiding a use-after-free if
+	 * userspace still holds an open file descriptor.
+	 */
+	v4l2_device_put(&dev->v4l2_dev);
+	dev_dbg(&intf->dev, "failed=%d\n", ret);
+	return ret;
 err_v4l2_device_unregister:
 	v4l2_device_unregister(&dev->v4l2_dev);
 err_v4l2_ctrl_handler_free_tx:
-- 
2.50.1