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_lock(void) { } 56 static inline void __kuap_save_and_lock(struct pt_regs *regs) { } 57 static inline void kuap_user_restore(struct pt_regs *regs) { } 58 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { } 59 60 static inline unsigned long __kuap_get_and_assert_locked(void) 61 { 62 return 0; 63 } 64 65 /* 66 * book3s/64/kup-radix.h defines these functions for the !KUAP case to flush 67 * the L1D cache after user accesses. Only include the empty stubs for other 68 * platforms. 69 */ 70 #ifndef CONFIG_PPC_BOOK3S_64 71 static inline void __allow_user_access(void __user *to, const void __user *from, 72 unsigned long size, unsigned long dir) { } 73 static inline void __prevent_user_access(unsigned long dir) { } 74 static inline unsigned long __prevent_user_access_return(void) { return 0UL; } 75 static inline void __restore_user_access(unsigned long flags) { } 76 #endif /* CONFIG_PPC_BOOK3S_64 */ 77 #endif /* CONFIG_PPC_KUAP */ 78 79 static __always_inline bool 80 bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write) 81 { 82 if (kuap_is_disabled()) 83 return false; 84 85 return __bad_kuap_fault(regs, address, is_write); 86 } 87 88 static __always_inline void kuap_assert_locked(void) 89 { 90 if (kuap_is_disabled()) 91 return; 92 93 if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) 94 __kuap_get_and_assert_locked(); 95 } 96 97 static __always_inline void kuap_lock(void) 98 { 99 if (kuap_is_disabled()) 100 return; 101 102 __kuap_lock(); 103 } 104 105 static __always_inline void kuap_save_and_lock(struct pt_regs *regs) 106 { 107 if (kuap_is_disabled()) 108 return; 109 110 __kuap_save_and_lock(regs); 111 } 112 113 static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) 114 { 115 if (kuap_is_disabled()) 116 return; 117 118 __kuap_kernel_restore(regs, amr); 119 } 120 121 static __always_inline unsigned long kuap_get_and_assert_locked(void) 122 { 123 if (kuap_is_disabled()) 124 return 0; 125 126 return __kuap_get_and_assert_locked(); 127 } 128 129 #ifndef CONFIG_PPC_BOOK3S_64 130 static __always_inline void allow_user_access(void __user *to, const void __user *from, 131 unsigned long size, unsigned long dir) 132 { 133 if (kuap_is_disabled()) 134 return; 135 136 __allow_user_access(to, from, size, dir); 137 } 138 139 static __always_inline void prevent_user_access(unsigned long dir) 140 { 141 if (kuap_is_disabled()) 142 return; 143 144 __prevent_user_access(dir); 145 } 146 147 static __always_inline unsigned long prevent_user_access_return(void) 148 { 149 if (kuap_is_disabled()) 150 return 0; 151 152 return __prevent_user_access_return(); 153 } 154 155 static __always_inline void restore_user_access(unsigned long flags) 156 { 157 if (kuap_is_disabled()) 158 return; 159 160 __restore_user_access(flags); 161 } 162 #endif /* CONFIG_PPC_BOOK3S_64 */ 163 164 static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) 165 { 166 barrier_nospec(); 167 allow_user_access(NULL, from, size, KUAP_READ); 168 } 169 170 static __always_inline void allow_write_to_user(void __user *to, unsigned long size) 171 { 172 allow_user_access(to, NULL, size, KUAP_WRITE); 173 } 174 175 static __always_inline void allow_read_write_user(void __user *to, const void __user *from, 176 unsigned long size) 177 { 178 barrier_nospec(); 179 allow_user_access(to, from, size, KUAP_READ_WRITE); 180 } 181 182 static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size) 183 { 184 prevent_user_access(KUAP_READ); 185 } 186 187 static __always_inline void prevent_write_to_user(void __user *to, unsigned long size) 188 { 189 prevent_user_access(KUAP_WRITE); 190 } 191 192 static __always_inline void prevent_read_write_user(void __user *to, const void __user *from, 193 unsigned long size) 194 { 195 prevent_user_access(KUAP_READ_WRITE); 196 } 197 198 static __always_inline void prevent_current_access_user(void) 199 { 200 prevent_user_access(KUAP_READ_WRITE); 201 } 202 203 static __always_inline void prevent_current_read_from_user(void) 204 { 205 prevent_user_access(KUAP_READ); 206 } 207 208 static __always_inline void prevent_current_write_to_user(void) 209 { 210 prevent_user_access(KUAP_WRITE); 211 } 212 213 #endif /* !__ASSEMBLY__ */ 214 215 #endif /* _ASM_POWERPC_KUAP_H_ */ 216