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