When handling a data abort from EL0, we currently zero the top byte of the faulting address, as we assume the address is a TTBR0 address, which may contain a non-zero address tag. However, the address may be a TTBR1 address, in which case we should not zero the top byte. This patch fixes that. The effect is that the full TTBR1 address is passed to the task's signal handler (or printed out in the kernel log). When handling a data abort from EL1, we leave the faulting address intact, as we assume it's either a TTBR1 address or a TTBR0 address with tag 0x00. This is true as far as I'm aware, we don't seem to access a tagged TTBR0 address anywhere in the kernel. Regardless, it's easy to forget about address tags, and code added in the future may not always remember to remove tags from addresses before accessing them. So add tag handling to the EL1 data abort handler as well. This also makes it consistent with the EL0 data abort handler. Fixes: d50240a5f6ce ("arm64: mm: permit use of tagged pointers at EL0") Cc: <stable@vger.kernel.org> # 3.12.x- Reviewed-by: Dave Martin <Dave.Martin@arm.com> Acked-by: Will Deacon <will.deacon@arm.com> Signed-off-by: Kristina Martsenko <kristina.martsenko@arm.com> Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
75 lines
1.7 KiB
C
75 lines
1.7 KiB
C
#ifndef __ASM_ASM_UACCESS_H
|
|
#define __ASM_ASM_UACCESS_H
|
|
|
|
#include <asm/alternative.h>
|
|
#include <asm/kernel-pgtable.h>
|
|
#include <asm/sysreg.h>
|
|
#include <asm/assembler.h>
|
|
|
|
/*
|
|
* User access enabling/disabling macros.
|
|
*/
|
|
#ifdef CONFIG_ARM64_SW_TTBR0_PAN
|
|
.macro __uaccess_ttbr0_disable, tmp1
|
|
mrs \tmp1, ttbr1_el1 // 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
|
|
isb
|
|
.endm
|
|
|
|
.macro __uaccess_ttbr0_enable, tmp1
|
|
get_thread_info \tmp1
|
|
ldr \tmp1, [\tmp1, #TSK_TI_TTBR0] // load saved TTBR0_EL1
|
|
msr ttbr0_el1, \tmp1 // set the non-PAN TTBR0_EL1
|
|
isb
|
|
.endm
|
|
|
|
.macro uaccess_ttbr0_disable, tmp1
|
|
alternative_if_not ARM64_HAS_PAN
|
|
__uaccess_ttbr0_disable \tmp1
|
|
alternative_else_nop_endif
|
|
.endm
|
|
|
|
.macro uaccess_ttbr0_enable, tmp1, tmp2
|
|
alternative_if_not ARM64_HAS_PAN
|
|
save_and_disable_irq \tmp2 // avoid preemption
|
|
__uaccess_ttbr0_enable \tmp1
|
|
restore_irq \tmp2
|
|
alternative_else_nop_endif
|
|
.endm
|
|
#else
|
|
.macro uaccess_ttbr0_disable, tmp1
|
|
.endm
|
|
|
|
.macro uaccess_ttbr0_enable, tmp1, tmp2
|
|
.endm
|
|
#endif
|
|
|
|
/*
|
|
* These macros are no-ops when UAO is present.
|
|
*/
|
|
.macro uaccess_disable_not_uao, tmp1
|
|
uaccess_ttbr0_disable \tmp1
|
|
alternative_if ARM64_ALT_PAN_NOT_UAO
|
|
SET_PSTATE_PAN(1)
|
|
alternative_else_nop_endif
|
|
.endm
|
|
|
|
.macro uaccess_enable_not_uao, tmp1, tmp2
|
|
uaccess_ttbr0_enable \tmp1, \tmp2
|
|
alternative_if ARM64_ALT_PAN_NOT_UAO
|
|
SET_PSTATE_PAN(0)
|
|
alternative_else_nop_endif
|
|
.endm
|
|
|
|
/*
|
|
* Remove the address tag from a virtual address, if present.
|
|
*/
|
|
.macro clear_address_tag, dst, addr
|
|
tst \addr, #(1 << 55)
|
|
bic \dst, \addr, #(0xff << 56)
|
|
csel \dst, \dst, \addr, eq
|
|
.endm
|
|
|
|
#endif
|