media: dvb-usb: fix memory leak in dvb_usb_adapter_init
authorPavel Skripkin <paskripkin@gmail.com>
Sun, 28 Mar 2021 19:32:19 +0000 (21:32 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 11 May 2021 12:47:29 +0000 (14:47 +0200)
[ 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

index c1a7634..adc8b28 100644 (file)
@@ -79,11 +79,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)
@@ -103,6 +109,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)