Commit fdfa59cd authored by Stefan Brüns's avatar Stefan Brüns Committed by Mauro Carvalho Chehab

media: dvbsky: Avoid leaking dvb frontend

Commit 14f4eaed ("media: dvbsky: fix driver unregister logic") fixed
a use-after-free by removing the reference to the frontend after deleting
the backing i2c device.

This has the unfortunate side effect the frontend device is never freed
in the dvb core leaving a dangling device, leading to errors when the
dvb core tries to register the frontend after e.g. a replug as reported
here: https://www.spinics.net/lists/linux-media/msg138181.html

media: dvbsky: issues with DVBSky T680CI

===
[  561.119145] sp2 8-0040: CIMaX SP2 successfully attached
[  561.119161] usb 2-3: DVB: registering adapter 0 frontend 0 (Silicon Labs
Si2168)...
[  561.119174] sysfs: cannot create duplicate filename '/class/dvb/
dvb0.frontend0'
===

The use after free happened as dvb_usbv2_disconnect calls in this order:
- dvb_usb_device::props->exit(...)
- dvb_usbv2_adapter_frontend_exit(...)
  + if (fe) dvb_unregister_frontend(fe)
  + dvb_usb_device::props->frontend_detach(...)

Moving the release of the i2c device from exit() to frontend_detach()
avoids the dangling pointer access and allows the core to unregister
the frontend.

This was originally reported for a DVBSky T680CI, but it also affects
the MyGica T230C. As all supported devices structure the registration/
unregistration identically, apply the change for all device types.
Signed-off-by: default avatarStefan Brüns <stefan.bruens@rwth-aachen.de>
Signed-off-by: default avatarSean Young <sean@mess.org>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent ef4bb63d
...@@ -615,16 +615,18 @@ static int dvbsky_init(struct dvb_usb_device *d) ...@@ -615,16 +615,18 @@ static int dvbsky_init(struct dvb_usb_device *d)
return 0; return 0;
} }
static void dvbsky_exit(struct dvb_usb_device *d) static int dvbsky_frontend_detach(struct dvb_usb_adapter *adap)
{ {
struct dvb_usb_device *d = adap_to_d(adap);
struct dvbsky_state *state = d_to_priv(d); struct dvbsky_state *state = d_to_priv(d);
struct dvb_usb_adapter *adap = &d->adapter[0];
dev_dbg(&d->udev->dev, "%s: adap=%d\n", __func__, adap->id);
dvb_module_release(state->i2c_client_tuner); dvb_module_release(state->i2c_client_tuner);
dvb_module_release(state->i2c_client_demod); dvb_module_release(state->i2c_client_demod);
dvb_module_release(state->i2c_client_ci); dvb_module_release(state->i2c_client_ci);
adap->fe[0] = NULL; return 0;
} }
/* DVB USB Driver stuff */ /* DVB USB Driver stuff */
...@@ -640,11 +642,11 @@ static struct dvb_usb_device_properties dvbsky_s960_props = { ...@@ -640,11 +642,11 @@ static struct dvb_usb_device_properties dvbsky_s960_props = {
.i2c_algo = &dvbsky_i2c_algo, .i2c_algo = &dvbsky_i2c_algo,
.frontend_attach = dvbsky_s960_attach, .frontend_attach = dvbsky_s960_attach,
.frontend_detach = dvbsky_frontend_detach,
.init = dvbsky_init, .init = dvbsky_init,
.get_rc_config = dvbsky_get_rc_config, .get_rc_config = dvbsky_get_rc_config,
.streaming_ctrl = dvbsky_streaming_ctrl, .streaming_ctrl = dvbsky_streaming_ctrl,
.identify_state = dvbsky_identify_state, .identify_state = dvbsky_identify_state,
.exit = dvbsky_exit,
.read_mac_address = dvbsky_read_mac_addr, .read_mac_address = dvbsky_read_mac_addr,
.num_adapters = 1, .num_adapters = 1,
...@@ -667,11 +669,11 @@ static struct dvb_usb_device_properties dvbsky_s960c_props = { ...@@ -667,11 +669,11 @@ static struct dvb_usb_device_properties dvbsky_s960c_props = {
.i2c_algo = &dvbsky_i2c_algo, .i2c_algo = &dvbsky_i2c_algo,
.frontend_attach = dvbsky_s960c_attach, .frontend_attach = dvbsky_s960c_attach,
.frontend_detach = dvbsky_frontend_detach,
.init = dvbsky_init, .init = dvbsky_init,
.get_rc_config = dvbsky_get_rc_config, .get_rc_config = dvbsky_get_rc_config,
.streaming_ctrl = dvbsky_streaming_ctrl, .streaming_ctrl = dvbsky_streaming_ctrl,
.identify_state = dvbsky_identify_state, .identify_state = dvbsky_identify_state,
.exit = dvbsky_exit,
.read_mac_address = dvbsky_read_mac_addr, .read_mac_address = dvbsky_read_mac_addr,
.num_adapters = 1, .num_adapters = 1,
...@@ -694,11 +696,11 @@ static struct dvb_usb_device_properties dvbsky_t680c_props = { ...@@ -694,11 +696,11 @@ static struct dvb_usb_device_properties dvbsky_t680c_props = {
.i2c_algo = &dvbsky_i2c_algo, .i2c_algo = &dvbsky_i2c_algo,
.frontend_attach = dvbsky_t680c_attach, .frontend_attach = dvbsky_t680c_attach,
.frontend_detach = dvbsky_frontend_detach,
.init = dvbsky_init, .init = dvbsky_init,
.get_rc_config = dvbsky_get_rc_config, .get_rc_config = dvbsky_get_rc_config,
.streaming_ctrl = dvbsky_streaming_ctrl, .streaming_ctrl = dvbsky_streaming_ctrl,
.identify_state = dvbsky_identify_state, .identify_state = dvbsky_identify_state,
.exit = dvbsky_exit,
.read_mac_address = dvbsky_read_mac_addr, .read_mac_address = dvbsky_read_mac_addr,
.num_adapters = 1, .num_adapters = 1,
...@@ -721,11 +723,11 @@ static struct dvb_usb_device_properties dvbsky_t330_props = { ...@@ -721,11 +723,11 @@ static struct dvb_usb_device_properties dvbsky_t330_props = {
.i2c_algo = &dvbsky_i2c_algo, .i2c_algo = &dvbsky_i2c_algo,
.frontend_attach = dvbsky_t330_attach, .frontend_attach = dvbsky_t330_attach,
.frontend_detach = dvbsky_frontend_detach,
.init = dvbsky_init, .init = dvbsky_init,
.get_rc_config = dvbsky_get_rc_config, .get_rc_config = dvbsky_get_rc_config,
.streaming_ctrl = dvbsky_streaming_ctrl, .streaming_ctrl = dvbsky_streaming_ctrl,
.identify_state = dvbsky_identify_state, .identify_state = dvbsky_identify_state,
.exit = dvbsky_exit,
.read_mac_address = dvbsky_read_mac_addr, .read_mac_address = dvbsky_read_mac_addr,
.num_adapters = 1, .num_adapters = 1,
...@@ -748,11 +750,11 @@ static struct dvb_usb_device_properties mygica_t230c_props = { ...@@ -748,11 +750,11 @@ static struct dvb_usb_device_properties mygica_t230c_props = {
.i2c_algo = &dvbsky_i2c_algo, .i2c_algo = &dvbsky_i2c_algo,
.frontend_attach = dvbsky_mygica_t230c_attach, .frontend_attach = dvbsky_mygica_t230c_attach,
.frontend_detach = dvbsky_frontend_detach,
.init = dvbsky_init, .init = dvbsky_init,
.get_rc_config = dvbsky_get_rc_config, .get_rc_config = dvbsky_get_rc_config,
.streaming_ctrl = dvbsky_streaming_ctrl, .streaming_ctrl = dvbsky_streaming_ctrl,
.identify_state = dvbsky_identify_state, .identify_state = dvbsky_identify_state,
.exit = dvbsky_exit,
.num_adapters = 1, .num_adapters = 1,
.adapter = { .adapter = {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment