]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/6.6.26/riscv-process-fix-kernel-gp-leakage.patch
Linux 6.1.85
[thirdparty/kernel/stable-queue.git] / releases / 6.6.26 / riscv-process-fix-kernel-gp-leakage.patch
1 From d14fa1fcf69db9d070e75f1c4425211fa619dfc8 Mon Sep 17 00:00:00 2001
2 From: Stefan O'Rear <sorear@fastmail.com>
3 Date: Wed, 27 Mar 2024 02:12:58 -0400
4 Subject: riscv: process: Fix kernel gp leakage
5
6 From: Stefan O'Rear <sorear@fastmail.com>
7
8 commit d14fa1fcf69db9d070e75f1c4425211fa619dfc8 upstream.
9
10 childregs represents the registers which are active for the new thread
11 in user context. For a kernel thread, childregs->gp is never used since
12 the kernel gp is not touched by switch_to. For a user mode helper, the
13 gp value can be observed in user space after execve or possibly by other
14 means.
15
16 [From the email thread]
17
18 The /* Kernel thread */ comment is somewhat inaccurate in that it is also used
19 for user_mode_helper threads, which exec a user process, e.g. /sbin/init or
20 when /proc/sys/kernel/core_pattern is a pipe. Such threads do not have
21 PF_KTHREAD set and are valid targets for ptrace etc. even before they exec.
22
23 childregs is the *user* context during syscall execution and it is observable
24 from userspace in at least five ways:
25
26 1. kernel_execve does not currently clear integer registers, so the starting
27 register state for PID 1 and other user processes started by the kernel has
28 sp = user stack, gp = kernel __global_pointer$, all other integer registers
29 zeroed by the memset in the patch comment.
30
31 This is a bug in its own right, but I'm unwilling to bet that it is the only
32 way to exploit the issue addressed by this patch.
33
34 2. ptrace(PTRACE_GETREGSET): you can PTRACE_ATTACH to a user_mode_helper thread
35 before it execs, but ptrace requires SIGSTOP to be delivered which can only
36 happen at user/kernel boundaries.
37
38 3. /proc/*/task/*/syscall: this is perfectly happy to read pt_regs for
39 user_mode_helpers before the exec completes, but gp is not one of the
40 registers it returns.
41
42 4. PERF_SAMPLE_REGS_USER: LOCKDOWN_PERF normally prevents access to kernel
43 addresses via PERF_SAMPLE_REGS_INTR, but due to this bug kernel addresses
44 are also exposed via PERF_SAMPLE_REGS_USER which is permitted under
45 LOCKDOWN_PERF. I have not attempted to write exploit code.
46
47 5. Much of the tracing infrastructure allows access to user registers. I have
48 not attempted to determine which forms of tracing allow access to user
49 registers without already allowing access to kernel registers.
50
51 Fixes: 7db91e57a0ac ("RISC-V: Task implementation")
52 Cc: stable@vger.kernel.org
53 Signed-off-by: Stefan O'Rear <sorear@fastmail.com>
54 Reviewed-by: Alexandre Ghiti <alexghiti@rivosinc.com>
55 Link: https://lore.kernel.org/r/20240327061258.2370291-1-sorear@fastmail.com
56 Signed-off-by: Palmer Dabbelt <palmer@rivosinc.com>
57 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
58 ---
59 arch/riscv/kernel/process.c | 3 ---
60 1 file changed, 3 deletions(-)
61
62 --- a/arch/riscv/kernel/process.c
63 +++ b/arch/riscv/kernel/process.c
64 @@ -26,8 +26,6 @@
65 #include <asm/cpuidle.h>
66 #include <asm/vector.h>
67
68 -register unsigned long gp_in_global __asm__("gp");
69 -
70 #if defined(CONFIG_STACKPROTECTOR) && !defined(CONFIG_STACKPROTECTOR_PER_TASK)
71 #include <linux/stackprotector.h>
72 unsigned long __stack_chk_guard __read_mostly;
73 @@ -186,7 +184,6 @@ int copy_thread(struct task_struct *p, c
74 if (unlikely(args->fn)) {
75 /* Kernel thread */
76 memset(childregs, 0, sizeof(struct pt_regs));
77 - childregs->gp = gp_in_global;
78 /* Supervisor/Machine, irqs on: */
79 childregs->status = SR_PP | SR_PIE;
80