[patch V2 1/6] ARM: uaccess: Implement missing __get_user_asm_dword()

Christophe Leroy christophe.leroy at csgroup.eu
Wed Sep 17 05:35:31 PDT 2025



Le 17/09/2025 à 11:41, Russell King (Oracle) a écrit :
> You may think this is easy to solve, just change the last cast to:
> 
>          (x) = (__typeof__(*(ptr)))(__typeof__(x))__gu_val;
> 
> but that doesn't work either (because in the test case __typeof__(x) is
> still a pointer type. You can't cast this down to a 32-bit quantity
> because that will knock off the upper 32 bits for the case you're trying
> to add.
> 
> You may think, why not  move this cast into each switch statement...
> there will still be warnings because the cast is still reachable at the
> point the compiler evaluates the code for warnings, even though the
> optimiser gets rid of it later.
> 
> Feel free to try to solve this, but I can assure you that you certainly
> are not the first. Several people have already tried.
> 

No such problem on powerpc/32, maybe because we have defined and use 
macro __long_type(x), see below:

#define __get_user_size_allowed(x, ptr, size, retval)		\
do {								\
	retval = 0;						\
	BUILD_BUG_ON(size > sizeof(x));				\
	switch (size) {						\
	case 1: __get_user_asm(x, (u8 __user *)ptr, retval, "lbz"); break;	\
	case 2: __get_user_asm(x, (u16 __user *)ptr, retval, "lhz"); break;	\
	case 4: __get_user_asm(x, (u32 __user *)ptr, retval, "lwz"); break;	\
	case 8: __get_user_asm2(x, (u64 __user *)ptr, retval);  break;	\
	default: x = 0; BUILD_BUG();				\
	}							\
} while (0)

/*
  * 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(x, ptr)					\
({								\
	long __gu_err;						\
	__long_type(*(ptr)) __gu_val;				\
	__typeof__(*(ptr)) __user *__gu_addr = (ptr);	\
	__typeof__(sizeof(*(ptr))) __gu_size = sizeof(*(ptr));	\
								\
	might_fault();					\
	allow_read_from_user(__gu_addr, __gu_size);		\
	__get_user_size_allowed(__gu_val, __gu_addr, __gu_size, __gu_err);	\
	prevent_read_from_user(__gu_addr, __gu_size);		\
	(x) = (__typeof__(*(ptr)))__gu_val;			\
								\
	__gu_err;						\
})





More information about the linux-arm-kernel mailing list