git: 2b2cef987353 - stable/13 - Add the arm64 table attributes and use them

From: Andrew Turner <andrew_at_FreeBSD.org>
Date: Mon, 25 Oct 2021 13:54:48 UTC
The branch stable/13 has been updated by andrew:

URL: https://cgit.FreeBSD.org/src/commit/?id=2b2cef987353d5867462b3dd6aa87db6e09fe693

commit 2b2cef987353d5867462b3dd6aa87db6e09fe693
Author:     Andrew Turner <andrew@FreeBSD.org>
AuthorDate: 2021-09-23 15:00:55 +0000
Commit:     Andrew Turner <andrew@FreeBSD.org>
CommitDate: 2021-10-25 13:46:44 +0000

    Add the arm64 table attributes and use them
    
    Add the table page table attributes on arm64 and use them to add
    restrictions to the block and page entries below them. This ensures
    we are unable to increase the permissions in these last level entries
    without also changing them in the upper levels.
    
    Use the attributes to ensure the kernel can't execute from userspace
    memory and vice versa, userspace has no access to read or write kernel
    memory, and that the DMAP region is non-executable.
    
    Reviewed by:    alc, kib
    Sponsored by:   The FreeBSD Foundation
    Differential Revision: https://reviews.freebsd.org/D32081
    
    (cherry picked from commit f6de51d3e0315891f6ea9d12340b98336df409b7)
---
 sys/arm64/arm64/locore.S |  1 +
 sys/arm64/arm64/pmap.c   | 25 +++++++++++++++++++------
 sys/arm64/include/pte.h  |  9 +++++++++
 3 files changed, 29 insertions(+), 6 deletions(-)

diff --git a/sys/arm64/arm64/locore.S b/sys/arm64/arm64/locore.S
index ae844c8ff473..06dcfd11404b 100644
--- a/sys/arm64/arm64/locore.S
+++ b/sys/arm64/arm64/locore.S
@@ -532,6 +532,7 @@ LENTRY(link_l0_pagetable)
 
 	/* Build the L0 block entry */
 	mov	x12, #L0_TABLE
+	orr	x12, x12, #(TATTR_UXN_TABLE | TATTR_AP_TABLE_NO_EL0)
 
 	/* Only use the output address bits */
 	lsr	x9, x9, #PAGE_SHIFT
diff --git a/sys/arm64/arm64/pmap.c b/sys/arm64/arm64/pmap.c
index 1ae6d87dee51..cdd1ed49fc7d 100644
--- a/sys/arm64/arm64/pmap.c
+++ b/sys/arm64/arm64/pmap.c
@@ -789,7 +789,8 @@ pmap_bootstrap_dmap(vm_offset_t kern_l1, vm_paddr_t min_pa,
 				freemempos += PAGE_SIZE;
 
 				pmap_store(&pagetable_dmap[l1_slot],
-				    (l2_pa & ~Ln_TABLE_MASK) | L1_TABLE);
+				    (l2_pa & ~Ln_TABLE_MASK) |
+				    TATTR_PXN_TABLE | L1_TABLE);
 
 				memset(l2, 0, PAGE_SIZE);
 			}
@@ -1873,14 +1874,26 @@ _pmap_alloc_l3(pmap_t pmap, vm_pindex_t ptepindex, struct rwlock **lockp)
 	 */
 
 	if (ptepindex >= (NUL2E + NUL1E)) {
-		pd_entry_t *l0;
+		pd_entry_t *l0p, l0e;
 		vm_pindex_t l0index;
 
 		l0index = ptepindex - (NUL2E + NUL1E);
-		l0 = &pmap->pm_l0[l0index];
-		KASSERT((pmap_load(l0) & ATTR_DESCR_VALID) == 0,
-		    ("%s: L0 entry %#lx is valid", __func__, pmap_load(l0)));
-		pmap_store(l0, VM_PAGE_TO_PHYS(m) | L0_TABLE);
+		l0p = &pmap->pm_l0[l0index];
+		KASSERT((pmap_load(l0p) & ATTR_DESCR_VALID) == 0,
+		    ("%s: L0 entry %#lx is valid", __func__, pmap_load(l0p)));
+		l0e = VM_PAGE_TO_PHYS(m) | L0_TABLE;
+
+		/*
+		 * Mark all kernel memory as not accessible from userspace
+		 * and userspace memory as not executable from the kernel.
+		 * This has been done for the bootstrap L0 entries in
+		 * locore.S.
+		 */
+		if (pmap == kernel_pmap)
+			l0e |= TATTR_UXN_TABLE | TATTR_AP_TABLE_NO_EL0;
+		else
+			l0e |= TATTR_PXN_TABLE;
+		pmap_store(l0p, l0e);
 	} else if (ptepindex >= NUL2E) {
 		vm_pindex_t l0index, l1index;
 		pd_entry_t *l0, *l1;
diff --git a/sys/arm64/include/pte.h b/sys/arm64/include/pte.h
index b3bec720e9f9..6b816464c167 100644
--- a/sys/arm64/include/pte.h
+++ b/sys/arm64/include/pte.h
@@ -38,6 +38,15 @@ typedef	uint64_t	pd_entry_t;		/* page directory entry */
 typedef	uint64_t	pt_entry_t;		/* page table entry */
 #endif
 
+/* Table attributes */
+#define	TATTR_MASK		UINT64_C(0xfff8000000000000)
+#define	TATTR_AP_TABLE_MASK	(3UL << 61)
+#define	TATTR_AP_TABLE_RO	(2UL << 61)
+#define	TATTR_AP_TABLE_NO_EL0	(1UL << 61)
+#define	TATTR_UXN_TABLE		(1UL << 60)
+#define	TATTR_PXN_TABLE		(1UL << 59)
+/* Bits 58:51 are ignored */
+
 /* Block and Page attributes */
 #define	ATTR_MASK_H		UINT64_C(0xfffc000000000000)
 #define	ATTR_MASK_L		UINT64_C(0x0000000000000fff)