Today, every platform checks that KUAP is not de-activated
before doing the real job.

Move the verification out of platform specific functions.

Signed-off-by: Christophe Leroy <christophe.le...@csgroup.eu>
---
v2: Added missing check in bad_kuap_fault()
---
 arch/powerpc/include/asm/book3s/32/kup.h     | 34 +++-------------
 arch/powerpc/include/asm/book3s/64/kup.h     | 41 ++++++++++----------
 arch/powerpc/include/asm/kup.h               | 29 ++++++++++++++
 arch/powerpc/include/asm/nohash/32/kup-8xx.h | 28 +------------
 4 files changed, 56 insertions(+), 76 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/kup.h 
b/arch/powerpc/include/asm/book3s/32/kup.h
index 8f04602dffff..f1617ba85068 100644
--- a/arch/powerpc/include/asm/book3s/32/kup.h
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -16,11 +16,6 @@ extern struct static_key_false disable_kuep_key;
 
 extern s32 patch__kuep_lock, patch__kuep_unlock;
 
-static __always_inline bool kuap_is_disabled(void)
-{
-       return !IS_ENABLED(CONFIG_PPC_KUAP) || 
static_branch_unlikely(&disable_kuap_key);
-}
-
 static __always_inline bool kuep_is_disabled(void)
 {
        return !IS_ENABLED(CONFIG_PPC_KUEP) || 
static_branch_unlikely(&disable_kuep_key);
@@ -33,6 +28,11 @@ static __always_inline bool kuep_is_disabled(void)
 #define KUAP_NONE      (~0UL)
 #define KUAP_ALL       (~1UL)
 
+static __always_inline bool kuap_is_disabled(void)
+{
+       return static_branch_unlikely(&disable_kuap_key);
+}
+
 static inline void kuap_lock_one(unsigned long addr)
 {
        mtsr(mfsr(addr) | SR_KS, addr);
@@ -84,9 +84,6 @@ static inline void __kuap_save_and_lock(struct pt_regs *regs)
 {
        unsigned long kuap = current->thread.kuap;
 
-       if (kuap_is_disabled())
-               return;
-
        regs->kuap = kuap;
        if (unlikely(kuap == KUAP_NONE))
                return;
@@ -101,9 +98,6 @@ static inline void kuap_user_restore(struct pt_regs *regs)
 
 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long 
kuap)
 {
-       if (kuap_is_disabled())
-               return;
-
        if (unlikely(kuap != KUAP_NONE)) {
                current->thread.kuap = KUAP_NONE;
                kuap_lock(kuap, false);
@@ -121,9 +115,6 @@ static inline unsigned long 
__kuap_get_and_assert_locked(void)
 {
        unsigned long kuap = current->thread.kuap;
 
-       if (kuap_is_disabled())
-               return KUAP_NONE;
-
        WARN_ON_ONCE(IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && kuap != KUAP_NONE);
 
        return kuap;
@@ -137,9 +128,6 @@ static inline void __kuap_assert_locked(void)
 static __always_inline void __allow_user_access(void __user *to, const void 
__user *from,
                                                u32 size, unsigned long dir)
 {
-       if (kuap_is_disabled())
-               return;
-
        BUILD_BUG_ON(!__builtin_constant_p(dir));
 
        if (!(dir & KUAP_WRITE))
@@ -153,9 +141,6 @@ static __always_inline void __prevent_user_access(unsigned 
long dir)
 {
        u32 kuap = current->thread.kuap;
 
-       if (kuap_is_disabled())
-               return;
-
        BUILD_BUG_ON(!__builtin_constant_p(dir));
 
        if (!(dir & KUAP_WRITE))
@@ -169,9 +154,6 @@ static inline unsigned long 
__prevent_user_access_return(void)
 {
        unsigned long flags = current->thread.kuap;
 
-       if (kuap_is_disabled())
-               return KUAP_NONE;
-
        if (flags != KUAP_NONE) {
                current->thread.kuap = KUAP_NONE;
                kuap_lock(flags, true);
@@ -182,9 +164,6 @@ static inline unsigned long 
__prevent_user_access_return(void)
 
 static inline void __restore_user_access(unsigned long flags)
 {
-       if (kuap_is_disabled())
-               return;
-
        if (flags != KUAP_NONE) {
                current->thread.kuap = flags;
                kuap_unlock(flags, true);
@@ -196,9 +175,6 @@ __bad_kuap_fault(struct pt_regs *regs, unsigned long 
address, bool is_write)
 {
        unsigned long kuap = regs->kuap;
 
-       if (kuap_is_disabled())
-               return false;
-
        if (!is_write || kuap == KUAP_ALL)
                return false;
        if (kuap == KUAP_NONE)
diff --git a/arch/powerpc/include/asm/book3s/64/kup.h 
b/arch/powerpc/include/asm/book3s/64/kup.h
index 03d61c5205a4..9f2099790658 100644
--- a/arch/powerpc/include/asm/book3s/64/kup.h
+++ b/arch/powerpc/include/asm/book3s/64/kup.h
@@ -229,6 +229,11 @@ static inline u64 current_thread_iamr(void)
 
 #ifdef CONFIG_PPC_KUAP
 
+static __always_inline bool kuap_is_disabled(void)
+{
+       return !mmu_has_feature(MMU_FTR_BOOK3S_KUAP);
+}
+
 static inline void kuap_user_restore(struct pt_regs *regs)
 {
        bool restore_amr = false, restore_iamr = false;
@@ -270,36 +275,32 @@ static inline void kuap_user_restore(struct pt_regs *regs)
 
 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long 
amr)
 {
-       if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) {
-               if (unlikely(regs->amr != amr)) {
-                       isync();
-                       mtspr(SPRN_AMR, regs->amr);
-                       /*
-                        * No isync required here because we are about to rfi
-                        * back to previous context before any user accesses
-                        * would be made, which is a CSI.
-                        */
-               }
-       }
+       if (likely(regs->amr == amr))
+               return;
+
+       isync();
+       mtspr(SPRN_AMR, regs->amr);
        /*
+        * No isync required here because we are about to rfi
+        * back to previous context before any user accesses
+        * would be made, which is a CSI.
+        *
         * No need to restore IAMR when returning to kernel space.
         */
 }
 
 static inline unsigned long __kuap_get_and_assert_locked(void)
 {
-       if (mmu_has_feature(MMU_FTR_BOOK3S_KUAP)) {
-               unsigned long amr = mfspr(SPRN_AMR);
-               if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) /* kuap_check_amr() */
-                       WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
-               return amr;
-       }
-       return 0;
+       unsigned long amr = mfspr(SPRN_AMR);
+
+       if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG)) /* kuap_check_amr() */
+               WARN_ON_ONCE(amr != AMR_KUAP_BLOCKED);
+       return amr;
 }
 
 static inline void __kuap_assert_locked(void)
 {
-       if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && 
mmu_has_feature(MMU_FTR_BOOK3S_KUAP))
+       if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
                WARN_ON_ONCE(mfspr(SPRN_AMR) != AMR_KUAP_BLOCKED);
 }
 
@@ -340,8 +341,6 @@ static inline void set_kuap(unsigned long value)
 
 static inline bool __bad_kuap_fault(struct pt_regs *regs, unsigned long 
address, bool is_write)
 {
-       if (!mmu_has_feature(MMU_FTR_BOOK3S_KUAP))
-               return false;
        /*
         * For radix this will be a storage protection fault (DSISR_PROTFAULT).
         * For hash this will be a key fault (DSISR_KEYFAULT)
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index 3dbd3f77b413..ea70e6f1df1e 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -43,6 +43,8 @@ void setup_kuap(bool disabled);
 #else
 static inline void setup_kuap(bool disabled) { }
 
+static __always_inline bool kuap_is_disabled(void) { return true; }
+
 static inline bool
 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
 {
@@ -76,28 +78,43 @@ static inline void __restore_user_access(unsigned long 
flags) { }
 static __always_inline bool
 bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
 {
+       if (kuap_is_disabled())
+               return false;
+
        return __bad_kuap_fault(regs, address, is_write);
 }
 
 static __always_inline void kuap_assert_locked(void)
 {
+       if (kuap_is_disabled())
+               return;
+
        __kuap_assert_locked();
 }
 
 #ifdef CONFIG_PPC32
 static __always_inline void kuap_save_and_lock(struct pt_regs *regs)
 {
+       if (kuap_is_disabled())
+               return;
+
        __kuap_save_and_lock(regs);
 }
 #endif
 
 static __always_inline void kuap_kernel_restore(struct pt_regs *regs, unsigned 
long amr)
 {
+       if (kuap_is_disabled())
+               return;
+
        __kuap_kernel_restore(regs, amr);
 }
 
 static __always_inline unsigned long kuap_get_and_assert_locked(void)
 {
+       if (kuap_is_disabled())
+               return 0;
+
        return __kuap_get_and_assert_locked();
 }
 
@@ -105,21 +122,33 @@ static __always_inline unsigned long 
kuap_get_and_assert_locked(void)
 static __always_inline void allow_user_access(void __user *to, const void 
__user *from,
                                     unsigned long size, unsigned long dir)
 {
+       if (kuap_is_disabled())
+               return;
+
        __allow_user_access(to, from, size, dir);
 }
 
 static __always_inline void prevent_user_access(unsigned long dir)
 {
+       if (kuap_is_disabled())
+               return;
+
        __prevent_user_access(dir);
 }
 
 static __always_inline unsigned long prevent_user_access_return(void)
 {
+       if (kuap_is_disabled())
+               return 0;
+
        return __prevent_user_access_return();
 }
 
 static __always_inline void restore_user_access(unsigned long flags)
 {
+       if (kuap_is_disabled())
+               return;
+
        __restore_user_access(flags);
 }
 #endif /* CONFIG_PPC_BOOK3S_64 */
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h 
b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
index a5db84164afd..74f15c386476 100644
--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -22,9 +22,6 @@ static __always_inline bool kuap_is_disabled(void)
 
 static inline void __kuap_save_and_lock(struct pt_regs *regs)
 {
-       if (kuap_is_disabled())
-               return;
-
        regs->kuap = mfspr(SPRN_MD_AP);
        mtspr(SPRN_MD_AP, MD_APG_KUAP);
 }
@@ -35,9 +32,6 @@ static inline void kuap_user_restore(struct pt_regs *regs)
 
 static inline void __kuap_kernel_restore(struct pt_regs *regs, unsigned long 
kuap)
 {
-       if (kuap_is_disabled())
-               return;
-
        mtspr(SPRN_MD_AP, regs->kuap);
 }
 
@@ -45,9 +39,6 @@ static inline unsigned long __kuap_get_and_assert_locked(void)
 {
        unsigned long kuap;
 
-       if (kuap_is_disabled())
-               return MD_APG_INIT;
-
        kuap = mfspr(SPRN_MD_AP);
 
        if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
@@ -58,24 +49,18 @@ static inline unsigned long 
__kuap_get_and_assert_locked(void)
 
 static inline void __kuap_assert_locked(void)
 {
-       if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG) && !kuap_is_disabled())
-               kuap_get_and_assert_locked();
+       if (IS_ENABLED(CONFIG_PPC_KUAP_DEBUG))
+               __kuap_get_and_assert_locked();
 }
 
 static inline void __allow_user_access(void __user *to, const void __user 
*from,
                                       unsigned long size, unsigned long dir)
 {
-       if (kuap_is_disabled())
-               return;
-
        mtspr(SPRN_MD_AP, MD_APG_INIT);
 }
 
 static inline void __prevent_user_access(unsigned long dir)
 {
-       if (kuap_is_disabled())
-               return;
-
        mtspr(SPRN_MD_AP, MD_APG_KUAP);
 }
 
@@ -83,9 +68,6 @@ static inline unsigned long __prevent_user_access_return(void)
 {
        unsigned long flags;
 
-       if (kuap_is_disabled())
-               return MD_APG_INIT;
-
        flags = mfspr(SPRN_MD_AP);
 
        mtspr(SPRN_MD_AP, MD_APG_KUAP);
@@ -95,18 +77,12 @@ static inline unsigned long 
__prevent_user_access_return(void)
 
 static inline void __restore_user_access(unsigned long flags)
 {
-       if (kuap_is_disabled())
-               return;
-
        mtspr(SPRN_MD_AP, flags);
 }
 
 static inline bool
 __bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
 {
-       if (kuap_is_disabled())
-               return false;
-
        return !((regs->kuap ^ MD_APG_KUAP) & 0xff000000);
 }
 
-- 
2.31.1

Reply via email to