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
@@ -1,6 +1,8 @@
|
||||
#ifndef __ASM_ALTERNATIVE_H
|
||||
#define __ASM_ALTERNATIVE_H
|
||||
|
||||
#include <asm/cpufeature.h>
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
#include <linux/init.h>
|
||||
@@ -63,6 +65,8 @@ void apply_alternatives(void *start, size_t length);
|
||||
|
||||
#else
|
||||
|
||||
#include <asm/assembler.h>
|
||||
|
||||
.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
|
||||
.word \orig_offset - .
|
||||
.word \alt_offset - .
|
||||
@@ -136,6 +140,74 @@ void apply_alternatives(void *start, size_t length);
|
||||
alternative_insn insn1, insn2, cap, IS_ENABLED(cfg)
|
||||
|
||||
|
||||
/*
|
||||
* Generate the assembly for UAO alternatives with exception table entries.
|
||||
* This is complicated as there is no post-increment or pair versions of the
|
||||
* unprivileged instructions, and USER() only works for single instructions.
|
||||
*/
|
||||
#ifdef CONFIG_ARM64_UAO
|
||||
.macro uao_ldp l, reg1, reg2, addr, post_inc
|
||||
alternative_if_not ARM64_HAS_UAO
|
||||
8888: ldp \reg1, \reg2, [\addr], \post_inc;
|
||||
8889: nop;
|
||||
nop;
|
||||
alternative_else
|
||||
ldtr \reg1, [\addr];
|
||||
ldtr \reg2, [\addr, #8];
|
||||
add \addr, \addr, \post_inc;
|
||||
alternative_endif
|
||||
|
||||
.section __ex_table,"a";
|
||||
.align 3;
|
||||
.quad 8888b,\l;
|
||||
.quad 8889b,\l;
|
||||
.previous;
|
||||
.endm
|
||||
|
||||
.macro uao_stp l, reg1, reg2, addr, post_inc
|
||||
alternative_if_not ARM64_HAS_UAO
|
||||
8888: stp \reg1, \reg2, [\addr], \post_inc;
|
||||
8889: nop;
|
||||
nop;
|
||||
alternative_else
|
||||
sttr \reg1, [\addr];
|
||||
sttr \reg2, [\addr, #8];
|
||||
add \addr, \addr, \post_inc;
|
||||
alternative_endif
|
||||
|
||||
.section __ex_table,"a";
|
||||
.align 3;
|
||||
.quad 8888b,\l;
|
||||
.quad 8889b,\l;
|
||||
.previous
|
||||
.endm
|
||||
|
||||
.macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
|
||||
alternative_if_not ARM64_HAS_UAO
|
||||
8888: \inst \reg, [\addr], \post_inc;
|
||||
nop;
|
||||
alternative_else
|
||||
\alt_inst \reg, [\addr];
|
||||
add \addr, \addr, \post_inc;
|
||||
alternative_endif
|
||||
|
||||
.section __ex_table,"a";
|
||||
.align 3;
|
||||
.quad 8888b,\l;
|
||||
.previous
|
||||
.endm
|
||||
#else
|
||||
.macro uao_ldp l, reg1, reg2, addr, post_inc
|
||||
USER(\l, ldp \reg1, \reg2, [\addr], \post_inc)
|
||||
.endm
|
||||
.macro uao_stp l, reg1, reg2, addr, post_inc
|
||||
USER(\l, stp \reg1, \reg2, [\addr], \post_inc)
|
||||
.endm
|
||||
.macro uao_user_alternative l, inst, alt_inst, reg, addr, post_inc
|
||||
USER(\l, \inst \reg, [\addr], \post_inc)
|
||||
.endm
|
||||
#endif
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user