Commit ea9ea6c6 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'media/v4.9-4' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media

Pull media fix from Mauro Carvalho Chehab:
 "Fix for the firmware load logic of the tuner-xc2028 driver"

* tag 'media/v4.9-4' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media:
  xc2028: Fix use-after-free bug properly
parents 6006d6e7 22a1e778
...@@ -281,6 +281,14 @@ static void free_firmware(struct xc2028_data *priv) ...@@ -281,6 +281,14 @@ static void free_firmware(struct xc2028_data *priv)
int i; int i;
tuner_dbg("%s called\n", __func__); tuner_dbg("%s called\n", __func__);
/* free allocated f/w string */
if (priv->fname != firmware_name)
kfree(priv->fname);
priv->fname = NULL;
priv->state = XC2028_NO_FIRMWARE;
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
if (!priv->firm) if (!priv->firm)
return; return;
...@@ -291,9 +299,6 @@ static void free_firmware(struct xc2028_data *priv) ...@@ -291,9 +299,6 @@ static void free_firmware(struct xc2028_data *priv)
priv->firm = NULL; priv->firm = NULL;
priv->firm_size = 0; priv->firm_size = 0;
priv->state = XC2028_NO_FIRMWARE;
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
} }
static int load_all_firmwares(struct dvb_frontend *fe, static int load_all_firmwares(struct dvb_frontend *fe,
...@@ -884,9 +889,8 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type, ...@@ -884,9 +889,8 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
return 0; return 0;
fail: fail:
priv->state = XC2028_NO_FIRMWARE; free_firmware(priv);
memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
if (retry_count < 8) { if (retry_count < 8) {
msleep(50); msleep(50);
retry_count++; retry_count++;
...@@ -1332,11 +1336,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe) ...@@ -1332,11 +1336,8 @@ static int xc2028_dvb_release(struct dvb_frontend *fe)
mutex_lock(&xc2028_list_mutex); mutex_lock(&xc2028_list_mutex);
/* only perform final cleanup if this is the last instance */ /* only perform final cleanup if this is the last instance */
if (hybrid_tuner_report_instance_count(priv) == 1) { if (hybrid_tuner_report_instance_count(priv) == 1)
free_firmware(priv); free_firmware(priv);
kfree(priv->ctrl.fname);
priv->ctrl.fname = NULL;
}
if (priv) if (priv)
hybrid_tuner_release_state(priv); hybrid_tuner_release_state(priv);
...@@ -1399,19 +1400,8 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) ...@@ -1399,19 +1400,8 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
/* /*
* Copy the config data. * Copy the config data.
* For the firmware name, keep a local copy of the string,
* in order to avoid troubles during device release.
*/ */
kfree(priv->ctrl.fname);
priv->ctrl.fname = NULL;
memcpy(&priv->ctrl, p, sizeof(priv->ctrl)); memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
if (p->fname) {
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL) {
rc = -ENOMEM;
goto unlock;
}
}
/* /*
* If firmware name changed, frees firmware. As free_firmware will * If firmware name changed, frees firmware. As free_firmware will
...@@ -1426,10 +1416,15 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg) ...@@ -1426,10 +1416,15 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
if (priv->state == XC2028_NO_FIRMWARE) { if (priv->state == XC2028_NO_FIRMWARE) {
if (!firmware_name[0]) if (!firmware_name[0])
priv->fname = priv->ctrl.fname; priv->fname = kstrdup(p->fname, GFP_KERNEL);
else else
priv->fname = firmware_name; priv->fname = firmware_name;
if (!priv->fname) {
rc = -ENOMEM;
goto unlock;
}
rc = request_firmware_nowait(THIS_MODULE, 1, rc = request_firmware_nowait(THIS_MODULE, 1,
priv->fname, priv->fname,
priv->i2c_props.adap->dev.parent, priv->i2c_props.adap->dev.parent,
......
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