Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 28 Mar 2014 15:38:39 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r263875 - in stable/10/sys: amd64/amd64 amd64/include kern sys vm
Message-ID:  <201403281538.s2SFcdO2040237@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Fri Mar 28 15:38:38 2014
New Revision: 263875
URL: http://svnweb.freebsd.org/changeset/base/263875

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/10/sys/amd64/amd64/mem.c
  stable/10/sys/amd64/amd64/pmap.c
  stable/10/sys/amd64/amd64/trap.c
  stable/10/sys/amd64/include/pmap.h
  stable/10/sys/kern/subr_trap.c
  stable/10/sys/sys/proc.h
  stable/10/sys/vm/vm_fault.c
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/sys/amd64/amd64/mem.c
==============================================================================
--- stable/10/sys/amd64/amd64/mem.c	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/amd64/amd64/mem.c	Fri Mar 28 15:38:38 2014	(r263875)
@@ -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/10/sys/amd64/amd64/pmap.c
==============================================================================
--- stable/10/sys/amd64/amd64/pmap.c	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/amd64/amd64/pmap.c	Fri Mar 28 15:38:38 2014	(r263875)
@@ -321,7 +321,7 @@ SYSCTL_INT(_machdep, OID_AUTO, nkpt, CTL
     "Number of kernel page table pages allocated on bootup");
 
 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/10/sys/amd64/amd64/trap.c
==============================================================================
--- stable/10/sys/amd64/amd64/trap.c	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/amd64/amd64/trap.c	Fri Mar 28 15:38:38 2014	(r263875)
@@ -788,6 +788,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/10/sys/amd64/include/pmap.h
==============================================================================
--- stable/10/sys/amd64/include/pmap.h	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/amd64/include/pmap.h	Fri Mar 28 15:38:38 2014	(r263875)
@@ -368,6 +368,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/10/sys/kern/subr_trap.c
==============================================================================
--- stable/10/sys/kern/subr_trap.c	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/kern/subr_trap.c	Fri Mar 28 15:38:38 2014	(r263875)
@@ -155,6 +155,8 @@ userret(struct thread *td, struct trapfr
 	    ("userret: Returning with %d locks held", td->td_locks));
 	KASSERT((td->td_pflags & TDP_NOFAULTING) == 0,
 	    ("userret: Returning with pagefaults disabled"));
+	KASSERT((td->td_pflags & TDP_DEVMEMIO) == 0,
+	    ("userret: Returning with /dev/mem i/o leaked"));
 	KASSERT(td->td_no_sleeping == 0,
 	    ("userret: Returning with sleep disabled"));
 	KASSERT(td->td_pinned == 0 || (td->td_pflags & TDP_CALLCHAIN) != 0,

Modified: stable/10/sys/sys/proc.h
==============================================================================
--- stable/10/sys/sys/proc.h	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/sys/proc.h	Fri Mar 28 15:38:38 2014	(r263875)
@@ -424,6 +424,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/10/sys/vm/vm_fault.c
==============================================================================
--- stable/10/sys/vm/vm_fault.c	Fri Mar 28 15:09:35 2014	(r263874)
+++ stable/10/sys/vm/vm_fault.c	Fri Mar 28 15:38:38 2014	(r263875)
@@ -276,6 +276,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);
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201403281538.s2SFcdO2040237>