Using vfinddev() leads to vnode races as it returns an unreferenced

vnode that may disappear before the caller has a chance to reference it.

Reference the vnode while the specfs cache is locked.

Welcome to 5.99.37.

No objections on tech-kern.
This commit is contained in:
hannken 2010-07-21 09:06:37 +00:00
parent e698a5d246
commit 1664eae7f3
6 changed files with 35 additions and 22 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: vnode.9,v 1.49 2010/06/06 08:01:31 hannken Exp $
.\" $NetBSD: vnode.9,v 1.50 2010/07/21 09:06:37 hannken Exp $
.\"
.\" Copyright (c) 2001, 2005, 2006 The NetBSD Foundation, Inc.
.\" All rights reserved.
@ -27,7 +27,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd June 6, 2010
.Dd July 21, 2010
.Dt VNODE 9
.Os
.Sh NAME
@ -654,7 +654,7 @@ Create a vnode for a character device.
is used for the console and kernfs special devices.
.It Fn vfinddev "dev" "vtype" "vpp"
Lookup a vnode by device number.
The vnode is returned in the address specified by
The vnode is referenced and returned in the address specified by
.Fa vpp .
.It Fn vdevgone "int maj" "int min" "int minh" "enum vtype type"
Reclaim all vnodes that correspond to the specified minor number range

View File

@ -1146,6 +1146,9 @@ int drm_mapbufs(struct drm_device *dev, void *data, struct drm_file *file_priv)
done:
request->count = dma->buf_count;
#if defined(__NetBSD__)
vrele(vn);
#endif
DRM_DEBUG("%d buffers, retcode = %d\n", request->count, retcode);

View File

@ -1,4 +1,4 @@
/* $NetBSD: vfs_subr.c,v 1.408 2010/07/01 13:00:56 hannken Exp $ */
/* $NetBSD: vfs_subr.c,v 1.409 2010/07/21 09:06:38 hannken Exp $ */
/*-
* Copyright (c) 1997, 1998, 2004, 2005, 2007, 2008 The NetBSD Foundation, Inc.
@ -91,7 +91,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.408 2010/07/01 13:00:56 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: vfs_subr.c,v 1.409 2010/07/21 09:06:38 hannken Exp $");
#include "opt_ddb.h"
#include "opt_compat_netbsd.h"
@ -1993,24 +1993,28 @@ vgone(vnode_t *vp)
}
/*
* Lookup a vnode by device number.
* Lookup a vnode by device number and return it referenced.
*/
int
vfinddev(dev_t dev, enum vtype type, vnode_t **vpp)
{
vnode_t *vp;
int rc = 0;
mutex_enter(&device_lock);
for (vp = specfs_hash[SPECHASH(dev)]; vp; vp = vp->v_specnext) {
if (dev != vp->v_rdev || type != vp->v_type)
continue;
*vpp = vp;
rc = 1;
break;
if (dev == vp->v_rdev && type == vp->v_type)
break;
}
if (vp == NULL) {
mutex_exit(&device_lock);
return 0;
}
mutex_enter(&vp->v_interlock);
mutex_exit(&device_lock);
return (rc);
if (vget(vp, LK_INTERLOCK) != 0)
return 0;
*vpp = vp;
return 1;
}
/*
@ -3366,9 +3370,11 @@ rawdev_mounted(struct vnode *vp, struct vnode **bvpp)
blkdev = devsw_chr2blk(dev);
if (blkdev != NODEV) {
vfinddev(blkdev, VBLK, &bvp);
if (bvp != NULL)
if (vfinddev(blkdev, VBLK, &bvp) != 0) {
d_type = (cdev->d_flag & D_TYPEMASK);
/* XXX: what if bvp disappears? */
vrele(bvp);
}
}
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: kernfs_subr.c,v 1.21 2010/07/01 13:00:56 hannken Exp $ */
/* $NetBSD: kernfs_subr.c,v 1.22 2010/07/21 09:06:38 hannken Exp $ */
/*
* Copyright (c) 1993
@ -73,7 +73,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kernfs_subr.c,v 1.21 2010/07/01 13:00:56 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: kernfs_subr.c,v 1.22 2010/07/21 09:06:38 hannken Exp $");
#ifdef _KERNEL_OPT
#include "opt_ipsec.h"
@ -176,8 +176,10 @@ kernfs_allocvp(struct mount *mp, struct vnode **vpp, kfstype kfs_type, const str
return (ENOENT);
}
vp = fvp;
if (vget(fvp, LK_EXCLUSIVE))
if (vn_lock(fvp, LK_EXCLUSIVE)) {
vrele(fvp);
goto loop;
}
*vpp = vp;
mutex_exit(&kfs_hashlock);
return (0);

View File

@ -1,4 +1,4 @@
/* $NetBSD: kernfs_vnops.c,v 1.142 2010/06/24 13:03:16 hannken Exp $ */
/* $NetBSD: kernfs_vnops.c,v 1.143 2010/07/21 09:06:38 hannken Exp $ */
/*
* Copyright (c) 1992, 1993
@ -39,7 +39,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.142 2010/06/24 13:03:16 hannken Exp $");
__KERNEL_RCSID(0, "$NetBSD: kernfs_vnops.c,v 1.143 2010/07/21 09:06:38 hannken Exp $");
#ifdef _KERNEL_OPT
#include "opt_ipsec.h"
@ -1168,6 +1168,7 @@ kernfs_readdir(void *v)
if (*dp == NODEV ||
!vfinddev(*dp, kt->kt_vtype, &fvp))
continue;
vrele(fvp);
}
if (kt->kt_tag == KFSmsgbuf) {
if (!msgbufenabled
@ -1250,6 +1251,7 @@ kernfs_readdir(void *v)
if (*dp == NODEV ||
!vfinddev(*dp, kt->kt_vtype, &fvp))
continue;
vrele(fvp);
}
d.d_namlen = kt->kt_namlen;
if ((error = kernfs_setdirentfileno(&d, i, kfs,

View File

@ -1,4 +1,4 @@
/* $NetBSD: param.h,v 1.371 2010/07/08 12:23:31 rmind Exp $ */
/* $NetBSD: param.h,v 1.372 2010/07/21 09:06:37 hannken Exp $ */
/*-
* Copyright (c) 1982, 1986, 1989, 1993
@ -63,7 +63,7 @@
* 2.99.9 (299000900)
*/
#define __NetBSD_Version__ 599003600 /* NetBSD 5.99.36 */
#define __NetBSD_Version__ 599003700 /* NetBSD 5.99.37 */
#define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
(m) * 1000000) + (p) * 100) <= __NetBSD_Version__)