From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754669AbYJPN23 (ORCPT ); Thu, 16 Oct 2008 09:28:29 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752187AbYJPN2U (ORCPT ); Thu, 16 Oct 2008 09:28:20 -0400 Received: from cantor2.suse.de ([195.135.220.15]:51051 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751816AbYJPN2U (ORCPT ); Thu, 16 Oct 2008 09:28:20 -0400 Date: Thu, 16 Oct 2008 15:28:00 +0200 Message-ID: From: Takashi Iwai To: Laurent Pinchart Cc: linux-kernel@vger.kernel.org, airlied@linux.ie, mchehab@infradead.org, perex@perex.cz, alan-jenkins@tuffmail.co.uk Subject: Re: [PATCH] Check fops_get() return value In-Reply-To: <200810161502.41159.laurent.pinchart@skynet.be> References: <200810161502.41159.laurent.pinchart@skynet.be> User-Agent: Wanderlust/2.12.0 (Your Wildest Dreams) SEMI/1.14.6 (Maruoka) FLIM/1.14.7 (=?ISO-8859-4?Q?Sanj=F2?=) APEL/10.6 Emacs/22.3 (x86_64-suse-linux-gnu) MULE/5.0 (SAKAKI) MIME-Version: 1.0 (generated by SEMI 1.14.6 - "Maruoka") Content-Type: text/plain; charset=US-ASCII Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org At Thu, 16 Oct 2008 15:02:40 +0200, Laurent Pinchart wrote: > > Several subsystem open handlers dereference the fops_get() return value > without checking it for nullness. This opens a race condition between the > open handler and module unloading. > > A module can be marked as being unloaded (MODULE_STATE_GOING) before its exit > function is called and gets the chance to unregister the driver. During that > window open handlers can still be called, and fops_get() will fail in > try_module_get() and return a NULL pointer. > > This change checks the fops_get() return value and returns -ENODEV if NULL. > > Reported-by: Alan Jenkins > Signed-off-by: Laurent Pinchart > --- > drivers/gpu/drm/drm_fops.c | 4 ++++ > drivers/media/dvb/dvb-core/dvbdev.c | 5 +++++ > sound/core/sound.c | 4 ++++ > 3 files changed, 13 insertions(+), 0 deletions(-) > > diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c > index 851a53f..ef5c295 100644 > --- a/drivers/gpu/drm/drm_fops.c > +++ b/drivers/gpu/drm/drm_fops.c > @@ -186,6 +186,10 @@ int drm_stub_open(struct inode *inode, struct file *filp) > > old_fops = filp->f_op; > filp->f_op = fops_get(&dev->driver->fops); > + if (filp->f_op == NULL) { I think the more standard style is if (!file->fop) { Except for that minor issue, it looks good to me. In any case, Acked-by: Takashi Iwai thanks, Takashi > + filp->f_op = old_fops; > + goto out; > + } > if (filp->f_op->open && (err = filp->f_op->open(inode, filp))) { > fops_put(filp->f_op); > filp->f_op = fops_get(old_fops); > diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c > index e713277..fb4e241 100644 > --- a/drivers/media/dvb/dvb-core/dvbdev.c > +++ b/drivers/media/dvb/dvb-core/dvbdev.c > @@ -85,6 +85,10 @@ static int dvb_device_open(struct inode *inode, struct file *file) > file->private_data = dvbdev; > old_fops = file->f_op; > file->f_op = fops_get(dvbdev->fops); > + if (file->f_op == NULL) { > + file->f_op = old_fops; > + goto fail; > + } > if(file->f_op->open) > err = file->f_op->open(inode,file); > if (err) { > @@ -95,6 +99,7 @@ static int dvb_device_open(struct inode *inode, struct file *file) > unlock_kernel(); > return err; > } > +fail: > unlock_kernel(); > return -ENODEV; > } > diff --git a/sound/core/sound.c b/sound/core/sound.c > index c0685e2..8659b84 100644 > --- a/sound/core/sound.c > +++ b/sound/core/sound.c > @@ -152,6 +152,10 @@ static int __snd_open(struct inode *inode, struct file *file) > } > old_fops = file->f_op; > file->f_op = fops_get(mptr->f_ops); > + if (file->f_op == NULL) { > + file->f_op = old_fops; > + return -ENODEV; > + } > if (file->f_op->open) > err = file->f_op->open(inode, file); > if (err) { > -- > 1.5.0 >