From owner-svn-src-all@FreeBSD.ORG Fri Mar 28 15:38:56 2014 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 45F23D31; Fri, 28 Mar 2014 15:38:56 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 31C56B91; Fri, 28 Mar 2014 15:38:56 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s2SFcuT5040399; Fri, 28 Mar 2014 15:38:56 GMT (envelope-from kib@svn.freebsd.org) Received: (from kib@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s2SFcscw040389; Fri, 28 Mar 2014 15:38:54 GMT (envelope-from kib@svn.freebsd.org) Message-Id: <201403281538.s2SFcscw040389@svn.freebsd.org> From: Konstantin Belousov Date: Fri, 28 Mar 2014 15:38:54 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org Subject: svn commit: r263876 - in stable/9/sys: amd64/amd64 amd64/include kern sys vm X-SVN-Group: stable-9 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.17 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 28 Mar 2014 15:38:56 -0000 Author: kib Date: Fri Mar 28 15:38:54 2014 New Revision: 263876 URL: http://svnweb.freebsd.org/changeset/base/263876 Log: MFC r263475: Fix two issues with /dev/mem access on amd64, both causing kernel page faults. First, for accesses to direct map region should check for the limit by which direct map is instantiated. Second, for accesses to the kernel map, use a new thread private flag TDP_DEVMEMIO, which instructs vm_fault() to return error when fault happens on the MAP_ENTRY_NOFAULT entry, instead of panicing. MFC r263498: Add change forgotten in r263475. Make dmaplimit accessible outside amd64/pmap.c. Modified: stable/9/sys/amd64/amd64/mem.c stable/9/sys/amd64/amd64/pmap.c stable/9/sys/amd64/amd64/trap.c stable/9/sys/amd64/include/pmap.h stable/9/sys/kern/subr_trap.c stable/9/sys/sys/proc.h stable/9/sys/vm/vm_fault.c Directory Properties: stable/9/sys/ (props changed) stable/9/sys/sys/ (props changed) Modified: stable/9/sys/amd64/amd64/mem.c ============================================================================== --- stable/9/sys/amd64/amd64/mem.c Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/amd64/amd64/mem.c Fri Mar 28 15:38:54 2014 (r263876) @@ -76,14 +76,16 @@ MALLOC_DEFINE(M_MEMDESC, "memdesc", "mem int memrw(struct cdev *dev, struct uio *uio, int flags) { - int o; - u_long c = 0, v; struct iovec *iov; - int error = 0; + u_long c, v; + int error, o, sflags; vm_offset_t addr, eaddr; GIANT_REQUIRED; + error = 0; + c = 0; + sflags = curthread_pflags_set(TDP_DEVMEMIO); while (uio->uio_resid > 0 && error == 0) { iov = uio->uio_iov; if (iov->iov_len == 0) { @@ -98,7 +100,15 @@ memrw(struct cdev *dev, struct uio *uio, kmemphys: o = v & PAGE_MASK; c = min(uio->uio_resid, (u_int)(PAGE_SIZE - o)); - error = uiomove((void *)PHYS_TO_DMAP(v), (int)c, uio); + v = PHYS_TO_DMAP(v); + if (v < DMAP_MIN_ADDRESS || + (v > DMAP_MIN_ADDRESS + dmaplimit && + v <= DMAP_MAX_ADDRESS) || + pmap_kextract(v) == 0) { + error = EFAULT; + goto ret; + } + error = uiomove((void *)v, (int)c, uio); continue; } else if (dev2unit(dev) == CDEV_MINOR_KMEM) { @@ -119,22 +129,30 @@ kmemphys: addr = trunc_page(v); eaddr = round_page(v + c); - if (addr < VM_MIN_KERNEL_ADDRESS) - return (EFAULT); - for (; addr < eaddr; addr += PAGE_SIZE) - if (pmap_extract(kernel_pmap, addr) == 0) - return (EFAULT); - + if (addr < VM_MIN_KERNEL_ADDRESS) { + error = EFAULT; + goto ret; + } + for (; addr < eaddr; addr += PAGE_SIZE) { + if (pmap_extract(kernel_pmap, addr) == 0) { + error = EFAULT; + goto ret; + } + } if (!kernacc((caddr_t)(long)v, c, uio->uio_rw == UIO_READ ? - VM_PROT_READ : VM_PROT_WRITE)) - return (EFAULT); + VM_PROT_READ : VM_PROT_WRITE)) { + error = EFAULT; + goto ret; + } error = uiomove((caddr_t)(long)v, (int)c, uio); continue; } /* else panic! */ } +ret: + curthread_pflags_restore(sflags); return (error); } Modified: stable/9/sys/amd64/amd64/pmap.c ============================================================================== --- stable/9/sys/amd64/amd64/pmap.c Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/amd64/amd64/pmap.c Fri Mar 28 15:38:54 2014 (r263876) @@ -210,7 +210,7 @@ vm_offset_t virtual_avail; /* VA of firs vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ static int ndmpdp; -static vm_paddr_t dmaplimit; +vm_paddr_t dmaplimit; vm_offset_t kernel_vm_end = VM_MIN_KERNEL_ADDRESS; pt_entry_t pg_nx; Modified: stable/9/sys/amd64/amd64/trap.c ============================================================================== --- stable/9/sys/amd64/amd64/trap.c Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/amd64/amd64/trap.c Fri Mar 28 15:38:54 2014 (r263876) @@ -785,6 +785,12 @@ nogo: frame->tf_rip = (long)curpcb->pcb_onfault; return (0); } + if ((td->td_pflags & TDP_DEVMEMIO) != 0) { + KASSERT(curpcb->pcb_onfault != NULL, + ("/dev/mem without pcb_onfault")); + frame->tf_rip = (long)curpcb->pcb_onfault; + return (0); + } trap_fatal(frame, eva); return (-1); } Modified: stable/9/sys/amd64/include/pmap.h ============================================================================== --- stable/9/sys/amd64/include/pmap.h Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/amd64/include/pmap.h Fri Mar 28 15:38:54 2014 (r263876) @@ -280,6 +280,7 @@ extern vm_paddr_t phys_avail[]; extern vm_paddr_t dump_avail[]; extern vm_offset_t virtual_avail; extern vm_offset_t virtual_end; +extern vm_paddr_t dmaplimit; #define pmap_page_get_memattr(m) ((vm_memattr_t)(m)->md.pat_mode) #define pmap_page_is_write_mapped(m) (((m)->aflags & PGA_WRITEABLE) != 0) Modified: stable/9/sys/kern/subr_trap.c ============================================================================== --- stable/9/sys/kern/subr_trap.c Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/kern/subr_trap.c Fri Mar 28 15:38:54 2014 (r263876) @@ -139,6 +139,8 @@ userret(struct thread *td, struct trapfr sched_userret(td); KASSERT(td->td_locks == 0, ("userret: Returning with %d locks held.", td->td_locks)); + KASSERT((td->td_pflags & TDP_DEVMEMIO) == 0, + ("userret: Returning with /dev/mem i/o leaked")); KASSERT(td->td_vp_reserv == 0, ("userret: Returning while holding vnode reservation")); KASSERT((td->td_flags & TDF_SBDRY) == 0, Modified: stable/9/sys/sys/proc.h ============================================================================== --- stable/9/sys/sys/proc.h Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/sys/proc.h Fri Mar 28 15:38:54 2014 (r263876) @@ -425,6 +425,7 @@ do { \ #define TDP_RESETSPUR 0x04000000 /* Reset spurious page fault history. */ #define TDP_NERRNO 0x08000000 /* Last errno is already in td_errno */ #define TDP_UIOHELD 0x10000000 /* Current uio has pages held in td_ma */ +#define TDP_DEVMEMIO 0x20000000 /* Accessing memory for /dev/mem */ /* * Reasons that the current thread can not be run yet. Modified: stable/9/sys/vm/vm_fault.c ============================================================================== --- stable/9/sys/vm/vm_fault.c Fri Mar 28 15:38:38 2014 (r263875) +++ stable/9/sys/vm/vm_fault.c Fri Mar 28 15:38:54 2014 (r263876) @@ -282,6 +282,10 @@ RetryFault:; map_generation = fs.map->timestamp; if (fs.entry->eflags & MAP_ENTRY_NOFAULT) { + if ((curthread->td_pflags & TDP_DEVMEMIO) != 0) { + vm_map_unlock_read(fs.map); + return (KERN_FAILURE); + } panic("vm_fault: fault on nofault entry, addr: %lx", (u_long)vaddr); }