From 6ad8f4bb1135275d7cfe8cbbd46819f9160bde8e Mon Sep 17 00:00:00 2001 From: Idan Horowitz Date: Sun, 2 Apr 2023 03:21:24 +0300 Subject: [PATCH] Kernel: Stop overwriting AArch64 link register in forked processes Forked processes already have an existing value for the link register, which we can't overwrite. But since they're forked the original link register value that points to exit_kernel_thread was already saved somewhere on the stack, so it's ok not to set it. --- Kernel/Arch/aarch64/Processor.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Kernel/Arch/aarch64/Processor.cpp b/Kernel/Arch/aarch64/Processor.cpp index 699bad1689..70894fe1dc 100644 --- a/Kernel/Arch/aarch64/Processor.cpp +++ b/Kernel/Arch/aarch64/Processor.cpp @@ -287,8 +287,13 @@ FlatPtr Processor::init_context(Thread& thread, bool leave_crit) RegisterState& eretframe = *reinterpret_cast(stack_top); memcpy(eretframe.x, thread_regs.x, sizeof(thread_regs.x)); - // x30 is the Link Register for the aarch64 ABI, so this will return to exit_kernel_thread when main thread function returns. - eretframe.x[30] = FlatPtr(&exit_kernel_thread); + // We don't overwrite the link register if it's not 0, since that means this thread's register state was already initialized with + // an existing link register value (e.g. it was fork()'ed), so we assume exit_kernel_thread is already saved as previous LR on the + // stack somewhere. + if (eretframe.x[30] == 0x0) { + // x30 is the Link Register for the aarch64 ABI, so this will return to exit_kernel_thread when main thread function returns. + eretframe.x[30] = FlatPtr(&exit_kernel_thread); + } eretframe.elr_el1 = thread_regs.elr_el1; eretframe.sp_el0 = thread_regs.sp_el0; eretframe.spsr_el1 = thread_regs.spsr_el1;