Skip to content

Commit

Permalink
arm64: mm: Fix and re-enable ARM64_SW_TTBR0_PAN
Browse files Browse the repository at this point in the history
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 <[email protected]>
Tested-by: Laura Abbott <[email protected]>
Tested-by: Shanker Donthineni <[email protected]>
Signed-off-by: Will Deacon <[email protected]>
  • Loading branch information
wildea01 committed Dec 11, 2017
1 parent 158d495 commit 27a921e
Show file tree
Hide file tree
Showing 10 changed files with 42 additions and 21 deletions.
1 change: 0 additions & 1 deletion arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -910,7 +910,6 @@ endif

config ARM64_SW_TTBR0_PAN
bool "Emulate Privileged Access Never using TTBR0_EL1 switching"
depends on BROKEN # Temporary while switch_mm is reworked
help
Enabling this option prevents the kernel from accessing
user-space memory directly by pointing TTBR0_EL1 to a reserved
Expand Down
25 changes: 17 additions & 8 deletions arch/arm64/include/asm/asm-uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,20 @@
add \tmp1, \tmp1, #SWAPPER_DIR_SIZE // reserved_ttbr0 at the end of swapper_pg_dir
msr ttbr0_el1, \tmp1 // set reserved TTBR0_EL1
isb
sub \tmp1, \tmp1, #SWAPPER_DIR_SIZE
bic \tmp1, \tmp1, #(0xffff << 48)
msr ttbr1_el1, \tmp1 // set reserved ASID
isb
.endm

.macro __uaccess_ttbr0_enable, tmp1
.macro __uaccess_ttbr0_enable, tmp1, tmp2
get_thread_info \tmp1
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
isb
.endm
Expand All @@ -31,18 +40,18 @@ alternative_if_not ARM64_HAS_PAN
alternative_else_nop_endif
.endm

.macro uaccess_ttbr0_enable, tmp1, tmp2
.macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3
alternative_if_not ARM64_HAS_PAN
save_and_disable_irq \tmp2 // avoid preemption
__uaccess_ttbr0_enable \tmp1
restore_irq \tmp2
save_and_disable_irq \tmp3 // avoid preemption
__uaccess_ttbr0_enable \tmp1, \tmp2
restore_irq \tmp3
alternative_else_nop_endif
.endm
#else
.macro uaccess_ttbr0_disable, tmp1
.endm

.macro uaccess_ttbr0_enable, tmp1, tmp2
.macro uaccess_ttbr0_enable, tmp1, tmp2, tmp3
.endm
#endif

Expand All @@ -56,8 +65,8 @@ alternative_if ARM64_ALT_PAN_NOT_UAO
alternative_else_nop_endif
.endm

.macro uaccess_enable_not_uao, tmp1, tmp2
uaccess_ttbr0_enable \tmp1, \tmp2
.macro uaccess_enable_not_uao, tmp1, tmp2, tmp3
uaccess_ttbr0_enable \tmp1, \tmp2, \tmp3
alternative_if ARM64_ALT_PAN_NOT_UAO
SET_PSTATE_PAN(0)
alternative_else_nop_endif
Expand Down
21 changes: 17 additions & 4 deletions arch/arm64/include/asm/uaccess.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,23 +107,36 @@ static inline void __uaccess_ttbr0_disable(void)
{
unsigned long ttbr;

ttbr = read_sysreg(ttbr1_el1);
/* reserved_ttbr0 placed at the end of swapper_pg_dir */
ttbr = read_sysreg(ttbr1_el1) + SWAPPER_DIR_SIZE;
write_sysreg(ttbr, ttbr0_el1);
write_sysreg(ttbr + SWAPPER_DIR_SIZE, ttbr0_el1);
isb();
/* Set reserved ASID */
ttbr &= ~(0xffffUL << 48);
write_sysreg(ttbr, ttbr1_el1);
isb();
}

static inline void __uaccess_ttbr0_enable(void)
{
unsigned long flags;
unsigned long flags, ttbr0, ttbr1;

/*
* Disable interrupts to avoid preemption between reading the 'ttbr0'
* variable and the MSR. A context switch could trigger an ASID
* roll-over and an update of 'ttbr0'.
*/
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();
local_irq_restore(flags);
}
Expand Down
4 changes: 2 additions & 2 deletions arch/arm64/kernel/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ alternative_if ARM64_HAS_PAN
alternative_else_nop_endif

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

__uaccess_ttbr0_enable x0
__uaccess_ttbr0_enable x0, x1

.if \el == 0
/*
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/lib/clear_user.S
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* Alignment fixed up by hardware.
*/
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
subs x1, x1, #8
b.mi 2f
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/lib/copy_from_user.S
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@

end .req x5
ENTRY(__arch_copy_from_user)
uaccess_enable_not_uao x3, x4
uaccess_enable_not_uao x3, x4, x5
add end, x0, x2
#include "copy_template.S"
uaccess_disable_not_uao x3
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/lib/copy_in_user.S
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@

end .req x5
ENTRY(raw_copy_in_user)
uaccess_enable_not_uao x3, x4
uaccess_enable_not_uao x3, x4, x5
add end, x0, x2
#include "copy_template.S"
uaccess_disable_not_uao x3
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/lib/copy_to_user.S
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@

end .req x5
ENTRY(__arch_copy_to_user)
uaccess_enable_not_uao x3, x4
uaccess_enable_not_uao x3, x4, x5
add end, x0, x2
#include "copy_template.S"
uaccess_disable_not_uao x3
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/mm/cache.S
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ENTRY(flush_icache_range)
* - end - virtual end address of region
*/
ENTRY(__flush_cache_user_range)
uaccess_ttbr0_enable x2, x3
uaccess_ttbr0_enable x2, x3, x4
dcache_line_size x2, x3
sub x3, x2, #1
bic x4, x0, x3
Expand Down
2 changes: 1 addition & 1 deletion arch/arm64/xen/hypercall.S
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ ENTRY(privcmd_call)
* need the explicit uaccess_enable/disable if the TTBR0 PAN emulation
* is enabled (it implies that hardware UAO and PAN disabled).
*/
uaccess_ttbr0_enable x6, x7
uaccess_ttbr0_enable x6, x7, x8
hvc XEN_IMM

/*
Expand Down

0 comments on commit 27a921e

Please sign in to comment.