162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * arch/arm/include/asm/uaccess.h 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#ifndef _ASMARM_UACCESS_H 662306a36Sopenharmony_ci#define _ASMARM_UACCESS_H 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * User space memory access functions 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci#include <asm/page.h> 1362306a36Sopenharmony_ci#include <asm/domain.h> 1462306a36Sopenharmony_ci#include <asm/unaligned.h> 1562306a36Sopenharmony_ci#include <asm/unified.h> 1662306a36Sopenharmony_ci#include <asm/compiler.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <asm/extable.h> 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* 2162306a36Sopenharmony_ci * These two functions allow hooking accesses to userspace to increase 2262306a36Sopenharmony_ci * system integrity by ensuring that the kernel can not inadvertantly 2362306a36Sopenharmony_ci * perform such accesses (eg, via list poison values) which could then 2462306a36Sopenharmony_ci * be exploited for priviledge escalation. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_cistatic __always_inline unsigned int uaccess_save_and_enable(void) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN 2962306a36Sopenharmony_ci unsigned int old_domain = get_domain(); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci /* Set the current domain access to permit user accesses */ 3262306a36Sopenharmony_ci set_domain((old_domain & ~domain_mask(DOMAIN_USER)) | 3362306a36Sopenharmony_ci domain_val(DOMAIN_USER, DOMAIN_CLIENT)); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci return old_domain; 3662306a36Sopenharmony_ci#else 3762306a36Sopenharmony_ci return 0; 3862306a36Sopenharmony_ci#endif 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic __always_inline void uaccess_restore(unsigned int flags) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN 4462306a36Sopenharmony_ci /* Restore the user access mask */ 4562306a36Sopenharmony_ci set_domain(flags); 4662306a36Sopenharmony_ci#endif 4762306a36Sopenharmony_ci} 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci/* 5062306a36Sopenharmony_ci * These two are intentionally not defined anywhere - if the kernel 5162306a36Sopenharmony_ci * code generates any references to them, that's a bug. 5262306a36Sopenharmony_ci */ 5362306a36Sopenharmony_ciextern int __get_user_bad(void); 5462306a36Sopenharmony_ciextern int __put_user_bad(void); 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci#ifdef CONFIG_MMU 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/* 5962306a36Sopenharmony_ci * This is a type: either unsigned long, if the argument fits into 6062306a36Sopenharmony_ci * that type, or otherwise unsigned long long. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci#define __inttype(x) \ 6362306a36Sopenharmony_ci __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci/* 6662306a36Sopenharmony_ci * Sanitise a uaccess pointer such that it becomes NULL if addr+size 6762306a36Sopenharmony_ci * is above the current addr_limit. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci#define uaccess_mask_range_ptr(ptr, size) \ 7062306a36Sopenharmony_ci ((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size)) 7162306a36Sopenharmony_cistatic inline void __user *__uaccess_mask_range_ptr(const void __user *ptr, 7262306a36Sopenharmony_ci size_t size) 7362306a36Sopenharmony_ci{ 7462306a36Sopenharmony_ci void __user *safe_ptr = (void __user *)ptr; 7562306a36Sopenharmony_ci unsigned long tmp; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci asm volatile( 7862306a36Sopenharmony_ci " .syntax unified\n" 7962306a36Sopenharmony_ci " sub %1, %3, #1\n" 8062306a36Sopenharmony_ci " subs %1, %1, %0\n" 8162306a36Sopenharmony_ci " addhs %1, %1, #1\n" 8262306a36Sopenharmony_ci " subshs %1, %1, %2\n" 8362306a36Sopenharmony_ci " movlo %0, #0\n" 8462306a36Sopenharmony_ci : "+r" (safe_ptr), "=&r" (tmp) 8562306a36Sopenharmony_ci : "r" (size), "r" (TASK_SIZE) 8662306a36Sopenharmony_ci : "cc"); 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci csdb(); 8962306a36Sopenharmony_ci return safe_ptr; 9062306a36Sopenharmony_ci} 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci/* 9362306a36Sopenharmony_ci * Single-value transfer routines. They automatically use the right 9462306a36Sopenharmony_ci * size if we just have the right pointer type. Note that the functions 9562306a36Sopenharmony_ci * which read from user space (*get_*) need to take care not to leak 9662306a36Sopenharmony_ci * kernel data even if the calling code is buggy and fails to check 9762306a36Sopenharmony_ci * the return value. This means zeroing out the destination variable 9862306a36Sopenharmony_ci * or buffer on error. Normally this is done out of line by the 9962306a36Sopenharmony_ci * fixup code, but there are a few places where it intrudes on the 10062306a36Sopenharmony_ci * main code path. When we only write to user space, there is no 10162306a36Sopenharmony_ci * problem. 10262306a36Sopenharmony_ci */ 10362306a36Sopenharmony_ciextern int __get_user_1(void *); 10462306a36Sopenharmony_ciextern int __get_user_2(void *); 10562306a36Sopenharmony_ciextern int __get_user_4(void *); 10662306a36Sopenharmony_ciextern int __get_user_32t_8(void *); 10762306a36Sopenharmony_ciextern int __get_user_8(void *); 10862306a36Sopenharmony_ciextern int __get_user_64t_1(void *); 10962306a36Sopenharmony_ciextern int __get_user_64t_2(void *); 11062306a36Sopenharmony_ciextern int __get_user_64t_4(void *); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci#define __GUP_CLOBBER_1 "lr", "cc" 11362306a36Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 11462306a36Sopenharmony_ci#define __GUP_CLOBBER_2 "ip", "lr", "cc" 11562306a36Sopenharmony_ci#else 11662306a36Sopenharmony_ci#define __GUP_CLOBBER_2 "lr", "cc" 11762306a36Sopenharmony_ci#endif 11862306a36Sopenharmony_ci#define __GUP_CLOBBER_4 "lr", "cc" 11962306a36Sopenharmony_ci#define __GUP_CLOBBER_32t_8 "lr", "cc" 12062306a36Sopenharmony_ci#define __GUP_CLOBBER_8 "lr", "cc" 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci#define __get_user_x(__r2, __p, __e, __l, __s) \ 12362306a36Sopenharmony_ci __asm__ __volatile__ ( \ 12462306a36Sopenharmony_ci __asmeq("%0", "r0") __asmeq("%1", "r2") \ 12562306a36Sopenharmony_ci __asmeq("%3", "r1") \ 12662306a36Sopenharmony_ci "bl __get_user_" #__s \ 12762306a36Sopenharmony_ci : "=&r" (__e), "=r" (__r2) \ 12862306a36Sopenharmony_ci : "0" (__p), "r" (__l) \ 12962306a36Sopenharmony_ci : __GUP_CLOBBER_##__s) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* narrowing a double-word get into a single 32bit word register: */ 13262306a36Sopenharmony_ci#ifdef __ARMEB__ 13362306a36Sopenharmony_ci#define __get_user_x_32t(__r2, __p, __e, __l, __s) \ 13462306a36Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 32t_8) 13562306a36Sopenharmony_ci#else 13662306a36Sopenharmony_ci#define __get_user_x_32t __get_user_x 13762306a36Sopenharmony_ci#endif 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci/* 14062306a36Sopenharmony_ci * storing result into proper least significant word of 64bit target var, 14162306a36Sopenharmony_ci * different only for big endian case where 64 bit __r2 lsw is r3: 14262306a36Sopenharmony_ci */ 14362306a36Sopenharmony_ci#ifdef __ARMEB__ 14462306a36Sopenharmony_ci#define __get_user_x_64t(__r2, __p, __e, __l, __s) \ 14562306a36Sopenharmony_ci __asm__ __volatile__ ( \ 14662306a36Sopenharmony_ci __asmeq("%0", "r0") __asmeq("%1", "r2") \ 14762306a36Sopenharmony_ci __asmeq("%3", "r1") \ 14862306a36Sopenharmony_ci "bl __get_user_64t_" #__s \ 14962306a36Sopenharmony_ci : "=&r" (__e), "=r" (__r2) \ 15062306a36Sopenharmony_ci : "0" (__p), "r" (__l) \ 15162306a36Sopenharmony_ci : __GUP_CLOBBER_##__s) 15262306a36Sopenharmony_ci#else 15362306a36Sopenharmony_ci#define __get_user_x_64t __get_user_x 15462306a36Sopenharmony_ci#endif 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci#define __get_user_check(x, p) \ 15862306a36Sopenharmony_ci ({ \ 15962306a36Sopenharmony_ci unsigned long __limit = TASK_SIZE - 1; \ 16062306a36Sopenharmony_ci register typeof(*(p)) __user *__p asm("r0") = (p); \ 16162306a36Sopenharmony_ci register __inttype(x) __r2 asm("r2"); \ 16262306a36Sopenharmony_ci register unsigned long __l asm("r1") = __limit; \ 16362306a36Sopenharmony_ci register int __e asm("r0"); \ 16462306a36Sopenharmony_ci unsigned int __ua_flags = uaccess_save_and_enable(); \ 16562306a36Sopenharmony_ci int __tmp_e; \ 16662306a36Sopenharmony_ci switch (sizeof(*(__p))) { \ 16762306a36Sopenharmony_ci case 1: \ 16862306a36Sopenharmony_ci if (sizeof((x)) >= 8) \ 16962306a36Sopenharmony_ci __get_user_x_64t(__r2, __p, __e, __l, 1); \ 17062306a36Sopenharmony_ci else \ 17162306a36Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 1); \ 17262306a36Sopenharmony_ci break; \ 17362306a36Sopenharmony_ci case 2: \ 17462306a36Sopenharmony_ci if (sizeof((x)) >= 8) \ 17562306a36Sopenharmony_ci __get_user_x_64t(__r2, __p, __e, __l, 2); \ 17662306a36Sopenharmony_ci else \ 17762306a36Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 2); \ 17862306a36Sopenharmony_ci break; \ 17962306a36Sopenharmony_ci case 4: \ 18062306a36Sopenharmony_ci if (sizeof((x)) >= 8) \ 18162306a36Sopenharmony_ci __get_user_x_64t(__r2, __p, __e, __l, 4); \ 18262306a36Sopenharmony_ci else \ 18362306a36Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 4); \ 18462306a36Sopenharmony_ci break; \ 18562306a36Sopenharmony_ci case 8: \ 18662306a36Sopenharmony_ci if (sizeof((x)) < 8) \ 18762306a36Sopenharmony_ci __get_user_x_32t(__r2, __p, __e, __l, 4); \ 18862306a36Sopenharmony_ci else \ 18962306a36Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 8); \ 19062306a36Sopenharmony_ci break; \ 19162306a36Sopenharmony_ci default: __e = __get_user_bad(); break; \ 19262306a36Sopenharmony_ci } \ 19362306a36Sopenharmony_ci __tmp_e = __e; \ 19462306a36Sopenharmony_ci uaccess_restore(__ua_flags); \ 19562306a36Sopenharmony_ci x = (typeof(*(p))) __r2; \ 19662306a36Sopenharmony_ci __tmp_e; \ 19762306a36Sopenharmony_ci }) 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci#define get_user(x, p) \ 20062306a36Sopenharmony_ci ({ \ 20162306a36Sopenharmony_ci might_fault(); \ 20262306a36Sopenharmony_ci __get_user_check(x, p); \ 20362306a36Sopenharmony_ci }) 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciextern int __put_user_1(void *, unsigned int); 20662306a36Sopenharmony_ciextern int __put_user_2(void *, unsigned int); 20762306a36Sopenharmony_ciextern int __put_user_4(void *, unsigned int); 20862306a36Sopenharmony_ciextern int __put_user_8(void *, unsigned long long); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci#define __put_user_check(__pu_val, __ptr, __err, __s) \ 21162306a36Sopenharmony_ci ({ \ 21262306a36Sopenharmony_ci unsigned long __limit = TASK_SIZE - 1; \ 21362306a36Sopenharmony_ci register typeof(__pu_val) __r2 asm("r2") = __pu_val; \ 21462306a36Sopenharmony_ci register const void __user *__p asm("r0") = __ptr; \ 21562306a36Sopenharmony_ci register unsigned long __l asm("r1") = __limit; \ 21662306a36Sopenharmony_ci register int __e asm("r0"); \ 21762306a36Sopenharmony_ci __asm__ __volatile__ ( \ 21862306a36Sopenharmony_ci __asmeq("%0", "r0") __asmeq("%2", "r2") \ 21962306a36Sopenharmony_ci __asmeq("%3", "r1") \ 22062306a36Sopenharmony_ci "bl __put_user_" #__s \ 22162306a36Sopenharmony_ci : "=&r" (__e) \ 22262306a36Sopenharmony_ci : "0" (__p), "r" (__r2), "r" (__l) \ 22362306a36Sopenharmony_ci : "ip", "lr", "cc"); \ 22462306a36Sopenharmony_ci __err = __e; \ 22562306a36Sopenharmony_ci }) 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci#else /* CONFIG_MMU */ 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci#define get_user(x, p) __get_user(x, p) 23062306a36Sopenharmony_ci#define __put_user_check __put_user_nocheck 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci#endif /* CONFIG_MMU */ 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#include <asm-generic/access_ok.h> 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE 23762306a36Sopenharmony_ci/* 23862306a36Sopenharmony_ci * When mitigating Spectre variant 1, it is not worth fixing the non- 23962306a36Sopenharmony_ci * verifying accessors, because we need to add verification of the 24062306a36Sopenharmony_ci * address space there. Force these to use the standard get_user() 24162306a36Sopenharmony_ci * version instead. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_ci#define __get_user(x, ptr) get_user(x, ptr) 24462306a36Sopenharmony_ci#else 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci/* 24762306a36Sopenharmony_ci * The "__xxx" versions of the user access functions do not verify the 24862306a36Sopenharmony_ci * address space - it must have been done previously with a separate 24962306a36Sopenharmony_ci * "access_ok()" call. 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * The "xxx_error" versions set the third argument to EFAULT if an 25262306a36Sopenharmony_ci * error occurs, and leave it unchanged on success. Note that these 25362306a36Sopenharmony_ci * versions are void (ie, don't return a value as such). 25462306a36Sopenharmony_ci */ 25562306a36Sopenharmony_ci#define __get_user(x, ptr) \ 25662306a36Sopenharmony_ci({ \ 25762306a36Sopenharmony_ci long __gu_err = 0; \ 25862306a36Sopenharmony_ci __get_user_err((x), (ptr), __gu_err, TUSER()); \ 25962306a36Sopenharmony_ci __gu_err; \ 26062306a36Sopenharmony_ci}) 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci#define __get_user_err(x, ptr, err, __t) \ 26362306a36Sopenharmony_cido { \ 26462306a36Sopenharmony_ci unsigned long __gu_addr = (unsigned long)(ptr); \ 26562306a36Sopenharmony_ci unsigned long __gu_val; \ 26662306a36Sopenharmony_ci unsigned int __ua_flags; \ 26762306a36Sopenharmony_ci __chk_user_ptr(ptr); \ 26862306a36Sopenharmony_ci might_fault(); \ 26962306a36Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); \ 27062306a36Sopenharmony_ci switch (sizeof(*(ptr))) { \ 27162306a36Sopenharmony_ci case 1: __get_user_asm_byte(__gu_val, __gu_addr, err, __t); break; \ 27262306a36Sopenharmony_ci case 2: __get_user_asm_half(__gu_val, __gu_addr, err, __t); break; \ 27362306a36Sopenharmony_ci case 4: __get_user_asm_word(__gu_val, __gu_addr, err, __t); break; \ 27462306a36Sopenharmony_ci default: (__gu_val) = __get_user_bad(); \ 27562306a36Sopenharmony_ci } \ 27662306a36Sopenharmony_ci uaccess_restore(__ua_flags); \ 27762306a36Sopenharmony_ci (x) = (__typeof__(*(ptr)))__gu_val; \ 27862306a36Sopenharmony_ci} while (0) 27962306a36Sopenharmony_ci#endif 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci#define __get_user_asm(x, addr, err, instr) \ 28262306a36Sopenharmony_ci __asm__ __volatile__( \ 28362306a36Sopenharmony_ci "1: " instr " %1, [%2], #0\n" \ 28462306a36Sopenharmony_ci "2:\n" \ 28562306a36Sopenharmony_ci " .pushsection .text.fixup,\"ax\"\n" \ 28662306a36Sopenharmony_ci " .align 2\n" \ 28762306a36Sopenharmony_ci "3: mov %0, %3\n" \ 28862306a36Sopenharmony_ci " mov %1, #0\n" \ 28962306a36Sopenharmony_ci " b 2b\n" \ 29062306a36Sopenharmony_ci " .popsection\n" \ 29162306a36Sopenharmony_ci " .pushsection __ex_table,\"a\"\n" \ 29262306a36Sopenharmony_ci " .align 3\n" \ 29362306a36Sopenharmony_ci " .long 1b, 3b\n" \ 29462306a36Sopenharmony_ci " .popsection" \ 29562306a36Sopenharmony_ci : "+r" (err), "=&r" (x) \ 29662306a36Sopenharmony_ci : "r" (addr), "i" (-EFAULT) \ 29762306a36Sopenharmony_ci : "cc") 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci#define __get_user_asm_byte(x, addr, err, __t) \ 30062306a36Sopenharmony_ci __get_user_asm(x, addr, err, "ldrb" __t) 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci#define __get_user_asm_half(x, addr, err, __t) \ 30562306a36Sopenharmony_ci __get_user_asm(x, addr, err, "ldrh" __t) 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#else 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#ifndef __ARMEB__ 31062306a36Sopenharmony_ci#define __get_user_asm_half(x, __gu_addr, err, __t) \ 31162306a36Sopenharmony_ci({ \ 31262306a36Sopenharmony_ci unsigned long __b1, __b2; \ 31362306a36Sopenharmony_ci __get_user_asm_byte(__b1, __gu_addr, err, __t); \ 31462306a36Sopenharmony_ci __get_user_asm_byte(__b2, __gu_addr + 1, err, __t); \ 31562306a36Sopenharmony_ci (x) = __b1 | (__b2 << 8); \ 31662306a36Sopenharmony_ci}) 31762306a36Sopenharmony_ci#else 31862306a36Sopenharmony_ci#define __get_user_asm_half(x, __gu_addr, err, __t) \ 31962306a36Sopenharmony_ci({ \ 32062306a36Sopenharmony_ci unsigned long __b1, __b2; \ 32162306a36Sopenharmony_ci __get_user_asm_byte(__b1, __gu_addr, err, __t); \ 32262306a36Sopenharmony_ci __get_user_asm_byte(__b2, __gu_addr + 1, err, __t); \ 32362306a36Sopenharmony_ci (x) = (__b1 << 8) | __b2; \ 32462306a36Sopenharmony_ci}) 32562306a36Sopenharmony_ci#endif 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ >= 6 */ 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci#define __get_user_asm_word(x, addr, err, __t) \ 33062306a36Sopenharmony_ci __get_user_asm(x, addr, err, "ldr" __t) 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci#define __put_user_switch(x, ptr, __err, __fn) \ 33362306a36Sopenharmony_ci do { \ 33462306a36Sopenharmony_ci const __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ 33562306a36Sopenharmony_ci __typeof__(*(ptr)) __pu_val = (x); \ 33662306a36Sopenharmony_ci unsigned int __ua_flags; \ 33762306a36Sopenharmony_ci might_fault(); \ 33862306a36Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); \ 33962306a36Sopenharmony_ci switch (sizeof(*(ptr))) { \ 34062306a36Sopenharmony_ci case 1: __fn(__pu_val, __pu_ptr, __err, 1); break; \ 34162306a36Sopenharmony_ci case 2: __fn(__pu_val, __pu_ptr, __err, 2); break; \ 34262306a36Sopenharmony_ci case 4: __fn(__pu_val, __pu_ptr, __err, 4); break; \ 34362306a36Sopenharmony_ci case 8: __fn(__pu_val, __pu_ptr, __err, 8); break; \ 34462306a36Sopenharmony_ci default: __err = __put_user_bad(); break; \ 34562306a36Sopenharmony_ci } \ 34662306a36Sopenharmony_ci uaccess_restore(__ua_flags); \ 34762306a36Sopenharmony_ci } while (0) 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci#define put_user(x, ptr) \ 35062306a36Sopenharmony_ci({ \ 35162306a36Sopenharmony_ci int __pu_err = 0; \ 35262306a36Sopenharmony_ci __put_user_switch((x), (ptr), __pu_err, __put_user_check); \ 35362306a36Sopenharmony_ci __pu_err; \ 35462306a36Sopenharmony_ci}) 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE 35762306a36Sopenharmony_ci/* 35862306a36Sopenharmony_ci * When mitigating Spectre variant 1.1, all accessors need to include 35962306a36Sopenharmony_ci * verification of the address space. 36062306a36Sopenharmony_ci */ 36162306a36Sopenharmony_ci#define __put_user(x, ptr) put_user(x, ptr) 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci#else 36462306a36Sopenharmony_ci#define __put_user(x, ptr) \ 36562306a36Sopenharmony_ci({ \ 36662306a36Sopenharmony_ci long __pu_err = 0; \ 36762306a36Sopenharmony_ci __put_user_switch((x), (ptr), __pu_err, __put_user_nocheck); \ 36862306a36Sopenharmony_ci __pu_err; \ 36962306a36Sopenharmony_ci}) 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci#define __put_user_nocheck(x, __pu_ptr, __err, __size) \ 37262306a36Sopenharmony_ci do { \ 37362306a36Sopenharmony_ci unsigned long __pu_addr = (unsigned long)__pu_ptr; \ 37462306a36Sopenharmony_ci __put_user_nocheck_##__size(x, __pu_addr, __err, TUSER());\ 37562306a36Sopenharmony_ci } while (0) 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci#define __put_user_nocheck_1 __put_user_asm_byte 37862306a36Sopenharmony_ci#define __put_user_nocheck_2 __put_user_asm_half 37962306a36Sopenharmony_ci#define __put_user_nocheck_4 __put_user_asm_word 38062306a36Sopenharmony_ci#define __put_user_nocheck_8 __put_user_asm_dword 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci#endif /* !CONFIG_CPU_SPECTRE */ 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci#define __put_user_asm(x, __pu_addr, err, instr) \ 38562306a36Sopenharmony_ci __asm__ __volatile__( \ 38662306a36Sopenharmony_ci "1: " instr " %1, [%2], #0\n" \ 38762306a36Sopenharmony_ci "2:\n" \ 38862306a36Sopenharmony_ci " .pushsection .text.fixup,\"ax\"\n" \ 38962306a36Sopenharmony_ci " .align 2\n" \ 39062306a36Sopenharmony_ci "3: mov %0, %3\n" \ 39162306a36Sopenharmony_ci " b 2b\n" \ 39262306a36Sopenharmony_ci " .popsection\n" \ 39362306a36Sopenharmony_ci " .pushsection __ex_table,\"a\"\n" \ 39462306a36Sopenharmony_ci " .align 3\n" \ 39562306a36Sopenharmony_ci " .long 1b, 3b\n" \ 39662306a36Sopenharmony_ci " .popsection" \ 39762306a36Sopenharmony_ci : "+r" (err) \ 39862306a36Sopenharmony_ci : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ 39962306a36Sopenharmony_ci : "cc") 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci#define __put_user_asm_byte(x, __pu_addr, err, __t) \ 40262306a36Sopenharmony_ci __put_user_asm(x, __pu_addr, err, "strb" __t) 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci#define __put_user_asm_half(x, __pu_addr, err, __t) \ 40762306a36Sopenharmony_ci __put_user_asm(x, __pu_addr, err, "strh" __t) 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci#else 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci#ifndef __ARMEB__ 41262306a36Sopenharmony_ci#define __put_user_asm_half(x, __pu_addr, err, __t) \ 41362306a36Sopenharmony_ci({ \ 41462306a36Sopenharmony_ci unsigned long __temp = (__force unsigned long)(x); \ 41562306a36Sopenharmony_ci __put_user_asm_byte(__temp, __pu_addr, err, __t); \ 41662306a36Sopenharmony_ci __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err, __t);\ 41762306a36Sopenharmony_ci}) 41862306a36Sopenharmony_ci#else 41962306a36Sopenharmony_ci#define __put_user_asm_half(x, __pu_addr, err, __t) \ 42062306a36Sopenharmony_ci({ \ 42162306a36Sopenharmony_ci unsigned long __temp = (__force unsigned long)(x); \ 42262306a36Sopenharmony_ci __put_user_asm_byte(__temp >> 8, __pu_addr, err, __t); \ 42362306a36Sopenharmony_ci __put_user_asm_byte(__temp, __pu_addr + 1, err, __t); \ 42462306a36Sopenharmony_ci}) 42562306a36Sopenharmony_ci#endif 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ >= 6 */ 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci#define __put_user_asm_word(x, __pu_addr, err, __t) \ 43062306a36Sopenharmony_ci __put_user_asm(x, __pu_addr, err, "str" __t) 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci#ifndef __ARMEB__ 43362306a36Sopenharmony_ci#define __reg_oper0 "%R2" 43462306a36Sopenharmony_ci#define __reg_oper1 "%Q2" 43562306a36Sopenharmony_ci#else 43662306a36Sopenharmony_ci#define __reg_oper0 "%Q2" 43762306a36Sopenharmony_ci#define __reg_oper1 "%R2" 43862306a36Sopenharmony_ci#endif 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci#define __put_user_asm_dword(x, __pu_addr, err, __t) \ 44162306a36Sopenharmony_ci __asm__ __volatile__( \ 44262306a36Sopenharmony_ci ARM( "1: str" __t " " __reg_oper1 ", [%1], #4\n" ) \ 44362306a36Sopenharmony_ci ARM( "2: str" __t " " __reg_oper0 ", [%1]\n" ) \ 44462306a36Sopenharmony_ci THUMB( "1: str" __t " " __reg_oper1 ", [%1]\n" ) \ 44562306a36Sopenharmony_ci THUMB( "2: str" __t " " __reg_oper0 ", [%1, #4]\n" ) \ 44662306a36Sopenharmony_ci "3:\n" \ 44762306a36Sopenharmony_ci " .pushsection .text.fixup,\"ax\"\n" \ 44862306a36Sopenharmony_ci " .align 2\n" \ 44962306a36Sopenharmony_ci "4: mov %0, %3\n" \ 45062306a36Sopenharmony_ci " b 3b\n" \ 45162306a36Sopenharmony_ci " .popsection\n" \ 45262306a36Sopenharmony_ci " .pushsection __ex_table,\"a\"\n" \ 45362306a36Sopenharmony_ci " .align 3\n" \ 45462306a36Sopenharmony_ci " .long 1b, 4b\n" \ 45562306a36Sopenharmony_ci " .long 2b, 4b\n" \ 45662306a36Sopenharmony_ci " .popsection" \ 45762306a36Sopenharmony_ci : "+r" (err), "+r" (__pu_addr) \ 45862306a36Sopenharmony_ci : "r" (x), "i" (-EFAULT) \ 45962306a36Sopenharmony_ci : "cc") 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci#define __get_kernel_nofault(dst, src, type, err_label) \ 46262306a36Sopenharmony_cido { \ 46362306a36Sopenharmony_ci const type *__pk_ptr = (src); \ 46462306a36Sopenharmony_ci unsigned long __src = (unsigned long)(__pk_ptr); \ 46562306a36Sopenharmony_ci type __val; \ 46662306a36Sopenharmony_ci int __err = 0; \ 46762306a36Sopenharmony_ci switch (sizeof(type)) { \ 46862306a36Sopenharmony_ci case 1: __get_user_asm_byte(__val, __src, __err, ""); break; \ 46962306a36Sopenharmony_ci case 2: __get_user_asm_half(__val, __src, __err, ""); break; \ 47062306a36Sopenharmony_ci case 4: __get_user_asm_word(__val, __src, __err, ""); break; \ 47162306a36Sopenharmony_ci case 8: { \ 47262306a36Sopenharmony_ci u32 *__v32 = (u32*)&__val; \ 47362306a36Sopenharmony_ci __get_user_asm_word(__v32[0], __src, __err, ""); \ 47462306a36Sopenharmony_ci if (__err) \ 47562306a36Sopenharmony_ci break; \ 47662306a36Sopenharmony_ci __get_user_asm_word(__v32[1], __src+4, __err, ""); \ 47762306a36Sopenharmony_ci break; \ 47862306a36Sopenharmony_ci } \ 47962306a36Sopenharmony_ci default: __err = __get_user_bad(); break; \ 48062306a36Sopenharmony_ci } \ 48162306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS)) \ 48262306a36Sopenharmony_ci put_unaligned(__val, (type *)(dst)); \ 48362306a36Sopenharmony_ci else \ 48462306a36Sopenharmony_ci *(type *)(dst) = __val; /* aligned by caller */ \ 48562306a36Sopenharmony_ci if (__err) \ 48662306a36Sopenharmony_ci goto err_label; \ 48762306a36Sopenharmony_ci} while (0) 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci#define __put_kernel_nofault(dst, src, type, err_label) \ 49062306a36Sopenharmony_cido { \ 49162306a36Sopenharmony_ci const type *__pk_ptr = (dst); \ 49262306a36Sopenharmony_ci unsigned long __dst = (unsigned long)__pk_ptr; \ 49362306a36Sopenharmony_ci int __err = 0; \ 49462306a36Sopenharmony_ci type __val = IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) \ 49562306a36Sopenharmony_ci ? get_unaligned((type *)(src)) \ 49662306a36Sopenharmony_ci : *(type *)(src); /* aligned by caller */ \ 49762306a36Sopenharmony_ci switch (sizeof(type)) { \ 49862306a36Sopenharmony_ci case 1: __put_user_asm_byte(__val, __dst, __err, ""); break; \ 49962306a36Sopenharmony_ci case 2: __put_user_asm_half(__val, __dst, __err, ""); break; \ 50062306a36Sopenharmony_ci case 4: __put_user_asm_word(__val, __dst, __err, ""); break; \ 50162306a36Sopenharmony_ci case 8: __put_user_asm_dword(__val, __dst, __err, ""); break; \ 50262306a36Sopenharmony_ci default: __err = __put_user_bad(); break; \ 50362306a36Sopenharmony_ci } \ 50462306a36Sopenharmony_ci if (__err) \ 50562306a36Sopenharmony_ci goto err_label; \ 50662306a36Sopenharmony_ci} while (0) 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci#ifdef CONFIG_MMU 50962306a36Sopenharmony_ciextern unsigned long __must_check 51062306a36Sopenharmony_ciarm_copy_from_user(void *to, const void __user *from, unsigned long n); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_cistatic inline unsigned long __must_check 51362306a36Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci unsigned int __ua_flags; 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); 51862306a36Sopenharmony_ci n = arm_copy_from_user(to, from, n); 51962306a36Sopenharmony_ci uaccess_restore(__ua_flags); 52062306a36Sopenharmony_ci return n; 52162306a36Sopenharmony_ci} 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ciextern unsigned long __must_check 52462306a36Sopenharmony_ciarm_copy_to_user(void __user *to, const void *from, unsigned long n); 52562306a36Sopenharmony_ciextern unsigned long __must_check 52662306a36Sopenharmony_ci__copy_to_user_std(void __user *to, const void *from, unsigned long n); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_cistatic inline unsigned long __must_check 52962306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci#ifndef CONFIG_UACCESS_WITH_MEMCPY 53262306a36Sopenharmony_ci unsigned int __ua_flags; 53362306a36Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); 53462306a36Sopenharmony_ci n = arm_copy_to_user(to, from, n); 53562306a36Sopenharmony_ci uaccess_restore(__ua_flags); 53662306a36Sopenharmony_ci return n; 53762306a36Sopenharmony_ci#else 53862306a36Sopenharmony_ci return arm_copy_to_user(to, from, n); 53962306a36Sopenharmony_ci#endif 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ciextern unsigned long __must_check 54362306a36Sopenharmony_ciarm_clear_user(void __user *addr, unsigned long n); 54462306a36Sopenharmony_ciextern unsigned long __must_check 54562306a36Sopenharmony_ci__clear_user_std(void __user *addr, unsigned long n); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_cistatic inline unsigned long __must_check 54862306a36Sopenharmony_ci__clear_user(void __user *addr, unsigned long n) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci unsigned int __ua_flags = uaccess_save_and_enable(); 55162306a36Sopenharmony_ci n = arm_clear_user(addr, n); 55262306a36Sopenharmony_ci uaccess_restore(__ua_flags); 55362306a36Sopenharmony_ci return n; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci#else 55762306a36Sopenharmony_cistatic inline unsigned long 55862306a36Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 55962306a36Sopenharmony_ci{ 56062306a36Sopenharmony_ci memcpy(to, (const void __force *)from, n); 56162306a36Sopenharmony_ci return 0; 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_cistatic inline unsigned long 56462306a36Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci memcpy((void __force *)to, from, n); 56762306a36Sopenharmony_ci return 0; 56862306a36Sopenharmony_ci} 56962306a36Sopenharmony_ci#define __clear_user(addr, n) (memset((void __force *)addr, 0, n), 0) 57062306a36Sopenharmony_ci#endif 57162306a36Sopenharmony_ci#define INLINE_COPY_TO_USER 57262306a36Sopenharmony_ci#define INLINE_COPY_FROM_USER 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to, unsigned long n) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci if (access_ok(to, n)) 57762306a36Sopenharmony_ci n = __clear_user(to, n); 57862306a36Sopenharmony_ci return n; 57962306a36Sopenharmony_ci} 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci/* These are from lib/ code, and use __get_user() and friends */ 58262306a36Sopenharmony_ciextern long strncpy_from_user(char *dest, const char __user *src, long count); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ciextern __must_check long strnlen_user(const char __user *str, long n); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci#endif /* _ASMARM_UACCESS_H */ 587