From: Sasha Levin Date: Mon, 10 Feb 2020 04:45:35 +0000 (-0500) Subject: fixes for 5.5 X-Git-Tag: v4.19.103~5 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c5eacc94bda5601f545ba0350cb6e847319a442a;p=thirdparty%2Fkernel%2Fstable-queue.git fixes for 5.5 Signed-off-by: Sasha Levin --- 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 index 00000000000..cc4da214026 --- /dev/null +++ b/queue-5.5/powerpc-kuap-fix-set-direction-in-allow-prevent_user.patch @@ -0,0 +1,249 @@ +From b309f8fa73d4eb90109419f9ccad925852e81e2d Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Fri, 24 Jan 2020 11:54:41 +0000 +Subject: powerpc/kuap: Fix set direction in allow/prevent_user_access() + +From: Christophe Leroy + +[ 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 +[mpe: Spell out the directions, s/KUAP_R/KUAP_READ/ etc.] +Signed-off-by: Michael Ellerman +Link: https://lore.kernel.org/r/f4e88ec4941d5facb35ce75026b0112f980086c3.1579866752.git.christophe.leroy@c-s.fr +Signed-off-by: Sasha Levin +--- + 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 + #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 + + 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 + diff --git a/queue-5.5/series b/queue-5.5/series index b37a7f5bb2e..34ee20708f4 100644 --- a/queue-5.5/series +++ b/queue-5.5/series @@ -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