xref: /linux/arch/x86/include/asm/uaccess_64.h (revision 1e525507)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_X86_UACCESS_64_H
3 #define _ASM_X86_UACCESS_64_H
4 
5 /*
6  * User space memory access functions
7  */
8 #include <linux/compiler.h>
9 #include <linux/lockdep.h>
10 #include <linux/kasan-checks.h>
11 #include <asm/alternative.h>
12 #include <asm/cpufeatures.h>
13 #include <asm/page.h>
14 #include <asm/percpu.h>
15 
16 #ifdef CONFIG_ADDRESS_MASKING
17 /*
18  * Mask out tag bits from the address.
19  */
20 static inline unsigned long __untagged_addr(unsigned long addr)
21 {
22 	asm (ALTERNATIVE("",
23 			 "and " __percpu_arg([mask]) ", %[addr]", X86_FEATURE_LAM)
24 	     : [addr] "+r" (addr)
25 	     : [mask] "m" (__my_cpu_var(tlbstate_untag_mask)));
26 
27 	return addr;
28 }
29 
30 #define untagged_addr(addr)	({					\
31 	unsigned long __addr = (__force unsigned long)(addr);		\
32 	(__force __typeof__(addr))__untagged_addr(__addr);		\
33 })
34 
35 static inline unsigned long __untagged_addr_remote(struct mm_struct *mm,
36 						   unsigned long addr)
37 {
38 	mmap_assert_locked(mm);
39 	return addr & (mm)->context.untag_mask;
40 }
41 
42 #define untagged_addr_remote(mm, addr)	({				\
43 	unsigned long __addr = (__force unsigned long)(addr);		\
44 	(__force __typeof__(addr))__untagged_addr_remote(mm, __addr);	\
45 })
46 
47 #endif
48 
49 /*
50  * The virtual address space space is logically divided into a kernel
51  * half and a user half.  When cast to a signed type, user pointers
52  * are positive and kernel pointers are negative.
53  */
54 #define valid_user_address(x) ((__force long)(x) >= 0)
55 
56 /*
57  * User pointers can have tag bits on x86-64.  This scheme tolerates
58  * arbitrary values in those bits rather then masking them off.
59  *
60  * Enforce two rules:
61  * 1. 'ptr' must be in the user half of the address space
62  * 2. 'ptr+size' must not overflow into kernel addresses
63  *
64  * Note that addresses around the sign change are not valid addresses,
65  * and will GP-fault even with LAM enabled if the sign bit is set (see
66  * "CR3.LAM_SUP" that can narrow the canonicality check if we ever
67  * enable it, but not remove it entirely).
68  *
69  * So the "overflow into kernel addresses" does not imply some sudden
70  * exact boundary at the sign bit, and we can allow a lot of slop on the
71  * size check.
72  *
73  * In fact, we could probably remove the size check entirely, since
74  * any kernel accesses will be in increasing address order starting
75  * at 'ptr', and even if the end might be in kernel space, we'll
76  * hit the GP faults for non-canonical accesses before we ever get
77  * there.
78  *
79  * That's a separate optimization, for now just handle the small
80  * constant case.
81  */
82 static inline bool __access_ok(const void __user *ptr, unsigned long size)
83 {
84 	if (__builtin_constant_p(size <= PAGE_SIZE) && size <= PAGE_SIZE) {
85 		return valid_user_address(ptr);
86 	} else {
87 		unsigned long sum = size + (__force unsigned long)ptr;
88 
89 		return valid_user_address(sum) && sum >= (__force unsigned long)ptr;
90 	}
91 }
92 #define __access_ok __access_ok
93 
94 /*
95  * Copy To/From Userspace
96  */
97 
98 /* Handles exceptions in both to and from, but doesn't do access_ok */
99 __must_check unsigned long
100 rep_movs_alternative(void *to, const void *from, unsigned len);
101 
102 static __always_inline __must_check unsigned long
103 copy_user_generic(void *to, const void *from, unsigned long len)
104 {
105 	stac();
106 	/*
107 	 * If CPU has FSRM feature, use 'rep movs'.
108 	 * Otherwise, use rep_movs_alternative.
109 	 */
110 	asm volatile(
111 		"1:\n\t"
112 		ALTERNATIVE("rep movsb",
113 			    "call rep_movs_alternative", ALT_NOT(X86_FEATURE_FSRM))
114 		"2:\n"
115 		_ASM_EXTABLE_UA(1b, 2b)
116 		:"+c" (len), "+D" (to), "+S" (from), ASM_CALL_CONSTRAINT
117 		: : "memory", "rax");
118 	clac();
119 	return len;
120 }
121 
122 static __always_inline __must_check unsigned long
123 raw_copy_from_user(void *dst, const void __user *src, unsigned long size)
124 {
125 	return copy_user_generic(dst, (__force void *)src, size);
126 }
127 
128 static __always_inline __must_check unsigned long
129 raw_copy_to_user(void __user *dst, const void *src, unsigned long size)
130 {
131 	return copy_user_generic((__force void *)dst, src, size);
132 }
133 
134 extern long __copy_user_nocache(void *dst, const void __user *src, unsigned size);
135 extern long __copy_user_flushcache(void *dst, const void __user *src, unsigned size);
136 
137 static inline int
138 __copy_from_user_inatomic_nocache(void *dst, const void __user *src,
139 				  unsigned size)
140 {
141 	long ret;
142 	kasan_check_write(dst, size);
143 	stac();
144 	ret = __copy_user_nocache(dst, src, size);
145 	clac();
146 	return ret;
147 }
148 
149 static inline int
150 __copy_from_user_flushcache(void *dst, const void __user *src, unsigned size)
151 {
152 	kasan_check_write(dst, size);
153 	return __copy_user_flushcache(dst, src, size);
154 }
155 
156 /*
157  * Zero Userspace.
158  */
159 
160 __must_check unsigned long
161 rep_stos_alternative(void __user *addr, unsigned long len);
162 
163 static __always_inline __must_check unsigned long __clear_user(void __user *addr, unsigned long size)
164 {
165 	might_fault();
166 	stac();
167 
168 	/*
169 	 * No memory constraint because it doesn't change any memory gcc
170 	 * knows about.
171 	 */
172 	asm volatile(
173 		"1:\n\t"
174 		ALTERNATIVE("rep stosb",
175 			    "call rep_stos_alternative", ALT_NOT(X86_FEATURE_FSRS))
176 		"2:\n"
177 	       _ASM_EXTABLE_UA(1b, 2b)
178 	       : "+c" (size), "+D" (addr), ASM_CALL_CONSTRAINT
179 	       : "a" (0));
180 
181 	clac();
182 
183 	return size;
184 }
185 
186 static __always_inline unsigned long clear_user(void __user *to, unsigned long n)
187 {
188 	if (__access_ok(to, n))
189 		return __clear_user(to, n);
190 	return n;
191 }
192 #endif /* _ASM_X86_UACCESS_64_H */
193