]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
powerpc/32s: Prepare prevent_user_access() for user_access_end()
authorChristophe Leroy <christophe.leroy@c-s.fr>
Fri, 24 Jan 2020 11:54:43 +0000 (11:54 +0000)
committerMichael Ellerman <mpe@ellerman.id.au>
Tue, 28 Jan 2020 12:14:40 +0000 (23:14 +1100)
In preparation of implementing user_access_begin and friends
on powerpc, the book3s/32 version of prevent_user_access() need
to be prepared for user_access_end().

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.

The list of segments which where unprotected by allow_user_access()
are available in current->kuap. But we don't want prevent_user_access()
to read this all the time, especially everytime it is 0 (for instance
because the access was not a write access).

Implement a special direction named KUAP_CURRENT. In this case only,
the addr and end are retrieved from current->kuap.

Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/55bcc1f25d8200892a31f67a0b024ff3b816c3cc.1579866752.git.christophe.leroy@c-s.fr
arch/powerpc/include/asm/book3s/32/kup.h
arch/powerpc/include/asm/book3s/64/kup-radix.h
arch/powerpc/include/asm/kup.h

index de29fb752cca62d4c0775c16945deef5edb482a7..17e069291c72a03ff91ab194771022d30a5289d2 100644 (file)
@@ -108,6 +108,8 @@ static __always_inline void allow_user_access(void __user *to, const void __user
        u32 addr, end;
 
        BUILD_BUG_ON(!__builtin_constant_p(dir));
+       BUILD_BUG_ON(dir == KUAP_CURRENT);
+
        if (!(dir & KUAP_WRITE))
                return;
 
@@ -117,6 +119,7 @@ static __always_inline void allow_user_access(void __user *to, const void __user
                return;
 
        end = min(addr + size, TASK_SIZE);
+
        current->thread.kuap = (addr & 0xf0000000) | ((((end - 1) >> 28) + 1) & 0xf);
        kuap_update_sr(mfsrin(addr) & ~SR_KS, addr, end);       /* Clear Ks */
 }
@@ -127,15 +130,25 @@ static __always_inline void prevent_user_access(void __user *to, const void __us
        u32 addr, end;
 
        BUILD_BUG_ON(!__builtin_constant_p(dir));
-       if (!(dir & KUAP_WRITE))
-               return;
 
-       addr = (__force u32)to;
+       if (dir == KUAP_CURRENT) {
+               u32 kuap = current->thread.kuap;
 
-       if (unlikely(addr >= TASK_SIZE || !size))
+               if (unlikely(!kuap))
+                       return;
+
+               addr = kuap & 0xf0000000;
+               end = kuap << 28;
+       } else if (dir & KUAP_WRITE) {
+               addr = (__force u32)to;
+               end = min(addr + size, TASK_SIZE);
+
+               if (unlikely(addr >= TASK_SIZE || !size))
+                       return;
+       } else {
                return;
+       }
 
-       end = min(addr + size, TASK_SIZE);
        current->thread.kuap = 0;
        kuap_update_sr(mfsrin(addr) | SR_KS, addr, end);        /* set Ks */
 }
index c8d1076e0ebbf81518b753373422adcc8b5fea49..a0263e94df33d4cc5f804829750d428d1d53b1a2 100644 (file)
@@ -86,8 +86,10 @@ static __always_inline void allow_user_access(void __user *to, const void __user
                set_kuap(AMR_KUAP_BLOCK_WRITE);
        else if (dir == KUAP_WRITE)
                set_kuap(AMR_KUAP_BLOCK_READ);
-       else
+       else if (dir == KUAP_READ_WRITE)
                set_kuap(0);
+       else
+               BUILD_BUG();
 }
 
 static inline void prevent_user_access(void __user *to, const void __user *from,
index 94f24928916a81766041277d7024d49166779fb0..c3ce7e8ae9eacb2ed1a3e5a3f4efe8273ca92a49 100644 (file)
@@ -5,6 +5,12 @@
 #define KUAP_READ      1
 #define KUAP_WRITE     2
 #define KUAP_READ_WRITE        (KUAP_READ | KUAP_WRITE)
+/*
+ * For prevent_user_access() only.
+ * Use the current saved situation instead of the to/from/size params.
+ * Used on book3s/32
+ */
+#define KUAP_CURRENT   4
 
 #ifdef CONFIG_PPC64
 #include <asm/book3s/64/kup-radix.h>
@@ -88,6 +94,11 @@ static inline void prevent_read_write_user(void __user *to, const void __user *f
        prevent_user_access(to, from, size, KUAP_READ_WRITE);
 }
 
+static inline void prevent_current_access_user(void)
+{
+       prevent_user_access(NULL, NULL, ~0UL, KUAP_CURRENT);
+}
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_KUAP_H_ */