From 1a992b271589d2ac1b193ade019c9eddf663444e Mon Sep 17 00:00:00 2001 From: pooka Date: Thu, 8 Apr 2010 15:56:26 +0000 Subject: [PATCH] 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 --- sys/miscfs/genfs/genfs_vnops.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/sys/miscfs/genfs/genfs_vnops.c b/sys/miscfs/genfs/genfs_vnops.c index 5139ac21d521..27bcca8fa4ea 100644 --- a/sys/miscfs/genfs/genfs_vnops.c +++ b/sys/miscfs/genfs/genfs_vnops.c @@ -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 -__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 #include @@ -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)