Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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: kernel test robot <lkp@intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Reviewed-by: Mathieu 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

authored by

Thomas Gleixner and committed by
Peter Zijlstra
44c5b676 6146a0f1

+25 -1
+25 -1
arch/arm/include/asm/uaccess.h
··· 283 283 __gu_err; \ 284 284 }) 285 285 286 + /* 287 + * This is a type: either unsigned long, if the argument fits into 288 + * that type, or otherwise unsigned long long. 289 + */ 290 + #define __long_type(x) \ 291 + __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) 292 + 286 293 #define __get_user_err(x, ptr, err, __t) \ 287 294 do { \ 288 295 unsigned long __gu_addr = (unsigned long)(ptr); \ 289 - unsigned long __gu_val; \ 296 + __long_type(x) __gu_val; \ 290 297 unsigned int __ua_flags; \ 291 298 __chk_user_ptr(ptr); \ 292 299 might_fault(); \ ··· 302 295 case 1: __get_user_asm_byte(__gu_val, __gu_addr, err, __t); break; \ 303 296 case 2: __get_user_asm_half(__gu_val, __gu_addr, err, __t); break; \ 304 297 case 4: __get_user_asm_word(__gu_val, __gu_addr, err, __t); break; \ 298 + case 8: __get_user_asm_dword(__gu_val, __gu_addr, err, __t); break; \ 305 299 default: (__gu_val) = __get_user_bad(); \ 306 300 } \ 307 301 uaccess_restore(__ua_flags); \ ··· 360 352 361 353 #define __get_user_asm_word(x, addr, err, __t) \ 362 354 __get_user_asm(x, addr, err, "ldr" __t) 355 + 356 + #ifdef __ARMEB__ 357 + #define __WORD0_OFFS 4 358 + #define __WORD1_OFFS 0 359 + #else 360 + #define __WORD0_OFFS 0 361 + #define __WORD1_OFFS 4 362 + #endif 363 + 364 + #define __get_user_asm_dword(x, addr, err, __t) \ 365 + ({ \ 366 + unsigned long __w0, __w1; \ 367 + __get_user_asm(__w0, addr + __WORD0_OFFS, err, "ldr" __t); \ 368 + __get_user_asm(__w1, addr + __WORD1_OFFS, err, "ldr" __t); \ 369 + (x) = ((u64)__w1 << 32) | (u64) __w0; \ 370 + }) 363 371 364 372 #define __put_user_switch(x, ptr, __err, __fn) \ 365 373 do { \