[PATCH] media: dvbdev: fix stale minor on registration failure

Laxman Acharya Padhya posted 1 patch 1 month, 2 weeks ago
drivers/media/dvb-core/dvbdev.c | 42 ++++++++++++++++-----------------
1 file changed, 20 insertions(+), 22 deletions(-)
[PATCH] media: dvbdev: fix stale minor on registration failure
Posted by Laxman Acharya Padhya 1 month, 2 weeks ago
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@gmail.com>
---
 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