0001
0002 #ifndef _ASM_POWERPC_BOOK3S_32_KUP_H
0003 #define _ASM_POWERPC_BOOK3S_32_KUP_H
0004
0005 #include <asm/bug.h>
0006 #include <asm/book3s/32/mmu-hash.h>
0007 #include <asm/mmu.h>
0008 #include <asm/synch.h>
0009
0010 #ifndef __ASSEMBLY__
0011
0012 #include <linux/jump_label.h>
0013
0014 extern struct static_key_false disable_kuap_key;
0015
0016 static __always_inline bool kuep_is_disabled(void)
0017 {
0018 return !IS_ENABLED(CONFIG_PPC_KUEP);
0019 }
0020
0021 #ifdef CONFIG_PPC_KUAP
0022
0023 #include <linux/sched.h>
0024
0025 #define KUAP_NONE (~0UL)
0026 #define KUAP_ALL (~1UL)
0027
0028 static __always_inline bool kuap_is_disabled(void)
0029 {
0030 return static_branch_unlikely(&disable_kuap_key);
0031 }
0032
0033 static inline void kuap_lock_one(unsigned long addr)
0034 {
0035 mtsr(mfsr(addr) | SR_KS, addr);
0036 isync();
0037 }
0038
0039 static inline void kuap_unlock_one(unsigned long addr)
0040 {
0041 mtsr(mfsr(addr) & ~SR_KS, addr);
0042 isync();
0043 }
0044
0045 static inline void kuap_lock_all(void)
0046 {
0047 update_user_segments(mfsr(0) | SR_KS);
0048 isync();
0049 }
0050
0051 static inline void kuap_unlock_all(void)
0052 {
0053 update_user_segments(mfsr(0) & ~SR_KS);
0054 isync();
0055 }
0056
0057 void kuap_lock_all_ool(void);
0058 void kuap_unlock_all_ool(void);
0059
0060 static inline void kuap_lock_addr(unsigned long addr, bool ool)
0061 {
0062 if (likely(addr != KUAP_ALL))
0063 kuap_lock_one(addr);
0064 else if (!ool)
0065 kuap_lock_all();
0066 else
0067 kuap_lock_all_ool();
0068 }
0069
0070 static inline void kuap_unlock(unsigned long addr, bool ool)
0071 {
0072 if (likely(addr != KUAP_ALL))
0073 kuap_unlock_one(addr);
0074 else if (!ool)
0075 kuap_unlock_all();
0076 else
0077 kuap_unlock_all_ool();
0078 }
0079
0080 static inline void __kuap_lock(void)
0081 {
0082 }
0083
0084 static inline void __kuap_save_and_lock(struct pt_regs *regs)
0085 {
0086 unsigned long kuap = current->thread.kuap;
0087
0088 regs->kuap = kuap;
0089 if (unlikely(kuap == KUAP_NONE))
0090 return;
0091
0092 current->thread.kuap = KUAP_NONE;
0093 kuap_lock_addr(kuap, false);
0094 }
0095
0096 static inline void kuap_user_restore(struct pt_regs *regs)
0097 {
0098 }
0099
0100 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long kuap)
0101 {
0102 if (unlikely(kuap != KUAP_NONE)) {
0103 current->thread.kuap = KUAP_NONE;
0104 kuap_lock_addr(kuap, false);
0105 }
0106
0107 if (likely(regs->kuap == KUAP_NONE))
0108 return;
0109
0110 current->thread.kuap = regs->kuap;
0111
0112 kuap_unlock(regs->kuap, false);
0113 }
0114
0115 static inline unsigned long __kuap_get_and_assert_locked(void)
0116 {
0117 unsigned long kuap = current->thread.kuap;
0118
0119 WARN_ON_ONCE(IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && kuap != KUAP_NONE);
0120
0121 return kuap;
0122 }
0123
0124 static __always_inline void __allow_user_access(void __user *to, const void __user *from,
0125 u32 size, unsigned long dir)
0126 {
0127 BUILD_BUG_ON(!__builtin_constant_p(dir));
0128
0129 if (!(dir & KUAP_WRITE))
0130 return;
0131
0132 current->thread.kuap = (__force u32)to;
0133 kuap_unlock_one((__force u32)to);
0134 }
0135
0136 static __always_inline void __prevent_user_access(unsigned long dir)
0137 {
0138 u32 kuap = current->thread.kuap;
0139
0140 BUILD_BUG_ON(!__builtin_constant_p(dir));
0141
0142 if (!(dir & KUAP_WRITE))
0143 return;
0144
0145 current->thread.kuap = KUAP_NONE;
0146 kuap_lock_addr(kuap, true);
0147 }
0148
0149 static inline unsigned long __prevent_user_access_return(void)
0150 {
0151 unsigned long flags = current->thread.kuap;
0152
0153 if (flags != KUAP_NONE) {
0154 current->thread.kuap = KUAP_NONE;
0155 kuap_lock_addr(flags, true);
0156 }
0157
0158 return flags;
0159 }
0160
0161 static inline void __restore_user_access(unsigned long flags)
0162 {
0163 if (flags != KUAP_NONE) {
0164 current->thread.kuap = flags;
0165 kuap_unlock(flags, true);
0166 }
0167 }
0168
0169 static inline bool
0170 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
0171 {
0172 unsigned long kuap = regs->kuap;
0173
0174 if (!is_write || kuap == KUAP_ALL)
0175 return false;
0176 if (kuap == KUAP_NONE)
0177 return true;
0178
0179
0180 if ((kuap ^ address) & 0xf0000000)
0181 regs->kuap = KUAP_ALL;
0182
0183 return false;
0184 }
0185
0186 #endif
0187
0188 #endif
0189
0190 #endif