In preparation of implementing user_access_begin and friends
on powerpc, allow_user_access() need to be prepared for
user_access_begin()

user_access_end() doesn't provide the address and size which
were passed to user_access_begin(), required by prevent_user_access()
to know which segment to modify. But user_access_end() takes an
opaque value returned by user_access_begin().

Make allow_user_access() return the value it writes to current->kuap.
This will allow user_access_end() to recalculate the segment range
without having to read current->kuap.

Signed-off-by: Christophe Leroy <christophe.le...@c-s.fr>
---
v3: Replaces the patch "Prepare prevent_user_access() for user_access_end()"
---
 arch/powerpc/include/asm/book3s/32/kup.h       | 15 ++++++++++-----
 arch/powerpc/include/asm/book3s/64/kup-radix.h |  7 +++++--
 arch/powerpc/include/asm/kup.h                 |  8 ++++++--
 arch/powerpc/include/asm/nohash/32/kup-8xx.h   |  6 ++++--
 4 files changed, 25 insertions(+), 11 deletions(-)

diff --git a/arch/powerpc/include/asm/book3s/32/kup.h 
b/arch/powerpc/include/asm/book3s/32/kup.h
index 3c1798e56b55..128dcbf3a19d 100644
--- a/arch/powerpc/include/asm/book3s/32/kup.h
+++ b/arch/powerpc/include/asm/book3s/32/kup.h
@@ -102,23 +102,28 @@ static inline void kuap_update_sr(u32 sr, u32 addr, u32 
end)
        isync();        /* Context sync required after mtsrin() */
 }
 
-static __always_inline void allow_user_access(void __user *to, const void 
__user *from,
-                                             u32 size, unsigned long dir)
+/* Make sure we never return 0. We only use top and bottom 4 bits */
+static __always_inline unsigned long
+allow_user_access(void __user *to, const void __user *from, u32 size, unsigned 
long dir)
 {
        u32 addr, end;
+       unsigned long kuap;
 
        BUILD_BUG_ON(!__builtin_constant_p(dir));
        if (!(dir & KUAP_W))
-               return;
+               return 0x100;
 
        addr = (__force u32)to;
 
        if (unlikely(addr >= TASK_SIZE || !size))
-               return;
+               return 0x100;
 
        end = min(addr + size, TASK_SIZE);
-       current->thread.kuap = (addr & 0xf0000000) | ((((end - 1) >> 28) + 1) & 
0xf);
+       kuap = (addr & 0xf0000000) | ((((end - 1) >> 28) + 1) & 0xf);
+       current->thread.kuap = kuap;
        kuap_update_sr(mfsrin(addr) & ~SR_KS, addr, end);       /* Clear Ks */
+
+       return kuap;
 }
 
 static __always_inline void prevent_user_access(void __user *to, const void 
__user *from,
diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h 
b/arch/powerpc/include/asm/book3s/64/kup-radix.h
index f11315306d41..183f0c87017b 100644
--- a/arch/powerpc/include/asm/book3s/64/kup-radix.h
+++ b/arch/powerpc/include/asm/book3s/64/kup-radix.h
@@ -77,8 +77,9 @@ static inline void set_kuap(unsigned long value)
        isync();
 }
 
-static __always_inline void allow_user_access(void __user *to, const void 
__user *from,
-                                             unsigned long size, unsigned long 
dir)
+static __always_inline unsigned long
+allow_user_access(void __user *to, const void __user *from,
+                 unsigned long size, unsigned long dir)
 {
        // This is written so we can resolve to a single case at build time
        BUILD_BUG_ON(!__builtin_constant_p(dir));
@@ -88,6 +89,8 @@ static __always_inline void allow_user_access(void __user 
*to, const void __user
                set_kuap(AMR_KUAP_BLOCK_READ);
        else
                set_kuap(0);
+
+       return 1;
 }
 
 static inline void prevent_user_access(void __user *to, const void __user 
*from,
diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
index ff57bfcb88f7..691fec5afd4a 100644
--- a/arch/powerpc/include/asm/kup.h
+++ b/arch/powerpc/include/asm/kup.h
@@ -45,8 +45,12 @@ static inline void setup_kuep(bool disabled) { }
 void setup_kuap(bool disabled);
 #else
 static inline void setup_kuap(bool disabled) { }
-static inline void allow_user_access(void __user *to, const void __user *from,
-                                    unsigned long size, unsigned long dir) { }
+static inline unsigned long allow_user_access(void __user *to, const void 
__user *from,
+                                             unsigned long size, unsigned long 
dir)
+{
+       return 1;
+}
+
 static inline void prevent_user_access(void __user *to, const void __user 
*from,
                                       unsigned long size, unsigned long dir) { 
}
 static inline bool
diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h 
b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
index 1d70c80366fd..ee673d3c0ab6 100644
--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
@@ -34,10 +34,12 @@
 
 #include <asm/reg.h>
 
-static inline void allow_user_access(void __user *to, const void __user *from,
-                                    unsigned long size, unsigned long dir)
+static inline unsigned long allow_user_access(void __user *to, const void 
__user *from,
+                                             unsigned long size, unsigned long 
dir)
 {
        mtspr(SPRN_MD_AP, MD_APG_INIT);
+
+       return 1;
 }
 
 static inline void prevent_user_access(void __user *to, const void __user 
*from,
-- 
2.25.0

Reply via email to