diff options
author | Chen Zhongjin <chenzhongjin@huawei.com> | 2022-11-08 03:30:05 +0000 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@kernel.org> | 2022-11-25 10:18:03 +0000 |
commit | a574359e2e71ce16be212df3a082ed60a4bd2c5f (patch) | |
tree | 76fa7f30d56f444283147f5e7bcce93b0485cc21 | |
parent | 0f298a4379fa7b47b0d0af8777098913ab44264d (diff) | |
download | linux-a574359e2e71ce16be212df3a082ed60a4bd2c5f.tar.gz linux-a574359e2e71ce16be212df3a082ed60a4bd2c5f.tar.bz2 linux-a574359e2e71ce16be212df3a082ed60a4bd2c5f.zip |
media: dvb-core: Fix ignored return value in dvb_register_frontend()
In dvb_register_frontend(), dvb_register_device() is possible to fail
but its return value is ignored.
It will cause use-after-free when module is removed, because in
dvb_unregister_frontend() it tries to unregister a not registered
device.
BUG: KASAN: use-after-free in dvb_remove_device+0x18b/0x1f0 [dvb_core]
Read of size 4 at addr ffff88800dff4824 by task rmmod/428
CPU: 3 PID: 428 Comm: rmmod
Call Trace:
<TASK>
...
dvb_remove_device+0x18b/0x1f0 [dvb_core]
dvb_unregister_frontend+0x7b/0x130 [dvb_core]
vidtv_bridge_remove+0x6e/0x160 [dvb_vidtv_bridge]
...
Fix this by catching return value of dvb_register_device().
However the fe->refcount can't be put to zero immediately, because
there are still modules calling dvb_frontend_detach() when
dvb_register_frontend() fails.
Link: https://lore.kernel.org/linux-media/20221108033005.169095-1-chenzhongjin@huawei.com
Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Signed-off-by: Chen Zhongjin <chenzhongjin@huawei.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
-rw-r--r-- | drivers/media/dvb-core/dvb_frontend.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c index 7ce4785c8d88..cc0a789f09ae 100644 --- a/drivers/media/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb-core/dvb_frontend.c @@ -3007,6 +3007,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, .name = fe->ops.info.name, #endif }; + int ret; dev_dbg(dvb->device, "%s:\n", __func__); @@ -3040,8 +3041,13 @@ int dvb_register_frontend(struct dvb_adapter *dvb, "DVB: registering adapter %i frontend %i (%s)...\n", fe->dvb->num, fe->id, fe->ops.info.name); - dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, + ret = dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND, 0); + if (ret) { + dvb_frontend_put(fe); + mutex_unlock(&frontend_mutex); + return ret; + } /* * Initialize the cache to the proper values according with the |