diff options
Diffstat (limited to 'arch/arm64/include/asm/uaccess.h')
| -rw-r--r-- | arch/arm64/include/asm/uaccess.h | 111 | 
1 files changed, 101 insertions, 10 deletions
| diff --git a/arch/arm64/include/asm/uaccess.h b/arch/arm64/include/asm/uaccess.h index 55d0adbf6509..46da3ea638bb 100644 --- a/arch/arm64/include/asm/uaccess.h +++ b/arch/arm64/include/asm/uaccess.h @@ -18,6 +18,10 @@  #ifndef __ASM_UACCESS_H  #define __ASM_UACCESS_H +#include <asm/alternative.h> +#include <asm/kernel-pgtable.h> +#include <asm/sysreg.h> +  /*   * User space memory access functions   */ @@ -26,10 +30,8 @@  #include <linux/string.h>  #include <linux/thread_info.h> -#include <asm/alternative.h>  #include <asm/cpufeature.h>  #include <asm/ptrace.h> -#include <asm/sysreg.h>  #include <asm/errno.h>  #include <asm/memory.h>  #include <asm/compiler.h> @@ -120,6 +122,99 @@ static inline void set_fs(mm_segment_t fs)  	"	.popsection\n"  /* + * User access enabling/disabling. + */ +#ifdef CONFIG_ARM64_SW_TTBR0_PAN +static inline void __uaccess_ttbr0_disable(void) +{ +	unsigned long ttbr; + +	/* reserved_ttbr0 placed at the end of swapper_pg_dir */ +	ttbr = read_sysreg(ttbr1_el1) + SWAPPER_DIR_SIZE; +	write_sysreg(ttbr, ttbr0_el1); +	isb(); +} + +static inline void __uaccess_ttbr0_enable(void) +{ +	unsigned long flags; + +	/* +	 * 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); +	isb(); +	local_irq_restore(flags); +} + +static inline bool uaccess_ttbr0_disable(void) +{ +	if (!system_uses_ttbr0_pan()) +		return false; +	__uaccess_ttbr0_disable(); +	return true; +} + +static inline bool uaccess_ttbr0_enable(void) +{ +	if (!system_uses_ttbr0_pan()) +		return false; +	__uaccess_ttbr0_enable(); +	return true; +} +#else +static inline bool uaccess_ttbr0_disable(void) +{ +	return false; +} + +static inline bool uaccess_ttbr0_enable(void) +{ +	return false; +} +#endif + +#define __uaccess_disable(alt)						\ +do {									\ +	if (!uaccess_ttbr0_disable())					\ +		asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), alt,		\ +				CONFIG_ARM64_PAN));			\ +} while (0) + +#define __uaccess_enable(alt)						\ +do {									\ +	if (!uaccess_ttbr0_enable())					\ +		asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), alt,		\ +				CONFIG_ARM64_PAN));			\ +} while (0) + +static inline void uaccess_disable(void) +{ +	__uaccess_disable(ARM64_HAS_PAN); +} + +static inline void uaccess_enable(void) +{ +	__uaccess_enable(ARM64_HAS_PAN); +} + +/* + * These functions are no-ops when UAO is present. + */ +static inline void uaccess_disable_not_uao(void) +{ +	__uaccess_disable(ARM64_ALT_PAN_NOT_UAO); +} + +static inline void uaccess_enable_not_uao(void) +{ +	__uaccess_enable(ARM64_ALT_PAN_NOT_UAO); +} + +/*   * The "__xxx" versions of the user access functions do not verify the address   * space - it must have been done previously with a separate "access_ok()"   * call. @@ -146,8 +241,7 @@ static inline void set_fs(mm_segment_t fs)  do {									\  	unsigned long __gu_val;						\  	__chk_user_ptr(ptr);						\ -	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\ -			CONFIG_ARM64_PAN));				\ +	uaccess_enable_not_uao();					\  	switch (sizeof(*(ptr))) {					\  	case 1:								\  		__get_user_asm("ldrb", "ldtrb", "%w", __gu_val, (ptr),  \ @@ -168,9 +262,8 @@ do {									\  	default:							\  		BUILD_BUG();						\  	}								\ +	uaccess_disable_not_uao();					\  	(x) = (__force __typeof__(*(ptr)))__gu_val;			\ -	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\ -			CONFIG_ARM64_PAN));				\  } while (0)  #define __get_user(x, ptr)						\ @@ -215,8 +308,7 @@ do {									\  do {									\  	__typeof__(*(ptr)) __pu_val = (x);				\  	__chk_user_ptr(ptr);						\ -	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(0), ARM64_ALT_PAN_NOT_UAO,\ -			CONFIG_ARM64_PAN));				\ +	uaccess_enable_not_uao();					\  	switch (sizeof(*(ptr))) {					\  	case 1:								\  		__put_user_asm("strb", "sttrb", "%w", __pu_val, (ptr),	\ @@ -237,8 +329,7 @@ do {									\  	default:							\  		BUILD_BUG();						\  	}								\ -	asm(ALTERNATIVE("nop", SET_PSTATE_PAN(1), ARM64_ALT_PAN_NOT_UAO,\ -			CONFIG_ARM64_PAN));				\ +	uaccess_disable_not_uao();					\  } while (0)  #define __put_user(x, ptr)						\ |