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:
parent
edde874555
commit
7818e0a545
@ -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)
|
||||
|
@ -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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user