KASAN reports a use-after-free: BUG: KASAN: use-after-free in dvb_dmxdev_release+0x4d5/0x5d0 [dvb_core] Call Trace: ... dvb_dmxdev_release+0x4d5/0x5d0 [dvb_core] vidtv_bridge_probe+0x7bf/0xa40 [dvb_vidtv_bridge] platform_probe+0xb6/0x170 ... Allocated by task 1238: ... dvb_register_device+0x1a7/0xa70 [dvb_core] dvb_dmxdev_init+0x2af/0x4a0 [dvb_core] vidtv_bridge_probe+0x766/0xa40 [dvb_vidtv_bridge] ... Freed by task 1238: dvb_register_device+0x6d2/0xa70 [dvb_core] dvb_dmxdev_init+0x2af/0x4a0 [dvb_core] vidtv_bridge_probe+0x766/0xa40 [dvb_vidtv_bridge] ... It is because the error handling in vidtv_bridge_dvb_init() is wrong. First, vidtv_bridge_dmx(dev)_init() will clean themselves when fail, but goto fail_dmx(_dev): calls release functions again, which causes use-after-free. Also, in fail_fe, fail_tuner_probe and fail_demod_probe, j = i will cause out-of-bound when i finished its loop (i == NUM_FE). And the loop releasing is wrong, although now NUM_FE is 1 so it won't cause problem. Fix this by correctly releasing everything. Fixes: f90cf6079bf6 ("media: vidtv: add a bridge driver") Signed-off-by: Chen Zhongjin <chenzhongjin@xxxxxxxxxx> --- .../media/test-drivers/vidtv/vidtv_bridge.c | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c index 82620613d56b..046e6785f0a3 100644 --- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c +++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c @@ -459,26 +459,21 @@ static int vidtv_bridge_dvb_init(struct vidtv_dvb *dvb) for (j = j - 1; j >= 0; --j) dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->dmx_fe[j]); -fail_dmx_dev: dvb_dmxdev_release(&dvb->dmx_dev); -fail_dmx: +fail_dmx_dev: dvb_dmx_release(&dvb->demux); +fail_dmx: +fail_demod_probe: + for (i = i - 1; i >= 0; --i) { + dvb_unregister_frontend(dvb->fe[i]); fail_fe: - for (j = i; j >= 0; --j) - dvb_unregister_frontend(dvb->fe[j]); + dvb_frontend_detach(dvb->fe[i]); + dvb_module_release(dvb->i2c_client_tuner[i]); fail_tuner_probe: - for (j = i; j >= 0; --j) - if (dvb->i2c_client_tuner[j]) - dvb_module_release(dvb->i2c_client_tuner[j]); - -fail_demod_probe: - for (j = i; j >= 0; --j) - if (dvb->i2c_client_demod[j]) - dvb_module_release(dvb->i2c_client_demod[j]); - + dvb_module_release(dvb->i2c_client_demod[i]); + } fail_adapter: dvb_unregister_adapter(&dvb->adapter); - fail_i2c: i2c_del_adapter(&dvb->i2c_adapter); @@ -550,6 +545,7 @@ static int vidtv_bridge_remove(struct platform_device *pdev) for (i = 0; i < NUM_FE; ++i) { dvb_unregister_frontend(dvb->fe[i]); + dvb_frontend_detach(dvb->fe[i]); dvb_module_release(dvb->i2c_client_tuner[i]); dvb_module_release(dvb->i2c_client_demod[i]); } -- 2.17.1