svn commit: r186277 - head/sys/kern

Konstantin Belousov kib at FreeBSD.org
Thu Dec 18 12:01:19 UTC 2008


Author: kib
Date: Thu Dec 18 12:01:19 2008
New Revision: 186277
URL: http://svn.freebsd.org/changeset/base/186277

Log:
  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

Modified:
  head/sys/kern/vfs_syscalls.c

Modified: head/sys/kern/vfs_syscalls.c
==============================================================================
--- head/sys/kern/vfs_syscalls.c	Thu Dec 18 11:58:12 2008	(r186276)
+++ head/sys/kern/vfs_syscalls.c	Thu Dec 18 12:01:19 2008	(r186277)
@@ -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 *pat
 	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 *pat
 	}
 	*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, 
 		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, 
 	*buf = *sp;
 out:
 	if (mp)
-		vfs_rel(mp);
+		vfs_unbusy(mp);
 	VFS_UNLOCK_GIANT(vfslocked);
 	return (error);
 }


More information about the svn-src-all mailing list