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 | |
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
-rw-r--r-- | sys/fs/devfs/devfs_vnops.c | 39 | ||||
-rw-r--r-- | sys/vm/device_pager.c | 6 |
2 files changed, 33 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) diff --git a/sys/vm/device_pager.c b/sys/vm/device_pager.c index e771928..5e31e2b 100644 --- a/sys/vm/device_pager.c +++ b/sys/vm/device_pager.c @@ -214,6 +214,8 @@ dev_pager_getpages(object, m, count, reqpage) int i, ret; int prot; struct cdevsw *csw; + struct thread *td; + struct file *fpop; VM_OBJECT_LOCK_ASSERT(object, MA_OWNED); dev = object->handle; @@ -224,8 +226,12 @@ dev_pager_getpages(object, m, count, reqpage) panic("dev_pager_getpage: no cdevsw"); prot = PROT_READ; /* XXX should pass in? */ + td = curthread; + fpop = td->td_fpop; + td->td_fpop = NULL; ret = (*csw->d_mmap)(dev, (vm_offset_t)offset << PAGE_SHIFT, &paddr, prot); KASSERT(ret == 0, ("dev_pager_getpage: map function returns error")); + td->td_fpop = fpop; dev_relthread(dev); if ((m[reqpage]->flags & PG_FICTITIOUS) != 0) { |