xref: /openbmc/linux/arch/powerpc/include/asm/kup.h (revision 20e8ef5c)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _ASM_POWERPC_KUP_H_
3 #define _ASM_POWERPC_KUP_H_
4 
5 #define KUAP_READ	1
6 #define KUAP_WRITE	2
7 #define KUAP_READ_WRITE	(KUAP_READ | KUAP_WRITE)
8 
9 #ifdef CONFIG_PPC_BOOK3S_64
10 #include <asm/book3s/64/kup.h>
11 #endif
12 
13 #ifdef CONFIG_PPC_8xx
14 #include <asm/nohash/32/kup-8xx.h>
15 #endif
16 
17 #ifdef CONFIG_BOOKE_OR_40x
18 #include <asm/nohash/kup-booke.h>
19 #endif
20 
21 #ifdef CONFIG_PPC_BOOK3S_32
22 #include <asm/book3s/32/kup.h>
23 #endif
24 
25 #ifdef __ASSEMBLY__
26 #ifndef CONFIG_PPC_KUAP
27 .macro kuap_check_amr	gpr1, gpr2
28 .endm
29 
30 #endif
31 
32 #else /* !__ASSEMBLY__ */
33 
34 extern bool disable_kuep;
35 extern bool disable_kuap;
36 
37 #include <linux/pgtable.h>
38 
39 void setup_kup(void);
40 void setup_kuep(bool disabled);
41 
42 #ifdef CONFIG_PPC_KUAP
43 void setup_kuap(bool disabled);
44 #else
45 static inline void setup_kuap(bool disabled) { }
46 
47 static __always_inline bool kuap_is_disabled(void) { return true; }
48 
49 static inline bool
50 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
51 {
52 	return false;
53 }
54 
55 static inline void __kuap_assert_locked(void) { }
56 static inline void __kuap_lock(void) { }
57 static inline void __kuap_save_and_lock(struct pt_regs *regs) { }
58 static inline void kuap_user_restore(struct pt_regs *regs) { }
59 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { }
60 
61 static inline unsigned long __kuap_get_and_assert_locked(void)
62 {
63 	return 0;
64 }
65 
66 /*
67  * book3s/64/kup-radix.h defines these functions for the !KUAP case to flush
68  * the L1D cache after user accesses. Only include the empty stubs for other
69  * platforms.
70  */
71 #ifndef CONFIG_PPC_BOOK3S_64
72 static inline void __allow_user_access(void __user *to, const void __user *from,
73 				       unsigned long size, unsigned long dir) { }
74 static inline void __prevent_user_access(unsigned long dir) { }
75 static inline unsigned long __prevent_user_access_return(void) { return 0UL; }
76 static inline void __restore_user_access(unsigned long flags) { }
77 #endif /* CONFIG_PPC_BOOK3S_64 */
78 #endif /* CONFIG_PPC_KUAP */
79 
80 static __always_inline bool
81 bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
82 {
83 	if (kuap_is_disabled())
84 		return false;
85 
86 	return __bad_kuap_fault(regs, address, is_write);
87 }
88 
89 static __always_inline void kuap_assert_locked(void)
90 {
91 	if (kuap_is_disabled())
92 		return;
93 
94 	if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
95 		__kuap_get_and_assert_locked();
96 }
97 
98 static __always_inline void kuap_lock(void)
99 {
100 	if (kuap_is_disabled())
101 		return;
102 
103 	__kuap_lock();
104 }
105 
106 static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
107 {
108 	if (kuap_is_disabled())
109 		return;
110 
111 	__kuap_save_and_lock(regs);
112 }
113 
114 static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr)
115 {
116 	if (kuap_is_disabled())
117 		return;
118 
119 	__kuap_kernel_restore(regs, amr);
120 }
121 
122 static __always_inline unsigned long kuap_get_and_assert_locked(void)
123 {
124 	if (kuap_is_disabled())
125 		return 0;
126 
127 	return __kuap_get_and_assert_locked();
128 }
129 
130 #ifndef CONFIG_PPC_BOOK3S_64
131 static __always_inline void allow_user_access(void __user *to, const void __user *from,
132 				     unsigned long size, unsigned long dir)
133 {
134 	if (kuap_is_disabled())
135 		return;
136 
137 	__allow_user_access(to, from, size, dir);
138 }
139 
140 static __always_inline void prevent_user_access(unsigned long dir)
141 {
142 	if (kuap_is_disabled())
143 		return;
144 
145 	__prevent_user_access(dir);
146 }
147 
148 static __always_inline unsigned long prevent_user_access_return(void)
149 {
150 	if (kuap_is_disabled())
151 		return 0;
152 
153 	return __prevent_user_access_return();
154 }
155 
156 static __always_inline void restore_user_access(unsigned long flags)
157 {
158 	if (kuap_is_disabled())
159 		return;
160 
161 	__restore_user_access(flags);
162 }
163 #endif /* CONFIG_PPC_BOOK3S_64 */
164 
165 static __always_inline void allow_read_from_user(const void __user *from, unsigned long size)
166 {
167 	barrier_nospec();
168 	allow_user_access(NULL, from, size, KUAP_READ);
169 }
170 
171 static __always_inline void allow_write_to_user(void __user *to, unsigned long size)
172 {
173 	allow_user_access(to, NULL, size, KUAP_WRITE);
174 }
175 
176 static __always_inline void allow_read_write_user(void __user *to, const void __user *from,
177 						  unsigned long size)
178 {
179 	barrier_nospec();
180 	allow_user_access(to, from, size, KUAP_READ_WRITE);
181 }
182 
183 static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size)
184 {
185 	prevent_user_access(KUAP_READ);
186 }
187 
188 static __always_inline void prevent_write_to_user(void __user *to, unsigned long size)
189 {
190 	prevent_user_access(KUAP_WRITE);
191 }
192 
193 static __always_inline void prevent_read_write_user(void __user *to, const void __user *from,
194 						    unsigned long size)
195 {
196 	prevent_user_access(KUAP_READ_WRITE);
197 }
198 
199 static __always_inline void prevent_current_access_user(void)
200 {
201 	prevent_user_access(KUAP_READ_WRITE);
202 }
203 
204 static __always_inline void prevent_current_read_from_user(void)
205 {
206 	prevent_user_access(KUAP_READ);
207 }
208 
209 static __always_inline void prevent_current_write_to_user(void)
210 {
211 	prevent_user_access(KUAP_WRITE);
212 }
213 
214 #endif /* !__ASSEMBLY__ */
215 
216 #endif /* _ASM_POWERPC_KUAP_H_ */
217