Hi, By specifying an invalid offset when reading /dev/kmem it is easy to crash the kernel from userland. sysctl kern.allowkmem=0 prevents this per default
kernel: protection fault trap, code=0 Stopped at copyout+0x53: repe movsq (%rsi),%es:(%rdi) ddb> trace copyout() at copyout+0x53 mmrw(201,ffff80002145a5f8,0) at mmrw+0x199 spec_read(ffff80002145a498) at spec_read+0xa6 VOP_READ(fffffd807c0d8068,ffff80002145a5f8,0,fffffd807f7ba300) at VOP_READ+0x41 vn_read(fffffd80792bc780,ffff80002145a5f8,1) at vn_read+0xa1 dofilereadv(ffff8000ffffd508,4,ffff80002145a5f8,1,ffff80002145a6d0) at dofilere adv+0x14c sys_pread(ffff8000ffffd508,ffff80002145a678,ffff80002145a6d0) at sys_pread+0x5c syscall(ffff80002145a740) at syscall+0x315 Xsyscall() at Xsyscall+0x128 end of kernel end trace frame: 0x7f7ffffe4880, count: -9 ddb> show register rdi 0x7f7ffffe5100 rsi 0x500bca4bc039b5b The && when checking the direct map is wrong, it should be ||. This bug exists since the check was added. ---------------------------- revision 1.3 date: 2004/07/22 00:48:41; author: art; state: Exp; lines: +4 -3; Fix access to direct mapped memory through /dev/kmem. ---------------------------- When we check if a range is within the limits, we have to check the end address including the size. So I think we should subtract the size from the end limit. ok? bluhm Index: arch/amd64/amd64/mem.c =================================================================== RCS file: /data/mirror/openbsd/cvs/src/sys/arch/amd64/amd64/mem.c,v retrieving revision 1.34 diff -u -p -r1.34 mem.c --- arch/amd64/amd64/mem.c 19 Feb 2018 08:59:52 -0000 1.34 +++ arch/amd64/amd64/mem.c 22 Mar 2021 20:10:16 -0000 @@ -148,13 +148,13 @@ mmrw(dev_t dev, struct uio *uio, int fla case 1: v = uio->uio_offset; c = ulmin(iov->iov_len, MAXPHYS); - if (v >= (vaddr_t)&start && v < kern_end) { - if (v < (vaddr_t)&etext && + if (v >= (vaddr_t)&start && v < kern_end - c) { + if (v < (vaddr_t)&etext - c && uio->uio_rw == UIO_WRITE) return EFAULT; } else if ((!uvm_kernacc((caddr_t)v, c, uio->uio_rw == UIO_READ ? B_READ : B_WRITE)) && - (v < PMAP_DIRECT_BASE && v > PMAP_DIRECT_END)) + (v < PMAP_DIRECT_BASE || v > PMAP_DIRECT_END - c)) return (EFAULT); error = uiomove((caddr_t)v, c, uio); continue;