From patchwork Tue Apr 2 14:07:30 2013 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Guennadi Liakhovetski X-Patchwork-Id: 2378671 Return-Path: X-Original-To: patchwork-linux-media@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork1.kernel.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by patchwork1.kernel.org (Postfix) with ESMTP id 259C33FD8C for ; Tue, 2 Apr 2013 14:07:35 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1760842Ab3DBOHc (ORCPT ); Tue, 2 Apr 2013 10:07:32 -0400 Received: from moutng.kundenserver.de ([212.227.17.8]:54208 "EHLO moutng.kundenserver.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1760543Ab3DBOHc (ORCPT ); Tue, 2 Apr 2013 10:07:32 -0400 Received: from axis700.grange (dslb-188-109-035-074.pools.arcor-ip.net [188.109.35.74]) by mrelayeu.kundenserver.de (node=mreu2) with ESMTP (Nemesis) id 0LcTCs-1V5OlQ44Na-00jLa5; Tue, 02 Apr 2013 16:07:31 +0200 Received: by axis700.grange (Postfix, from userid 1000) id 6FA2C40BB4; Tue, 2 Apr 2013 16:07:30 +0200 (CEST) Received: from localhost (localhost [127.0.0.1]) by axis700.grange (Postfix) with ESMTP id 6356640BB3 for ; Tue, 2 Apr 2013 16:07:30 +0200 (CEST) Date: Tue, 2 Apr 2013 16:07:30 +0200 (CEST) From: Guennadi Liakhovetski X-X-Sender: lyakh@axis700.grange To: Linux Media Mailing List Subject: [PATCH] soc-camera: protect against racing open(2) and rmmod Message-ID: MIME-Version: 1.0 X-Provags-ID: V02:K0:BHt8YzWiB5j6UkpCGFWSjbO94vBQkoIH9rdsE7bKAy/ 1g7L6uhZbgv2d1SqgnsdZOUmjQm4OFaPoOoG29KvsyqYqVIug/ 64ZuCu9lgQqA7Ep+eU1tfx6sBMzBZNctc43c8W4tt6HcM9IUSq hOq/q5Oj95Zb1uJiBVpgkmkt6I7liY2uGHwY7uflNhFaoRU9S7 xehVZo1H6S+l7A4+uJG0EsJ4VRtRQTMhG3+LKzUCw47JoQBAck s4DmiEEr0zSNEjLTFFAyFq3VEj3PIW67/3nuJj3njHNh2Rp0e/ hscg+3UhkqTXYsvzhtXHxfEdtKC6ZU3BK2vAHzXfEwFINBbR2U 07ZtWDyEIZIzGVfa8h0XcbV01VoV5bYlQbvyH66Uj7o9eTU8tX ZzcT6mMHjwptQ== Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org 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 --- drivers/media/platform/soc_camera/soc_camera.c | 42 ++++++++++++++++-------- 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 8ec9805..9cc3898 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; }