]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
x86/uaccess: Use unsafe wrappers for ASM GOTO
authorThomas Gleixner <tglx@linutronix.de>
Mon, 27 Oct 2025 08:43:46 +0000 (09:43 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Mon, 3 Nov 2025 14:26:09 +0000 (15:26 +0100)
ASM GOTO is miscompiled by GCC when it is used inside a auto cleanup scope:

bool foo(u32 __user *p, u32 val)
{
scoped_guard(pagefault)
unsafe_put_user(val, p, efault);
return true;
efault:
return false;
}

It ends up leaking the pagefault disable counter in the fault path. clang
at least fails the build.

Rename unsafe_*_user() to arch_unsafe_*_user() which makes the generic
uaccess header wrap it with a local label that makes both compilers emit
correct code. Same for the kernel_nofault() variants.

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>
Link: https://patch.msgid.link/20251027083745.294359925@linutronix.de
arch/x86/include/asm/uaccess.h

index 91a3fb8ae7ff4683bdcf13ae8d7f15d5342162c2..367297b188c39cfc0ae6d52a06a5c5e6f170a09b 100644 (file)
@@ -528,18 +528,18 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt
 #define user_access_save()     smap_save()
 #define user_access_restore(x) smap_restore(x)
 
-#define unsafe_put_user(x, ptr, label) \
+#define arch_unsafe_put_user(x, ptr, label)    \
        __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label)
 
 #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
-#define unsafe_get_user(x, ptr, err_label)                                     \
+#define arch_unsafe_get_user(x, ptr, err_label)                                        \
 do {                                                                           \
        __inttype(*(ptr)) __gu_val;                                             \
        __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), err_label);            \
        (x) = (__force __typeof__(*(ptr)))__gu_val;                             \
 } while (0)
 #else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
-#define unsafe_get_user(x, ptr, err_label)                                     \
+#define arch_unsafe_get_user(x, ptr, err_label)                                        \
 do {                                                                           \
        int __gu_err;                                                           \
        __inttype(*(ptr)) __gu_val;                                             \
@@ -618,11 +618,11 @@ do {                                                                      \
 } while (0)
 
 #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT
-#define __get_kernel_nofault(dst, src, type, err_label)                        \
+#define arch_get_kernel_nofault(dst, src, type, err_label)             \
        __get_user_size(*((type *)(dst)), (__force type __user *)(src), \
                        sizeof(type), err_label)
 #else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT
-#define __get_kernel_nofault(dst, src, type, err_label)                        \
+#define arch_get_kernel_nofault(dst, src, type, err_label)                     \
 do {                                                                   \
        int __kr_err;                                                   \
                                                                        \
@@ -633,7 +633,7 @@ do {                                                                        \
 } while (0)
 #endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT
 
-#define __put_kernel_nofault(dst, src, type, err_label)                        \
+#define arch_put_kernel_nofault(dst, src, type, err_label)             \
        __put_user_size(*((type *)(src)), (__force type __user *)(dst), \
                        sizeof(type), err_label)