summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2013-02-10 10:17:33 +0000
committerkib <kib@FreeBSD.org>2013-02-10 10:17:33 +0000
commitf5429c7c6e76a7e435129573b8f5d42490e39851 (patch)
treead5cb6a2e87290604c9e5fca2c5713a046c6474c /sys
parentcde657f5b102f59e8b6ea59855aeb883fac1a7dd (diff)
downloadFreeBSD-src-f5429c7c6e76a7e435129573b8f5d42490e39851.zip
FreeBSD-src-f5429c7c6e76a7e435129573b8f5d42490e39851.tar.gz
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
Diffstat (limited to 'sys')
-rw-r--r--sys/ufs/ffs/ffs_alloc.c26
1 files changed, 23 insertions, 3 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c
index 5ad5775..d462cbb 100644
--- a/sys/ufs/ffs/ffs_alloc.c
+++ b/sys/ufs/ffs/ffs_alloc.c
@@ -2906,10 +2906,11 @@ buffered_write(fp, uio, active_cred, flags, td)
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, flags, td)
* 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
OpenPOWER on IntegriCloud