Commit 44c5b676 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Peter Zijlstra
Browse files

ARM: uaccess: Implement missing __get_user_asm_dword()



When CONFIG_CPU_SPECTRE=n then get_user() is missing the 8 byte ASM variant
for no real good reason. This prevents using get_user(u64) in generic code.

Implement it as a sequence of two 4-byte reads with LE/BE awareness and
make the unsigned long (or long long) type for the intermediate variable to
read into dependend on the the target type.

The __long_type() macro and idea was lifted from PowerPC. Thanks to
Christophe for pointing it out.

Reported-by: default avatarkernel test robot <lkp@intel.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: default avatarMathieu Desnoyers <mathieu.desnoyers@efficios.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202509120155.pFgwfeUD-lkp@intel.com/
Link: https://patch.msgid.link/20251027083745.168468637@linutronix.de
parent 6146a0f1
Loading
Loading
Loading
Loading
+25 −1
Original line number Diff line number Diff line
@@ -283,10 +283,17 @@ extern int __put_user_8(void *, unsigned long long);
	__gu_err;							\
})

/*
 * This is a type: either unsigned long, if the argument fits into
 * that type, or otherwise unsigned long long.
 */
#define __long_type(x) \
	__typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))

#define __get_user_err(x, ptr, err, __t)				\
do {									\
	unsigned long __gu_addr = (unsigned long)(ptr);			\
	unsigned long __gu_val;						\
	__long_type(x) __gu_val;					\
	unsigned int __ua_flags;					\
	__chk_user_ptr(ptr);						\
	might_fault();							\
@@ -295,6 +302,7 @@ do { \
	case 1:	__get_user_asm_byte(__gu_val, __gu_addr, err, __t); break;	\
	case 2:	__get_user_asm_half(__gu_val, __gu_addr, err, __t); break;	\
	case 4:	__get_user_asm_word(__gu_val, __gu_addr, err, __t); break;	\
	case 8:	__get_user_asm_dword(__gu_val, __gu_addr, err, __t); break;	\
	default: (__gu_val) = __get_user_bad();				\
	}								\
	uaccess_restore(__ua_flags);					\
@@ -353,6 +361,22 @@ do { \
#define __get_user_asm_word(x, addr, err, __t)			\
	__get_user_asm(x, addr, err, "ldr" __t)

#ifdef __ARMEB__
#define __WORD0_OFFS	4
#define __WORD1_OFFS	0
#else
#define __WORD0_OFFS	0
#define __WORD1_OFFS	4
#endif

#define __get_user_asm_dword(x, addr, err, __t)				\
	({								\
	unsigned long __w0, __w1;					\
	__get_user_asm(__w0, addr + __WORD0_OFFS, err, "ldr" __t);	\
	__get_user_asm(__w1, addr + __WORD1_OFFS, err, "ldr" __t);	\
	(x) = ((u64)__w1 << 32) | (u64) __w0;				\
})

#define __put_user_switch(x, ptr, __err, __fn)				\
	do {								\
		const __typeof__(*(ptr)) __user *__pu_ptr = (ptr);	\