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
This commit is contained in:
parent
9837f3e457
commit
c4df27d5c8
@ -251,20 +251,31 @@ cd9660_ioctl(ap)
|
||||
struct thread *a_td;
|
||||
} */ *ap;
|
||||
{
|
||||
struct vnode *vp = ap->a_vp;
|
||||
struct iso_node *ip = VTOI(vp);
|
||||
struct vnode *vp;
|
||||
struct iso_node *ip;
|
||||
int error;
|
||||
|
||||
if (vp->v_type == VCHR || vp->v_type == VBLK)
|
||||
vp = ap->a_vp;
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
if (vp->v_type == VCHR || vp->v_type == VBLK) {
|
||||
VOP_UNLOCK(vp, 0);
|
||||
return (EOPNOTSUPP);
|
||||
}
|
||||
|
||||
ip = VTOI(vp);
|
||||
error = 0;
|
||||
|
||||
switch (ap->a_command) {
|
||||
|
||||
case FIOGETLBA:
|
||||
*(int *)(ap->a_data) = ip->iso_start;
|
||||
return 0;
|
||||
break;
|
||||
default:
|
||||
return (ENOTTY);
|
||||
error = ENOTTY;
|
||||
break;
|
||||
}
|
||||
|
||||
VOP_UNLOCK(vp, 0);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1276,11 +1276,19 @@ devfs_revoke(struct vop_revoke_args *ap)
|
||||
static int
|
||||
devfs_rioctl(struct vop_ioctl_args *ap)
|
||||
{
|
||||
int error;
|
||||
struct vnode *vp;
|
||||
struct devfs_mount *dmp;
|
||||
int error;
|
||||
|
||||
dmp = VFSTODEVFS(ap->a_vp->v_mount);
|
||||
vp = ap->a_vp;
|
||||
vn_lock(vp, LK_SHARED | LK_RETRY);
|
||||
if (vp->v_iflag & VI_DOOMED) {
|
||||
VOP_UNLOCK(vp, 0);
|
||||
return (EBADF);
|
||||
}
|
||||
dmp = VFSTODEVFS(vp->v_mount);
|
||||
sx_xlock(&dmp->dm_lock);
|
||||
VOP_UNLOCK(vp, 0);
|
||||
DEVFS_DMP_HOLD(dmp);
|
||||
devfs_populate(dmp);
|
||||
if (DEVFS_DMP_DROP(dmp)) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user