[PATCH] media: dvbdev: fix stale minor on registration failure
From: Laxman Acharya Padhya
Date: Sun Aug 09 2026 - 06:17:35 EST
dvb_register_device() gives the new device one reference and publishes
a second reference through dvb_minors[] before media-device
registration and device_create() complete.
If either operation fails, the current error paths free the device
directly. The published minor then retains a pointer to freed memory,
and the global DVB character device can pass that pointer to
dvb_device_open().
Route both failures through one cleanup path. Remove the minor under
minor_rwsem, drop its reference, release the registration resources,
and finally drop the initial device reference.
Assisted-by: ChatGPT:gpt-5
Signed-off-by: Laxman Acharya Padhya <acharyalaxman8848@xxxxxxxxx>
---
drivers/media/dvb-core/dvbdev.c | 42 ++++++++++++++++-----------------
1 file changed, 20 insertions(+), 22 deletions(-)
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index d753d329502a..9a2783175771 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -551,36 +551,17 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
if (ret) {
pr_err("%s: dvb_register_media_device failed to create the mediagraph\n",
__func__);
- if (new_node) {
- list_del(&new_node->list_head);
- kfree(dvbdevfops);
- kfree(new_node);
- }
- dvb_media_device_free(dvbdev);
- list_del(&dvbdev->list_head);
- kfree(dvbdev);
- *pdvbdev = NULL;
- mutex_unlock(&dvbdev_register_lock);
- return ret;
+ goto err_register;
}
clsdev = device_create(dvb_class, adap->device,
MKDEV(DVB_MAJOR, minor),
dvbdev, "dvb%d.%s%d", adap->num, dnames[type], id);
if (IS_ERR(clsdev)) {
+ ret = PTR_ERR(clsdev);
pr_err("%s: failed to create device dvb%d.%s%d (%pe)\n",
__func__, adap->num, dnames[type], id, clsdev);
- if (new_node) {
- list_del(&new_node->list_head);
- kfree(dvbdevfops);
- kfree(new_node);
- }
- dvb_media_device_free(dvbdev);
- list_del(&dvbdev->list_head);
- kfree(dvbdev);
- *pdvbdev = NULL;
- mutex_unlock(&dvbdev_register_lock);
- return PTR_ERR(clsdev);
+ goto err_register;
}
dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
@@ -588,6 +569,23 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
return 0;
+
+err_register:
+ down_write(&minor_rwsem);
+ dvb_minors[minor] = NULL;
+ dvb_device_put(dvbdev);
+ up_write(&minor_rwsem);
+ if (new_node) {
+ list_del(&new_node->list_head);
+ kfree(dvbdevfops);
+ kfree(new_node);
+ }
+ dvb_media_device_free(dvbdev);
+ list_del(&dvbdev->list_head);
+ *pdvbdev = NULL;
+ mutex_unlock(&dvbdev_register_lock);
+ dvb_device_put(dvbdev);
+ return ret;
}
EXPORT_SYMBOL(dvb_register_device);
--
2.51.2