arm64: mm: Fix and re-enable ARM64_SW_TTBR0_PAN

With the ASID now installed in TTBR1, we can re-enable ARM64_SW_TTBR0_PAN
by ensuring that we switch to a reserved ASID of zero when disabling
user access and restore the active user ASID on the uaccess enable path.

Reviewed-by: Mark Rutland <mark.rutland@arm.com>
Tested-by: Laura Abbott <labbott@redhat.com>
Tested-by: Shanker Donthineni <shankerd@codeaurora.org>
Signed-off-by: Will Deacon <will.deacon@arm.com>
This commit is contained in:
Will Deacon 2017-08-10 13:58:16 +01:00
parent 158d495899
commit 27a921e757
10 changed files with 42 additions and 21 deletions

View File

@ -910,7 +910,6 @@ endif
config ARM64_SW_TTBR0_PAN config ARM64_SW_TTBR0_PAN
bool "Emulate Privileged Access Never using TTBR0_EL1 switching" bool "Emulate Privileged Access Never using TTBR0_EL1 switching"
depends on BROKEN # Temporary while switch_mm is reworked
help help
Enabling this option prevents the kernel from accessing Enabling this option prevents the kernel from accessing
user-space memory directly by pointing TTBR0_EL1 to a reserved user-space memory directly by pointing TTBR0_EL1 to a reserved

View File

@ -16,11 +16,20 @@
add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir
msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1 msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1
isb isb
sub \tmp1, \tmp1, #SWAPPER_DIR_SIZE
bic \tmp1, \tmp1, #(0xffff << 48)
msr ttbr1_el1, \tmp1 // set reserved ASID
isb
.endm .endm
.macro __uaccess_ttbr0_enable, tmp1 .macro __uaccess_ttbr0_enable, tmp1, tmp2
get_thread_info \tmp1 get_thread_info \tmp1
ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1 ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1
mrs \tmp2, ttbr1_el1
extr \tmp2, \tmp2, \tmp1, #48
ror \tmp2, \tmp2, #16
msr ttbr1_el1, \tmp2 // set the active ASID
isb
msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1 msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1
isb isb
.endm .endm
@ -31,18 +40,18 @@ alternative_if_not ARM64_HAS_PAN
alternative_else_nop_endif alternative_else_nop_endif
.endm .endm
.macro uaccess_ttbr0_enable, tmp1, tmp2 .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3
alternative_if_not ARM64_HAS_PAN alternative_if_not ARM64_HAS_PAN
save_and_disable_irq \tmp2 // avoid preemption save_and_disable_irq \tmp3 // avoid preemption
__uaccess_ttbr0_enable \tmp1 __uaccess_ttbr0_enable \tmp1, \tmp2
restore_irq \tmp2 restore_irq \tmp3
alternative_else_nop_endif alternative_else_nop_endif
.endm .endm
#else #else
.macro uaccess_ttbr0_disable, tmp1 .macro uaccess_ttbr0_disable, tmp1
.endm .endm
.macro uaccess_ttbr0_enable, tmp1, tmp2 .macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3
.endm .endm
#endif #endif
@ -56,8 +65,8 @@ alternative_if ARM64_ALT_PAN_NOT_UAO
alternative_else_nop_endif alternative_else_nop_endif
.endm .endm
.macro uaccess_enable_not_uao, tmp1, tmp2 .macro uaccess_enable_not_uao, tmp1, tmp2, tmp3
uaccess_ttbr0_enable \tmp1, \tmp2 uaccess_ttbr0_enable \tmp1, \tmp2, \tmp3
alternative_if ARM64_ALT_PAN_NOT_UAO alternative_if ARM64_ALT_PAN_NOT_UAO
SET_PSTATE_PAN(0) SET_PSTATE_PAN(0)
alternative_else_nop_endif alternative_else_nop_endif

View File

@ -107,15 +107,19 @@ static inline void __uaccess_ttbr0_disable(void)
{ {
unsigned long ttbr; unsigned long ttbr;
ttbr = read_sysreg(ttbr1_el1);
/* reserved_ttbr0 placed at the end of swapper_pg_dir */ /* reserved_ttbr0 placed at the end of swapper_pg_dir */
ttbr = read_sysreg(ttbr1_el1) + SWAPPER_DIR_SIZE; write_sysreg(ttbr + SWAPPER_DIR_SIZE, ttbr0_el1);
write_sysreg(ttbr, ttbr0_el1); isb();
/* Set reserved ASID */
ttbr &= ~(0xffffUL << 48);
write_sysreg(ttbr, ttbr1_el1);
isb(); isb();
} }
static inline void __uaccess_ttbr0_enable(void) static inline void __uaccess_ttbr0_enable(void)
{ {
unsigned long flags; unsigned long flags, ttbr0, ttbr1;
/* /*
* Disable interrupts to avoid preemption between reading the 'ttbr0' * Disable interrupts to avoid preemption between reading the 'ttbr0'
@ -123,7 +127,16 @@ static inline void __uaccess_ttbr0_enable(void)
* roll-over and an update of 'ttbr0'. * roll-over and an update of 'ttbr0'.
*/ */
local_irq_save(flags); local_irq_save(flags);
write_sysreg(current_thread_info()->ttbr0, ttbr0_el1); ttbr0 = current_thread_info()->ttbr0;
/* Restore active ASID */
ttbr1 = read_sysreg(ttbr1_el1);
ttbr1 |= ttbr0 & (0xffffUL << 48);
write_sysreg(ttbr1, ttbr1_el1);
isb();
/* Restore user page table */
write_sysreg(ttbr0, ttbr0_el1);
isb(); isb();
local_irq_restore(flags); local_irq_restore(flags);
} }

View File

@ -184,7 +184,7 @@ alternative_if ARM64_HAS_PAN
alternative_else_nop_endif alternative_else_nop_endif
.if \el != 0 .if \el != 0
mrs x21, ttbr0_el1 mrs x21, ttbr1_el1
tst x21, #0xffff << 48 // Check for the reserved ASID tst x21, #0xffff << 48 // Check for the reserved ASID
orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR orr x23, x23, #PSR_PAN_BIT // Set the emulated PAN in the saved SPSR
b.eq 1f // TTBR0 access already disabled b.eq 1f // TTBR0 access already disabled
@ -248,7 +248,7 @@ alternative_else_nop_endif
tbnz x22, #22, 1f // Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set tbnz x22, #22, 1f // Skip re-enabling TTBR0 access if the PSR_PAN_BIT is set
.endif .endif
__uaccess_ttbr0_enable x0 __uaccess_ttbr0_enable x0, x1
.if \el == 0 .if \el == 0
/* /*

View File

@ -30,7 +30,7 @@
* Alignment fixed up by hardware. * Alignment fixed up by hardware.
*/ */
ENTRY(__clear_user) ENTRY(__clear_user)
uaccess_enable_not_uao x2, x3 uaccess_enable_not_uao x2, x3, x4
mov x2, x1 // save the size for fixup return mov x2, x1 // save the size for fixup return
subs x1, x1, #8 subs x1, x1, #8
b.mi 2f b.mi 2f

View File

@ -64,7 +64,7 @@
end .req x5 end .req x5
ENTRY(__arch_copy_from_user) ENTRY(__arch_copy_from_user)
uaccess_enable_not_uao x3, x4 uaccess_enable_not_uao x3, x4, x5
add end, x0, x2 add end, x0, x2
#include "copy_template.S" #include "copy_template.S"
uaccess_disable_not_uao x3 uaccess_disable_not_uao x3

View File

@ -65,7 +65,7 @@
end .req x5 end .req x5
ENTRY(raw_copy_in_user) ENTRY(raw_copy_in_user)
uaccess_enable_not_uao x3, x4 uaccess_enable_not_uao x3, x4, x5
add end, x0, x2 add end, x0, x2
#include "copy_template.S" #include "copy_template.S"
uaccess_disable_not_uao x3 uaccess_disable_not_uao x3

View File

@ -63,7 +63,7 @@
end .req x5 end .req x5
ENTRY(__arch_copy_to_user) ENTRY(__arch_copy_to_user)
uaccess_enable_not_uao x3, x4 uaccess_enable_not_uao x3, x4, x5
add end, x0, x2 add end, x0, x2
#include "copy_template.S" #include "copy_template.S"
uaccess_disable_not_uao x3 uaccess_disable_not_uao x3

View File

@ -49,7 +49,7 @@ ENTRY(flush_icache_range)
* - end - virtual end address of region * - end - virtual end address of region
*/ */
ENTRY(__flush_cache_user_range) ENTRY(__flush_cache_user_range)
uaccess_ttbr0_enable x2, x3 uaccess_ttbr0_enable x2, x3, x4
dcache_line_size x2, x3 dcache_line_size x2, x3
sub x3, x2, #1 sub x3, x2, #1
bic x4, x0, x3 bic x4, x0, x3

View File

@ -101,7 +101,7 @@ ENTRY(privcmd_call)
* need the explicit uaccess_enable/disable if the TTBR0 PAN emulation * need the explicit uaccess_enable/disable if the TTBR0 PAN emulation
* is enabled (it implies that hardware UAO and PAN disabled). * is enabled (it implies that hardware UAO and PAN disabled).
*/ */
uaccess_ttbr0_enable x6, x7 uaccess_ttbr0_enable x6, x7, x8
hvc XEN_IMM hvc XEN_IMM
/* /*