]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
fixes for 5.5
authorSasha Levin <sashal@kernel.org>
Mon, 10 Feb 2020 04:45:35 +0000 (23:45 -0500)
committerSasha Levin <sashal@kernel.org>
Mon, 10 Feb 2020 04:45:35 +0000 (23:45 -0500)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-5.5/powerpc-kuap-fix-set-direction-in-allow-prevent_user.patch [new file with mode: 0644]
queue-5.5/series

diff --git a/queue-5.5/powerpc-kuap-fix-set-direction-in-allow-prevent_user.patch b/queue-5.5/powerpc-kuap-fix-set-direction-in-allow-prevent_user.patch
new file mode 100644 (file)
index 0000000..cc4da21
--- /dev/null
@@ -0,0 +1,249 @@
+From b309f8fa73d4eb90109419f9ccad925852e81e2d Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 24 Jan 2020 11:54:41 +0000
+Subject: powerpc/kuap: Fix set direction in allow/prevent_user_access()
+
+From: Christophe Leroy <christophe.leroy@c-s.fr>
+
+[ Upstream commit 1d8f739b07bd538f272f60bf53f10e7e6248d295 ]
+
+__builtin_constant_p() always return 0 for pointers, so on RADIX
+we always end up opening both direction (by writing 0 in SPR29):
+
+  0000000000000170 <._copy_to_user>:
+  ...
+   1b0:        4c 00 01 2c     isync
+   1b4:        39 20 00 00     li      r9,0
+   1b8:        7d 3d 03 a6     mtspr   29,r9
+   1bc:        4c 00 01 2c     isync
+   1c0:        48 00 00 01     bl      1c0 <._copy_to_user+0x50>
+                       1c0: R_PPC64_REL24      .__copy_tofrom_user
+  ...
+  0000000000000220 <._copy_from_user>:
+  ...
+   2ac:        4c 00 01 2c     isync
+   2b0:        39 20 00 00     li      r9,0
+   2b4:        7d 3d 03 a6     mtspr   29,r9
+   2b8:        4c 00 01 2c     isync
+   2bc:        7f c5 f3 78     mr      r5,r30
+   2c0:        7f 83 e3 78     mr      r3,r28
+   2c4:        48 00 00 01     bl      2c4 <._copy_from_user+0xa4>
+                       2c4: R_PPC64_REL24      .__copy_tofrom_user
+  ...
+
+Use an explicit parameter for direction selection, so that GCC
+is able to see it is a constant:
+
+  00000000000001b0 <._copy_to_user>:
+  ...
+   1f0:        4c 00 01 2c     isync
+   1f4:        3d 20 40 00     lis     r9,16384
+   1f8:        79 29 07 c6     rldicr  r9,r9,32,31
+   1fc:        7d 3d 03 a6     mtspr   29,r9
+   200:        4c 00 01 2c     isync
+   204:        48 00 00 01     bl      204 <._copy_to_user+0x54>
+                       204: R_PPC64_REL24      .__copy_tofrom_user
+  ...
+  0000000000000260 <._copy_from_user>:
+  ...
+   2ec:        4c 00 01 2c     isync
+   2f0:        39 20 ff ff     li      r9,-1
+   2f4:        79 29 00 04     rldicr  r9,r9,0,0
+   2f8:        7d 3d 03 a6     mtspr   29,r9
+   2fc:        4c 00 01 2c     isync
+   300:        7f c5 f3 78     mr      r5,r30
+   304:        7f 83 e3 78     mr      r3,r28
+   308:        48 00 00 01     bl      308 <._copy_from_user+0xa8>
+                       308: R_PPC64_REL24      .__copy_tofrom_user
+  ...
+
+Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
+[mpe: Spell out the directions, s/KUAP_R/KUAP_READ/ etc.]
+Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
+Link: https://lore.kernel.org/r/f4e88ec4941d5facb35ce75026b0112f980086c3.1579866752.git.christophe.leroy@c-s.fr
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ arch/powerpc/include/asm/book3s/32/kup.h      | 13 ++++++--
+ .../powerpc/include/asm/book3s/64/kup-radix.h | 11 +++----
+ arch/powerpc/include/asm/kup.h                | 30 ++++++++++++++-----
+ arch/powerpc/include/asm/nohash/32/kup-8xx.h  |  4 +--
+ arch/powerpc/include/asm/uaccess.h            |  4 +--
+ 5 files changed, 43 insertions(+), 19 deletions(-)
+
+diff --git a/arch/powerpc/include/asm/book3s/32/kup.h b/arch/powerpc/include/asm/book3s/32/kup.h
+index d88008c8eb852..91c8f1d9bceef 100644
+--- a/arch/powerpc/include/asm/book3s/32/kup.h
++++ b/arch/powerpc/include/asm/book3s/32/kup.h
+@@ -102,11 +102,13 @@ static inline void kuap_update_sr(u32 sr, u32 addr, u32 end)
+       isync();        /* Context sync required after mtsrin() */
+ }
+-static inline void allow_user_access(void __user *to, const void __user *from, u32 size)
++static __always_inline void allow_user_access(void __user *to, const void __user *from,
++                                            u32 size, unsigned long dir)
+ {
+       u32 addr, end;
+-      if (__builtin_constant_p(to) && to == NULL)
++      BUILD_BUG_ON(!__builtin_constant_p(dir));
++      if (!(dir & KUAP_WRITE))
+               return;
+       addr = (__force u32)to;
+@@ -119,11 +121,16 @@ static inline void allow_user_access(void __user *to, const void __user *from, u
+       kuap_update_sr(mfsrin(addr) & ~SR_KS, addr, end);       /* Clear Ks */
+ }
+-static inline void prevent_user_access(void __user *to, const void __user *from, u32 size)
++static __always_inline void prevent_user_access(void __user *to, const void __user *from,
++                                              u32 size, unsigned long dir)
+ {
+       u32 addr = (__force u32)to;
+       u32 end = min(addr + size, TASK_SIZE);
++      BUILD_BUG_ON(!__builtin_constant_p(dir));
++      if (!(dir & KUAP_WRITE))
++              return;
++
+       if (!addr || addr >= TASK_SIZE || !size)
+               return;
+diff --git a/arch/powerpc/include/asm/book3s/64/kup-radix.h b/arch/powerpc/include/asm/book3s/64/kup-radix.h
+index dbbd22cb80f5a..c8d1076e0ebbf 100644
+--- a/arch/powerpc/include/asm/book3s/64/kup-radix.h
++++ b/arch/powerpc/include/asm/book3s/64/kup-radix.h
+@@ -77,20 +77,21 @@ static inline void set_kuap(unsigned long value)
+       isync();
+ }
+-static inline void allow_user_access(void __user *to, const void __user *from,
+-                                   unsigned long size)
++static __always_inline void 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
+-      if (__builtin_constant_p(to) && to == NULL)
++      BUILD_BUG_ON(!__builtin_constant_p(dir));
++      if (dir == KUAP_READ)
+               set_kuap(AMR_KUAP_BLOCK_WRITE);
+-      else if (__builtin_constant_p(from) && from == NULL)
++      else if (dir == KUAP_WRITE)
+               set_kuap(AMR_KUAP_BLOCK_READ);
+       else
+               set_kuap(0);
+ }
+ static inline void prevent_user_access(void __user *to, const void __user *from,
+-                                     unsigned long size)
++                                     unsigned long size, unsigned long dir)
+ {
+       set_kuap(AMR_KUAP_BLOCKED);
+ }
+diff --git a/arch/powerpc/include/asm/kup.h b/arch/powerpc/include/asm/kup.h
+index 812e66f31934f..94f24928916a8 100644
+--- a/arch/powerpc/include/asm/kup.h
++++ b/arch/powerpc/include/asm/kup.h
+@@ -2,6 +2,10 @@
+ #ifndef _ASM_POWERPC_KUP_H_
+ #define _ASM_POWERPC_KUP_H_
++#define KUAP_READ     1
++#define KUAP_WRITE    2
++#define KUAP_READ_WRITE       (KUAP_READ | KUAP_WRITE)
++
+ #ifdef CONFIG_PPC64
+ #include <asm/book3s/64/kup-radix.h>
+ #endif
+@@ -42,9 +46,9 @@ 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 size, unsigned long dir) { }
+ static inline void prevent_user_access(void __user *to, const void __user *from,
+-                                     unsigned long size) { }
++                                     unsigned long size, unsigned long dir) { }
+ static inline bool
+ bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+ {
+@@ -54,24 +58,36 @@ bad_kuap_fault(struct pt_regs *regs, unsigned long address, bool is_write)
+ static inline void allow_read_from_user(const void __user *from, unsigned long size)
+ {
+-      allow_user_access(NULL, from, size);
++      allow_user_access(NULL, from, size, KUAP_READ);
+ }
+ static inline void allow_write_to_user(void __user *to, unsigned long size)
+ {
+-      allow_user_access(to, NULL, size);
++      allow_user_access(to, NULL, size, KUAP_WRITE);
++}
++
++static inline void allow_read_write_user(void __user *to, const void __user *from,
++                                       unsigned long size)
++{
++      allow_user_access(to, from, size, KUAP_READ_WRITE);
+ }
+ static inline void prevent_read_from_user(const void __user *from, unsigned long size)
+ {
+-      prevent_user_access(NULL, from, size);
++      prevent_user_access(NULL, from, size, KUAP_READ);
+ }
+ static inline void prevent_write_to_user(void __user *to, unsigned long size)
+ {
+-      prevent_user_access(to, NULL, size);
++      prevent_user_access(to, NULL, size, KUAP_WRITE);
++}
++
++static inline void prevent_read_write_user(void __user *to, const void __user *from,
++                                         unsigned long size)
++{
++      prevent_user_access(to, from, size, KUAP_READ_WRITE);
+ }
+ #endif /* !__ASSEMBLY__ */
+-#endif /* _ASM_POWERPC_KUP_H_ */
++#endif /* _ASM_POWERPC_KUAP_H_ */
+diff --git a/arch/powerpc/include/asm/nohash/32/kup-8xx.h b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+index f2fea603b929a..1d70c80366fd3 100644
+--- a/arch/powerpc/include/asm/nohash/32/kup-8xx.h
++++ b/arch/powerpc/include/asm/nohash/32/kup-8xx.h
+@@ -35,13 +35,13 @@
+ #include <asm/reg.h>
+ static inline void allow_user_access(void __user *to, const void __user *from,
+-                                   unsigned long size)
++                                   unsigned long size, unsigned long dir)
+ {
+       mtspr(SPRN_MD_AP, MD_APG_INIT);
+ }
+ static inline void prevent_user_access(void __user *to, const void __user *from,
+-                                     unsigned long size)
++                                     unsigned long size, unsigned long dir)
+ {
+       mtspr(SPRN_MD_AP, MD_APG_KUAP);
+ }
+diff --git a/arch/powerpc/include/asm/uaccess.h b/arch/powerpc/include/asm/uaccess.h
+index c92fe7fe9692c..cafad1960e766 100644
+--- a/arch/powerpc/include/asm/uaccess.h
++++ b/arch/powerpc/include/asm/uaccess.h
+@@ -313,9 +313,9 @@ raw_copy_in_user(void __user *to, const void __user *from, unsigned long n)
+       unsigned long ret;
+       barrier_nospec();
+-      allow_user_access(to, from, n);
++      allow_read_write_user(to, from, n);
+       ret = __copy_tofrom_user(to, from, n);
+-      prevent_user_access(to, from, n);
++      prevent_read_write_user(to, from, n);
+       return ret;
+ }
+ #endif /* __powerpc64__ */
+-- 
+2.20.1
+
index b37a7f5bb2e489895739332be1a54a18261652ff..34ee20708f43fd00ddc4105d1bc19fc6705da565 100644 (file)
@@ -364,3 +364,4 @@ crypto-atmel-aes-fix-saving-of-iv-for-ctr-mode.patch
 crypto-atmel-aes-fix-ctr-counter-overflow-when-multi.patch
 crypto-atmel-tdes-map-driver-data-flags-to-mode-regi.patch
 regulator-fix-for-regulator-core-add-regulator_is_eq.patch
+powerpc-kuap-fix-set-direction-in-allow-prevent_user.patch