Author: andrew Date: Tue May 30 12:26:36 2017 New Revision: 319202 URL: https://svnweb.freebsd.org/changeset/base/319202
Log: MFC r316732, r316756: Enable Privileged Access Never on arm64. r316732: Use the unprivileged variant of the load and store instructions most places possible in the kernel. This forces these functions to fail if userspace is unable to access a given memory location, even if it is in the user memory range. This will simplify adding Privileged Access Never support later. r316756: In ARMv8.1 ARM has added a process state bit to disable access to userspace from the kernel. Make use of this to restrict accessing userspace to just the functions that explicitly handle crossing the user kernel boundary. Modified: stable/11/sys/arm64/arm64/copyinout.S stable/11/sys/arm64/arm64/machdep.c stable/11/sys/arm64/arm64/mp_machdep.c stable/11/sys/arm64/arm64/support.S stable/11/sys/arm64/include/armreg.h stable/11/sys/arm64/include/asm.h stable/11/sys/arm64/include/cpufunc.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/arm64/arm64/copyinout.S ============================================================================== --- stable/11/sys/arm64/arm64/copyinout.S Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/arm64/copyinout.S Tue May 30 12:26:36 2017 (r319202) @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); */ ENTRY(copyio_fault) SET_FAULT_HANDLER(xzr, x1) /* Clear the handler */ + EXIT_USER_ACCESS_CHECK(w0, x1) copyio_fault_nopcb: mov x0, #EFAULT ret @@ -99,19 +100,23 @@ ENTRY(copyinstr) adr x6, copyio_fault /* Get the handler address */ SET_FAULT_HANDLER(x6, x7) /* Set the handler */ + ENTER_USER_ACCESS(w6, x7) ldr x7, =VM_MAXUSER_ADDRESS 1: cmp x0, x7 b.cs copyio_fault - ldrb w4, [x0], #1 /* Load from uaddr */ + ldtrb w4, [x0] /* Load from uaddr */ + add x0, x0, #1 /* Next char */ strb w4, [x1], #1 /* Store in kaddr */ add x5, x5, #1 /* count++ */ cbz w4, 2f /* Break when NUL-terminated */ sub x2, x2, #1 /* len-- */ cbnz x2, 1b -2: SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */ +2: EXIT_USER_ACCESS(w6) + SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */ + 3: cbz x3, 4f /* Check if done != NULL */ str x5, [x3] /* done = count */ @@ -144,8 +149,8 @@ END(copyinstr) copycommon: adr x6, copyio_fault /* Get the handler address */ SET_FAULT_HANDLER(x6, x7) /* Set the handler */ + ENTER_USER_ACCESS(w6, x7) - /* Check alignment */ orr x3, x0, x1 ands x3, x3, 0x07 @@ -213,6 +218,7 @@ last_byte: strb w3, [x1] ending: + EXIT_USER_ACCESS_CHECK(w6, x7) SET_FAULT_HANDLER(xzr, x7) /* Clear the handler */ mov x0, xzr /* return 0 */ Modified: stable/11/sys/arm64/arm64/machdep.c ============================================================================== --- stable/11/sys/arm64/arm64/machdep.c Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/arm64/machdep.c Tue May 30 12:26:36 2017 (r319202) @@ -109,6 +109,7 @@ int64_t dcache_line_size; /* The minimum D cache line int64_t icache_line_size; /* The minimum I cache line size */ int64_t idcache_line_size; /* The minimum cache line size */ int64_t dczva_line_size; /* The size of cache line the dc zva zeroes */ +int has_pan; /* pagezero_* implementations are provided in support.S */ void pagezero_simple(void *); @@ -118,6 +119,37 @@ void pagezero_cache(void *); void (*pagezero)(void *p) = pagezero_simple; static void +pan_setup(void) +{ + uint64_t id_aa64mfr1; + + id_aa64mfr1 = READ_SPECIALREG(id_aa64mmfr1_el1); + if (ID_AA64MMFR1_PAN(id_aa64mfr1) != ID_AA64MMFR1_PAN_NONE) + has_pan = 1; +} + +void +pan_enable(void) +{ + + /* + * The LLVM integrated assembler doesn't understand the PAN + * PSTATE field. Because of this we need to manually create + * the instruction in an asm block. This is equivalent to: + * msr pan, #1 + * + * This sets the PAN bit, stopping the kernel from accessing + * memory when userspace can also access it unless the kernel + * uses the userspace load/store instructions. + */ + if (has_pan) { + WRITE_SPECIALREG(sctlr_el1, + READ_SPECIALREG(sctlr_el1) & ~SCTLR_SPAN); + __asm __volatile(".inst 0xd500409f | (0x1 << 8)"); + } +} + +static void cpu_startup(void *dummy) { @@ -920,6 +952,7 @@ initarm(struct arm64_bootparams *abp) init_param1(); cache_setup(); + pan_setup(); /* Bootstrap enough of pmap to enter the kernel proper */ pmap_bootstrap(abp->kern_l0pt, abp->kern_l1pt, @@ -936,6 +969,7 @@ initarm(struct arm64_bootparams *abp) dbg_monitor_init(); kdb_init(); + pan_enable(); early_boot = 0; } Modified: stable/11/sys/arm64/arm64/mp_machdep.c ============================================================================== --- stable/11/sys/arm64/arm64/mp_machdep.c Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/arm64/mp_machdep.c Tue May 30 12:26:36 2017 (r319202) @@ -278,6 +278,7 @@ init_secondary(uint64_t cpu) #endif dbg_monitor_init(); + pan_enable(); /* Enable interrupts */ intr_enable(); Modified: stable/11/sys/arm64/arm64/support.S ============================================================================== --- stable/11/sys/arm64/arm64/support.S Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/arm64/support.S Tue May 30 12:26:36 2017 (r319202) @@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$"); */ ENTRY(fsu_fault) SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */ + EXIT_USER_ACCESS_CHECK(w0, x1) fsu_fault_nopcb: mov x0, #-1 ret @@ -57,11 +58,13 @@ ENTRY(casueword32) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x4) /* And set it */ + ENTER_USER_ACCESS(w6, x4) 1: ldxr w4, [x0] /* Load-exclusive the data */ cmp w4, w1 /* Compare */ b.ne 2f /* Not equal, exit */ stxr w5, w3, [x0] /* Store the new data */ cbnz w5, 1b /* Retry on failure */ + EXIT_USER_ACCESS(w6) 2: SET_FAULT_HANDLER(xzr, x5) /* Reset the fault handler */ str w4, [x2] /* Store the read data */ mov x0, #0 /* Success */ @@ -77,11 +80,13 @@ ENTRY(casueword) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x4) /* And set it */ + ENTER_USER_ACCESS(w6, x4) 1: ldxr x4, [x0] /* Load-exclusive the data */ cmp x4, x1 /* Compare */ b.ne 2f /* Not equal, exit */ stxr w5, x3, [x0] /* Store the new data */ cbnz w5, 1b /* Retry on failure */ + EXIT_USER_ACCESS(w6) 2: SET_FAULT_HANDLER(xzr, x5) /* Reset the fault handler */ str x4, [x2] /* Store the read data */ mov x0, #0 /* Success */ @@ -97,7 +102,7 @@ ENTRY(fubyte) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x1) /* And set it */ - ldrb w0, [x0] /* Try loading the data */ + ldtrb w0, [x0] /* Try loading the data */ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */ ret /* Return */ END(fubyte) @@ -111,7 +116,7 @@ ENTRY(fuword16) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x1) /* And set it */ - ldrh w0, [x0] /* Try loading the data */ + ldtrh w0, [x0] /* Try loading the data */ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */ ret /* Return */ END(fuword16) @@ -125,7 +130,7 @@ ENTRY(fueword32) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - ldr w0, [x0] /* Try loading the data */ + ldtr w0, [x0] /* Try loading the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ str w0, [x1] /* Save the data in kernel space */ mov w0, #0 /* Success */ @@ -143,7 +148,7 @@ EENTRY(fueword64) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - ldr x0, [x0] /* Try loading the data */ + ldtr x0, [x0] /* Try loading the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ str x0, [x1] /* Save the data in kernel space */ mov x0, #0 /* Success */ @@ -160,7 +165,7 @@ ENTRY(subyte) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - strb w1, [x0] /* Try storing the data */ + sttrb w1, [x0] /* Try storing the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ mov x0, #0 /* Success */ ret /* Return */ @@ -175,7 +180,7 @@ ENTRY(suword16) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - strh w1, [x0] /* Try storing the data */ + sttrh w1, [x0] /* Try storing the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ mov x0, #0 /* Success */ ret /* Return */ @@ -190,7 +195,7 @@ ENTRY(suword32) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - str w1, [x0] /* Try storing the data */ + sttr w1, [x0] /* Try storing the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ mov x0, #0 /* Success */ ret /* Return */ @@ -206,7 +211,7 @@ EENTRY(suword64) b.cs fsu_fault_nopcb adr x6, fsu_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - str x1, [x0] /* Try storing the data */ + sttr x1, [x0] /* Try storing the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ mov x0, #0 /* Success */ ret /* Return */ @@ -224,6 +229,7 @@ END(suword) */ ENTRY(fsu_intr_fault) SET_FAULT_HANDLER(xzr, x1) /* Reset the handler function */ + EXIT_USER_ACCESS_CHECK(w0, x1) mov x0, #-1 ret END(fsu_fault) @@ -237,7 +243,7 @@ ENTRY(fuswintr) b.cs fsu_fault_nopcb adr x6, fsu_intr_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x1) /* And set it */ - ldr w0, [x0] /* Try loading the data */ + ldtr w0, [x0] /* Try loading the data */ SET_FAULT_HANDLER(xzr, x1) /* Reset the fault handler */ ret /* Return */ END(fuswintr) @@ -251,7 +257,7 @@ ENTRY(suswintr) b.cs fsu_fault_nopcb adr x6, fsu_intr_fault /* Load the fault handler */ SET_FAULT_HANDLER(x6, x2) /* And set it */ - str w1, [x0] /* Try storing the data */ + sttr w1, [x0] /* Try storing the data */ SET_FAULT_HANDLER(xzr, x2) /* Reset the fault handler */ mov x0, #0 /* Success */ ret /* Return */ Modified: stable/11/sys/arm64/include/armreg.h ============================================================================== --- stable/11/sys/arm64/include/armreg.h Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/include/armreg.h Tue May 30 12:26:36 2017 (r319202) @@ -312,6 +312,7 @@ #define ID_AA64MMFR1_PAN(x) ((x) & ID_AA64MMFR1_PAN_MASK) #define ID_AA64MMFR1_PAN_NONE (0x0 << ID_AA64MMFR1_PAN_SHIFT) #define ID_AA64MMFR1_PAN_IMPL (0x1 << ID_AA64MMFR1_PAN_SHIFT) +#define ID_AA64MMFR1_PAN_ATS1E1 (0x2 << ID_AA64MMFR1_PAN_SHIFT) /* ID_AA64PFR0_EL1 */ #define ID_AA64PFR0_MASK 0x0fffffff Modified: stable/11/sys/arm64/include/asm.h ============================================================================== --- stable/11/sys/arm64/include/asm.h Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/include/asm.h Tue May 30 12:26:36 2017 (r319202) @@ -68,4 +68,23 @@ ldr tmp, [tmp, #TD_PCB]; /* Load the pcb */ \ str handler, [tmp, #PCB_ONFAULT] /* Set the handler */ +#define ENTER_USER_ACCESS(reg, tmp) \ + ldr tmp, =has_pan; /* Get the addr of has_pan */ \ + ldr reg, [tmp]; /* Read it */ \ + cbz reg, 997f; /* If no PAN skip */ \ + .inst 0xd500409f | (0 << 8); /* Clear PAN */ \ + 997: + +#define EXIT_USER_ACCESS(reg) \ + cbz reg, 998f; /* If no PAN skip */ \ + .inst 0xd500409f | (1 << 8); /* Set PAN */ \ + 998: + +#define EXIT_USER_ACCESS_CHECK(reg, tmp) \ + ldr tmp, =has_pan; /* Get the addr of has_pan */ \ + ldr reg, [tmp]; /* Read it */ \ + cbz reg, 999f; /* If no PAN skip */ \ + .inst 0xd500409f | (1 << 8); /* Set PAN */ \ + 999: + #endif /* _MACHINE_ASM_H_ */ Modified: stable/11/sys/arm64/include/cpufunc.h ============================================================================== --- stable/11/sys/arm64/include/cpufunc.h Tue May 30 12:00:56 2017 (r319201) +++ stable/11/sys/arm64/include/cpufunc.h Tue May 30 12:26:36 2017 (r319202) @@ -33,6 +33,8 @@ #include <machine/armreg.h> +void pan_enable(void); + static __inline void breakpoint(void) { _______________________________________________ svn-src-all@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"