[media] soc-camera: protect against racing open(2) and rmmod
To protect against open() racing with rmmod, hold the list_lock also while obtaining a reference to the camera host driver and check that the video device hasn't been unregistered yet. Signed-off-by: Guennadi Liakhovetski <g.liakhovetski@gmx.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
53faa685fa
commit
2400a1f89d
|
@ -508,36 +508,49 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
|
||||||
static int soc_camera_open(struct file *file)
|
static int soc_camera_open(struct file *file)
|
||||||
{
|
{
|
||||||
struct video_device *vdev = video_devdata(file);
|
struct video_device *vdev = video_devdata(file);
|
||||||
struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
|
struct soc_camera_device *icd;
|
||||||
struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
|
|
||||||
struct soc_camera_host *ici;
|
struct soc_camera_host *ici;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!to_soc_camera_control(icd))
|
|
||||||
/* No device driver attached */
|
|
||||||
return -ENODEV;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't mess with the host during probe: wait until the loop in
|
* Don't mess with the host during probe: wait until the loop in
|
||||||
* scan_add_host() completes
|
* scan_add_host() completes. Also protect against a race with
|
||||||
|
* soc_camera_host_unregister().
|
||||||
*/
|
*/
|
||||||
if (mutex_lock_interruptible(&list_lock))
|
if (mutex_lock_interruptible(&list_lock))
|
||||||
return -ERESTARTSYS;
|
return -ERESTARTSYS;
|
||||||
ici = to_soc_camera_host(icd->parent);
|
|
||||||
mutex_unlock(&list_lock);
|
|
||||||
|
|
||||||
if (mutex_lock_interruptible(&ici->host_lock))
|
if (!vdev || !video_is_registered(vdev)) {
|
||||||
return -ERESTARTSYS;
|
mutex_unlock(&list_lock);
|
||||||
if (!try_module_get(ici->ops->owner)) {
|
return -ENODEV;
|
||||||
dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
|
|
||||||
ret = -EINVAL;
|
|
||||||
goto emodule;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
icd = dev_get_drvdata(vdev->parent);
|
||||||
|
ici = to_soc_camera_host(icd->parent);
|
||||||
|
|
||||||
|
ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV;
|
||||||
|
mutex_unlock(&list_lock);
|
||||||
|
|
||||||
|
if (ret < 0) {
|
||||||
|
dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!to_soc_camera_control(icd)) {
|
||||||
|
/* No device driver attached */
|
||||||
|
ret = -ENODEV;
|
||||||
|
goto econtrol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mutex_lock_interruptible(&ici->host_lock)) {
|
||||||
|
ret = -ERESTARTSYS;
|
||||||
|
goto elockhost;
|
||||||
|
}
|
||||||
icd->use_count++;
|
icd->use_count++;
|
||||||
|
|
||||||
/* Now we really have to activate the camera */
|
/* Now we really have to activate the camera */
|
||||||
if (icd->use_count == 1) {
|
if (icd->use_count == 1) {
|
||||||
|
struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
|
||||||
/* Restore parameters before the last close() per V4L2 API */
|
/* Restore parameters before the last close() per V4L2 API */
|
||||||
struct v4l2_format f = {
|
struct v4l2_format f = {
|
||||||
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
|
||||||
|
@ -609,9 +622,10 @@ epower:
|
||||||
ici->ops->remove(icd);
|
ici->ops->remove(icd);
|
||||||
eiciadd:
|
eiciadd:
|
||||||
icd->use_count--;
|
icd->use_count--;
|
||||||
module_put(ici->ops->owner);
|
|
||||||
emodule:
|
|
||||||
mutex_unlock(&ici->host_lock);
|
mutex_unlock(&ici->host_lock);
|
||||||
|
elockhost:
|
||||||
|
econtrol:
|
||||||
|
module_put(ici->ops->owner);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue