at v4.17-rc2 228 lines 5.3 kB view raw
1/* SPDX-License-Identifier: GPL-2.0 */ 2#ifndef __ASM_GENERIC_UACCESS_H 3#define __ASM_GENERIC_UACCESS_H 4 5/* 6 * User space memory access functions, these should work 7 * on any machine that has kernel and user data in the same 8 * address space, e.g. all NOMMU machines. 9 */ 10#include <linux/string.h> 11 12#include <asm/segment.h> 13 14#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) 15 16#ifndef KERNEL_DS 17#define KERNEL_DS MAKE_MM_SEG(~0UL) 18#endif 19 20#ifndef USER_DS 21#define USER_DS MAKE_MM_SEG(TASK_SIZE - 1) 22#endif 23 24#ifndef get_fs 25#define get_ds() (KERNEL_DS) 26#define get_fs() (current_thread_info()->addr_limit) 27 28static inline void set_fs(mm_segment_t fs) 29{ 30 current_thread_info()->addr_limit = fs; 31} 32#endif 33 34#ifndef segment_eq 35#define segment_eq(a, b) ((a).seg == (b).seg) 36#endif 37 38#define access_ok(type, addr, size) __access_ok((unsigned long)(addr),(size)) 39 40/* 41 * The architecture should really override this if possible, at least 42 * doing a check on the get_fs() 43 */ 44#ifndef __access_ok 45static inline int __access_ok(unsigned long addr, unsigned long size) 46{ 47 return 1; 48} 49#endif 50 51/* 52 * These are the main single-value transfer routines. They automatically 53 * use the right size if we just have the right pointer type. 54 * This version just falls back to copy_{from,to}_user, which should 55 * provide a fast-path for small values. 56 */ 57#define __put_user(x, ptr) \ 58({ \ 59 __typeof__(*(ptr)) __x = (x); \ 60 int __pu_err = -EFAULT; \ 61 __chk_user_ptr(ptr); \ 62 switch (sizeof (*(ptr))) { \ 63 case 1: \ 64 case 2: \ 65 case 4: \ 66 case 8: \ 67 __pu_err = __put_user_fn(sizeof (*(ptr)), \ 68 ptr, &__x); \ 69 break; \ 70 default: \ 71 __put_user_bad(); \ 72 break; \ 73 } \ 74 __pu_err; \ 75}) 76 77#define put_user(x, ptr) \ 78({ \ 79 void __user *__p = (ptr); \ 80 might_fault(); \ 81 access_ok(VERIFY_WRITE, __p, sizeof(*ptr)) ? \ 82 __put_user((x), ((__typeof__(*(ptr)) __user *)__p)) : \ 83 -EFAULT; \ 84}) 85 86#ifndef __put_user_fn 87 88static inline int __put_user_fn(size_t size, void __user *ptr, void *x) 89{ 90 return unlikely(raw_copy_to_user(ptr, x, size)) ? -EFAULT : 0; 91} 92 93#define __put_user_fn(sz, u, k) __put_user_fn(sz, u, k) 94 95#endif 96 97extern int __put_user_bad(void) __attribute__((noreturn)); 98 99#define __get_user(x, ptr) \ 100({ \ 101 int __gu_err = -EFAULT; \ 102 __chk_user_ptr(ptr); \ 103 switch (sizeof(*(ptr))) { \ 104 case 1: { \ 105 unsigned char __x = 0; \ 106 __gu_err = __get_user_fn(sizeof (*(ptr)), \ 107 ptr, &__x); \ 108 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 109 break; \ 110 }; \ 111 case 2: { \ 112 unsigned short __x = 0; \ 113 __gu_err = __get_user_fn(sizeof (*(ptr)), \ 114 ptr, &__x); \ 115 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 116 break; \ 117 }; \ 118 case 4: { \ 119 unsigned int __x = 0; \ 120 __gu_err = __get_user_fn(sizeof (*(ptr)), \ 121 ptr, &__x); \ 122 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 123 break; \ 124 }; \ 125 case 8: { \ 126 unsigned long long __x = 0; \ 127 __gu_err = __get_user_fn(sizeof (*(ptr)), \ 128 ptr, &__x); \ 129 (x) = *(__force __typeof__(*(ptr)) *) &__x; \ 130 break; \ 131 }; \ 132 default: \ 133 __get_user_bad(); \ 134 break; \ 135 } \ 136 __gu_err; \ 137}) 138 139#define get_user(x, ptr) \ 140({ \ 141 const void __user *__p = (ptr); \ 142 might_fault(); \ 143 access_ok(VERIFY_READ, __p, sizeof(*ptr)) ? \ 144 __get_user((x), (__typeof__(*(ptr)) __user *)__p) :\ 145 ((x) = (__typeof__(*(ptr)))0,-EFAULT); \ 146}) 147 148#ifndef __get_user_fn 149static inline int __get_user_fn(size_t size, const void __user *ptr, void *x) 150{ 151 return unlikely(raw_copy_from_user(x, ptr, size)) ? -EFAULT : 0; 152} 153 154#define __get_user_fn(sz, u, k) __get_user_fn(sz, u, k) 155 156#endif 157 158extern int __get_user_bad(void) __attribute__((noreturn)); 159 160/* 161 * Copy a null terminated string from userspace. 162 */ 163#ifndef __strncpy_from_user 164static inline long 165__strncpy_from_user(char *dst, const char __user *src, long count) 166{ 167 char *tmp; 168 strncpy(dst, (const char __force *)src, count); 169 for (tmp = dst; *tmp && count > 0; tmp++, count--) 170 ; 171 return (tmp - dst); 172} 173#endif 174 175static inline long 176strncpy_from_user(char *dst, const char __user *src, long count) 177{ 178 if (!access_ok(VERIFY_READ, src, 1)) 179 return -EFAULT; 180 return __strncpy_from_user(dst, src, count); 181} 182 183/* 184 * Return the size of a string (including the ending 0) 185 * 186 * Return 0 on exception, a value greater than N if too long 187 */ 188#ifndef __strnlen_user 189#define __strnlen_user(s, n) (strnlen((s), (n)) + 1) 190#endif 191 192/* 193 * Unlike strnlen, strnlen_user includes the nul terminator in 194 * its returned count. Callers should check for a returned value 195 * greater than N as an indication the string is too long. 196 */ 197static inline long strnlen_user(const char __user *src, long n) 198{ 199 if (!access_ok(VERIFY_READ, src, 1)) 200 return 0; 201 return __strnlen_user(src, n); 202} 203 204/* 205 * Zero Userspace 206 */ 207#ifndef __clear_user 208static inline __must_check unsigned long 209__clear_user(void __user *to, unsigned long n) 210{ 211 memset((void __force *)to, 0, n); 212 return 0; 213} 214#endif 215 216static inline __must_check unsigned long 217clear_user(void __user *to, unsigned long n) 218{ 219 might_fault(); 220 if (!access_ok(VERIFY_WRITE, to, n)) 221 return n; 222 223 return __clear_user(to, n); 224} 225 226#include <asm/extable.h> 227 228#endif /* __ASM_GENERIC_UACCESS_H */