dvb_register_device() stores the dvb_device in the global dvb_minors[] array via dvb_device_get() and releases minor_rwsem before calling dvb_register_media_device() and device_create(). If either of these fails, the error paths call kfree() on dvbdev without clearing the dvb_minors[minor] entry and without going through dvb_device_put(). This leaves a stale pointer in the array that dvb_device_open() can dereference under minor_rwsem, and bypasses the reference count established by dvb_device_get(). Fix both error paths by: 1. Clearing dvb_minors[minor] under minor_rwsem and calling dvb_device_put() to release the array reference. 2. Replacing the direct kfree() with dvb_device_put() to release the initial reference and allow the release callback to free the object when the count reaches zero. This mirrors the cleanup sequence in dvb_unregister_device(). Fixes: 0fc044b2b5e2 ("media: dvbdev: adopts refcnt to avoid UAF") Cc: stable@vger.kernel.org Signed-off-by: Tristan Madani --- drivers/media/dvb-core/dvbdev.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c index d753d329502a6..c931c467d4c52 100644 --- a/drivers/media/dvb-core/dvbdev.c +++ b/drivers/media/dvb-core/dvbdev.c @@ -551,6 +551,10 @@ 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__); + 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); @@ -558,7 +562,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } dvb_media_device_free(dvbdev); list_del(&dvbdev->list_head); - kfree(dvbdev); + dvb_device_put(dvbdev); *pdvbdev = NULL; mutex_unlock(&dvbdev_register_lock); return ret; @@ -570,6 +574,10 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if (IS_ERR(clsdev)) { pr_err("%s: failed to create device dvb%d.%s%d (%pe)\n", __func__, adap->num, dnames[type], id, clsdev); + 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); @@ -577,7 +585,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, } dvb_media_device_free(dvbdev); list_del(&dvbdev->list_head); - kfree(dvbdev); + dvb_device_put(dvbdev); *pdvbdev = NULL; mutex_unlock(&dvbdev_register_lock); return PTR_ERR(clsdev); -- 2.47.3