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
6 From: Stefan O'Rear <sorear@fastmail.com>
8 commit d14fa1fcf69db9d070e75f1c4425211fa619dfc8 upstream.
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
16 [From the email thread]
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.
23 childregs is the *user* context during syscall execution and it is observable
24 from userspace in at least five ways:
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.
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.
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.
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
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.
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.
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>
59 arch/riscv/kernel/process.c | 3 ---
60 1 file changed, 3 deletions(-)
62 --- a/arch/riscv/kernel/process.c
63 +++ b/arch/riscv/kernel/process.c
65 #include <asm/cpuidle.h>
66 #include <asm/vector.h>
68 -register unsigned long gp_in_global __asm__("gp");
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)) {
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;