svn commit: r319203 - in stable/11/sys/arm64: arm64 include

Andrew Turner andrew at FreeBSD.org
Tue May 30 12:44:03 UTC 2017


Author: andrew
Date: Tue May 30 12:44:01 2017
New Revision: 319203
URL: https://svnweb.freebsd.org/changeset/base/319203

Log:
  MFC r316734, r316761: Support Execute-Never bit in the arm64 pmap.
  
  r316734:
  Start to use the User and Privileged execute-never bits in the arm64
  pagetables. This sets both bits when entering an address we know shouldn't
  be executed.
  
  I expect we could mark all userspace pages as Privileged execute-never to
  ensure the kernel doesn't branch to one of these addresses.
  
  While here add the ARMv8.1 upper attributes.
  
  r316761:
  Set the arm64 Execute-never bits in more places.
  
  We need to set the Execute-never bits when mapping device memory as the
  hardware may perform speculative instruction fetches.
  
  Set the Privileged Execute-ever bit on userspace memory to stop the kernel
  if it is tricked into executing it.

Modified:
  stable/11/sys/arm64/arm64/pmap.c
  stable/11/sys/arm64/include/pte.h
Directory Properties:
  stable/11/   (props changed)

Modified: stable/11/sys/arm64/arm64/pmap.c
==============================================================================
--- stable/11/sys/arm64/arm64/pmap.c	Tue May 30 12:26:36 2017	(r319202)
+++ stable/11/sys/arm64/arm64/pmap.c	Tue May 30 12:44:01 2017	(r319203)
@@ -606,7 +606,7 @@ pmap_bootstrap_dmap(vm_offset_t kern_l1, vm_paddr_t mi
 		l1_slot = ((va - DMAP_MIN_ADDRESS) >> L1_SHIFT);
 
 		pmap_load_store(&pagetable_dmap[l1_slot],
-		    (pa & ~L1_OFFSET) | ATTR_DEFAULT |
+		    (pa & ~L1_OFFSET) | ATTR_DEFAULT | ATTR_XN |
 		    ATTR_IDX(CACHED_MEMORY) | L1_BLOCK);
 	}
 
@@ -1127,7 +1127,7 @@ static void
 pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_t pa, int mode)
 {
 	pd_entry_t *pde;
-	pt_entry_t *pte;
+	pt_entry_t *pte, attr;
 	vm_offset_t va;
 	int lvl;
 
@@ -1138,6 +1138,10 @@ pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_
 	KASSERT((size & PAGE_MASK) == 0,
 	    ("pmap_kenter: Mapping is not page-sized"));
 
+	attr = ATTR_DEFAULT | ATTR_IDX(mode) | L3_PAGE;
+	if (mode == DEVICE_MEMORY)
+		attr |= ATTR_XN;
+
 	va = sva;
 	while (size != 0) {
 		pde = pmap_pde(kernel_pmap, va, &lvl);
@@ -1146,8 +1150,7 @@ pmap_kenter(vm_offset_t sva, vm_size_t size, vm_paddr_
 		KASSERT(lvl == 2, ("pmap_kenter: Invalid level %d", lvl));
 
 		pte = pmap_l2_to_l3(pde, va);
-		pmap_load_store(pte, (pa & ~L3_OFFSET) | ATTR_DEFAULT |
-		    ATTR_IDX(mode) | L3_PAGE);
+		pmap_load_store(pte, (pa & ~L3_OFFSET) | attr);
 		PTE_SYNC(pte);
 
 		va += PAGE_SIZE;
@@ -1259,6 +1262,8 @@ pmap_qenter(vm_offset_t sva, vm_page_t *ma, int count)
 		m = ma[i];
 		pa = VM_PAGE_TO_PHYS(m) | ATTR_DEFAULT | ATTR_AP(ATTR_AP_RW) |
 		    ATTR_IDX(m->md.pv_memattr) | L3_PAGE;
+		if (m->md.pv_memattr == DEVICE_MEMORY)
+			pa |= ATTR_XN;
 		pte = pmap_l2_to_l3(pde, va);
 		pmap_load_store(pte, pa);
 		PTE_SYNC(pte);
@@ -2428,14 +2433,16 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t
 {
 	vm_offset_t va, va_next;
 	pd_entry_t *l0, *l1, *l2;
-	pt_entry_t *l3p, l3;
+	pt_entry_t *l3p, l3, nbits;
 
-	if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
+	KASSERT((prot & ~VM_PROT_ALL) == 0, ("invalid prot %x", prot));
+	if (prot == VM_PROT_NONE) {
 		pmap_remove(pmap, sva, eva);
 		return;
 	}
 
-	if ((prot & VM_PROT_WRITE) == VM_PROT_WRITE)
+	if ((prot & (VM_PROT_WRITE | VM_PROT_EXECUTE)) ==
+	    (VM_PROT_WRITE | VM_PROT_EXECUTE))
 		return;
 
 	PMAP_LOCK(pmap);
@@ -2480,17 +2487,25 @@ pmap_protect(pmap_t pmap, vm_offset_t sva, vm_offset_t
 		for (l3p = pmap_l2_to_l3(l2, sva); sva != va_next; l3p++,
 		    sva += L3_SIZE) {
 			l3 = pmap_load(l3p);
-			if (pmap_l3_valid(l3)) {
+			if (!pmap_l3_valid(l3))
+				continue;
+
+			nbits = 0;
+			if ((prot & VM_PROT_WRITE) == 0) {
 				if ((l3 & ATTR_SW_MANAGED) &&
 				    pmap_page_dirty(l3)) {
 					vm_page_dirty(PHYS_TO_VM_PAGE(l3 &
 					    ~ATTR_MASK));
 				}
-				pmap_set(l3p, ATTR_AP(ATTR_AP_RO));
-				PTE_SYNC(l3p);
-				/* XXX: Use pmap_invalidate_range */
-				pmap_invalidate_page(pmap, va);
+				nbits |= ATTR_AP(ATTR_AP_RO);
 			}
+			if ((prot & VM_PROT_EXECUTE) == 0)
+				nbits |= ATTR_XN;
+
+			pmap_set(l3p, nbits);
+			PTE_SYNC(l3p);
+			/* XXX: Use pmap_invalidate_range */
+			pmap_invalidate_page(pmap, va);
 		}
 	}
 	PMAP_UNLOCK(pmap);
@@ -2709,10 +2724,12 @@ pmap_enter(pmap_t pmap, vm_offset_t va, vm_page_t m, v
 	    L3_PAGE);
 	if ((prot & VM_PROT_WRITE) == 0)
 		new_l3 |= ATTR_AP(ATTR_AP_RO);
+	if ((prot & VM_PROT_EXECUTE) == 0 || m->md.pv_memattr == DEVICE_MEMORY)
+		new_l3 |= ATTR_XN;
 	if ((flags & PMAP_ENTER_WIRED) != 0)
 		new_l3 |= ATTR_SW_WIRED;
 	if ((va >> 63) == 0)
-		new_l3 |= ATTR_AP(ATTR_AP_USER);
+		new_l3 |= ATTR_AP(ATTR_AP_USER) | ATTR_PXN;
 
 	CTR2(KTR_PMAP, "pmap_enter: %.16lx -> %.16lx", va, pa);
 
@@ -3115,6 +3132,10 @@ pmap_enter_quick_locked(pmap_t pmap, vm_offset_t va, v
 
 	pa = VM_PAGE_TO_PHYS(m) | ATTR_DEFAULT | ATTR_IDX(m->md.pv_memattr) |
 	    ATTR_AP(ATTR_AP_RO) | L3_PAGE;
+	if ((prot & VM_PROT_EXECUTE) == 0 || m->md.pv_memattr == DEVICE_MEMORY)
+		pa |= ATTR_XN;
+	else if (va < VM_MAXUSER_ADDRESS)
+		pa |= ATTR_PXN;
 
 	/*
 	 * Now validate mapping with RO protection
@@ -4251,6 +4272,8 @@ pmap_change_attr_locked(vm_offset_t va, vm_size_t size
 				l3 = pmap_load(pte);
 				l3 &= ~ATTR_IDX_MASK;
 				l3 |= ATTR_IDX(mode);
+				if (mode == DEVICE_MEMORY)
+					l3 |= ATTR_XN;
 
 				pmap_update_entry(kernel_pmap, pte, l3, tmpva,
 				    PAGE_SIZE);

Modified: stable/11/sys/arm64/include/pte.h
==============================================================================
--- stable/11/sys/arm64/include/pte.h	Tue May 30 12:26:36 2017	(r319202)
+++ stable/11/sys/arm64/include/pte.h	Tue May 30 12:44:01 2017	(r319203)
@@ -46,6 +46,11 @@ typedef	uint64_t	pt_entry_t;		/* page table entry */
 /* Bits 58:55 are reserved for software */
 #define	ATTR_SW_MANAGED	(1UL << 56)
 #define	ATTR_SW_WIRED	(1UL << 55)
+#define	ATTR_UXN	(1UL << 54)
+#define	ATTR_PXN	(1UL << 53)
+#define	ATTR_XN		(ATTR_PXN | ATTR_UXN)
+#define	ATTR_CONTIGUOUS	(1UL << 52)
+#define	ATTR_DBM	(1UL << 51)
 #define	ATTR_nG		(1 << 11)
 #define	ATTR_AF		(1 << 10)
 #define	ATTR_SH(x)	((x) << 8)


More information about the svn-src-all mailing list