Call VOP_ABORTOP in genfs_eopnotsupp. This prevents file system

authors from having to get down on their knees and pray they won't
get POGA'd(*) again.

This plugs componentname leaks in at least smbfs and buggy puffs
servers (buggy servers shouldn't be able to leak kernel memory).

*) principle of greatest astonishment
This commit is contained in:
pooka 2010-04-08 15:56:26 +00:00
parent ed7e284d5c
commit 1a992b2715
1 changed files with 28 additions and 6 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: genfs_vnops.c,v 1.176 2010/01/27 15:52:31 uebayasi Exp $ */
/* $NetBSD: genfs_vnops.c,v 1.177 2010/04/08 15:56:26 pooka Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
@ -57,7 +57,7 @@
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.176 2010/01/27 15:52:31 uebayasi Exp $");
__KERNEL_RCSID(0, "$NetBSD: genfs_vnops.c,v 1.177 2010/04/08 15:56:26 pooka Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -170,7 +170,8 @@ genfs_einval(void *v)
/*
* Called when an fs doesn't support a particular vop.
* This takes care to vrele, vput, or vunlock passed in vnodes.
* This takes care to vrele, vput, or vunlock passed in vnodes
* and calls VOP_ABORTOP for a componentname (in non-rename VOP).
*/
int
genfs_eopnotsupp(void *v)
@ -181,14 +182,35 @@ genfs_eopnotsupp(void *v)
} */ *ap = v;
struct vnodeop_desc *desc = ap->a_desc;
struct vnode *vp, *vp_last = NULL;
int flags, i, j, offset;
int flags, i, j, offset_cnp, offset_vp;
KASSERT(desc->vdesc_offset != VOP_LOOKUP_DESCOFFSET);
KASSERT(desc->vdesc_offset != VOP_ABORTOP_DESCOFFSET);
/*
* Free componentname that lookup potentially SAVENAMEd.
*
* As is logical, componentnames for VOP_RENAME are handled by
* the caller of VOP_RENAME. Yay, rename!
*/
if (desc->vdesc_offset != VOP_RENAME_DESCOFFSET &&
(offset_vp = desc->vdesc_vp_offsets[0]) != VDESC_NO_OFFSET &&
(offset_cnp = desc->vdesc_componentname_offset) != VDESC_NO_OFFSET){
struct componentname *cnp;
struct vnode *dvp;
dvp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
cnp = *VOPARG_OFFSETTO(struct componentname **, offset_cnp, ap);
VOP_ABORTOP(dvp, cnp);
}
flags = desc->vdesc_flags;
for (i = 0; i < VDESC_MAX_VPS; flags >>=1, i++) {
if ((offset = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
if ((offset_vp = desc->vdesc_vp_offsets[i]) == VDESC_NO_OFFSET)
break; /* stop at end of list */
if ((j = flags & VDESC_VP0_WILLPUT)) {
vp = *VOPARG_OFFSETTO(struct vnode **, offset, ap);
vp = *VOPARG_OFFSETTO(struct vnode **, offset_vp, ap);
/* Skip if NULL */
if (!vp)