Commit 40624a6e authored by Jinyang He's avatar Jinyang He Committed by Tiezhu Yang
Browse files

LoongArch: Add kernel livepatching support

mainline inclusion
from mainline-v6.9
commit 199cc14cb4f1cb8668be45f67af41755ed5f0175
category: feature
bugzilla: https://gitee.com/openeuler/kernel/issues/IB3IRE

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=199cc14cb4f1cb8668be45f67af41755ed5f0175



---------------------------------------------------------------------------

The arch-specified function ftrace_regs_set_instruction_pointer() has
been implemented in arch/loongarch/include/asm/ftrace.h, so here only
implement arch_stack_walk_reliable() function.

Here are the test logs:

[root@linux fedora]# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.8.0-rc2 root=/dev/sda3

[root@linux fedora]# modprobe livepatch-sample
[root@linux fedora]# cat /proc/cmdline
this has been live patched

[root@linux fedora]# echo 0 > /sys/kernel/livepatch/livepatch_sample/enabled
[root@linux fedora]# rmmod livepatch_sample
[root@linux fedora]# cat /proc/cmdline
BOOT_IMAGE=/vmlinuz-6.8.0-rc2 root=/dev/sda3

[root@linux fedora]# dmesg -t | tail -5
livepatch: enabling patch 'livepatch_sample'
livepatch: 'livepatch_sample': starting patching transition
livepatch: 'livepatch_sample': patching complete
livepatch: 'livepatch_sample': starting unpatching transition
livepatch: 'livepatch_sample': unpatching complete

Signed-off-by: default avatarJinyang He <hejinyang@loongson.cn>
[select HAVE_LIVEPATCH_FTRACE to enable LIVEPATCH - yangtiezhu]
[add empty asm/livepatch.h to avoid building errors - yangtiezhu]
Signed-off-by: default avatarTiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: default avatarHuacai Chen <chenhuacai@loongson.cn>
parent baf22419
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -135,6 +135,8 @@ config LOONGARCH
	select HAVE_KPROBES_ON_FTRACE
	select HAVE_KRETPROBES
	select HAVE_KVM
	select HAVE_LIVEPATCH
	select HAVE_LIVEPATCH_FTRACE
	select HAVE_MOD_ARCH_SPECIFIC
	select HAVE_NMI
	select HAVE_OBJTOOL if AS_HAS_EXPLICIT_RELOCS
@@ -143,6 +145,7 @@ config LOONGARCH
	select HAVE_PERF_REGS
	select HAVE_PERF_USER_STACK_DUMP
	select HAVE_REGS_AND_STACK_ACCESS_API
	select HAVE_RELIABLE_STACKTRACE if UNWINDER_ORC
	select HAVE_RETHOOK
	select HAVE_RSEQ
	select HAVE_SAMPLE_FTRACE_DIRECT
@@ -623,6 +626,8 @@ config RANDOMIZE_BASE_MAX_OFFSET

	  This is limited by the size of the lower address memory, 256MB.

source "kernel/livepatch/Kconfig"

endmenu

config ARCH_SELECT_MEMORY_MODEL
+15 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * livepatch.h - LoongArch-specific Kernel Live Patching Core
 *
 * Copyright (C) 2024 Loongson Technology Corporation Limited
 */

#ifndef _ASM_LOONGARCH_LIVEPATCH_H
#define _ASM_LOONGARCH_LIVEPATCH_H

#ifdef CONFIG_LIVEPATCH_WO_FTRACE

#endif /* CONFIG_LIVEPATCH_WO_FTRACE */

#endif /* _ASM_LOONGARCH_LIVEPATCH_H */
+2 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ register unsigned long current_stack_pointer __asm__("$sp");
#define TIF_LASX_CTX_LIVE	18	/* LASX context must be preserved */
#define TIF_USEDLBT		19	/* LBT was used by this task this quantum (SMP) */
#define TIF_LBT_CTX_LIVE	20	/* LBT context must be preserved */
#define TIF_PATCH_PENDING	21	/* pending live patching update */

#define _TIF_SIGPENDING		(1<<TIF_SIGPENDING)
#define _TIF_NEED_RESCHED	(1<<TIF_NEED_RESCHED)
@@ -105,6 +106,7 @@ register unsigned long current_stack_pointer __asm__("$sp");
#define _TIF_LASX_CTX_LIVE	(1<<TIF_LASX_CTX_LIVE)
#define _TIF_USEDLBT		(1<<TIF_USEDLBT)
#define _TIF_LBT_CTX_LIVE	(1<<TIF_LBT_CTX_LIVE)
#define _TIF_PATCH_PENDING	(1<<TIF_PATCH_PENDING)

#endif /* __KERNEL__ */
#endif /* _ASM_THREAD_INFO_H */
+40 −0
Original line number Diff line number Diff line
@@ -40,6 +40,46 @@ void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
	}
}

int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
			     void *cookie, struct task_struct *task)
{
	unsigned long addr;
	struct pt_regs dummyregs;
	struct pt_regs *regs = &dummyregs;
	struct unwind_state state;

	if (task == current) {
		regs->regs[3] = (unsigned long)__builtin_frame_address(0);
		regs->csr_era = (unsigned long)__builtin_return_address(0);
	} else {
		regs->regs[3] = thread_saved_fp(task);
		regs->csr_era = thread_saved_ra(task);
	}
	regs->regs[1] = 0;
	regs->regs[22] = 0;

	for (unwind_start(&state, task, regs);
	     !unwind_done(&state) && !unwind_error(&state); unwind_next_frame(&state)) {
		addr = unwind_get_return_address(&state);

		/*
		 * A NULL or invalid return address probably means there's some
		 * generated code which __kernel_text_address() doesn't know about.
		 */
		if (!addr)
			return -EINVAL;

		if (!consume_entry(cookie, addr))
			return -EINVAL;
	}

	/* Check for stack corruption */
	if (unwind_error(&state))
		return -EINVAL;

	return 0;
}

static int
copy_stack_frame(unsigned long fp, struct stack_frame *frame)
{