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
This commit is contained in:
Konstantin Belousov 2008-09-26 14:50:49 +00:00
parent edde874555
commit 7818e0a545
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=183383
2 changed files with 33 additions and 12 deletions

View File

@ -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)

View File

@ -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) {