summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuennadi Liakhovetski <g.liakhovetski@gmx.de>2013-01-09 12:14:48 (GMT)
committerMauro Carvalho Chehab <mchehab@redhat.com>2013-04-04 22:38:27 (GMT)
commit2400a1f89d329ad8948c08e6e08fef33ce42f73b (patch)
treebd414e8bc45b187584624d7b7f9e7d49f84ee236
parent53faa685fa7df0e12751eebbda30bc7e7bb5e71a (diff)
downloadlinux-fsl-qoriq-2400a1f89d329ad8948c08e6e08fef33ce42f73b.tar.xz
[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>
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c42
1 files changed, 28 insertions, 14 deletions
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index bf55abf..eea832c 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -508,36 +508,49 @@ static int soc_camera_set_fmt(struct soc_camera_device *icd,
static int soc_camera_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct soc_camera_device *icd = dev_get_drvdata(vdev->parent);
- struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
+ struct soc_camera_device *icd;
struct soc_camera_host *ici;
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
- * scan_add_host() completes
+ * scan_add_host() completes. Also protect against a race with
+ * soc_camera_host_unregister().
*/
if (mutex_lock_interruptible(&list_lock))
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);
+
+ ret = try_module_get(ici->ops->owner) ? 0 : -ENODEV;
mutex_unlock(&list_lock);
- if (mutex_lock_interruptible(&ici->host_lock))
- return -ERESTARTSYS;
- if (!try_module_get(ici->ops->owner)) {
+ if (ret < 0) {
dev_err(icd->pdev, "Couldn't lock capture bus driver.\n");
- ret = -EINVAL;
- goto emodule;
+ 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++;
/* Now we really have to activate the camera */
if (icd->use_count == 1) {
+ struct soc_camera_desc *sdesc = to_soc_camera_desc(icd);
/* Restore parameters before the last close() per V4L2 API */
struct v4l2_format f = {
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
@@ -609,9 +622,10 @@ epower:
ici->ops->remove(icd);
eiciadd:
icd->use_count--;
- module_put(ici->ops->owner);
-emodule:
mutex_unlock(&ici->host_lock);
+elockhost:
+econtrol:
+ module_put(ici->ops->owner);
return ret;
}