Commit 1dce5069 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'core-uaccess-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull scoped user access updates from Thomas Gleixner:
 "Scoped user mode access and related changes:

   - Implement the missing u64 user access function on ARM when
     CONFIG_CPU_SPECTRE=n.

     This makes it possible to access a 64bit value in generic code with
     [unsafe_]get_user(). All other architectures and ARM variants
     provide the relevant accessors already.

   - Ensure that ASM GOTO jump label usage in the user mode access
     helpers always goes through a local C scope label indirection
     inside the helpers.

     This is required because compilers are not supporting that a ASM
     GOTO target leaves a auto cleanup scope. GCC silently fails to emit
     the cleanup invocation and CLANG fails the build.

     [ Editor's note: gcc-16 will have fixed the code generation issue
       in commit f68fe3ddda4 ("eh: Invoke cleanups/destructors in asm
       goto jumps [PR122835]"). But we obviously have to deal with clang
       and older versions of gcc, so.. - Linus ]

     This provides generic wrapper macros and the conversion of affected
     architecture code to use them.

   - Scoped user mode access with auto cleanup

     Access to user mode memory can be required in hot code paths, but
     if it has to be done with user controlled pointers, the access is
     shielded with a speculation barrier, so that the CPU cannot
     speculate around the address range check. Those speculation
     barriers impact performance quite significantly.

     This cost can be avoided by "masking" the provided pointer so it is
     guaranteed to be in the valid user memory access range and
     otherwise to point to a guaranteed unpopulated address space. This
     has to be done without branches so it creates an address dependency
     for the access, which the CPU cannot speculate ahead.

     This results in repeating and error prone programming patterns:

       	    if (can_do_masked_user_access())
                      from = masked_user_read_access_begin((from));
              else if (!user_read_access_begin(from, sizeof(*from)))
                      return -EFAULT;
              unsafe_get_user(val, from, Efault);
              user_read_access_end();
              return 0;
        Efault:
              user_read_access_end();
              return -EFAULT;

      which can be replaced with scopes and automatic cleanup:

              scoped_user_read_access(from, Efault)
                      unsafe_get_user(val, from, Efault);
              return 0;
         Efault:
              return -EFAULT;

   - Convert code which implements the above pattern over to
     scope_user.*.access(). This also corrects a couple of imbalanced
     masked_*_begin() instances which are harmless on most
     architectures, but prevent PowerPC from implementing the masking
     optimization.

   - Add a missing speculation barrier in copy_from_user_iter()"

* tag 'core-uaccess-2025-11-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  lib/strn*,uaccess: Use masked_user_{read/write}_access_begin when required
  scm: Convert put_cmsg() to scoped user access
  iov_iter: Add missing speculation barrier to copy_from_user_iter()
  iov_iter: Convert copy_from_user_iter() to masked user access
  select: Convert to scoped user access
  x86/futex: Convert to scoped user access
  futex: Convert to get/put_user_inline()
  uaccess: Provide put/get_user_inline()
  uaccess: Provide scoped user access regions
  arm64: uaccess: Use unsafe wrappers for ASM GOTO
  s390/uaccess: Use unsafe wrappers for ASM GOTO
  riscv/uaccess: Use unsafe wrappers for ASM GOTO
  powerpc/uaccess: Use unsafe wrappers for ASM GOTO
  x86/uaccess: Use unsafe wrappers for ASM GOTO
  uaccess: Provide ASM GOTO safe wrappers for unsafe_*_user()
  ARM: uaccess: Implement missing __get_user_asm_dword()
parents 4a26e703 4322c8f8
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);	\
+2 −2
Original line number Diff line number Diff line
@@ -422,9 +422,9 @@ static __must_check __always_inline bool user_access_begin(const void __user *pt
}
#define user_access_begin(a,b)	user_access_begin(a,b)
#define user_access_end()	uaccess_ttbr0_disable()
#define unsafe_put_user(x, ptr, label) \
#define arch_unsafe_put_user(x, ptr, label) \
	__raw_put_mem("sttr", x, uaccess_mask_ptr(ptr), label, U)
#define unsafe_get_user(x, ptr, label) \
#define arch_unsafe_get_user(x, ptr, label) \
	__raw_get_mem("ldtr", x, uaccess_mask_ptr(ptr), label, U)

/*
+4 −4
Original line number Diff line number Diff line
@@ -451,7 +451,7 @@ user_write_access_begin(const void __user *ptr, size_t len)
#define user_write_access_begin	user_write_access_begin
#define user_write_access_end		prevent_current_write_to_user

#define unsafe_get_user(x, p, e) do {					\
#define arch_unsafe_get_user(x, p, e) do {			\
	__long_type(*(p)) __gu_val;				\
	__typeof__(*(p)) __user *__gu_addr = (p);		\
								\
@@ -459,7 +459,7 @@ user_write_access_begin(const void __user *ptr, size_t len)
	(x) = (__typeof__(*(p)))__gu_val;			\
} while (0)

#define unsafe_put_user(x, p, e) \
#define arch_unsafe_put_user(x, p, e)				\
	__put_user_size_goto((__typeof__(*(p)))(x), (p), sizeof(*(p)), e)

#define unsafe_copy_from_user(d, s, l, e) \
@@ -504,11 +504,11 @@ do { \
		unsafe_put_user(*(u8*)(_src + _i), (u8 __user *)(_dst + _i), e); \
} while (0)

#define __get_kernel_nofault(dst, src, type, err_label)			\
#define arch_get_kernel_nofault(dst, src, type, err_label)		\
	__get_user_size_goto(*((type *)(dst)),				\
		(__force type __user *)(src), sizeof(type), err_label)

#define __put_kernel_nofault(dst, src, type, err_label)			\
#define arch_put_kernel_nofault(dst, src, type, err_label)		\
	__put_user_size_goto(*((type *)(src)),				\
		(__force type __user *)(dst), sizeof(type), err_label)

+4 −4
Original line number Diff line number Diff line
@@ -437,10 +437,10 @@ unsigned long __must_check clear_user(void __user *to, unsigned long n)
		__clear_user(untagged_addr(to), n) : n;
}

#define __get_kernel_nofault(dst, src, type, err_label)			\
#define arch_get_kernel_nofault(dst, src, type, err_label)			\
	__get_user_nocheck(*((type *)(dst)), (__force __user type *)(src), err_label)

#define __put_kernel_nofault(dst, src, type, err_label)			\
#define arch_put_kernel_nofault(dst, src, type, err_label)			\
	__put_user_nocheck(*((type *)(src)), (__force __user type *)(dst), err_label)

static __must_check __always_inline bool user_access_begin(const void __user *ptr, size_t len)
@@ -460,10 +460,10 @@ static inline void user_access_restore(unsigned long enabled) { }
 * We want the unsafe accessors to always be inlined and use
 * the error labels - thus the macro games.
 */
#define unsafe_put_user(x, ptr, label)					\
#define arch_unsafe_put_user(x, ptr, label)				\
	__put_user_nocheck(x, (ptr), label)

#define unsafe_get_user(x, ptr, label)	do {				\
#define arch_unsafe_get_user(x, ptr, label)	do {			\
	__inttype(*(ptr)) __gu_val;					\
	__get_user_nocheck(__gu_val, (ptr), label);			\
	(x) = (__force __typeof__(*(ptr)))__gu_val;			\
+2 −2
Original line number Diff line number Diff line
@@ -468,8 +468,8 @@ do { \

#endif /* CONFIG_CC_HAS_ASM_GOTO_OUTPUT && CONFIG_CC_HAS_ASM_AOR_FORMAT_FLAGS */

#define __get_kernel_nofault __mvc_kernel_nofault
#define __put_kernel_nofault __mvc_kernel_nofault
#define arch_get_kernel_nofault __mvc_kernel_nofault
#define arch_put_kernel_nofault __mvc_kernel_nofault

void __cmpxchg_user_key_called_with_bad_pointer(void);

Loading