arm64: kernel: Add support for User Access Override
'User Access Override' is a new ARMv8.2 feature which allows the unprivileged load and store instructions to be overridden to behave in the normal way. This patch converts {get,put}_user() and friends to use ldtr*/sttr* instructions - so that they can only access EL0 memory, then enables UAO when fs==KERNEL_DS so that these functions can access kernel memory. This allows user space's read/write permissions to be checked against the page tables, instead of testing addr<USER_DS, then using the kernel's read/write permissions. Signed-off-by: James Morse <james.morse@arm.com> [catalin.marinas@arm.com: move uao_thread_switch() above dsb()] Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
This commit is contained in:

committed by
Catalin Marinas

parent
406e308770
commit
57f4959bad
@@ -192,6 +192,14 @@ out:
|
||||
return fault;
|
||||
}
|
||||
|
||||
static inline int permission_fault(unsigned int esr)
|
||||
{
|
||||
unsigned int ec = (esr & ESR_ELx_EC_MASK) >> ESR_ELx_EC_SHIFT;
|
||||
unsigned int fsc_type = esr & ESR_ELx_FSC_TYPE;
|
||||
|
||||
return (ec == ESR_ELx_EC_DABT_CUR && fsc_type == ESR_ELx_FSC_PERM);
|
||||
}
|
||||
|
||||
static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
|
||||
struct pt_regs *regs)
|
||||
{
|
||||
@@ -225,12 +233,10 @@ static int __kprobes do_page_fault(unsigned long addr, unsigned int esr,
|
||||
mm_flags |= FAULT_FLAG_WRITE;
|
||||
}
|
||||
|
||||
/*
|
||||
* PAN bit set implies the fault happened in kernel space, but not
|
||||
* in the arch's user access functions.
|
||||
*/
|
||||
if (IS_ENABLED(CONFIG_ARM64_PAN) && (regs->pstate & PSR_PAN_BIT))
|
||||
goto no_context;
|
||||
if (permission_fault(esr) && (addr < USER_DS)) {
|
||||
if (!search_exception_tables(regs->pc))
|
||||
panic("Accessing user space memory outside uaccess.h routines");
|
||||
}
|
||||
|
||||
/*
|
||||
* As per x86, we may deadlock here. However, since the kernel only
|
||||
@@ -561,3 +567,16 @@ void cpu_enable_pan(void *__unused)
|
||||
config_sctlr_el1(SCTLR_EL1_SPAN, 0);
|
||||
}
|
||||
#endif /* CONFIG_ARM64_PAN */
|
||||
|
||||
#ifdef CONFIG_ARM64_UAO
|
||||
/*
|
||||
* Kernel threads have fs=KERNEL_DS by default, and don't need to call
|
||||
* set_fs(), devtmpfs in particular relies on this behaviour.
|
||||
* We need to enable the feature at runtime (instead of adding it to
|
||||
* PSR_MODE_EL1h) as the feature may not be implemented by the cpu.
|
||||
*/
|
||||
void cpu_enable_uao(void *__unused)
|
||||
{
|
||||
asm(SET_PSTATE_UAO(1));
|
||||
}
|
||||
#endif /* CONFIG_ARM64_UAO */
|
||||
|
Reference in New Issue
Block a user