Commit 2400a1f8 authored by Guennadi Liakhovetski's avatar Guennadi Liakhovetski Committed by Mauro Carvalho Chehab

[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: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 53faa685
...@@ -508,36 +508,49 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd, ...@@ -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;
if (!vdev || !video_is_registered(vdev)) {
mutex_unlock(&list_lock);
return -ENODEV;
}
icd = dev_get_drvdata(vdev->parent);
ici = to_soc_camera_host(icd->parent); ici = to_soc_camera_host(icd->parent);
ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV;
mutex_unlock(&list_lock); mutex_unlock(&list_lock);
if (mutex_lock_interruptible(&ici->host_lock)) if (ret < 0) {
return -ERESTARTSYS;
if (!try_module_get(ici->ops->owner)) {
dev_err(icd->pdev, "Couldn't lock capture bus driver.\n"); dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
ret = -EINVAL; return ret;
goto emodule; }
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 @@ static int soc_camera_open(struct file *file) ...@@ -609,9 +622,10 @@ static int soc_camera_open(struct file *file)
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;
} }
......
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