mirror of
https://git.FreeBSD.org/src.git
synced 2024-12-20 11:11:24 +00:00
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
This commit is contained in:
parent
5e60cb948e
commit
9604a7f1b8
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246612
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user