diff options
author | kib <kib@FreeBSD.org> | 2009-06-10 13:57:36 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2009-06-10 13:57:36 +0000 |
commit | e0d7459c716fb9105aa2ae9ebf00c6de6a1f8796 (patch) | |
tree | 073060ebf4b60bba932ec2b080cc808f1b347c02 /sys/fs/pseudofs | |
parent | ff56813d72ced1434a2e9649783a322834dc196f (diff) | |
download | FreeBSD-src-e0d7459c716fb9105aa2ae9ebf00c6de6a1f8796.zip FreeBSD-src-e0d7459c716fb9105aa2ae9ebf00c6de6a1f8796.tar.gz |
VOP_IOCTL takes unlocked vnode as an argument. Due to this, v_data may
be NULL or derefenced memory may become free at arbitrary moment.
Lock the vnode in cd9660, devfs and pseudofs implementation of VOP_IOCTL
to prevent reclaim; check whether the vnode was already reclaimed after
the lock is granted.
Reported by: georg at dts su
Reviewed by: des (pseudofs)
MFC after: 2 weeks
Diffstat (limited to 'sys/fs/pseudofs')
-rw-r--r-- | sys/fs/pseudofs/pseudofs_vnops.c | 28 |
1 files changed, 22 insertions, 6 deletions
diff --git a/sys/fs/pseudofs/pseudofs_vnops.c b/sys/fs/pseudofs/pseudofs_vnops.c index 7cd9ca4..8421d17 100644 --- a/sys/fs/pseudofs/pseudofs_vnops.c +++ b/sys/fs/pseudofs/pseudofs_vnops.c @@ -260,34 +260,50 @@ pfs_getattr(struct vop_getattr_args *va) static int pfs_ioctl(struct vop_ioctl_args *va) { - struct vnode *vn = va->a_vp; - struct pfs_vdata *pvd = vn->v_data; - struct pfs_node *pn = pvd->pvd_pn; + struct vnode *vn; + struct pfs_vdata *pvd; + struct pfs_node *pn; struct proc *proc; int error; + vn = va->a_vp; + vn_lock(vn, LK_SHARED | LK_RETRY); + if (vn->v_iflag & VI_DOOMED) { + VOP_UNLOCK(vn, 0); + return (EBADF); + } + pvd = vn->v_data; + pn = pvd->pvd_pn; + PFS_TRACE(("%s: %lx", pn->pn_name, va->a_command)); pfs_assert_not_owned(pn); - if (vn->v_type != VREG) + if (vn->v_type != VREG) { + VOP_UNLOCK(vn, 0); PFS_RETURN (EINVAL); + } KASSERT_PN_IS_FILE(pn); - if (pn->pn_ioctl == NULL) + if (pn->pn_ioctl == NULL) { + VOP_UNLOCK(vn, 0); PFS_RETURN (ENOTTY); + } /* * This is necessary because process' privileges may * have changed since the open() call. */ - if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) + if (!pfs_visible(curthread, pn, pvd->pvd_pid, &proc)) { + VOP_UNLOCK(vn, 0); PFS_RETURN (EIO); + } error = pn_ioctl(curthread, proc, pn, va->a_command, va->a_data); if (proc != NULL) PROC_UNLOCK(proc); + VOP_UNLOCK(vn, 0); PFS_RETURN (error); } |