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
This commit is contained in:
Andrew Turner 2021-09-23 15:00:55 +00:00
parent 0cfc8b10ed
commit f6de51d3e0
3 changed files with 29 additions and 6 deletions

View file

@ -552,6 +552,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

View file

@ -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;

View file

@ -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)