summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2008-09-26 14:50:49 +0000
committerkib <kib@FreeBSD.org>2008-09-26 14:50:49 +0000
commit496b70bc6ae4c9f8b2f01168acbb39b39e6f3112 (patch)
tree83ec201504ae8c58d18c3600f36c7e08a41162df
parentd421caabf98d87498154b13c49b8f5d352aea70c (diff)
downloadFreeBSD-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.c39
-rw-r--r--sys/vm/device_pager.c6
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) {
OpenPOWER on IntegriCloud