18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-only */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * arch/arm/include/asm/uaccess.h 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#ifndef _ASMARM_UACCESS_H 68c2ecf20Sopenharmony_ci#define _ASMARM_UACCESS_H 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* 98c2ecf20Sopenharmony_ci * User space memory access functions 108c2ecf20Sopenharmony_ci */ 118c2ecf20Sopenharmony_ci#include <linux/string.h> 128c2ecf20Sopenharmony_ci#include <asm/memory.h> 138c2ecf20Sopenharmony_ci#include <asm/domain.h> 148c2ecf20Sopenharmony_ci#include <asm/unified.h> 158c2ecf20Sopenharmony_ci#include <asm/compiler.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <asm/extable.h> 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * These two functions allow hooking accesses to userspace to increase 218c2ecf20Sopenharmony_ci * system integrity by ensuring that the kernel can not inadvertantly 228c2ecf20Sopenharmony_ci * perform such accesses (eg, via list poison values) which could then 238c2ecf20Sopenharmony_ci * be exploited for priviledge escalation. 248c2ecf20Sopenharmony_ci */ 258c2ecf20Sopenharmony_cistatic __always_inline unsigned int uaccess_save_and_enable(void) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN 288c2ecf20Sopenharmony_ci unsigned int old_domain = get_domain(); 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci /* Set the current domain access to permit user accesses */ 318c2ecf20Sopenharmony_ci set_domain((old_domain & ~domain_mask(DOMAIN_USER)) | 328c2ecf20Sopenharmony_ci domain_val(DOMAIN_USER, DOMAIN_CLIENT)); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci return old_domain; 358c2ecf20Sopenharmony_ci#else 368c2ecf20Sopenharmony_ci return 0; 378c2ecf20Sopenharmony_ci#endif 388c2ecf20Sopenharmony_ci} 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic __always_inline void uaccess_restore(unsigned int flags) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SW_DOMAIN_PAN 438c2ecf20Sopenharmony_ci /* Restore the user access mask */ 448c2ecf20Sopenharmony_ci set_domain(flags); 458c2ecf20Sopenharmony_ci#endif 468c2ecf20Sopenharmony_ci} 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/* 498c2ecf20Sopenharmony_ci * These two are intentionally not defined anywhere - if the kernel 508c2ecf20Sopenharmony_ci * code generates any references to them, that's a bug. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_ciextern int __get_user_bad(void); 538c2ecf20Sopenharmony_ciextern int __put_user_bad(void); 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci/* 568c2ecf20Sopenharmony_ci * Note that this is actually 0x1,0000,0000 578c2ecf20Sopenharmony_ci */ 588c2ecf20Sopenharmony_ci#define KERNEL_DS 0x00000000 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ci#define USER_DS TASK_SIZE 638c2ecf20Sopenharmony_ci#define get_fs() (current_thread_info()->addr_limit) 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic inline void set_fs(mm_segment_t fs) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci current_thread_info()->addr_limit = fs; 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ci /* 708c2ecf20Sopenharmony_ci * Prevent a mispredicted conditional call to set_fs from forwarding 718c2ecf20Sopenharmony_ci * the wrong address limit to access_ok under speculation. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci dsb(nsh); 748c2ecf20Sopenharmony_ci isb(); 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci modify_domain(DOMAIN_KERNEL, fs ? DOMAIN_CLIENT : DOMAIN_MANAGER); 778c2ecf20Sopenharmony_ci} 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci#define uaccess_kernel() (get_fs() == KERNEL_DS) 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * We use 33-bit arithmetic here. Success returns zero, failure returns 838c2ecf20Sopenharmony_ci * addr_limit. We take advantage that addr_limit will be zero for KERNEL_DS, 848c2ecf20Sopenharmony_ci * so this will always return success in that case. 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci#define __range_ok(addr, size) ({ \ 878c2ecf20Sopenharmony_ci unsigned long flag, roksum; \ 888c2ecf20Sopenharmony_ci __chk_user_ptr(addr); \ 898c2ecf20Sopenharmony_ci __asm__(".syntax unified\n" \ 908c2ecf20Sopenharmony_ci "adds %1, %2, %3; sbcscc %1, %1, %0; movcc %0, #0" \ 918c2ecf20Sopenharmony_ci : "=&r" (flag), "=&r" (roksum) \ 928c2ecf20Sopenharmony_ci : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ 938c2ecf20Sopenharmony_ci : "cc"); \ 948c2ecf20Sopenharmony_ci flag; }) 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci/* 978c2ecf20Sopenharmony_ci * This is a type: either unsigned long, if the argument fits into 988c2ecf20Sopenharmony_ci * that type, or otherwise unsigned long long. 998c2ecf20Sopenharmony_ci */ 1008c2ecf20Sopenharmony_ci#define __inttype(x) \ 1018c2ecf20Sopenharmony_ci __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL)) 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/* 1048c2ecf20Sopenharmony_ci * Sanitise a uaccess pointer such that it becomes NULL if addr+size 1058c2ecf20Sopenharmony_ci * is above the current addr_limit. 1068c2ecf20Sopenharmony_ci */ 1078c2ecf20Sopenharmony_ci#define uaccess_mask_range_ptr(ptr, size) \ 1088c2ecf20Sopenharmony_ci ((__typeof__(ptr))__uaccess_mask_range_ptr(ptr, size)) 1098c2ecf20Sopenharmony_cistatic inline void __user *__uaccess_mask_range_ptr(const void __user *ptr, 1108c2ecf20Sopenharmony_ci size_t size) 1118c2ecf20Sopenharmony_ci{ 1128c2ecf20Sopenharmony_ci void __user *safe_ptr = (void __user *)ptr; 1138c2ecf20Sopenharmony_ci unsigned long tmp; 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci asm volatile( 1168c2ecf20Sopenharmony_ci " .syntax unified\n" 1178c2ecf20Sopenharmony_ci " sub %1, %3, #1\n" 1188c2ecf20Sopenharmony_ci " subs %1, %1, %0\n" 1198c2ecf20Sopenharmony_ci " addhs %1, %1, #1\n" 1208c2ecf20Sopenharmony_ci " subshs %1, %1, %2\n" 1218c2ecf20Sopenharmony_ci " movlo %0, #0\n" 1228c2ecf20Sopenharmony_ci : "+r" (safe_ptr), "=&r" (tmp) 1238c2ecf20Sopenharmony_ci : "r" (size), "r" (current_thread_info()->addr_limit) 1248c2ecf20Sopenharmony_ci : "cc"); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci csdb(); 1278c2ecf20Sopenharmony_ci return safe_ptr; 1288c2ecf20Sopenharmony_ci} 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci/* 1318c2ecf20Sopenharmony_ci * Single-value transfer routines. They automatically use the right 1328c2ecf20Sopenharmony_ci * size if we just have the right pointer type. Note that the functions 1338c2ecf20Sopenharmony_ci * which read from user space (*get_*) need to take care not to leak 1348c2ecf20Sopenharmony_ci * kernel data even if the calling code is buggy and fails to check 1358c2ecf20Sopenharmony_ci * the return value. This means zeroing out the destination variable 1368c2ecf20Sopenharmony_ci * or buffer on error. Normally this is done out of line by the 1378c2ecf20Sopenharmony_ci * fixup code, but there are a few places where it intrudes on the 1388c2ecf20Sopenharmony_ci * main code path. When we only write to user space, there is no 1398c2ecf20Sopenharmony_ci * problem. 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ciextern int __get_user_1(void *); 1428c2ecf20Sopenharmony_ciextern int __get_user_2(void *); 1438c2ecf20Sopenharmony_ciextern int __get_user_4(void *); 1448c2ecf20Sopenharmony_ciextern int __get_user_32t_8(void *); 1458c2ecf20Sopenharmony_ciextern int __get_user_8(void *); 1468c2ecf20Sopenharmony_ciextern int __get_user_64t_1(void *); 1478c2ecf20Sopenharmony_ciextern int __get_user_64t_2(void *); 1488c2ecf20Sopenharmony_ciextern int __get_user_64t_4(void *); 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci#define __GUP_CLOBBER_1 "lr", "cc" 1518c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_USE_DOMAINS 1528c2ecf20Sopenharmony_ci#define __GUP_CLOBBER_2 "ip", "lr", "cc" 1538c2ecf20Sopenharmony_ci#else 1548c2ecf20Sopenharmony_ci#define __GUP_CLOBBER_2 "lr", "cc" 1558c2ecf20Sopenharmony_ci#endif 1568c2ecf20Sopenharmony_ci#define __GUP_CLOBBER_4 "lr", "cc" 1578c2ecf20Sopenharmony_ci#define __GUP_CLOBBER_32t_8 "lr", "cc" 1588c2ecf20Sopenharmony_ci#define __GUP_CLOBBER_8 "lr", "cc" 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci#define __get_user_x(__r2, __p, __e, __l, __s) \ 1618c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 1628c2ecf20Sopenharmony_ci __asmeq("%0", "r0") __asmeq("%1", "r2") \ 1638c2ecf20Sopenharmony_ci __asmeq("%3", "r1") \ 1648c2ecf20Sopenharmony_ci "bl __get_user_" #__s \ 1658c2ecf20Sopenharmony_ci : "=&r" (__e), "=r" (__r2) \ 1668c2ecf20Sopenharmony_ci : "0" (__p), "r" (__l) \ 1678c2ecf20Sopenharmony_ci : __GUP_CLOBBER_##__s) 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/* narrowing a double-word get into a single 32bit word register: */ 1708c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 1718c2ecf20Sopenharmony_ci#define __get_user_x_32t(__r2, __p, __e, __l, __s) \ 1728c2ecf20Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 32t_8) 1738c2ecf20Sopenharmony_ci#else 1748c2ecf20Sopenharmony_ci#define __get_user_x_32t __get_user_x 1758c2ecf20Sopenharmony_ci#endif 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/* 1788c2ecf20Sopenharmony_ci * storing result into proper least significant word of 64bit target var, 1798c2ecf20Sopenharmony_ci * different only for big endian case where 64 bit __r2 lsw is r3: 1808c2ecf20Sopenharmony_ci */ 1818c2ecf20Sopenharmony_ci#ifdef __ARMEB__ 1828c2ecf20Sopenharmony_ci#define __get_user_x_64t(__r2, __p, __e, __l, __s) \ 1838c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 1848c2ecf20Sopenharmony_ci __asmeq("%0", "r0") __asmeq("%1", "r2") \ 1858c2ecf20Sopenharmony_ci __asmeq("%3", "r1") \ 1868c2ecf20Sopenharmony_ci "bl __get_user_64t_" #__s \ 1878c2ecf20Sopenharmony_ci : "=&r" (__e), "=r" (__r2) \ 1888c2ecf20Sopenharmony_ci : "0" (__p), "r" (__l) \ 1898c2ecf20Sopenharmony_ci : __GUP_CLOBBER_##__s) 1908c2ecf20Sopenharmony_ci#else 1918c2ecf20Sopenharmony_ci#define __get_user_x_64t __get_user_x 1928c2ecf20Sopenharmony_ci#endif 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci#define __get_user_check(x, p) \ 1968c2ecf20Sopenharmony_ci ({ \ 1978c2ecf20Sopenharmony_ci unsigned long __limit = current_thread_info()->addr_limit - 1; \ 1988c2ecf20Sopenharmony_ci register typeof(*(p)) __user *__p asm("r0") = (p); \ 1998c2ecf20Sopenharmony_ci register __inttype(x) __r2 asm("r2"); \ 2008c2ecf20Sopenharmony_ci register unsigned long __l asm("r1") = __limit; \ 2018c2ecf20Sopenharmony_ci register int __e asm("r0"); \ 2028c2ecf20Sopenharmony_ci unsigned int __ua_flags = uaccess_save_and_enable(); \ 2038c2ecf20Sopenharmony_ci int __tmp_e; \ 2048c2ecf20Sopenharmony_ci switch (sizeof(*(__p))) { \ 2058c2ecf20Sopenharmony_ci case 1: \ 2068c2ecf20Sopenharmony_ci if (sizeof((x)) >= 8) \ 2078c2ecf20Sopenharmony_ci __get_user_x_64t(__r2, __p, __e, __l, 1); \ 2088c2ecf20Sopenharmony_ci else \ 2098c2ecf20Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 1); \ 2108c2ecf20Sopenharmony_ci break; \ 2118c2ecf20Sopenharmony_ci case 2: \ 2128c2ecf20Sopenharmony_ci if (sizeof((x)) >= 8) \ 2138c2ecf20Sopenharmony_ci __get_user_x_64t(__r2, __p, __e, __l, 2); \ 2148c2ecf20Sopenharmony_ci else \ 2158c2ecf20Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 2); \ 2168c2ecf20Sopenharmony_ci break; \ 2178c2ecf20Sopenharmony_ci case 4: \ 2188c2ecf20Sopenharmony_ci if (sizeof((x)) >= 8) \ 2198c2ecf20Sopenharmony_ci __get_user_x_64t(__r2, __p, __e, __l, 4); \ 2208c2ecf20Sopenharmony_ci else \ 2218c2ecf20Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 4); \ 2228c2ecf20Sopenharmony_ci break; \ 2238c2ecf20Sopenharmony_ci case 8: \ 2248c2ecf20Sopenharmony_ci if (sizeof((x)) < 8) \ 2258c2ecf20Sopenharmony_ci __get_user_x_32t(__r2, __p, __e, __l, 4); \ 2268c2ecf20Sopenharmony_ci else \ 2278c2ecf20Sopenharmony_ci __get_user_x(__r2, __p, __e, __l, 8); \ 2288c2ecf20Sopenharmony_ci break; \ 2298c2ecf20Sopenharmony_ci default: __e = __get_user_bad(); break; \ 2308c2ecf20Sopenharmony_ci } \ 2318c2ecf20Sopenharmony_ci __tmp_e = __e; \ 2328c2ecf20Sopenharmony_ci uaccess_restore(__ua_flags); \ 2338c2ecf20Sopenharmony_ci x = (typeof(*(p))) __r2; \ 2348c2ecf20Sopenharmony_ci __tmp_e; \ 2358c2ecf20Sopenharmony_ci }) 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci#define get_user(x, p) \ 2388c2ecf20Sopenharmony_ci ({ \ 2398c2ecf20Sopenharmony_ci might_fault(); \ 2408c2ecf20Sopenharmony_ci __get_user_check(x, p); \ 2418c2ecf20Sopenharmony_ci }) 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciextern int __put_user_1(void *, unsigned int); 2448c2ecf20Sopenharmony_ciextern int __put_user_2(void *, unsigned int); 2458c2ecf20Sopenharmony_ciextern int __put_user_4(void *, unsigned int); 2468c2ecf20Sopenharmony_ciextern int __put_user_8(void *, unsigned long long); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci#define __put_user_check(__pu_val, __ptr, __err, __s) \ 2498c2ecf20Sopenharmony_ci ({ \ 2508c2ecf20Sopenharmony_ci unsigned long __limit = current_thread_info()->addr_limit - 1; \ 2518c2ecf20Sopenharmony_ci register typeof(__pu_val) __r2 asm("r2") = __pu_val; \ 2528c2ecf20Sopenharmony_ci register const void __user *__p asm("r0") = __ptr; \ 2538c2ecf20Sopenharmony_ci register unsigned long __l asm("r1") = __limit; \ 2548c2ecf20Sopenharmony_ci register int __e asm("r0"); \ 2558c2ecf20Sopenharmony_ci __asm__ __volatile__ ( \ 2568c2ecf20Sopenharmony_ci __asmeq("%0", "r0") __asmeq("%2", "r2") \ 2578c2ecf20Sopenharmony_ci __asmeq("%3", "r1") \ 2588c2ecf20Sopenharmony_ci "bl __put_user_" #__s \ 2598c2ecf20Sopenharmony_ci : "=&r" (__e) \ 2608c2ecf20Sopenharmony_ci : "0" (__p), "r" (__r2), "r" (__l) \ 2618c2ecf20Sopenharmony_ci : "ip", "lr", "cc"); \ 2628c2ecf20Sopenharmony_ci __err = __e; \ 2638c2ecf20Sopenharmony_ci }) 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci#else /* CONFIG_MMU */ 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* 2688c2ecf20Sopenharmony_ci * uClinux has only one addr space, so has simplified address limits. 2698c2ecf20Sopenharmony_ci */ 2708c2ecf20Sopenharmony_ci#define USER_DS KERNEL_DS 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci#define uaccess_kernel() (true) 2738c2ecf20Sopenharmony_ci#define __addr_ok(addr) ((void)(addr), 1) 2748c2ecf20Sopenharmony_ci#define __range_ok(addr, size) ((void)(addr), 0) 2758c2ecf20Sopenharmony_ci#define get_fs() (KERNEL_DS) 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_cistatic inline void set_fs(mm_segment_t fs) 2788c2ecf20Sopenharmony_ci{ 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci#define get_user(x, p) __get_user(x, p) 2828c2ecf20Sopenharmony_ci#define __put_user_check __put_user_nocheck 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci#endif /* CONFIG_MMU */ 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci#define access_ok(addr, size) (__range_ok(addr, size) == 0) 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci#define user_addr_max() \ 2898c2ecf20Sopenharmony_ci (uaccess_kernel() ? ~0UL : get_fs()) 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE 2928c2ecf20Sopenharmony_ci/* 2938c2ecf20Sopenharmony_ci * When mitigating Spectre variant 1, it is not worth fixing the non- 2948c2ecf20Sopenharmony_ci * verifying accessors, because we need to add verification of the 2958c2ecf20Sopenharmony_ci * address space there. Force these to use the standard get_user() 2968c2ecf20Sopenharmony_ci * version instead. 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_ci#define __get_user(x, ptr) get_user(x, ptr) 2998c2ecf20Sopenharmony_ci#else 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci/* 3028c2ecf20Sopenharmony_ci * The "__xxx" versions of the user access functions do not verify the 3038c2ecf20Sopenharmony_ci * address space - it must have been done previously with a separate 3048c2ecf20Sopenharmony_ci * "access_ok()" call. 3058c2ecf20Sopenharmony_ci * 3068c2ecf20Sopenharmony_ci * The "xxx_error" versions set the third argument to EFAULT if an 3078c2ecf20Sopenharmony_ci * error occurs, and leave it unchanged on success. Note that these 3088c2ecf20Sopenharmony_ci * versions are void (ie, don't return a value as such). 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci#define __get_user(x, ptr) \ 3118c2ecf20Sopenharmony_ci({ \ 3128c2ecf20Sopenharmony_ci long __gu_err = 0; \ 3138c2ecf20Sopenharmony_ci __get_user_err((x), (ptr), __gu_err); \ 3148c2ecf20Sopenharmony_ci __gu_err; \ 3158c2ecf20Sopenharmony_ci}) 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci#define __get_user_err(x, ptr, err) \ 3188c2ecf20Sopenharmony_cido { \ 3198c2ecf20Sopenharmony_ci unsigned long __gu_addr = (unsigned long)(ptr); \ 3208c2ecf20Sopenharmony_ci unsigned long __gu_val; \ 3218c2ecf20Sopenharmony_ci unsigned int __ua_flags; \ 3228c2ecf20Sopenharmony_ci __chk_user_ptr(ptr); \ 3238c2ecf20Sopenharmony_ci might_fault(); \ 3248c2ecf20Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); \ 3258c2ecf20Sopenharmony_ci switch (sizeof(*(ptr))) { \ 3268c2ecf20Sopenharmony_ci case 1: __get_user_asm_byte(__gu_val, __gu_addr, err); break; \ 3278c2ecf20Sopenharmony_ci case 2: __get_user_asm_half(__gu_val, __gu_addr, err); break; \ 3288c2ecf20Sopenharmony_ci case 4: __get_user_asm_word(__gu_val, __gu_addr, err); break; \ 3298c2ecf20Sopenharmony_ci default: (__gu_val) = __get_user_bad(); \ 3308c2ecf20Sopenharmony_ci } \ 3318c2ecf20Sopenharmony_ci uaccess_restore(__ua_flags); \ 3328c2ecf20Sopenharmony_ci (x) = (__typeof__(*(ptr)))__gu_val; \ 3338c2ecf20Sopenharmony_ci} while (0) 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci#define __get_user_asm(x, addr, err, instr) \ 3368c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 3378c2ecf20Sopenharmony_ci "1: " TUSER(instr) " %1, [%2], #0\n" \ 3388c2ecf20Sopenharmony_ci "2:\n" \ 3398c2ecf20Sopenharmony_ci " .pushsection .text.fixup,\"ax\"\n" \ 3408c2ecf20Sopenharmony_ci " .align 2\n" \ 3418c2ecf20Sopenharmony_ci "3: mov %0, %3\n" \ 3428c2ecf20Sopenharmony_ci " mov %1, #0\n" \ 3438c2ecf20Sopenharmony_ci " b 2b\n" \ 3448c2ecf20Sopenharmony_ci " .popsection\n" \ 3458c2ecf20Sopenharmony_ci " ex_entry 1b, 3b\n" \ 3468c2ecf20Sopenharmony_ci : "+r" (err), "=&r" (x) \ 3478c2ecf20Sopenharmony_ci : "r" (addr), "i" (-EFAULT) \ 3488c2ecf20Sopenharmony_ci : "cc") 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci#define __get_user_asm_byte(x, addr, err) \ 3518c2ecf20Sopenharmony_ci __get_user_asm(x, addr, err, ldrb) 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci#define __get_user_asm_half(x, addr, err) \ 3568c2ecf20Sopenharmony_ci __get_user_asm(x, addr, err, ldrh) 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ci#else 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci#ifndef __ARMEB__ 3618c2ecf20Sopenharmony_ci#define __get_user_asm_half(x, __gu_addr, err) \ 3628c2ecf20Sopenharmony_ci({ \ 3638c2ecf20Sopenharmony_ci unsigned long __b1, __b2; \ 3648c2ecf20Sopenharmony_ci __get_user_asm_byte(__b1, __gu_addr, err); \ 3658c2ecf20Sopenharmony_ci __get_user_asm_byte(__b2, __gu_addr + 1, err); \ 3668c2ecf20Sopenharmony_ci (x) = __b1 | (__b2 << 8); \ 3678c2ecf20Sopenharmony_ci}) 3688c2ecf20Sopenharmony_ci#else 3698c2ecf20Sopenharmony_ci#define __get_user_asm_half(x, __gu_addr, err) \ 3708c2ecf20Sopenharmony_ci({ \ 3718c2ecf20Sopenharmony_ci unsigned long __b1, __b2; \ 3728c2ecf20Sopenharmony_ci __get_user_asm_byte(__b1, __gu_addr, err); \ 3738c2ecf20Sopenharmony_ci __get_user_asm_byte(__b2, __gu_addr + 1, err); \ 3748c2ecf20Sopenharmony_ci (x) = (__b1 << 8) | __b2; \ 3758c2ecf20Sopenharmony_ci}) 3768c2ecf20Sopenharmony_ci#endif 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ >= 6 */ 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci#define __get_user_asm_word(x, addr, err) \ 3818c2ecf20Sopenharmony_ci __get_user_asm(x, addr, err, ldr) 3828c2ecf20Sopenharmony_ci#endif 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_ci#define __put_user_switch(x, ptr, __err, __fn) \ 3868c2ecf20Sopenharmony_ci do { \ 3878c2ecf20Sopenharmony_ci const __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \ 3888c2ecf20Sopenharmony_ci __typeof__(*(ptr)) __pu_val = (x); \ 3898c2ecf20Sopenharmony_ci unsigned int __ua_flags; \ 3908c2ecf20Sopenharmony_ci might_fault(); \ 3918c2ecf20Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); \ 3928c2ecf20Sopenharmony_ci switch (sizeof(*(ptr))) { \ 3938c2ecf20Sopenharmony_ci case 1: __fn(__pu_val, __pu_ptr, __err, 1); break; \ 3948c2ecf20Sopenharmony_ci case 2: __fn(__pu_val, __pu_ptr, __err, 2); break; \ 3958c2ecf20Sopenharmony_ci case 4: __fn(__pu_val, __pu_ptr, __err, 4); break; \ 3968c2ecf20Sopenharmony_ci case 8: __fn(__pu_val, __pu_ptr, __err, 8); break; \ 3978c2ecf20Sopenharmony_ci default: __err = __put_user_bad(); break; \ 3988c2ecf20Sopenharmony_ci } \ 3998c2ecf20Sopenharmony_ci uaccess_restore(__ua_flags); \ 4008c2ecf20Sopenharmony_ci } while (0) 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#define put_user(x, ptr) \ 4038c2ecf20Sopenharmony_ci({ \ 4048c2ecf20Sopenharmony_ci int __pu_err = 0; \ 4058c2ecf20Sopenharmony_ci __put_user_switch((x), (ptr), __pu_err, __put_user_check); \ 4068c2ecf20Sopenharmony_ci __pu_err; \ 4078c2ecf20Sopenharmony_ci}) 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_SPECTRE 4108c2ecf20Sopenharmony_ci/* 4118c2ecf20Sopenharmony_ci * When mitigating Spectre variant 1.1, all accessors need to include 4128c2ecf20Sopenharmony_ci * verification of the address space. 4138c2ecf20Sopenharmony_ci */ 4148c2ecf20Sopenharmony_ci#define __put_user(x, ptr) put_user(x, ptr) 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci#else 4178c2ecf20Sopenharmony_ci#define __put_user(x, ptr) \ 4188c2ecf20Sopenharmony_ci({ \ 4198c2ecf20Sopenharmony_ci long __pu_err = 0; \ 4208c2ecf20Sopenharmony_ci __put_user_switch((x), (ptr), __pu_err, __put_user_nocheck); \ 4218c2ecf20Sopenharmony_ci __pu_err; \ 4228c2ecf20Sopenharmony_ci}) 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci#define __put_user_nocheck(x, __pu_ptr, __err, __size) \ 4258c2ecf20Sopenharmony_ci do { \ 4268c2ecf20Sopenharmony_ci unsigned long __pu_addr = (unsigned long)__pu_ptr; \ 4278c2ecf20Sopenharmony_ci __put_user_nocheck_##__size(x, __pu_addr, __err); \ 4288c2ecf20Sopenharmony_ci } while (0) 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci#define __put_user_nocheck_1 __put_user_asm_byte 4318c2ecf20Sopenharmony_ci#define __put_user_nocheck_2 __put_user_asm_half 4328c2ecf20Sopenharmony_ci#define __put_user_nocheck_4 __put_user_asm_word 4338c2ecf20Sopenharmony_ci#define __put_user_nocheck_8 __put_user_asm_dword 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci#define __put_user_asm(x, __pu_addr, err, instr) \ 4368c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 4378c2ecf20Sopenharmony_ci "1: " TUSER(instr) " %1, [%2], #0\n" \ 4388c2ecf20Sopenharmony_ci "2:\n" \ 4398c2ecf20Sopenharmony_ci " .pushsection .text.fixup,\"ax\"\n" \ 4408c2ecf20Sopenharmony_ci " .align 2\n" \ 4418c2ecf20Sopenharmony_ci "3: mov %0, %3\n" \ 4428c2ecf20Sopenharmony_ci " b 2b\n" \ 4438c2ecf20Sopenharmony_ci " .popsection\n" \ 4448c2ecf20Sopenharmony_ci " ex_entry 1b, 3b\n" \ 4458c2ecf20Sopenharmony_ci : "+r" (err) \ 4468c2ecf20Sopenharmony_ci : "r" (x), "r" (__pu_addr), "i" (-EFAULT) \ 4478c2ecf20Sopenharmony_ci : "cc") 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci#define __put_user_asm_byte(x, __pu_addr, err) \ 4508c2ecf20Sopenharmony_ci __put_user_asm(x, __pu_addr, err, strb) 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci#define __put_user_asm_half(x, __pu_addr, err) \ 4558c2ecf20Sopenharmony_ci __put_user_asm(x, __pu_addr, err, strh) 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci#else 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci#ifndef __ARMEB__ 4608c2ecf20Sopenharmony_ci#define __put_user_asm_half(x, __pu_addr, err) \ 4618c2ecf20Sopenharmony_ci({ \ 4628c2ecf20Sopenharmony_ci unsigned long __temp = (__force unsigned long)(x); \ 4638c2ecf20Sopenharmony_ci __put_user_asm_byte(__temp, __pu_addr, err); \ 4648c2ecf20Sopenharmony_ci __put_user_asm_byte(__temp >> 8, __pu_addr + 1, err); \ 4658c2ecf20Sopenharmony_ci}) 4668c2ecf20Sopenharmony_ci#else 4678c2ecf20Sopenharmony_ci#define __put_user_asm_half(x, __pu_addr, err) \ 4688c2ecf20Sopenharmony_ci({ \ 4698c2ecf20Sopenharmony_ci unsigned long __temp = (__force unsigned long)(x); \ 4708c2ecf20Sopenharmony_ci __put_user_asm_byte(__temp >> 8, __pu_addr, err); \ 4718c2ecf20Sopenharmony_ci __put_user_asm_byte(__temp, __pu_addr + 1, err); \ 4728c2ecf20Sopenharmony_ci}) 4738c2ecf20Sopenharmony_ci#endif 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ >= 6 */ 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci#define __put_user_asm_word(x, __pu_addr, err) \ 4788c2ecf20Sopenharmony_ci __put_user_asm(x, __pu_addr, err, str) 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci#ifndef __ARMEB__ 4818c2ecf20Sopenharmony_ci#define __reg_oper0 "%R2" 4828c2ecf20Sopenharmony_ci#define __reg_oper1 "%Q2" 4838c2ecf20Sopenharmony_ci#else 4848c2ecf20Sopenharmony_ci#define __reg_oper0 "%Q2" 4858c2ecf20Sopenharmony_ci#define __reg_oper1 "%R2" 4868c2ecf20Sopenharmony_ci#endif 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci#define __put_user_asm_dword(x, __pu_addr, err) \ 4898c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 4908c2ecf20Sopenharmony_ci ARM( "1: " TUSER(str) " " __reg_oper1 ", [%1], #4\n" ) \ 4918c2ecf20Sopenharmony_ci ARM( "2: " TUSER(str) " " __reg_oper0 ", [%1]\n" ) \ 4928c2ecf20Sopenharmony_ci THUMB( "1: " TUSER(str) " " __reg_oper1 ", [%1]\n" ) \ 4938c2ecf20Sopenharmony_ci THUMB( "2: " TUSER(str) " " __reg_oper0 ", [%1, #4]\n" ) \ 4948c2ecf20Sopenharmony_ci "3:\n" \ 4958c2ecf20Sopenharmony_ci " .pushsection .text.fixup,\"ax\"\n" \ 4968c2ecf20Sopenharmony_ci " .align 2\n" \ 4978c2ecf20Sopenharmony_ci "4: mov %0, %3\n" \ 4988c2ecf20Sopenharmony_ci " b 3b\n" \ 4998c2ecf20Sopenharmony_ci " .popsection\n" \ 5008c2ecf20Sopenharmony_ci " ex_entry 1b, 4b\n" \ 5018c2ecf20Sopenharmony_ci " ex_entry 2b, 4b\n" \ 5028c2ecf20Sopenharmony_ci : "+r" (err), "+r" (__pu_addr) \ 5038c2ecf20Sopenharmony_ci : "r" (x), "i" (-EFAULT) \ 5048c2ecf20Sopenharmony_ci : "cc") 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci#endif /* !CONFIG_CPU_SPECTRE */ 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci#ifdef CONFIG_MMU 5098c2ecf20Sopenharmony_ciextern unsigned long __must_check 5108c2ecf20Sopenharmony_ciarm_copy_from_user(void *to, const void __user *from, unsigned long n); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_cistatic inline unsigned long __must_check 5138c2ecf20Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 5148c2ecf20Sopenharmony_ci{ 5158c2ecf20Sopenharmony_ci unsigned int __ua_flags; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); 5188c2ecf20Sopenharmony_ci n = arm_copy_from_user(to, from, n); 5198c2ecf20Sopenharmony_ci uaccess_restore(__ua_flags); 5208c2ecf20Sopenharmony_ci return n; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ciextern unsigned long __must_check 5248c2ecf20Sopenharmony_ciarm_copy_to_user(void __user *to, const void *from, unsigned long n); 5258c2ecf20Sopenharmony_ciextern unsigned long __must_check 5268c2ecf20Sopenharmony_ci__copy_to_user_std(void __user *to, const void *from, unsigned long n); 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_cistatic inline unsigned long __must_check 5298c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 5308c2ecf20Sopenharmony_ci{ 5318c2ecf20Sopenharmony_ci#ifndef CONFIG_UACCESS_WITH_MEMCPY 5328c2ecf20Sopenharmony_ci unsigned int __ua_flags; 5338c2ecf20Sopenharmony_ci __ua_flags = uaccess_save_and_enable(); 5348c2ecf20Sopenharmony_ci n = arm_copy_to_user(to, from, n); 5358c2ecf20Sopenharmony_ci uaccess_restore(__ua_flags); 5368c2ecf20Sopenharmony_ci return n; 5378c2ecf20Sopenharmony_ci#else 5388c2ecf20Sopenharmony_ci return arm_copy_to_user(to, from, n); 5398c2ecf20Sopenharmony_ci#endif 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ciextern unsigned long __must_check 5438c2ecf20Sopenharmony_ciarm_clear_user(void __user *addr, unsigned long n); 5448c2ecf20Sopenharmony_ciextern unsigned long __must_check 5458c2ecf20Sopenharmony_ci__clear_user_std(void __user *addr, unsigned long n); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic inline unsigned long __must_check 5488c2ecf20Sopenharmony_ci__clear_user(void __user *addr, unsigned long n) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci unsigned int __ua_flags = uaccess_save_and_enable(); 5518c2ecf20Sopenharmony_ci n = arm_clear_user(addr, n); 5528c2ecf20Sopenharmony_ci uaccess_restore(__ua_flags); 5538c2ecf20Sopenharmony_ci return n; 5548c2ecf20Sopenharmony_ci} 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci#else 5578c2ecf20Sopenharmony_cistatic inline unsigned long 5588c2ecf20Sopenharmony_ciraw_copy_from_user(void *to, const void __user *from, unsigned long n) 5598c2ecf20Sopenharmony_ci{ 5608c2ecf20Sopenharmony_ci memcpy(to, (const void __force *)from, n); 5618c2ecf20Sopenharmony_ci return 0; 5628c2ecf20Sopenharmony_ci} 5638c2ecf20Sopenharmony_cistatic inline unsigned long 5648c2ecf20Sopenharmony_ciraw_copy_to_user(void __user *to, const void *from, unsigned long n) 5658c2ecf20Sopenharmony_ci{ 5668c2ecf20Sopenharmony_ci memcpy((void __force *)to, from, n); 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci#define __clear_user(addr, n) (memset((void __force *)addr, 0, n), 0) 5708c2ecf20Sopenharmony_ci#endif 5718c2ecf20Sopenharmony_ci#define INLINE_COPY_TO_USER 5728c2ecf20Sopenharmony_ci#define INLINE_COPY_FROM_USER 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_cistatic inline unsigned long __must_check clear_user(void __user *to, unsigned long n) 5758c2ecf20Sopenharmony_ci{ 5768c2ecf20Sopenharmony_ci if (access_ok(to, n)) 5778c2ecf20Sopenharmony_ci n = __clear_user(to, n); 5788c2ecf20Sopenharmony_ci return n; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci/* These are from lib/ code, and use __get_user() and friends */ 5828c2ecf20Sopenharmony_ciextern long strncpy_from_user(char *dest, const char __user *src, long count); 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ciextern __must_check long strnlen_user(const char __user *str, long n); 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci#endif /* _ASMARM_UACCESS_H */ 587