Re: [RFC PATCH v1 7/9] x86: Add unsafe_copy_from_user()

Christophe Leroy (CS GROUP)
2026-04-27T18:20:53Z

Le 27/04/2026 à 19:58, Yury Norov a écrit :
> On Mon, Apr 27, 2026 at 07:13:48PM +0200, Christophe Leroy (CS GROUP) wrote:
>> At the time being, x86 and arm64 are missing unsafe_copy_from_user().
>
> No, they don't. They (should) rely on a generic implementation from
> linux/uaccess.h, like every other arch, except for PPC and RISCV.
>
> But they #define arch_unsafe_get_user, and the unsafe_copy_from_user()
> becomes undefined conditionally on that.
>
> So please, fix that bug instead of introducing another arch flavor.
> We'd always choose generic version, unless there's strong evidence
> that arch one is better.

But they both implement the exact same unsafe_copy_to_user(). What is
the difference here ?

Should that function become generic too ?

Christophe

>
>
> Thanks,
> Yury
>
>> Add it.
>>
>> Signed-off-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
>> ---
>> arch/x86/include/asm/uaccess.h | 29 ++++++++++++++++++++++++-----
>> 1 file changed, 24 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
>> index 3a0dd3c2b233..10c458ffa399 100644
>> --- a/arch/x86/include/asm/uaccess.h
>> +++ b/arch/x86/include/asm/uaccess.h
>> @@ -598,7 +598,7 @@ _label: \
>> * We want the unsafe accessors to always be inlined and use
>> * the error labels - thus the macro games.
>> */
>> -#define unsafe_copy_loop(dst, src, len, type, label) \
>> +#define unsafe_put_loop(dst, src, len, type, label) \
>> while (len >= sizeof(type)) { \
>> unsafe_put_user(*(type *)(src),(type __user *)(dst),label); \
>> dst += sizeof(type); \
>> @@ -611,10 +611,29 @@ do { \
>> char __user *__ucu_dst = (_dst); \
>> const char *__ucu_src = (_src); \
>> size_t __ucu_len = (_len); \
>> - unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u64, label); \
>> - unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u32, label); \
>> - unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u16, label); \
>> - unsafe_copy_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label); \
>> + unsafe_put_loop(__ucu_dst, __ucu_src, __ucu_len, u64, label); \
>> + unsafe_put_loop(__ucu_dst, __ucu_src, __ucu_len, u32, label); \
>> + unsafe_put_loop(__ucu_dst, __ucu_src, __ucu_len, u16, label); \
>> + unsafe_put_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label); \
>> +} while (0)
>> +
>> +#define unsafe_get_loop(dst, src, len, type, label) \
>> + while (len >= sizeof(type)) { \
>> + unsafe_get_user(*(type __user *)(src),(type *)(dst),label); \
>> + dst += sizeof(type); \
>> + src += sizeof(type); \
>> + len -= sizeof(type); \
>> + }
>> +
>> +#define unsafe_copy_from_user(_dst,_src,_len,label) \
>> +do { \
>> + char *__ucu_dst = (_dst); \
>> + const char __user *__ucu_src = (_src); \
>> + size_t __ucu_len = (_len); \
>> + unsafe_get_loop(__ucu_dst, __ucu_src, __ucu_len, u64, label); \
>> + unsafe_get_loop(__ucu_dst, __ucu_src, __ucu_len, u32, label); \
>> + unsafe_get_loop(__ucu_dst, __ucu_src, __ucu_len, u16, label); \
>> + unsafe_get_loop(__ucu_dst, __ucu_src, __ucu_len, u8, label); \
>> } while (0)
>>
>> #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
>> --
>> 2.49.0
>>