From: Greg Kroah-Hartman Date: Tue, 20 Feb 2024 14:53:41 +0000 (+0100) Subject: 6.1-stable patches X-Git-Tag: v4.19.307~62 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=64ec8b19c9e3e4d5b325042da896b7ddbb13f2d3;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: parisc-fix-random-data-corruption-from-exception-handler.patch --- diff --git a/queue-6.1/parisc-fix-random-data-corruption-from-exception-handler.patch b/queue-6.1/parisc-fix-random-data-corruption-from-exception-handler.patch new file mode 100644 index 00000000000..db6420d1763 --- /dev/null +++ b/queue-6.1/parisc-fix-random-data-corruption-from-exception-handler.patch @@ -0,0 +1,386 @@ +From 8b1d72395635af45410b66cc4c4ab37a12c4a831 Mon Sep 17 00:00:00 2001 +From: Helge Deller +Date: Sat, 20 Jan 2024 15:29:27 +0100 +Subject: parisc: Fix random data corruption from exception handler + +From: Helge Deller + +commit 8b1d72395635af45410b66cc4c4ab37a12c4a831 upstream. + +The current exception handler implementation, which assists when accessing +user space memory, may exhibit random data corruption if the compiler decides +to use a different register than the specified register %r29 (defined in +ASM_EXCEPTIONTABLE_REG) for the error code. If the compiler choose another +register, the fault handler will nevertheless store -EFAULT into %r29 and thus +trash whatever this register is used for. +Looking at the assembly I found that this happens sometimes in emulate_ldd(). + +To solve the issue, the easiest solution would be if it somehow is +possible to tell the fault handler which register is used to hold the error +code. Using %0 or %1 in the inline assembly is not posssible as it will show +up as e.g. %r29 (with the "%r" prefix), which the GNU assembler can not +convert to an integer. + +This patch takes another, better and more flexible approach: +We extend the __ex_table (which is out of the execution path) by one 32-word. +In this word we tell the compiler to insert the assembler instruction +"or %r0,%r0,%reg", where %reg references the register which the compiler +choosed for the error return code. +In case of an access failure, the fault handler finds the __ex_table entry and +can examine the opcode. The used register is encoded in the lowest 5 bits, and +the fault handler can then store -EFAULT into this register. + +Since we extend the __ex_table to 3 words we can't use the BUILDTIME_TABLE_SORT +config option any longer. + +Signed-off-by: Helge Deller +Cc: # v6.0+ +Signed-off-by: Greg Kroah-Hartman +--- + +--- + arch/parisc/Kconfig | 1 + arch/parisc/include/asm/assembly.h | 1 + arch/parisc/include/asm/extable.h | 64 ++++++++++++++++++++++++++++++++ + arch/parisc/include/asm/special_insns.h | 6 ++- + arch/parisc/include/asm/uaccess.h | 48 +++--------------------- + arch/parisc/kernel/unaligned.c | 44 +++++++++++----------- + arch/parisc/mm/fault.c | 11 ++++- + 7 files changed, 106 insertions(+), 69 deletions(-) + +--- a/arch/parisc/Kconfig ++++ b/arch/parisc/Kconfig +@@ -24,7 +24,6 @@ config PARISC + select RTC_DRV_GENERIC + select INIT_ALL_POSSIBLE + select BUG +- select BUILDTIME_TABLE_SORT + select HAVE_PCI + select HAVE_PERF_EVENTS + select HAVE_KERNEL_BZIP2 +--- a/arch/parisc/include/asm/assembly.h ++++ b/arch/parisc/include/asm/assembly.h +@@ -576,6 +576,7 @@ + .section __ex_table,"aw" ! \ + .align 4 ! \ + .word (fault_addr - .), (except_addr - .) ! \ ++ or %r0,%r0,%r0 ! \ + .previous + + +--- /dev/null ++++ b/arch/parisc/include/asm/extable.h +@@ -0,0 +1,64 @@ ++/* SPDX-License-Identifier: GPL-2.0 */ ++#ifndef __PARISC_EXTABLE_H ++#define __PARISC_EXTABLE_H ++ ++#include ++#include ++ ++/* ++ * The exception table consists of three addresses: ++ * ++ * - A relative address to the instruction that is allowed to fault. ++ * - A relative address at which the program should continue (fixup routine) ++ * - An asm statement which specifies which CPU register will ++ * receive -EFAULT when an exception happens if the lowest bit in ++ * the fixup address is set. ++ * ++ * Note: The register specified in the err_opcode instruction will be ++ * modified at runtime if a fault happens. Register %r0 will be ignored. ++ * ++ * Since relative addresses are used, 32bit values are sufficient even on ++ * 64bit kernel. ++ */ ++ ++struct pt_regs; ++int fixup_exception(struct pt_regs *regs); ++ ++#define ARCH_HAS_RELATIVE_EXTABLE ++struct exception_table_entry { ++ int insn; /* relative address of insn that is allowed to fault. */ ++ int fixup; /* relative address of fixup routine */ ++ int err_opcode; /* sample opcode with register which holds error code */ ++}; ++ ++#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr, opcode )\ ++ ".section __ex_table,\"aw\"\n" \ ++ ".align 4\n" \ ++ ".word (" #fault_addr " - .), (" #except_addr " - .)\n" \ ++ opcode "\n" \ ++ ".previous\n" ++ ++/* ++ * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry ++ * (with lowest bit set) for which the fault handler in fixup_exception() will ++ * load -EFAULT on fault into the register specified by the err_opcode instruction, ++ * and zeroes the target register in case of a read fault in get_user(). ++ */ ++#define ASM_EXCEPTIONTABLE_VAR(__err_var) \ ++ int __err_var = 0 ++#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr, register )\ ++ ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1, "or %%r0,%%r0," register) ++ ++static inline void swap_ex_entry_fixup(struct exception_table_entry *a, ++ struct exception_table_entry *b, ++ struct exception_table_entry tmp, ++ int delta) ++{ ++ a->fixup = b->fixup + delta; ++ b->fixup = tmp.fixup - delta; ++ a->err_opcode = b->err_opcode; ++ b->err_opcode = tmp.err_opcode; ++} ++#define swap_ex_entry_fixup swap_ex_entry_fixup ++ ++#endif +--- a/arch/parisc/include/asm/special_insns.h ++++ b/arch/parisc/include/asm/special_insns.h +@@ -8,7 +8,8 @@ + "copy %%r0,%0\n" \ + "8:\tlpa %%r0(%1),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ ++ "or %%r0,%%r0,%%r0") \ + : "=&r" (pa) \ + : "r" (va) \ + : "memory" \ +@@ -22,7 +23,8 @@ + "copy %%r0,%0\n" \ + "8:\tlpa %%r0(%%sr3,%1),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY(8b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY(8b, 9b, \ ++ "or %%r0,%%r0,%%r0") \ + : "=&r" (pa) \ + : "r" (va) \ + : "memory" \ +--- a/arch/parisc/include/asm/uaccess.h ++++ b/arch/parisc/include/asm/uaccess.h +@@ -7,6 +7,7 @@ + */ + #include + #include ++#include + + #include + #include +@@ -26,37 +27,6 @@ + #define STD_USER(sr, x, ptr) __put_user_asm(sr, "std", x, ptr) + #endif + +-/* +- * The exception table contains two values: the first is the relative offset to +- * the address of the instruction that is allowed to fault, and the second is +- * the relative offset to the address of the fixup routine. Since relative +- * addresses are used, 32bit values are sufficient even on 64bit kernel. +- */ +- +-#define ARCH_HAS_RELATIVE_EXTABLE +-struct exception_table_entry { +- int insn; /* relative address of insn that is allowed to fault. */ +- int fixup; /* relative address of fixup routine */ +-}; +- +-#define ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr )\ +- ".section __ex_table,\"aw\"\n" \ +- ".align 4\n" \ +- ".word (" #fault_addr " - .), (" #except_addr " - .)\n\t" \ +- ".previous\n" +- +-/* +- * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() creates a special exception table entry +- * (with lowest bit set) for which the fault handler in fixup_exception() will +- * load -EFAULT into %r29 for a read or write fault, and zeroes the target +- * register in case of a read fault in get_user(). +- */ +-#define ASM_EXCEPTIONTABLE_REG 29 +-#define ASM_EXCEPTIONTABLE_VAR(__variable) \ +- register long __variable __asm__ ("r29") = 0 +-#define ASM_EXCEPTIONTABLE_ENTRY_EFAULT( fault_addr, except_addr )\ +- ASM_EXCEPTIONTABLE_ENTRY( fault_addr, except_addr + 1) +- + #define __get_user_internal(sr, val, ptr) \ + ({ \ + ASM_EXCEPTIONTABLE_VAR(__gu_err); \ +@@ -83,7 +53,7 @@ struct exception_table_entry { + \ + __asm__("1: " ldx " 0(%%sr%2,%3),%0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ + : "=r"(__gu_val), "+r"(__gu_err) \ + : "i"(sr), "r"(ptr)); \ + \ +@@ -115,8 +85,8 @@ struct exception_table_entry { + "1: ldw 0(%%sr%2,%3),%0\n" \ + "2: ldw 4(%%sr%2,%3),%R0\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%1") \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%1") \ + : "=&r"(__gu_tmp.l), "+r"(__gu_err) \ + : "i"(sr), "r"(ptr)); \ + \ +@@ -174,7 +144,7 @@ struct exception_table_entry { + __asm__ __volatile__ ( \ + "1: " stx " %1,0(%%sr%2,%3)\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ + : "+r"(__pu_err) \ + : "r"(x), "i"(sr), "r"(ptr)) + +@@ -186,15 +156,14 @@ struct exception_table_entry { + "1: stw %1,0(%%sr%2,%3)\n" \ + "2: stw %R1,4(%%sr%2,%3)\n" \ + "9:\n" \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b) \ +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b) \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 9b, "%0") \ ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 9b, "%0") \ + : "+r"(__pu_err) \ + : "r"(__val), "i"(sr), "r"(ptr)); \ + } while (0) + + #endif /* !defined(CONFIG_64BIT) */ + +- + /* + * Complex access routines -- external declarations + */ +@@ -216,7 +185,4 @@ unsigned long __must_check raw_copy_from + #define INLINE_COPY_TO_USER + #define INLINE_COPY_FROM_USER + +-struct pt_regs; +-int fixup_exception(struct pt_regs *regs); +- + #endif /* __PARISC_UACCESS_H */ +--- a/arch/parisc/kernel/unaligned.c ++++ b/arch/parisc/kernel/unaligned.c +@@ -118,8 +118,8 @@ static int emulate_ldh(struct pt_regs *r + "2: ldbs 1(%%sr1,%3), %0\n" + " depw %2, 23, 24, %0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "+r" (val), "+r" (ret), "=&r" (temp1) + : "r" (saddr), "r" (regs->isr) ); + +@@ -150,8 +150,8 @@ static int emulate_ldw(struct pt_regs *r + " mtctl %2,11\n" + " vshd %0,%3,%0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "+r" (val), "+r" (ret), "=&r" (temp1), "=&r" (temp2) + : "r" (saddr), "r" (regs->isr) ); + +@@ -187,8 +187,8 @@ static int emulate_ldd(struct pt_regs *r + " mtsar %%r19\n" + " shrpd %0,%%r20,%%sar,%0\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%1") + : "=r" (val), "+r" (ret) + : "0" (val), "r" (saddr), "r" (regs->isr) + : "r19", "r20" ); +@@ -207,9 +207,9 @@ static int emulate_ldd(struct pt_regs *r + " vshd %0,%R0,%0\n" + " vshd %R0,%4,%R0\n" + "4: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 4b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 4b, "%1") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 4b, "%1") + : "+r" (val), "+r" (ret), "+r" (saddr), "=&r" (shift), "=&r" (temp1) + : "r" (regs->isr) ); + } +@@ -242,8 +242,8 @@ static int emulate_sth(struct pt_regs *r + "1: stb %1, 0(%%sr1, %3)\n" + "2: stb %2, 1(%%sr1, %3)\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") + : "+r" (ret), "=&r" (temp1) + : "r" (val), "r" (regs->ior), "r" (regs->isr) ); + +@@ -283,8 +283,8 @@ static int emulate_stw(struct pt_regs *r + " stw %%r20,0(%%sr1,%2)\n" + " stw %%r21,4(%%sr1,%2)\n" + "3: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 3b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 3b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r22", "r1" ); +@@ -327,10 +327,10 @@ static int emulate_std(struct pt_regs *r + "3: std %%r20,0(%%sr1,%2)\n" + "4: std %%r21,8(%%sr1,%2)\n" + "5: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 5b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 5b, "%0") + : "+r" (ret) + : "r" (val), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r22", "r1" ); +@@ -356,11 +356,11 @@ static int emulate_std(struct pt_regs *r + "4: stw %%r1,4(%%sr1,%3)\n" + "5: stw %2,8(%%sr1,%3)\n" + "6: \n" +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b) +- ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b) ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(2b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(3b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(4b, 6b, "%0") ++ ASM_EXCEPTIONTABLE_ENTRY_EFAULT(5b, 6b, "%0") + : "+r" (ret) + : "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr) + : "r19", "r20", "r21", "r1" ); +--- a/arch/parisc/mm/fault.c ++++ b/arch/parisc/mm/fault.c +@@ -150,11 +150,16 @@ int fixup_exception(struct pt_regs *regs + * Fix up get_user() and put_user(). + * ASM_EXCEPTIONTABLE_ENTRY_EFAULT() sets the least-significant + * bit in the relative address of the fixup routine to indicate +- * that gr[ASM_EXCEPTIONTABLE_REG] should be loaded with +- * -EFAULT to report a userspace access error. ++ * that the register encoded in the "or %r0,%r0,register" ++ * opcode should be loaded with -EFAULT to report a userspace ++ * access error. + */ + if (fix->fixup & 1) { +- regs->gr[ASM_EXCEPTIONTABLE_REG] = -EFAULT; ++ int fault_error_reg = fix->err_opcode & 0x1f; ++ if (!WARN_ON(!fault_error_reg)) ++ regs->gr[fault_error_reg] = -EFAULT; ++ pr_debug("Unalignment fixup of register %d at %pS\n", ++ fault_error_reg, (void*)regs->iaoq[0]); + + /* zero target register for get_user() */ + if (parisc_acctyp(0, regs->iir) == VM_READ) { diff --git a/queue-6.1/series b/queue-6.1/series index 6defc7c8ea1..140999b24e8 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -183,3 +183,4 @@ crypto-lib-mpi-fix-unexpected-pointer-access-in-mpi_.patch block-fix-partial-zone-append-completion-handling-in.patch netfilter-ipset-fix-performance-regression-in-swap-operation.patch netfilter-ipset-missing-gc-cancellations-fixed.patch +parisc-fix-random-data-corruption-from-exception-handler.patch