Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F137059314
D2658.id5753.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
18 KB
Referenced Files
None
Subscribers
None
D2658.id5753.diff
View Options
Index: sys/fs/devfs/devfs_vnops.c
===================================================================
--- sys/fs/devfs/devfs_vnops.c
+++ sys/fs/devfs/devfs_vnops.c
@@ -1760,6 +1760,7 @@
.fo_sendfile = vn_sendfile,
.fo_seek = vn_seek,
.fo_fill_kinfo = vn_fill_kinfo,
+ .fo_mmap = vn_mmap,
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
};
Index: sys/kern/uipc_shm.c
===================================================================
--- sys/kern/uipc_shm.c
+++ sys/kern/uipc_shm.c
@@ -127,6 +127,7 @@
static fo_chown_t shm_chown;
static fo_seek_t shm_seek;
static fo_fill_kinfo_t shm_fill_kinfo;
+static fo_mmap_t shm_mmap;
/* File descriptor operations. */
static struct fileops shm_ops = {
@@ -143,6 +144,7 @@
.fo_sendfile = vn_sendfile,
.fo_seek = shm_seek,
.fo_fill_kinfo = shm_fill_kinfo,
+ .fo_mmap = shm_mmap,
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
};
@@ -851,15 +853,37 @@
return (error);
}
-/*
- * mmap() helper to validate mmap() requests against shm object state
- * and give mmap() the vm_object to use for the mapping.
- */
int
-shm_mmap(struct shmfd *shmfd, vm_size_t objsize, vm_ooffset_t foff,
- vm_object_t *obj)
+shm_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t objsize,
+ vm_prot_t prot, vm_prot_t cap_maxprot, int flags,
+ vm_ooffset_t foff, struct thread *td)
{
+ struct shmfd *shmfd;
+ vm_prot_t maxprot;
+ int error;
+
+ shmfd = fp->f_data;
+ maxprot = VM_PROT_NONE;
+
+ /* FREAD should always be set. */
+ if ((fp->f_flag & FREAD) != 0)
+ maxprot |= VM_PROT_EXECUTE | VM_PROT_READ;
+ if ((fp->f_flag & FWRITE) != 0)
+ maxprot |= VM_PROT_WRITE;
+
+ /* Don't permit shared writable mappings on read-only descriptors. */
+ if ((flags & MAP_SHARED) != 0 &&
+ (maxprot & VM_PROT_WRITE) == 0 &&
+ (prot & PROT_WRITE) != 0)
+ return (EACCES);
+ maxprot &= cap_maxprot;
+#ifdef MAC
+ error = mac_posixshm_check_mmap(td->td_ucred, shmfd, prot, flags);
+ if (error != 0)
+ return (error);
+#endif
+
/*
* XXXRW: This validation is probably insufficient, and subject to
* sign errors. It should be fixed.
@@ -872,7 +896,12 @@
vfs_timestamp(&shmfd->shm_atime);
mtx_unlock(&shm_timestamp_lock);
vm_object_reference(shmfd->shm_object);
- *obj = shmfd->shm_object;
+
+ /* This relies on VM_PROT_* matching PROT_*. */
+ error = vm_mmap_object(map, addr, objsize, prot, maxprot, flags,
+ shmfd->shm_object, foff, FALSE, td);
+ if (error != 0)
+ vm_object_deallocate(shmfd->shm_object);
return (0);
}
Index: sys/kern/vfs_vnops.c
===================================================================
--- sys/kern/vfs_vnops.c
+++ sys/kern/vfs_vnops.c
@@ -54,6 +54,7 @@
#include <sys/proc.h>
#include <sys/limits.h>
#include <sys/lock.h>
+#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/mutex.h>
#include <sys/namei.h>
@@ -105,6 +106,7 @@
.fo_sendfile = vn_sendfile,
.fo_seek = vn_seek,
.fo_fill_kinfo = vn_fill_kinfo,
+ .fo_mmap = vn_mmap,
.fo_flags = DFLAG_PASSABLE | DFLAG_SEEKABLE
};
@@ -2358,3 +2360,93 @@
kif->kf_un.kf_file.kf_file_rdev = va.va_rdev;
return (0);
}
+
+int
+vn_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t size,
+ vm_prot_t prot, vm_prot_t cap_maxprot, int flags, vm_ooffset_t foff,
+ struct thread *td)
+{
+#ifdef HWPMC_HOOKS
+ struct pmckern_map_in pkm;
+#endif
+ struct vnode *vp;
+ vm_object_t object;
+ vm_prot_t maxprot;
+ boolean_t writecounted;
+ int error;
+
+#if defined(COMPAT_FREEBSD7) || defined(COMPAT_FREEBSD6) || \
+ defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4)
+ /*
+ * POSIX shared-memory objects are defined to have
+ * kernel persistence, and are not defined to support
+ * read(2)/write(2) -- or even open(2). Thus, we can
+ * use MAP_ASYNC to trade on-disk coherence for speed.
+ * The shm_open(3) library routine turns on the FPOSIXSHM
+ * flag to request this behavior.
+ */
+ if ((fp->f_flag & FPOSIXSHM) != 0)
+ flags |= MAP_NOSYNC;
+#endif
+ vp = fp->f_vnode;
+
+ /*
+ * Ensure that file and memory protections are
+ * compatible. Note that we only worry about
+ * writability if mapping is shared; in this case,
+ * current and max prot are dictated by the open file.
+ * XXX use the vnode instead? Problem is: what
+ * credentials do we use for determination? What if
+ * proc does a setuid?
+ */
+ if (vp->v_mount != NULL && (vp->v_mount->mnt_flag & MNT_NOEXEC) != 0)
+ maxprot = VM_PROT_NONE;
+ else
+ maxprot = VM_PROT_EXECUTE;
+ if ((fp->f_flag & FREAD) != 0)
+ maxprot |= VM_PROT_READ;
+ else if ((prot & PROT_READ) != 0)
+ return (EACCES);
+
+ /*
+ * If we are sharing potential changes (either via
+ * MAP_SHARED or via the implicit sharing of character
+ * device mappings), and we are trying to get write
+ * permission although we opened it without asking
+ * for it, bail out.
+ */
+ if ((flags & MAP_SHARED) != 0) {
+ if ((fp->f_flag & FWRITE) != 0)
+ maxprot |= VM_PROT_WRITE;
+ else if ((prot & PROT_WRITE) != 0)
+ return (EACCES);
+ } else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) {
+ maxprot |= VM_PROT_WRITE;
+ cap_maxprot |= VM_PROT_WRITE;
+ }
+ maxprot &= cap_maxprot;
+
+ /* These rely on VM_PROT_* matching PROT_*. */
+ writecounted = FALSE;
+ if (vp->v_type == VCHR)
+ error = vm_mmap_cdev(td, size, prot, &maxprot, &flags,
+ vp->v_rdev, &foff, &object);
+ else
+ error = vm_mmap_vnode(td, size, prot, &maxprot, &flags, vp,
+ &foff, &object, &writecounted);
+ if (error)
+ return (error);
+ error = vm_mmap_object(map, addr, size, prot, maxprot, flags, object,
+ foff, writecounted, td);
+ if (error != 0)
+ vm_object_deallocate(object);
+#ifdef HWPMC_HOOKS
+ /* Inform hwpmc(4) if an executable is being mapped. */
+ if (error == 0 && (prot & PROT_EXEC) != 0) {
+ pkm.pm_file = vp;
+ pkm.pm_address = (uintptr_t) addr;
+ PMC_CALL_HOOK(td, PMC_FN_MMAP, (void *) &pkm);
+ }
+#endif
+ return (error);
+}
Index: sys/sys/file.h
===================================================================
--- sys/sys/file.h
+++ sys/sys/file.h
@@ -42,6 +42,7 @@
#include <sys/refcount.h>
#include <sys/_lock.h>
#include <sys/_mutex.h>
+#include <vm/vm.h>
struct filedesc;
struct stat;
@@ -115,6 +116,9 @@
struct thread *td);
typedef int fo_fill_kinfo_t(struct file *fp, struct kinfo_file *kif,
struct filedesc *fdp);
+typedef int fo_mmap_t(struct file *fp, vm_map_t map, vm_offset_t *addr,
+ vm_size_t size, vm_prot_t prot, vm_prot_t cap_maxprot,
+ int flags, vm_ooffset_t foff, struct thread *td);
typedef int fo_flags_t;
struct fileops {
@@ -131,6 +135,7 @@
fo_sendfile_t *fo_sendfile;
fo_seek_t *fo_seek;
fo_fill_kinfo_t *fo_fill_kinfo;
+ fo_mmap_t *fo_mmap;
fo_flags_t fo_flags; /* DFLAG_* below */
};
@@ -248,6 +253,7 @@
fo_seek_t vn_seek;
fo_fill_kinfo_t vn_fill_kinfo;
int vn_fill_kinfo_vnode(struct vnode *vp, struct kinfo_file *kif);
+fo_mmap_t vn_mmap;
void finit(struct file *, u_int, short, void *, struct fileops *);
int fgetvp(struct thread *td, int fd, cap_rights_t *rightsp,
@@ -391,6 +397,18 @@
return ((*fp->f_ops->fo_fill_kinfo)(fp, kif, fdp));
}
+static __inline int
+fo_mmap(struct file *fp, vm_map_t map, vm_offset_t *addr, vm_size_t size,
+ vm_prot_t prot, vm_prot_t cap_maxprot, int flags, vm_ooffset_t foff,
+ struct thread *td)
+{
+
+ if (fp->f_ops->fo_mmap == NULL)
+ return (ENODEV);
+ return ((*fp->f_ops->fo_mmap)(fp, map, addr, size, prot, cap_maxprot,
+ flags, foff, td));
+}
+
#endif /* _KERNEL */
#endif /* !SYS_FILE_H */
Index: sys/sys/mman.h
===================================================================
--- sys/sys/mman.h
+++ sys/sys/mman.h
@@ -230,8 +230,6 @@
#endif
#ifdef _KERNEL
-int shm_mmap(struct shmfd *shmfd, vm_size_t objsize, vm_ooffset_t foff,
- vm_object_t *obj);
int shm_map(struct file *fp, size_t size, off_t offset, void **memp);
int shm_unmap(struct file *fp, void *mem, size_t size);
Index: sys/vm/vm_extern.h
===================================================================
--- sys/vm/vm_extern.h
+++ sys/vm/vm_extern.h
@@ -81,10 +81,18 @@
int fault_flags, vm_page_t *m_hold);
int vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len,
vm_prot_t prot, vm_page_t *ma, int max_count);
-int vm_forkproc(struct thread *, struct proc *, struct thread *, struct vmspace *, int);
+int vm_forkproc(struct thread *, struct proc *, struct thread *,
+ struct vmspace *, int);
void vm_waitproc(struct proc *);
-int vm_mmap(vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int, objtype_t, void *, vm_ooffset_t);
+int vm_mmap(vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t, vm_prot_t, int,
+ objtype_t, void *, vm_ooffset_t);
+int vm_mmap_object(vm_map_t, vm_offset_t *, vm_size_t, vm_prot_t,
+ vm_prot_t, int, vm_object_t, vm_ooffset_t, boolean_t, struct thread *);
int vm_mmap_to_errno(int rv);
+int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
+ int *, struct cdev *, vm_ooffset_t *, vm_object_t *);
+int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *, int *,
+ struct vnode *, vm_ooffset_t *, vm_object_t *, boolean_t *);
void vm_set_page_size(void);
void vm_sync_icache(vm_map_t, vm_offset_t, vm_size_t);
typedef int (*pmap_pinit_t)(struct pmap *pmap);
Index: sys/vm/vm_mmap.c
===================================================================
--- sys/vm/vm_mmap.c
+++ sys/vm/vm_mmap.c
@@ -100,13 +100,6 @@
#define MAP_32BIT_MAX_ADDR ((vm_offset_t)1 << 31)
#endif
-static int vm_mmap_vnode(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
- int *, struct vnode *, vm_ooffset_t *, vm_object_t *, boolean_t *);
-static int vm_mmap_cdev(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
- int *, struct cdev *, vm_ooffset_t *, vm_object_t *);
-static int vm_mmap_shm(struct thread *, vm_size_t, vm_prot_t, vm_prot_t *,
- int *, struct shmfd *, vm_ooffset_t, vm_object_t *);
-
#ifndef _SYS_SYSPROTO_H_
struct sbrk_args {
int incr;
@@ -197,16 +190,10 @@
struct thread *td;
struct mmap_args *uap;
{
-#ifdef HWPMC_HOOKS
- struct pmckern_map_in pkm;
-#endif
struct file *fp;
- struct vnode *vp;
vm_offset_t addr;
vm_size_t size, pageoff;
- vm_prot_t cap_maxprot, maxprot;
- void *handle;
- objtype_t handle_type;
+ vm_prot_t cap_maxprot;
int align, error, flags, prot;
off_t pos;
struct vmspace *vms = td->td_proc->p_vmspace;
@@ -337,11 +324,11 @@
if (flags & MAP_ANON) {
/*
* Mapping blank space is trivial.
+ *
+ * This relies on VM_PROT_* matching PROT_*.
*/
- handle = NULL;
- handle_type = OBJT_DEFAULT;
- maxprot = VM_PROT_ALL;
- cap_maxprot = VM_PROT_ALL;
+ error = vm_mmap_object(&vms->vm_map, &addr, size, prot,
+ VM_PROT_ALL, flags, NULL, pos, FALSE, td);
} else {
/*
* Mapping file, get fp for validation and don't let the
@@ -366,93 +353,12 @@
error = EINVAL;
goto done;
}
- if (fp->f_type == DTYPE_SHM) {
- handle = fp->f_data;
- handle_type = OBJT_SWAP;
- maxprot = VM_PROT_NONE;
-
- /* FREAD should always be set. */
- if (fp->f_flag & FREAD)
- maxprot |= VM_PROT_EXECUTE | VM_PROT_READ;
- if (fp->f_flag & FWRITE)
- maxprot |= VM_PROT_WRITE;
- goto map;
- }
- if (fp->f_type != DTYPE_VNODE) {
- error = ENODEV;
- goto done;
- }
-#if defined(COMPAT_FREEBSD7) || defined(COMPAT_FREEBSD6) || \
- defined(COMPAT_FREEBSD5) || defined(COMPAT_FREEBSD4)
- /*
- * POSIX shared-memory objects are defined to have
- * kernel persistence, and are not defined to support
- * read(2)/write(2) -- or even open(2). Thus, we can
- * use MAP_ASYNC to trade on-disk coherence for speed.
- * The shm_open(3) library routine turns on the FPOSIXSHM
- * flag to request this behavior.
- */
- if (fp->f_flag & FPOSIXSHM)
- flags |= MAP_NOSYNC;
-#endif
- vp = fp->f_vnode;
- /*
- * Ensure that file and memory protections are
- * compatible. Note that we only worry about
- * writability if mapping is shared; in this case,
- * current and max prot are dictated by the open file.
- * XXX use the vnode instead? Problem is: what
- * credentials do we use for determination? What if
- * proc does a setuid?
- */
- if (vp->v_mount != NULL && vp->v_mount->mnt_flag & MNT_NOEXEC)
- maxprot = VM_PROT_NONE;
- else
- maxprot = VM_PROT_EXECUTE;
- if (fp->f_flag & FREAD) {
- maxprot |= VM_PROT_READ;
- } else if (prot & PROT_READ) {
- error = EACCES;
- goto done;
- }
- /*
- * If we are sharing potential changes (either via
- * MAP_SHARED or via the implicit sharing of character
- * device mappings), and we are trying to get write
- * permission although we opened it without asking
- * for it, bail out.
- */
- if ((flags & MAP_SHARED) != 0) {
- if ((fp->f_flag & FWRITE) != 0) {
- maxprot |= VM_PROT_WRITE;
- } else if ((prot & PROT_WRITE) != 0) {
- error = EACCES;
- goto done;
- }
- } else if (vp->v_type != VCHR || (fp->f_flag & FWRITE) != 0) {
- maxprot |= VM_PROT_WRITE;
- cap_maxprot |= VM_PROT_WRITE;
- }
- handle = (void *)vp;
- handle_type = OBJT_VNODE;
- }
-map:
- td->td_fpop = fp;
- maxprot &= cap_maxprot;
-
- /* This relies on VM_PROT_* matching PROT_*. */
- error = vm_mmap(&vms->vm_map, &addr, size, prot, maxprot,
- flags, handle_type, handle, pos);
- td->td_fpop = NULL;
-#ifdef HWPMC_HOOKS
- /* inform hwpmc(4) if an executable is being mapped */
- if (error == 0 && handle_type == OBJT_VNODE &&
- (prot & PROT_EXEC)) {
- pkm.pm_file = handle;
- pkm.pm_address = (uintptr_t) addr;
- PMC_CALL_HOOK(td, PMC_FN_MMAP, (void *) &pkm);
+ td->td_fpop = fp;
+ error = fo_mmap(fp, &vms->vm_map, &addr, size, prot,
+ cap_maxprot, flags, pos, td);
+ td->td_fpop = NULL;
}
-#endif
+
if (error == 0)
td->td_retval[0] = (register_t) (addr + pageoff);
done:
@@ -1311,9 +1217,6 @@
*
* Helper function for vm_mmap. Perform sanity check specific for mmap
* operations on vnodes.
- *
- * For VCHR vnodes, the vnode lock is held over the call to
- * vm_mmap_cdev() to keep vp->v_rdev valid.
*/
int
vm_mmap_vnode(struct thread *td, vm_size_t objsize,
@@ -1360,12 +1263,6 @@
*writecounted = TRUE;
vnode_pager_update_writecount(obj, 0, objsize);
}
- } else if (vp->v_type == VCHR) {
- error = vm_mmap_cdev(td, objsize, prot, maxprotp, flagsp,
- vp->v_rdev, foffp, objp);
- if (error == 0)
- goto mark_atime;
- goto done;
} else {
error = EINVAL;
goto done;
@@ -1414,7 +1311,6 @@
*objp = obj;
*flagsp = flags;
-mark_atime:
vfs_mark_atime(vp, cred);
done:
@@ -1450,6 +1346,8 @@
return (ENXIO);
if (dsw->d_flags & D_MMAP_ANON) {
dev_relthread(cdev, ref);
+ *objp = NULL;
+ *foff = 0;
*maxprotp = VM_PROT_ALL;
*flagsp |= MAP_ANON;
return (0);
@@ -1500,36 +1398,6 @@
}
/*
- * vm_mmap_shm()
- *
- * MPSAFE
- *
- * Helper function for vm_mmap. Perform sanity check specific for mmap
- * operations on shm file descriptors.
- */
-int
-vm_mmap_shm(struct thread *td, vm_size_t objsize,
- vm_prot_t prot, vm_prot_t *maxprotp, int *flagsp,
- struct shmfd *shmfd, vm_ooffset_t foff, vm_object_t *objp)
-{
- int error;
-
- if ((*flagsp & MAP_SHARED) != 0 &&
- (*maxprotp & VM_PROT_WRITE) == 0 &&
- (prot & PROT_WRITE) != 0)
- return (EACCES);
-#ifdef MAC
- error = mac_posixshm_check_mmap(td->td_ucred, shmfd, prot, *flagsp);
- if (error != 0)
- return (error);
-#endif
- error = shm_mmap(shmfd, objsize, foff, objp);
- if (error)
- return (error);
- return (0);
-}
-
-/*
* vm_mmap()
*
* MPSAFE
@@ -1543,16 +1411,57 @@
objtype_t handle_type, void *handle,
vm_ooffset_t foff)
{
- boolean_t fitit;
- vm_object_t object = NULL;
+ vm_object_t object;
struct thread *td = curthread;
- int docow, error, findspace, rv;
+ int error;
boolean_t writecounted;
+ /* XXX: Why? */
if (size == 0)
return (0);
size = round_page(size);
+ writecounted = FALSE;
+
+ /*
+ * Lookup/allocate object.
+ */
+ switch (handle_type) {
+ case OBJT_DEVICE:
+ error = vm_mmap_cdev(td, size, prot, &maxprot, &flags,
+ handle, &foff, &object);
+ break;
+ case OBJT_VNODE:
+ error = vm_mmap_vnode(td, size, prot, &maxprot, &flags,
+ handle, &foff, &object, &writecounted);
+ break;
+ case OBJT_DEFAULT:
+ if (handle == NULL) {
+ error = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+ default:
+ error = EINVAL;
+ break;
+ }
+ if (error)
+ return (error);
+
+ error = vm_mmap_object(map, addr, size, prot, maxprot, flags, object,
+ foff, writecounted, td);
+ if (error != 0 && object != NULL)
+ vm_object_deallocate(object);
+ return (error);
+}
+
+int
+vm_mmap_object(vm_map_t map, vm_offset_t *addr, vm_size_t size, vm_prot_t prot,
+ vm_prot_t maxprot, int flags, vm_object_t object, vm_ooffset_t foff,
+ boolean_t writecounted, struct thread *td)
+{
+ boolean_t fitit;
+ int docow, error, findspace, rv;
if (map == &td->td_proc->p_vmspace->vm_map) {
PROC_LOCK(td->td_proc);
@@ -1586,11 +1495,11 @@
/*
* We currently can only deal with page aligned file offsets.
- * The check is here rather than in the syscall because the
- * kernel calls this function internally for other mmaping
- * operations (such as in exec) and non-aligned offsets will
- * cause pmap inconsistencies...so we want to be sure to
- * disallow this in all cases.
+ * The mmap() system call already enforces this by subtracting
+ * the page offset from the file offset, but checking here
+ * catches errors in device drivers (e.g. d_single_mmap()
+ * callbacks or other internal mapping requests (such as in
+ * exec).
*/
if (foff & PAGE_MASK)
return (EINVAL);
@@ -1603,44 +1512,11 @@
return (EINVAL);
fitit = FALSE;
}
- writecounted = FALSE;
- /*
- * Lookup/allocate object.
- */
- switch (handle_type) {
- case OBJT_DEVICE:
- error = vm_mmap_cdev(td, size, prot, &maxprot, &flags,
- handle, &foff, &object);
- break;
- case OBJT_VNODE:
- error = vm_mmap_vnode(td, size, prot, &maxprot, &flags,
- handle, &foff, &object, &writecounted);
- break;
- case OBJT_SWAP:
- error = vm_mmap_shm(td, size, prot, &maxprot, &flags,
- handle, foff, &object);
- break;
- case OBJT_DEFAULT:
- if (handle == NULL) {
- error = 0;
- break;
- }
- /* FALLTHROUGH */
- default:
- error = EINVAL;
- break;
- }
- if (error)
- return (error);
if (flags & MAP_ANON) {
- object = NULL;
+ if (object != NULL || foff != 0)
+ return (EINVAL);
docow = 0;
- /*
- * Unnamed anonymous regions always start at 0.
- */
- if (handle == 0)
- foff = 0;
} else if (flags & MAP_PREFAULT_READ)
docow = MAP_PREFAULT;
else
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Nov 22, 1:50 AM (21 h, 31 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25866343
Default Alt Text
D2658.id5753.diff (18 KB)
Attached To
Mode
D2658: Add a file ops hook for mmap().
Attached
Detach File
Event Timeline
Log In to Comment