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