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

Laxman Acharya Padhya <[email protected]>
Newsgroups org.kernel.vger.linux-media,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
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 <[email protected]>
---
 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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.