svn commit: r246612 - head/sys/ufs/ffs

Konstantin Belousov kib at FreeBSD.org
Sun Feb 10 10:17:34 UTC 2013


Author: kib
Date: Sun Feb 10 10:17:33 2013
New Revision: 246612
URL: http://svnweb.freebsd.org/changeset/base/246612

Log:
  Fix several unsafe pointer dereferences in the buffered_write()
  function, implementing the sysctl vfs.ffs.set_bufoutput (not used in
  the tree yet).
  
  - The current directory vnode dereference is unsafe since fd_cdir
    could be changed and unreferenced, lock the filedesc around and vref
    the fd_cdir.
  - The VTOI() conversion of the fd_cdir is unsafe without first
    checking that the vnode is indeed from an FFS mount, otherwise
    the code dereferences a random memory.
  - The cdir could be reclaimed from under us, lock it around the
    checks.
  - The type of the fp vnode might be not a disk, or it might have
    changed while the thread was in flight, check the type.
  
  Reviewed and tested by:	mckusick
  MFC after:	2 weeks

Modified:
  head/sys/ufs/ffs/ffs_alloc.c

Modified: head/sys/ufs/ffs/ffs_alloc.c
==============================================================================
--- head/sys/ufs/ffs/ffs_alloc.c	Sun Feb 10 10:00:35 2013	(r246611)
+++ head/sys/ufs/ffs/ffs_alloc.c	Sun Feb 10 10:17:33 2013	(r246612)
@@ -2906,10 +2906,11 @@ buffered_write(fp, uio, active_cred, fla
 	int flags;
 	struct thread *td;
 {
-	struct vnode *devvp;
+	struct vnode *devvp, *vp;
 	struct inode *ip;
 	struct buf *bp;
 	struct fs *fs;
+	struct filedesc *fdp;
 	int error;
 	daddr_t lbn;
 
@@ -2920,10 +2921,29 @@ buffered_write(fp, uio, active_cred, fla
 	 * within the filesystem being written. Yes, this is an ugly hack.
 	 */
 	devvp = fp->f_vnode;
-	ip = VTOI(td->td_proc->p_fd->fd_cdir);
-	if (ip->i_devvp != devvp)
+	if (!vn_isdisk(devvp, NULL))
 		return (EINVAL);
+	fdp = td->td_proc->p_fd;
+	FILEDESC_SLOCK(fdp);
+	vp = fdp->fd_cdir;
+	vref(vp);
+	FILEDESC_SUNLOCK(fdp);
+	vn_lock(vp, LK_SHARED | LK_RETRY);
+	/*
+	 * Check that the current directory vnode indeed belongs to
+	 * UFS before trying to dereference UFS-specific v_data fields.
+	 */
+	if (vp->v_op != &ffs_vnodeops1 && vp->v_op != &ffs_vnodeops2) {
+		vput(vp);
+		return (EINVAL);
+	}
+	ip = VTOI(vp);
+	if (ip->i_devvp != devvp) {
+		vput(vp);
+		return (EINVAL);
+	}
 	fs = ip->i_fs;
+	vput(vp);
 	foffset_lock_uio(fp, uio, flags);
 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
 #ifdef DEBUG


More information about the svn-src-all mailing list