diff --git a/sys/dev/audio/audio.c b/sys/dev/audio/audio.c index ab7bda60cce4..fcbea43ac5de 100644 --- a/sys/dev/audio/audio.c +++ b/sys/dev/audio/audio.c @@ -2098,6 +2098,8 @@ audiommap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, int bound; int error; + KASSERT(len > 0); + KASSERT(fp->f_audioctx); file = fp->f_audioctx; dev = file->dev; @@ -3551,10 +3553,10 @@ audio_kqfilter(struct audio_softc *sc, audio_file_t *file, struct knote *kn) /* * Must be called without sc_lock nor sc_exlock held. */ -int +static int audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot, - int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp, - audio_file_t *file) + int *flagsp, int *advicep, struct uvm_object **uobjp, int *maxprotp, + audio_file_t *file) { audio_track_t *track; vsize_t vsize; @@ -3562,6 +3564,8 @@ audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot, TRACEF(2, file, "off=%lld, prot=%d", (long long)(*offp), prot); + KASSERT(len > 0); + if (*offp < 0) return EINVAL; @@ -3594,7 +3598,7 @@ audio_mmap(struct audio_softc *sc, off_t *offp, size_t len, int prot, vsize = roundup2(MAX(track->usrbuf.capacity, PAGE_SIZE), PAGE_SIZE); if (len > vsize) return EOVERFLOW; - if (*offp > (uint)(vsize - len)) + if (*offp > (uint)(vsize - len)) /* XXX integer truncation? */ return EOVERFLOW; /* XXX TODO: what happens when mmap twice. */ diff --git a/sys/dev/nvmm/nvmm.c b/sys/dev/nvmm/nvmm.c index 316366c721d2..fe5e58be2ecc 100644 --- a/sys/dev/nvmm/nvmm.c +++ b/sys/dev/nvmm/nvmm.c @@ -1099,6 +1099,8 @@ nvmm_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp, nvmm_cpuid_t cpuid; int error; + KASESRT(size > 0); + if (prot & PROT_EXEC) return EACCES; if (size != PAGE_SIZE) diff --git a/sys/external/bsd/drm2/drm/drm_cdevsw.c b/sys/external/bsd/drm2/drm/drm_cdevsw.c index 004ffc5ec689..862192fdffff 100644 --- a/sys/external/bsd/drm2/drm/drm_cdevsw.c +++ b/sys/external/bsd/drm2/drm/drm_cdevsw.c @@ -513,13 +513,15 @@ drm_stat(struct file *fp, struct stat *st) static int drm_fop_mmap(struct file *fp, off_t *offp, size_t len, int prot, int *flagsp, - int *advicep, struct uvm_object **uobjp, int *maxprotp) + int *advicep, struct uvm_object **uobjp, int *maxprotp) { struct drm_file *const file = fp->f_data; struct drm_device *const dev = file->minor->dev; int error; KASSERT(fp == file->filp); + KASSERT(len > 0); + /* XXX errno Linux->NetBSD */ error = -(*dev->driver->mmap_object)(dev, *offp, len, prot, uobjp, offp, file->filp); diff --git a/sys/external/bsd/drm2/drm/drm_gem_vm.c b/sys/external/bsd/drm2/drm/drm_gem_vm.c index af2c8bf5def8..1d663ea07b66 100644 --- a/sys/external/bsd/drm2/drm/drm_gem_vm.c +++ b/sys/external/bsd/drm2/drm/drm_gem_vm.c @@ -71,6 +71,8 @@ drm_gem_or_legacy_mmap_object(struct drm_device *dev, off_t byte_offset, { int ret; + KASSERT(nbytes > 0); + ret = drm_gem_mmap_object(dev, byte_offset, nbytes, prot, uobjp, uoffsetp, file); if (ret) @@ -88,6 +90,8 @@ drm_gem_mmap_object(struct drm_device *dev, off_t byte_offset, size_t nbytes, { int ret; + KASSERT(nbytes > 0); + mutex_lock(&dev->struct_mutex); ret = drm_gem_mmap_object_locked(dev, byte_offset, nbytes, prot, uobjp, uoffsetp, file); diff --git a/sys/external/bsd/drm2/drm/drm_vm.c b/sys/external/bsd/drm2/drm/drm_vm.c index 3dbe4c5b9b16..a3ddcc44c1c7 100644 --- a/sys/external/bsd/drm2/drm/drm_vm.c +++ b/sys/external/bsd/drm2/drm/drm_vm.c @@ -60,6 +60,7 @@ drm_legacy_mmap_object(struct drm_device *dev, off_t offset, size_t size, struct uvm_object *uobj; KASSERT(offset == (offset & ~(PAGE_SIZE-1))); + KASSERT(size != 0); /* * Attach the device. The size and offset are used only for diff --git a/sys/kern/kern_ksyms.c b/sys/kern/kern_ksyms.c index 8dc7ca57a3f5..9346d459258b 100644 --- a/sys/kern/kern_ksyms.c +++ b/sys/kern/kern_ksyms.c @@ -1426,6 +1426,7 @@ ksymsmmap(struct file *fp, off_t *offp, size_t nbytes, int prot, int *flagsp, /* uvm_mmap guarantees page-aligned offset and size. */ KASSERT(*offp == round_page(*offp)); KASSERT(nbytes == round_page(nbytes)); + KASSERT(nbytes > 0); /* Refuse negative offsets. */ if (*offp < 0) diff --git a/sys/kern/subr_kcov.c b/sys/kern/subr_kcov.c index d8f9e42719c0..14324f7472e2 100644 --- a/sys/kern/subr_kcov.c +++ b/sys/kern/subr_kcov.c @@ -524,6 +524,8 @@ kcov_fops_mmap(file_t *fp, off_t *offp, size_t size, int prot, int *flagsp, kcov_t *kd, *kdbuf; int error = 0; + KASSERT(size > 0); + if (prot & PROT_EXEC) return EACCES; if (off < 0) diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c index e750b8498ccd..680fb011de10 100644 --- a/sys/kern/vfs_vnops.c +++ b/sys/kern/vfs_vnops.c @@ -111,16 +111,16 @@ int (*vn_union_readdir_hook) (struct vnode **, struct file *, struct lwp *); #include static int vn_read(file_t *fp, off_t *offset, struct uio *uio, - kauth_cred_t cred, int flags); + kauth_cred_t cred, int flags); static int vn_write(file_t *fp, off_t *offset, struct uio *uio, - kauth_cred_t cred, int flags); + kauth_cred_t cred, int flags); static int vn_closefile(file_t *fp); static int vn_poll(file_t *fp, int events); static int vn_fcntl(file_t *fp, u_int com, void *data); static int vn_statfile(file_t *fp, struct stat *sb); static int vn_ioctl(file_t *fp, u_long com, void *data); static int vn_mmap(struct file *, off_t *, size_t, int, int *, int *, - struct uvm_object **, int *); + struct uvm_object **, int *); static int vn_seek(struct file *, off_t, int, off_t *, int); const struct fileops vnops = { @@ -902,7 +902,7 @@ vn_kqfilter(file_t *fp, struct knote *kn) static int vn_mmap(struct file *fp, off_t *offp, size_t size, int prot, int *flagsp, - int *advicep, struct uvm_object **uobjp, int *maxprotp) + int *advicep, struct uvm_object **uobjp, int *maxprotp) { struct uvm_object *uobj; struct vnode *vp; @@ -919,6 +919,8 @@ vn_mmap(struct file *fp, off_t *offp, size_t size, int prot, int *flagsp, flags = *flagsp; maxprot = VM_PROT_EXECUTE; + KASSERT(size > 0); + vp = fp->f_vnode; if (vp->v_type != VREG && vp->v_type != VCHR && vp->v_type != VBLK) { @@ -928,7 +930,8 @@ vn_mmap(struct file *fp, off_t *offp, size_t size, int prot, int *flagsp, if (vp->v_type != VCHR && off < 0) { return EINVAL; } - if (vp->v_type != VCHR && (off_t)(off + size) < off) { + if (vp->v_type != VCHR && + (size > __type_max(off_t) || off > __type_max(off_t) - size)) { /* no offset wrapping */ return EOVERFLOW; } diff --git a/sys/uvm/uvm_device.c b/sys/uvm/uvm_device.c index 997e0dba7bde..c2517e5a2b64 100644 --- a/sys/uvm/uvm_device.c +++ b/sys/uvm/uvm_device.c @@ -117,6 +117,8 @@ udv_attach(dev_t device, vm_prot_t accessprot, UVMHIST_FUNC(__func__); UVMHIST_CALLARGS(maphist, "(device=%#jx)", device,0,0,0); + KASSERT(size != 0); + /* * before we do anything, ensure this device supports mmap */ @@ -131,12 +133,17 @@ udv_attach(dev_t device, vm_prot_t accessprot, } /* - * Negative offsets on the object are not allowed. + * Negative offsets on the object are not allowed, unless the + * device has affirmatively set D_NEGOFFSAFE. */ - - if ((cdev->d_flag & D_NEGOFFSAFE) == 0 && - off != UVM_UNKNOWN_OFFSET && off < 0) - return(NULL); + if ((cdev->d_flag & D_NEGOFFSAFE) == 0 && off != UVM_UNKNOWN_OFFSET) { + if (off < 0) + return NULL; + if (size > __type_max(voff_t)) + return NULL; + if (off > __type_max(voff_t) - size) + return NULL; + } /* * Check that the specified range of the device allows the @@ -145,13 +152,29 @@ udv_attach(dev_t device, vm_prot_t accessprot, * XXX assumes VM_PROT_* == PROT_* * XXX clobbers off and size, but nothing else here needs them. */ - - while (size != 0) { - if (cdev_mmap(device, off, accessprot) == -1) { - return (NULL); + do { + KASSERTMSG((off % PAGE_SIZE) == 0, "off=%jd", (intmax_t)off); + KASSERTMSG(size >= PAGE_SIZE, "size=%"PRIuVSIZE, size); + if (cdev_mmap(device, off, accessprot) == -1) + return NULL; + KASSERT(off <= __type_max(voff_t) - PAGE_SIZE || + (cdev->d_flag & D_NEGOFFSAFE) != 0); + if (__predict_false(off > __type_max(voff_t) - PAGE_SIZE)) { + /* + * off += PAGE_SIZE, with two's-complement + * wraparound, or + * + * off += PAGE_SIZE - 2*(VOFF_MAX + 1). + */ + CTASSERT(PAGE_SIZE >= 2); + off -= __type_max(voff_t); + off += PAGE_SIZE - 2; + off -= __type_max(voff_t); + } else { + off += PAGE_SIZE; } - off += PAGE_SIZE; size -= PAGE_SIZE; - } + size -= PAGE_SIZE; + } while (size != 0); /* * keep looping until we get it diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c index 618a2d52ed89..831c9213b034 100644 --- a/sys/uvm/uvm_mmap.c +++ b/sys/uvm/uvm_mmap.c @@ -274,7 +274,7 @@ sys_mmap(struct lwp *l, const struct sys_mmap_args *uap, register_t *retval) struct proc *p = l->l_proc; vaddr_t addr; off_t pos; - vsize_t size, pageoff, newsize; + vsize_t size, pageoff; vm_prot_t prot, maxprot, extraprot; int flags, fd, advice; vaddr_t defaddr = 0; /* XXXGCC */ @@ -309,17 +309,21 @@ sys_mmap(struct lwp *l, const struct sys_mmap_args *uap, register_t *retval) return EINVAL; /* - * align file position and save offset. adjust size. + * Align file position and save offset into page. Adjust size + * so that it is an integral multiple of the page size. */ - - pageoff = (pos & PAGE_MASK); - pos -= pageoff; - newsize = size + pageoff; /* add offset */ - newsize = (vsize_t)round_page(newsize); /* round up */ - - if (newsize < size) + pageoff = pos & PAGE_MASK; + pos -= pageoff; + CTASSERT(PAGE_MASK <= __type_max(vsize_t)); + CTASSERT((__type_max(vsize_t) - PAGE_SIZE + 1) % PAGE_SIZE == 0); + if (size > __type_max(vsize_t) - PAGE_SIZE + 1 - pageoff) return ENOMEM; - size = newsize; + /* + * size + pageoff <= VSIZE_MAX + 1 - PAGE_SIZE, and the + * right-hand side is an integral multiple of the page size, so + * round_page(size + pageoff) <= VSIZE_MAX + 1 - PAGE_SIZE. + */ + size = round_page(size + pageoff); /* * now check (MAP_FIXED) or get (!MAP_FIXED) the "addr" @@ -364,6 +368,8 @@ sys_mmap(struct lwp *l, const struct sys_mmap_args *uap, register_t *retval) advice = UVM_ADV_NORMAL; if ((flags & MAP_ANON) == 0) { + KASSERT(size != 0); + if ((fp = fd_getfile(fd)) == NULL) return EBADF; @@ -1005,6 +1011,8 @@ uvm_mmap_dev(struct proc *p, void **addrp, size_t len, dev_t dev, struct uvm_object *uobj; int error, flags, prot; + KASSERT(len > 0); + flags = MAP_SHARED; prot = VM_PROT_READ | VM_PROT_WRITE; if (*addrp)