Back to home page

OSCL-LXR

 
 

    


0001 /* SPDX-License-Identifier: GPL-2.0 */
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();    /* Context sync required after mtsr() */
0037 }
0038 
0039 static inline void kuap_unlock_one(unsigned long addr)
0040 {
0041     mtsr(mfsr(addr) & ~SR_KS, addr);
0042     isync();    /* Context sync required after mtsr() */
0043 }
0044 
0045 static inline void kuap_lock_all(void)
0046 {
0047     update_user_segments(mfsr(0) | SR_KS);
0048     isync();    /* Context sync required after mtsr() */
0049 }
0050 
0051 static inline void kuap_unlock_all(void)
0052 {
0053     update_user_segments(mfsr(0) & ~SR_KS);
0054     isync();    /* Context sync required after mtsr() */
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     /* If faulting address doesn't match unlocked segment, unlock all */
0180     if ((kuap ^ address) & 0xf0000000)
0181         regs->kuap = KUAP_ALL;
0182 
0183     return false;
0184 }
0185 
0186 #endif /* CONFIG_PPC_KUAP */
0187 
0188 #endif /* __ASSEMBLY__ */
0189 
0190 #endif /* _ASM_POWERPC_BOOK3S_32_KUP_H */