diff options
author | kib <kib@FreeBSD.org> | 2008-09-26 14:50:49 +0000 |
---|---|---|
committer | kib <kib@FreeBSD.org> | 2008-09-26 14:50:49 +0000 |
commit | 496b70bc6ae4c9f8b2f01168acbb39b39e6f3112 (patch) | |
tree | 83ec201504ae8c58d18c3600f36c7e08a41162df /sys/fs | |
parent | d421caabf98d87498154b13c49b8f5d352aea70c (diff) | |
download | FreeBSD-src-496b70bc6ae4c9f8b2f01168acbb39b39e6f3112.zip FreeBSD-src-496b70bc6ae4c9f8b2f01168acbb39b39e6f3112.tar.gz |
Save previous content of the td_fpop before storing the current
filedescriptor into it. Make sure that td_fpop is NULL when calling
d_mmap from dev_pager_getpages().
Change guards against td_fpop field being non-NULL with private state
for another device, and against sudden clearing the td_fpop. This
could occur when either a driver method calls another driver through
the filedescriptor operation, or a page fault happen while driver is
writing to a memory backed by another driver.
Noted by: rwatson
Tested by: rnoland
MFC after: 3 days
Diffstat (limited to 'sys/fs')
-rw-r--r-- | sys/fs/devfs/devfs_vnops.c | 39 |
1 files changed, 27 insertions, 12 deletions
diff --git a/sys/fs/devfs/devfs_vnops.c b/sys/fs/devfs/devfs_vnops.c index 94ea0dd..54afebe 100644 --- a/sys/fs/devfs/devfs_vnops.c +++ b/sys/fs/devfs/devfs_vnops.c @@ -466,10 +466,12 @@ static int devfs_close_f(struct file *fp, struct thread *td) { int error; + struct file *fpop; - curthread->td_fpop = fp; + fpop = td->td_fpop; + td->td_fpop = fp; error = vnops.fo_close(fp, td); - curthread->td_fpop = NULL; + td->td_fpop = fpop; return (error); } @@ -559,14 +561,16 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc int error, i; const char *p; struct fiodgname_arg *fgn; + struct file *fpop; + fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw); if (error) return (error); if (com == FIODTYPE) { *(int *)data = dsw->d_flags & D_TYPEMASK; - td->td_fpop = NULL; + td->td_fpop = fpop; dev_relthread(dev); return (0); } else if (com == FIODGNAME) { @@ -577,7 +581,7 @@ devfs_ioctl_f(struct file *fp, u_long com, void *data, struct ucred *cred, struc error = EINVAL; else error = copyout(p, fgn->buf, i); - td->td_fpop = NULL; + td->td_fpop = fpop; dev_relthread(dev); return (error); } @@ -618,12 +622,16 @@ devfs_kqfilter_f(struct file *fp, struct knote *kn) struct cdev *dev; struct cdevsw *dsw; int error; + struct file *fpop; + struct thread *td; + td = curthread; + fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw); if (error) return (error); error = dsw->d_kqfilter(dev, kn); - curthread->td_fpop = NULL; + td->td_fpop = fpop; dev_relthread(dev); return (error); } @@ -840,6 +848,7 @@ devfs_open(struct vop_open_args *ap) struct file *fp = ap->a_fp; int error; struct cdevsw *dsw; + struct file *fpop; if (vp->v_type == VBLK) return (ENXIO); @@ -861,15 +870,15 @@ devfs_open(struct vop_open_args *ap) VOP_UNLOCK(vp, 0); - if (fp != NULL) { - td->td_fpop = fp; + fpop = td->td_fpop; + td->td_fpop = fp; + if (fp != NULL) fp->f_data = dev; - } if (dsw->d_fdopen != NULL) error = dsw->d_fdopen(dev, ap->a_mode, td, fp); else error = dsw->d_open(dev, ap->a_mode, S_IFCHR, td); - td->td_fpop = NULL; + td->td_fpop = fpop; vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); @@ -919,12 +928,14 @@ devfs_poll_f(struct file *fp, int events, struct ucred *cred, struct thread *td) struct cdev *dev; struct cdevsw *dsw; int error; + struct file *fpop; + fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw); if (error) return (error); error = dsw->d_poll(dev, events, td); - curthread->td_fpop = NULL; + td->td_fpop = fpop; dev_relthread(dev); return(error); } @@ -947,7 +958,9 @@ devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, st struct cdev *dev; int ioflag, error, resid; struct cdevsw *dsw; + struct file *fpop; + fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw); if (error) return (error); @@ -962,7 +975,7 @@ devfs_read_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, st error = dsw->d_read(dev, uio, ioflag); if (uio->uio_resid != resid || (error == 0 && resid != 0)) vfs_timestamp(&dev->si_atime); - curthread->td_fpop = NULL; + td->td_fpop = fpop; dev_relthread(dev); if ((flags & FOF_OFFSET) == 0) @@ -1383,7 +1396,9 @@ devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, s struct cdev *dev; int error, ioflag, resid; struct cdevsw *dsw; + struct file *fpop; + fpop = td->td_fpop; error = devfs_fp_check(fp, &dev, &dsw); if (error) return (error); @@ -1401,7 +1416,7 @@ devfs_write_f(struct file *fp, struct uio *uio, struct ucred *cred, int flags, s vfs_timestamp(&dev->si_ctime); dev->si_mtime = dev->si_ctime; } - curthread->td_fpop = NULL; + td->td_fpop = fpop; dev_relthread(dev); if ((flags & FOF_OFFSET) == 0) |