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