| From bdc98f2c910744de42c693e8460c3572b303ce81 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sun, 28 Mar 2021 21:32:19 +0200 |
| Subject: media: dvb-usb: fix memory leak in dvb_usb_adapter_init |
| |
| From: Pavel Skripkin <paskripkin@gmail.com> |
| |
| [ Upstream commit b7cd0da982e3043f2eec7235ac5530cb18d6af1d ] |
| |
| syzbot reported memory leak in dvb-usb. The problem was |
| in invalid error handling in dvb_usb_adapter_init(). |
| |
| for (n = 0; n < d->props.num_adapters; n++) { |
| .... |
| if ((ret = dvb_usb_adapter_stream_init(adap)) || |
| (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || |
| (ret = dvb_usb_adapter_frontend_init(adap))) { |
| return ret; |
| } |
| ... |
| d->num_adapters_initialized++; |
| ... |
| } |
| |
| In case of error in dvb_usb_adapter_dvb_init() or |
| dvb_usb_adapter_dvb_init() d->num_adapters_initialized won't be |
| incremented, but dvb_usb_adapter_exit() relies on it: |
| |
| for (n = 0; n < d->num_adapters_initialized; n++) |
| |
| So, allocated objects won't be freed. |
| |
| Signed-off-by: Pavel Skripkin <paskripkin@gmail.com> |
| Reported-by: syzbot+3c2be7424cea3b932b0e@syzkaller.appspotmail.com |
| Signed-off-by: Sean Young <sean@mess.org> |
| Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/media/usb/dvb-usb/dvb-usb-init.c | 20 ++++++++++++++++---- |
| 1 file changed, 16 insertions(+), 4 deletions(-) |
| |
| diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c |
| index b3413404f91a..690c1e06fbfa 100644 |
| --- a/drivers/media/usb/dvb-usb/dvb-usb-init.c |
| +++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c |
| @@ -82,11 +82,17 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) |
| } |
| } |
| |
| - if ((ret = dvb_usb_adapter_stream_init(adap)) || |
| - (ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs)) || |
| - (ret = dvb_usb_adapter_frontend_init(adap))) { |
| + ret = dvb_usb_adapter_stream_init(adap); |
| + if (ret) |
| return ret; |
| - } |
| + |
| + ret = dvb_usb_adapter_dvb_init(adap, adapter_nrs); |
| + if (ret) |
| + goto dvb_init_err; |
| + |
| + ret = dvb_usb_adapter_frontend_init(adap); |
| + if (ret) |
| + goto frontend_init_err; |
| |
| /* use exclusive FE lock if there is multiple shared FEs */ |
| if (adap->fe_adap[1].fe) |
| @@ -106,6 +112,12 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs) |
| } |
| |
| return 0; |
| + |
| +frontend_init_err: |
| + dvb_usb_adapter_dvb_exit(adap); |
| +dvb_init_err: |
| + dvb_usb_adapter_stream_exit(adap); |
| + return ret; |
| } |
| |
| static int dvb_usb_adapter_exit(struct dvb_usb_device *d) |
| -- |
| 2.30.2 |
| |