diff options
author | tegge <tegge@FreeBSD.org> | 2000-08-09 01:57:11 +0000 |
---|---|---|
committer | tegge <tegge@FreeBSD.org> | 2000-08-09 01:57:11 +0000 |
commit | 31d32eb7b17096bc631f7f00b1420754eac118b9 (patch) | |
tree | d301ee68a27508451a9155c0d2171300c23e8af0 /sys/kern/vfs_extattr.c | |
parent | 2eaedc55c80e3792597be951cb8634c86aef49b0 (diff) | |
download | FreeBSD-src-31d32eb7b17096bc631f7f00b1420754eac118b9.zip FreeBSD-src-31d32eb7b17096bc631f7f00b1420754eac118b9.tar.gz |
Don't set flags on the mount structure before all permission checks have
been done.
Don't allow multiple mount operations with MNT_UPDATE at the same
time on the same mount point. When the first mount operation
completed, MNT_UPDATE was cleared in the mount structure, causing
the second to complete as if it was a no-update mount operation
with the following bad side effects:
- mount structure inserted multiple times onto the mountlist
- vp->v_mountedhere incorrectly set, causing next namei
operation walking into the mountpoint to crash with
a locking against myself panic.
Plug a vnode leak in case vinvalbuf fails.
Diffstat (limited to 'sys/kern/vfs_extattr.c')
-rw-r--r-- | sys/kern/vfs_extattr.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/sys/kern/vfs_extattr.c b/sys/kern/vfs_extattr.c index 3a15d64..9b68dd7 100644 --- a/sys/kern/vfs_extattr.c +++ b/sys/kern/vfs_extattr.c @@ -164,8 +164,6 @@ mount(p, uap) vput(vp); return (EOPNOTSUPP); /* Needs translation */ } - mp->mnt_flag |= SCARG(uap, flags) & - (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT); /* * Only root, or the user that did the original mount is * permitted to update it. @@ -179,6 +177,18 @@ mount(p, uap) vput(vp); return (EBUSY); } + simple_lock(&vp->v_interlock); + if ((vp->v_flag & VMOUNT) != 0 || + vp->v_mountedhere != NULL) { + simple_unlock(&vp->v_interlock); + vfs_unbusy(mp, p); + vput(vp); + return (EBUSY); + } + vp->v_flag |= VMOUNT; + simple_unlock(&vp->v_interlock); + mp->mnt_flag |= SCARG(uap, flags) & + (MNT_RELOAD | MNT_FORCE | MNT_UPDATE | MNT_SNAPSHOT); VOP_UNLOCK(vp, 0, p); goto update; } @@ -192,8 +202,10 @@ mount(p, uap) vput(vp); return (error); } - if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) + if ((error = vinvalbuf(vp, V_SAVE, p->p_ucred, p, 0, 0)) != 0) { + vput(vp); return (error); + } if (vp->v_type != VDIR) { vput(vp); return (ENOTDIR); @@ -300,7 +312,6 @@ update: */ error = VFS_MOUNT(mp, SCARG(uap, path), SCARG(uap, data), &nd, p); if (mp->mnt_flag & MNT_UPDATE) { - vrele(vp); if (mp->mnt_kern_flag & MNTK_WANTRDWR) mp->mnt_flag &= ~MNT_RDONLY; mp->mnt_flag &=~ @@ -319,6 +330,10 @@ update: mp->mnt_syncer = NULL; } vfs_unbusy(mp, p); + simple_lock(&vp->v_interlock); + vp->v_flag &= ~VMOUNT; + simple_unlock(&vp->v_interlock); + vrele(vp); return (error); } vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, p); |