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