Christophe Leroy | 69795ca | 2019-04-18 16:51:18 +1000 | [diff] [blame] | 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | #ifndef _ASM_POWERPC_KUP_H_ |
| 3 | #define _ASM_POWERPC_KUP_H_ |
| 4 | |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 5 | #define KUAP_READ 1 |
| 6 | #define KUAP_WRITE 2 |
| 7 | #define KUAP_READ_WRITE (KUAP_READ | KUAP_WRITE) |
| 8 | |
Michael Ellerman | 178d52c | 2020-11-19 23:43:53 +1100 | [diff] [blame] | 9 | #ifdef CONFIG_PPC_BOOK3S_64 |
Aneesh Kumar K.V | 3b47b75 | 2020-11-27 10:14:07 +0530 | [diff] [blame] | 10 | #include <asm/book3s/64/kup.h> |
Michael Ellerman | 890274c | 2019-04-18 16:51:24 +1000 | [diff] [blame] | 11 | #endif |
Aneesh Kumar K.V | 3b47b75 | 2020-11-27 10:14:07 +0530 | [diff] [blame] | 12 | |
Christophe Leroy | 2679f9b | 2019-03-11 08:30:34 +0000 | [diff] [blame] | 13 | #ifdef CONFIG_PPC_8xx |
| 14 | #include <asm/nohash/32/kup-8xx.h> |
| 15 | #endif |
Aneesh Kumar K.V | 3b47b75 | 2020-11-27 10:14:07 +0530 | [diff] [blame] | 16 | |
Christophe Leroy | 43afcf8 | 2021-10-19 09:29:28 +0200 | [diff] [blame] | 17 | #ifdef CONFIG_BOOKE_OR_40x |
| 18 | #include <asm/nohash/kup-booke.h> |
| 19 | #endif |
| 20 | |
Christophe Leroy | 31ed2b1 | 2019-03-11 08:30:35 +0000 | [diff] [blame] | 21 | #ifdef CONFIG_PPC_BOOK3S_32 |
| 22 | #include <asm/book3s/32/kup.h> |
| 23 | #endif |
Michael Ellerman | 890274c | 2019-04-18 16:51:24 +1000 | [diff] [blame] | 24 | |
Christophe Leroy | e2fb9f5 | 2019-03-11 08:30:31 +0000 | [diff] [blame] | 25 | #ifdef __ASSEMBLY__ |
| 26 | #ifndef CONFIG_PPC_KUAP |
Michael Ellerman | 178d52c | 2020-11-19 23:43:53 +1100 | [diff] [blame] | 27 | .macro kuap_check_amr gpr1, gpr2 |
| 28 | .endm |
| 29 | |
Christophe Leroy | e2fb9f5 | 2019-03-11 08:30:31 +0000 | [diff] [blame] | 30 | #endif |
| 31 | |
| 32 | #else /* !__ASSEMBLY__ */ |
Christophe Leroy | 69795ca | 2019-04-18 16:51:18 +1000 | [diff] [blame] | 33 | |
Aneesh Kumar K.V | 61130e2 | 2020-12-02 10:08:54 +0530 | [diff] [blame] | 34 | extern bool disable_kuep; |
| 35 | extern bool disable_kuap; |
| 36 | |
Mike Rapoport | ca5999f | 2020-06-08 21:32:38 -0700 | [diff] [blame] | 37 | #include <linux/pgtable.h> |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 38 | |
Christophe Leroy | 6c1fa60 | 2021-10-19 09:29:12 +0200 | [diff] [blame] | 39 | void setup_kup(void); |
Christophe Leroy | 0fb1c25 | 2019-04-18 16:51:19 +1000 | [diff] [blame] | 40 | void setup_kuep(bool disabled); |
Christophe Leroy | 0fb1c25 | 2019-04-18 16:51:19 +1000 | [diff] [blame] | 41 | |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 42 | #ifdef CONFIG_PPC_KUAP |
| 43 | void setup_kuap(bool disabled); |
| 44 | #else |
| 45 | static inline void setup_kuap(bool disabled) { } |
Nicholas Piggin | 9a32a7e | 2020-11-17 16:59:13 +1100 | [diff] [blame] | 46 | |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 47 | static __always_inline bool kuap_is_disabled(void) { return true; } |
| 48 | |
Aneesh Kumar K.V | 475c874 | 2020-12-08 08:45:39 +0530 | [diff] [blame] | 49 | static inline bool |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 50 | __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write) |
Nicholas Piggin | 9a32a7e | 2020-11-17 16:59:13 +1100 | [diff] [blame] | 51 | { |
| 52 | return false; |
| 53 | } |
| 54 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 55 | static inline void __kuap_assert_locked(void) { } |
Christophe Leroy | 937fb70 | 2021-10-19 09:29:23 +0200 | [diff] [blame] | 56 | static inline void __kuap_lock(void) { } |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 57 | static inline void __kuap_save_and_lock(struct pt_regs *regs) { } |
Christophe Leroy | ad2d234 | 2021-03-12 12:50:48 +0000 | [diff] [blame] | 58 | static inline void kuap_user_restore(struct pt_regs *regs) { } |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 59 | static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) { } |
Christophe Leroy | ad2d234 | 2021-03-12 12:50:48 +0000 | [diff] [blame] | 60 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 61 | static inline unsigned long __kuap_get_and_assert_locked(void) |
Christophe Leroy | ad2d234 | 2021-03-12 12:50:48 +0000 | [diff] [blame] | 62 | { |
| 63 | return 0; |
| 64 | } |
Michael Ellerman | 178d52c | 2020-11-19 23:43:53 +1100 | [diff] [blame] | 65 | |
Nicholas Piggin | 9a32a7e | 2020-11-17 16:59:13 +1100 | [diff] [blame] | 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 | */ |
Michael Ellerman | 178d52c | 2020-11-19 23:43:53 +1100 | [diff] [blame] | 71 | #ifndef CONFIG_PPC_BOOK3S_64 |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 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) { } |
Michael Ellerman | 178d52c | 2020-11-19 23:43:53 +1100 | [diff] [blame] | 77 | #endif /* CONFIG_PPC_BOOK3S_64 */ |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 78 | #endif /* CONFIG_PPC_KUAP */ |
| 79 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 80 | static __always_inline bool |
| 81 | bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write) |
| 82 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 83 | if (kuap_is_disabled()) |
| 84 | return false; |
| 85 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 86 | return __bad_kuap_fault(regs, address, is_write); |
| 87 | } |
| 88 | |
| 89 | static __always_inline void kuap_assert_locked(void) |
| 90 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 91 | if (kuap_is_disabled()) |
| 92 | return; |
| 93 | |
Christophe Leroy | 2341964 | 2021-10-19 09:29:22 +0200 | [diff] [blame] | 94 | if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) |
| 95 | __kuap_get_and_assert_locked(); |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 96 | } |
| 97 | |
Christophe Leroy | 937fb70 | 2021-10-19 09:29:23 +0200 | [diff] [blame] | 98 | static __always_inline void kuap_lock(void) |
| 99 | { |
| 100 | if (kuap_is_disabled()) |
| 101 | return; |
| 102 | |
| 103 | __kuap_lock(); |
| 104 | } |
| 105 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 106 | static __always_inline void kuap_save_and_lock(struct pt_regs *regs) |
| 107 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 108 | if (kuap_is_disabled()) |
| 109 | return; |
| 110 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 111 | __kuap_save_and_lock(regs); |
| 112 | } |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 113 | |
| 114 | static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned long amr) |
| 115 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 116 | if (kuap_is_disabled()) |
| 117 | return; |
| 118 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 119 | __kuap_kernel_restore(regs, amr); |
| 120 | } |
| 121 | |
| 122 | static __always_inline unsigned long kuap_get_and_assert_locked(void) |
| 123 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 124 | if (kuap_is_disabled()) |
| 125 | return 0; |
| 126 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 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 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 134 | if (kuap_is_disabled()) |
| 135 | return; |
| 136 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 137 | __allow_user_access(to, from, size, dir); |
| 138 | } |
| 139 | |
| 140 | static __always_inline void prevent_user_access(unsigned long dir) |
| 141 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 142 | if (kuap_is_disabled()) |
| 143 | return; |
| 144 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 145 | __prevent_user_access(dir); |
| 146 | } |
| 147 | |
| 148 | static __always_inline unsigned long prevent_user_access_return(void) |
| 149 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 150 | if (kuap_is_disabled()) |
| 151 | return 0; |
| 152 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 153 | return __prevent_user_access_return(); |
| 154 | } |
| 155 | |
| 156 | static __always_inline void restore_user_access(unsigned long flags) |
| 157 | { |
Christophe Leroy | c252f38 | 2021-10-19 09:29:21 +0200 | [diff] [blame] | 158 | if (kuap_is_disabled()) |
| 159 | return; |
| 160 | |
Christophe Leroy | ba454f9 | 2021-10-19 09:29:20 +0200 | [diff] [blame] | 161 | __restore_user_access(flags); |
| 162 | } |
| 163 | #endif /* CONFIG_PPC_BOOK3S_64 */ |
| 164 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 165 | static __always_inline void allow_read_from_user(const void __user *from, unsigned long size) |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 166 | { |
Christophe Leroy | 8524e2e | 2021-02-07 10:08:11 +0000 | [diff] [blame] | 167 | barrier_nospec(); |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 168 | allow_user_access(NULL, from, size, KUAP_READ); |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 169 | } |
| 170 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 171 | static __always_inline void allow_write_to_user(void __user *to, unsigned long size) |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 172 | { |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 173 | allow_user_access(to, NULL, size, KUAP_WRITE); |
| 174 | } |
| 175 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 176 | static __always_inline void allow_read_write_user(void __user *to, const void __user *from, |
| 177 | unsigned long size) |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 178 | { |
Christophe Leroy | 8524e2e | 2021-02-07 10:08:11 +0000 | [diff] [blame] | 179 | barrier_nospec(); |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 180 | allow_user_access(to, from, size, KUAP_READ_WRITE); |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 181 | } |
| 182 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 183 | static __always_inline void prevent_read_from_user(const void __user *from, unsigned long size) |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 184 | { |
Christophe Leroy | cb2f1fb | 2021-06-03 08:41:48 +0000 | [diff] [blame] | 185 | prevent_user_access(KUAP_READ); |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 186 | } |
| 187 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 188 | static __always_inline void prevent_write_to_user(void __user *to, unsigned long size) |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 189 | { |
Christophe Leroy | cb2f1fb | 2021-06-03 08:41:48 +0000 | [diff] [blame] | 190 | prevent_user_access(KUAP_WRITE); |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 191 | } |
| 192 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 193 | static __always_inline void prevent_read_write_user(void __user *to, const void __user *from, |
| 194 | unsigned long size) |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 195 | { |
Christophe Leroy | cb2f1fb | 2021-06-03 08:41:48 +0000 | [diff] [blame] | 196 | prevent_user_access(KUAP_READ_WRITE); |
Christophe Leroy | de78a9c | 2019-04-18 16:51:20 +1000 | [diff] [blame] | 197 | } |
| 198 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 199 | static __always_inline void prevent_current_access_user(void) |
Christophe Leroy | bedb4db | 2020-01-24 11:54:43 +0000 | [diff] [blame] | 200 | { |
Christophe Leroy | cb2f1fb | 2021-06-03 08:41:48 +0000 | [diff] [blame] | 201 | prevent_user_access(KUAP_READ_WRITE); |
Christophe Leroy | bedb4db | 2020-01-24 11:54:43 +0000 | [diff] [blame] | 202 | } |
| 203 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 204 | static __always_inline void prevent_current_read_from_user(void) |
Christophe Leroy | 4fe5cda | 2020-04-03 07:20:53 +0000 | [diff] [blame] | 205 | { |
Christophe Leroy | cb2f1fb | 2021-06-03 08:41:48 +0000 | [diff] [blame] | 206 | prevent_user_access(KUAP_READ); |
Christophe Leroy | 4fe5cda | 2020-04-03 07:20:53 +0000 | [diff] [blame] | 207 | } |
| 208 | |
Christophe Leroy | 240efd7 | 2021-06-03 09:13:54 +0000 | [diff] [blame] | 209 | static __always_inline void prevent_current_write_to_user(void) |
Christophe Leroy | 4fe5cda | 2020-04-03 07:20:53 +0000 | [diff] [blame] | 210 | { |
Christophe Leroy | cb2f1fb | 2021-06-03 08:41:48 +0000 | [diff] [blame] | 211 | prevent_user_access(KUAP_WRITE); |
Christophe Leroy | 4fe5cda | 2020-04-03 07:20:53 +0000 | [diff] [blame] | 212 | } |
| 213 | |
Christophe Leroy | 69795ca | 2019-04-18 16:51:18 +1000 | [diff] [blame] | 214 | #endif /* !__ASSEMBLY__ */ |
| 215 | |
Christophe Leroy | 1d8f739 | 2020-01-24 11:54:41 +0000 | [diff] [blame] | 216 | #endif /* _ASM_POWERPC_KUAP_H_ */ |