The quotactl, statfs and fstatfs syscall implementations may dereference
NULL pointer to struct mount if the looked up vnode is reclaimed. Also, these syscalls only mnt_ref() the mp, still allowing it to be unmounted; only struct mount memory is kept from being reused. Lock the vnode when doing name lookup, then reference its mount point, unlock the vnode and vfs_busy the mountpoint. This sequence shall take care of both races. Reported and tested by: pho Discussed with: attilio MFC after: 1 month
This commit is contained in:
parent
2cfddad734
commit
548066ea66
@ -200,19 +200,21 @@ quotactl(td, uap)
|
||||
AUDIT_ARG(uid, uap->uid);
|
||||
if (jailed(td->td_ucred) && !prison_quotas)
|
||||
return (EPERM);
|
||||
NDINIT(&nd, LOOKUP, FOLLOW | MPSAFE | AUDITVNODE1,
|
||||
NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1,
|
||||
UIO_USERSPACE, uap->path, td);
|
||||
if ((error = namei(&nd)) != 0)
|
||||
return (error);
|
||||
vfslocked = NDHASGIANT(&nd);
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
mp = nd.ni_vp->v_mount;
|
||||
if ((error = vfs_busy(mp, 0))) {
|
||||
vrele(nd.ni_vp);
|
||||
vfs_ref(mp);
|
||||
vput(nd.ni_vp);
|
||||
error = vfs_busy(mp, 0);
|
||||
vfs_rel(mp);
|
||||
if (error) {
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
return (error);
|
||||
}
|
||||
vrele(nd.ni_vp);
|
||||
error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, td);
|
||||
vfs_unbusy(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
@ -306,6 +308,12 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
vfs_ref(mp);
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
vput(nd.ni_vp);
|
||||
error = vfs_busy(mp, 0);
|
||||
vfs_rel(mp);
|
||||
if (error) {
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
return (error);
|
||||
}
|
||||
#ifdef MAC
|
||||
error = mac_mount_check_stat(td->td_ucred, mp);
|
||||
if (error)
|
||||
@ -329,7 +337,7 @@ kern_statfs(struct thread *td, char *path, enum uio_seg pathseg,
|
||||
}
|
||||
*buf = *sp;
|
||||
out:
|
||||
vfs_rel(mp);
|
||||
vfs_unbusy(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
if (mtx_owned(&Giant))
|
||||
printf("statfs(%d): %s: %d\n", vfslocked, path, error);
|
||||
@ -391,6 +399,10 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
|
||||
error = EBADF;
|
||||
goto out;
|
||||
}
|
||||
error = vfs_busy(mp, 0);
|
||||
vfs_rel(mp);
|
||||
if (error)
|
||||
goto out;
|
||||
#ifdef MAC
|
||||
error = mac_mount_check_stat(td->td_ucred, mp);
|
||||
if (error)
|
||||
@ -415,7 +427,7 @@ kern_fstatfs(struct thread *td, int fd, struct statfs *buf)
|
||||
*buf = *sp;
|
||||
out:
|
||||
if (mp)
|
||||
vfs_rel(mp);
|
||||
vfs_unbusy(mp);
|
||||
VFS_UNLOCK_GIANT(vfslocked);
|
||||
return (error);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user