Loading arch/arm/Kconfig +15 −0 Original line number Diff line number Diff line Loading @@ -1700,6 +1700,21 @@ config HIGHPTE consumed by page tables. Setting this option will allow user-space 2nd level page tables to reside in high memory. config CPU_SW_DOMAIN_PAN bool "Enable use of CPU domains to implement privileged no-access" depends on MMU && !ARM_LPAE default y help Increase kernel security by ensuring that normal kernel accesses are unable to access userspace addresses. This can help prevent use-after-free bugs becoming an exploitable privilege escalation by ensuring that magic values (such as LIST_POISON) will always fault when dereferenced. CPUs with low-vector mappings use a best-efforts implementation. Their lower 1MB needs to remain accessible for the vectors, but the remainder of userspace will become appropriately inaccessible. config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" depends on PERF_EVENTS Loading arch/arm/include/asm/assembler.h +42 −0 Original line number Diff line number Diff line Loading @@ -445,6 +445,48 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm .macro uaccess_disable, tmp, isb=1 #ifdef CONFIG_CPU_SW_DOMAIN_PAN /* * Whenever we re-enter userspace, the domains should always be * set appropriately. */ mov \tmp, #DACR_UACCESS_DISABLE mcr p15, 0, \tmp, c3, c0, 0 @ Set domain register .if \isb instr_sync .endif #endif .endm .macro uaccess_enable, tmp, isb=1 #ifdef CONFIG_CPU_SW_DOMAIN_PAN /* * Whenever we re-enter userspace, the domains should always be * set appropriately. */ mov \tmp, #DACR_UACCESS_ENABLE mcr p15, 0, \tmp, c3, c0, 0 .if \isb instr_sync .endif #endif .endm .macro uaccess_save, tmp #ifdef CONFIG_CPU_SW_DOMAIN_PAN mrc p15, 0, \tmp, c3, c0, 0 str \tmp, [sp, #S_FRAME_SIZE] #endif .endm .macro uaccess_restore #ifdef CONFIG_CPU_SW_DOMAIN_PAN ldr r0, [sp, #S_FRAME_SIZE] mcr p15, 0, r0, c3, c0, 0 #endif .endm .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo .macro ret\c, reg #if __LINUX_ARM_ARCH__ < 6 Loading arch/arm/include/asm/domain.h +46 −11 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #ifndef __ASSEMBLY__ #include <asm/barrier.h> #include <asm/thread_info.h> #endif /* Loading @@ -34,15 +35,14 @@ */ #ifndef CONFIG_IO_36 #define DOMAIN_KERNEL 0 #define DOMAIN_TABLE 0 #define DOMAIN_USER 1 #define DOMAIN_IO 2 #else #define DOMAIN_KERNEL 2 #define DOMAIN_TABLE 2 #define DOMAIN_USER 1 #define DOMAIN_IO 0 #endif #define DOMAIN_VECTORS 3 /* * Domain types Loading @@ -55,30 +55,65 @@ #define DOMAIN_MANAGER 1 #endif #define domain_mask(dom) ((3) << (2 * (dom))) #define domain_val(dom,type) ((type) << (2 * (dom))) #ifdef CONFIG_CPU_SW_DOMAIN_PAN #define DACR_INIT \ (domain_val(DOMAIN_USER, DOMAIN_NOACCESS) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) #else #define DACR_INIT \ (domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) #endif #define __DACR_DEFAULT \ domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT) #define DACR_UACCESS_DISABLE \ (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) #define DACR_UACCESS_ENABLE \ (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_CLIENT)) #ifndef __ASSEMBLY__ #ifdef CONFIG_CPU_USE_DOMAINS static inline unsigned int get_domain(void) { unsigned int domain; asm( "mrc p15, 0, %0, c3, c0 @ get domain" : "=r" (domain) : "m" (current_thread_info()->cpu_domain)); return domain; } static inline void set_domain(unsigned val) { asm volatile( "mcr p15, 0, %0, c3, c0 @ set domain" : : "r" (val)); : : "r" (val) : "memory"); isb(); } #ifdef CONFIG_CPU_USE_DOMAINS #define modify_domain(dom,type) \ do { \ struct thread_info *thread = current_thread_info(); \ unsigned int domain = thread->cpu_domain; \ domain &= ~domain_val(dom, DOMAIN_MANAGER); \ thread->cpu_domain = domain | domain_val(dom, type); \ set_domain(thread->cpu_domain); \ unsigned int domain = get_domain(); \ domain &= ~domain_mask(dom); \ domain = domain | domain_val(dom, type); \ set_domain(domain); \ } while (0) #else static inline void set_domain(unsigned val) { } static inline void modify_domain(unsigned dom, unsigned type) { } #endif Loading arch/arm/include/asm/futex.h +17 −2 Original line number Diff line number Diff line Loading @@ -22,8 +22,11 @@ #ifdef CONFIG_SMP #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ ({ \ unsigned int __ua_flags; \ smp_mb(); \ prefetchw(uaddr); \ __ua_flags = uaccess_save_and_enable(); \ __asm__ __volatile__( \ "1: ldrex %1, [%3]\n" \ " " insn "\n" \ Loading @@ -34,12 +37,15 @@ __futex_atomic_ex_table("%5") \ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ : "cc", "memory") : "cc", "memory"); \ uaccess_restore(__ua_flags); \ }) static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { unsigned int __ua_flags; int ret; u32 val; Loading @@ -49,6 +55,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, smp_mb(); /* Prefetching cannot fault */ prefetchw(uaddr); __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: ldrex %1, [%4]\n" " teq %1, %2\n" Loading @@ -61,6 +68,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "=&r" (ret), "=&r" (val) : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) : "cc", "memory"); uaccess_restore(__ua_flags); smp_mb(); *uval = val; Loading @@ -73,6 +81,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, #include <asm/domain.h> #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ ({ \ unsigned int __ua_flags = uaccess_save_and_enable(); \ __asm__ __volatile__( \ "1: " TUSER(ldr) " %1, [%3]\n" \ " " insn "\n" \ Loading @@ -81,12 +91,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, __futex_atomic_ex_table("%5") \ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ : "cc", "memory") : "cc", "memory"); \ uaccess_restore(__ua_flags); \ }) static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { unsigned int __ua_flags; int ret = 0; u32 val; Loading @@ -94,6 +107,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; preempt_disable(); __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: " TUSER(ldr) " %1, [%4]\n" " teq %1, %2\n" Loading @@ -103,6 +117,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "+r" (ret), "=&r" (val) : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) : "cc", "memory"); uaccess_restore(__ua_flags); *uval = val; preempt_enable(); Loading arch/arm/include/asm/pgtable-2level-hwdef.h +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #define PMD_PXNTABLE (_AT(pmdval_t, 1) << 2) /* v7 */ #define PMD_BIT4 (_AT(pmdval_t, 1) << 4) #define PMD_DOMAIN(x) (_AT(pmdval_t, (x)) << 5) #define PMD_DOMAIN_MASK PMD_DOMAIN(0x0f) #define PMD_PROTECTION (_AT(pmdval_t, 1) << 9) /* v5 */ /* * - section Loading Loading
arch/arm/Kconfig +15 −0 Original line number Diff line number Diff line Loading @@ -1700,6 +1700,21 @@ config HIGHPTE consumed by page tables. Setting this option will allow user-space 2nd level page tables to reside in high memory. config CPU_SW_DOMAIN_PAN bool "Enable use of CPU domains to implement privileged no-access" depends on MMU && !ARM_LPAE default y help Increase kernel security by ensuring that normal kernel accesses are unable to access userspace addresses. This can help prevent use-after-free bugs becoming an exploitable privilege escalation by ensuring that magic values (such as LIST_POISON) will always fault when dereferenced. CPUs with low-vector mappings use a best-efforts implementation. Their lower 1MB needs to remain accessible for the vectors, but the remainder of userspace will become appropriately inaccessible. config HW_PERF_EVENTS bool "Enable hardware performance counter support for perf events" depends on PERF_EVENTS Loading
arch/arm/include/asm/assembler.h +42 −0 Original line number Diff line number Diff line Loading @@ -445,6 +445,48 @@ THUMB( orr \reg , \reg , #PSR_T_BIT ) #endif .endm .macro uaccess_disable, tmp, isb=1 #ifdef CONFIG_CPU_SW_DOMAIN_PAN /* * Whenever we re-enter userspace, the domains should always be * set appropriately. */ mov \tmp, #DACR_UACCESS_DISABLE mcr p15, 0, \tmp, c3, c0, 0 @ Set domain register .if \isb instr_sync .endif #endif .endm .macro uaccess_enable, tmp, isb=1 #ifdef CONFIG_CPU_SW_DOMAIN_PAN /* * Whenever we re-enter userspace, the domains should always be * set appropriately. */ mov \tmp, #DACR_UACCESS_ENABLE mcr p15, 0, \tmp, c3, c0, 0 .if \isb instr_sync .endif #endif .endm .macro uaccess_save, tmp #ifdef CONFIG_CPU_SW_DOMAIN_PAN mrc p15, 0, \tmp, c3, c0, 0 str \tmp, [sp, #S_FRAME_SIZE] #endif .endm .macro uaccess_restore #ifdef CONFIG_CPU_SW_DOMAIN_PAN ldr r0, [sp, #S_FRAME_SIZE] mcr p15, 0, r0, c3, c0, 0 #endif .endm .irp c,,eq,ne,cs,cc,mi,pl,vs,vc,hi,ls,ge,lt,gt,le,hs,lo .macro ret\c, reg #if __LINUX_ARM_ARCH__ < 6 Loading
arch/arm/include/asm/domain.h +46 −11 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ #ifndef __ASSEMBLY__ #include <asm/barrier.h> #include <asm/thread_info.h> #endif /* Loading @@ -34,15 +35,14 @@ */ #ifndef CONFIG_IO_36 #define DOMAIN_KERNEL 0 #define DOMAIN_TABLE 0 #define DOMAIN_USER 1 #define DOMAIN_IO 2 #else #define DOMAIN_KERNEL 2 #define DOMAIN_TABLE 2 #define DOMAIN_USER 1 #define DOMAIN_IO 0 #endif #define DOMAIN_VECTORS 3 /* * Domain types Loading @@ -55,30 +55,65 @@ #define DOMAIN_MANAGER 1 #endif #define domain_mask(dom) ((3) << (2 * (dom))) #define domain_val(dom,type) ((type) << (2 * (dom))) #ifdef CONFIG_CPU_SW_DOMAIN_PAN #define DACR_INIT \ (domain_val(DOMAIN_USER, DOMAIN_NOACCESS) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) #else #define DACR_INIT \ (domain_val(DOMAIN_USER, DOMAIN_CLIENT) | \ domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT)) #endif #define __DACR_DEFAULT \ domain_val(DOMAIN_KERNEL, DOMAIN_CLIENT) | \ domain_val(DOMAIN_IO, DOMAIN_CLIENT) | \ domain_val(DOMAIN_VECTORS, DOMAIN_CLIENT) #define DACR_UACCESS_DISABLE \ (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_NOACCESS)) #define DACR_UACCESS_ENABLE \ (__DACR_DEFAULT | domain_val(DOMAIN_USER, DOMAIN_CLIENT)) #ifndef __ASSEMBLY__ #ifdef CONFIG_CPU_USE_DOMAINS static inline unsigned int get_domain(void) { unsigned int domain; asm( "mrc p15, 0, %0, c3, c0 @ get domain" : "=r" (domain) : "m" (current_thread_info()->cpu_domain)); return domain; } static inline void set_domain(unsigned val) { asm volatile( "mcr p15, 0, %0, c3, c0 @ set domain" : : "r" (val)); : : "r" (val) : "memory"); isb(); } #ifdef CONFIG_CPU_USE_DOMAINS #define modify_domain(dom,type) \ do { \ struct thread_info *thread = current_thread_info(); \ unsigned int domain = thread->cpu_domain; \ domain &= ~domain_val(dom, DOMAIN_MANAGER); \ thread->cpu_domain = domain | domain_val(dom, type); \ set_domain(thread->cpu_domain); \ unsigned int domain = get_domain(); \ domain &= ~domain_mask(dom); \ domain = domain | domain_val(dom, type); \ set_domain(domain); \ } while (0) #else static inline void set_domain(unsigned val) { } static inline void modify_domain(unsigned dom, unsigned type) { } #endif Loading
arch/arm/include/asm/futex.h +17 −2 Original line number Diff line number Diff line Loading @@ -22,8 +22,11 @@ #ifdef CONFIG_SMP #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ ({ \ unsigned int __ua_flags; \ smp_mb(); \ prefetchw(uaddr); \ __ua_flags = uaccess_save_and_enable(); \ __asm__ __volatile__( \ "1: ldrex %1, [%3]\n" \ " " insn "\n" \ Loading @@ -34,12 +37,15 @@ __futex_atomic_ex_table("%5") \ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ : "cc", "memory") : "cc", "memory"); \ uaccess_restore(__ua_flags); \ }) static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { unsigned int __ua_flags; int ret; u32 val; Loading @@ -49,6 +55,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, smp_mb(); /* Prefetching cannot fault */ prefetchw(uaddr); __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: ldrex %1, [%4]\n" " teq %1, %2\n" Loading @@ -61,6 +68,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "=&r" (ret), "=&r" (val) : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) : "cc", "memory"); uaccess_restore(__ua_flags); smp_mb(); *uval = val; Loading @@ -73,6 +81,8 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, #include <asm/domain.h> #define __futex_atomic_op(insn, ret, oldval, tmp, uaddr, oparg) \ ({ \ unsigned int __ua_flags = uaccess_save_and_enable(); \ __asm__ __volatile__( \ "1: " TUSER(ldr) " %1, [%3]\n" \ " " insn "\n" \ Loading @@ -81,12 +91,15 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, __futex_atomic_ex_table("%5") \ : "=&r" (ret), "=&r" (oldval), "=&r" (tmp) \ : "r" (uaddr), "r" (oparg), "Ir" (-EFAULT) \ : "cc", "memory") : "cc", "memory"); \ uaccess_restore(__ua_flags); \ }) static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, u32 oldval, u32 newval) { unsigned int __ua_flags; int ret = 0; u32 val; Loading @@ -94,6 +107,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, return -EFAULT; preempt_disable(); __ua_flags = uaccess_save_and_enable(); __asm__ __volatile__("@futex_atomic_cmpxchg_inatomic\n" "1: " TUSER(ldr) " %1, [%4]\n" " teq %1, %2\n" Loading @@ -103,6 +117,7 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr, : "+r" (ret), "=&r" (val) : "r" (oldval), "r" (newval), "r" (uaddr), "Ir" (-EFAULT) : "cc", "memory"); uaccess_restore(__ua_flags); *uval = val; preempt_enable(); Loading
arch/arm/include/asm/pgtable-2level-hwdef.h +1 −0 Original line number Diff line number Diff line Loading @@ -23,6 +23,7 @@ #define PMD_PXNTABLE (_AT(pmdval_t, 1) << 2) /* v7 */ #define PMD_BIT4 (_AT(pmdval_t, 1) << 4) #define PMD_DOMAIN(x) (_AT(pmdval_t, (x)) << 5) #define PMD_DOMAIN_MASK PMD_DOMAIN(0x0f) #define PMD_PROTECTION (_AT(pmdval_t, 1) << 9) /* v5 */ /* * - section Loading