From e8ee8919243dbead160c1bb1c2484ba93419c74b Mon Sep 17 00:00:00 2001 From: Andrew Werner Date: Mon, 21 Oct 2024 13:42:40 +0200 Subject: [PATCH] linux: Allocate stack for injector's remote calls For some target programs it's not reasonable to assume that any hijacked thread has a large stack. For example, in Go, stacks are often small and are allocated on the heap. The injector bootstrap program uses kilobytes of stack. In order to side-step this problem, this patch changes the boostrapper to allocate an auxiliary stack for remote calls to use and, for the bootstrapper and loader, uses it. The calls to mmap and munmap don't use much stack, so they are fine. Fixes #544. --- src/linux/frida-helper-backend.vala | 31 ++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/linux/frida-helper-backend.vala b/src/linux/frida-helper-backend.vala index ed84fc4d6..058319cb1 100644 --- a/src/linux/frida-helper-backend.vala +++ b/src/linux/frida-helper-backend.vala @@ -1017,8 +1017,9 @@ namespace Frida { establish_connection (launch, spec, bres, agent_ctrl, fallback_address, cancellable); uint64 loader_base = (uintptr) bres.context.allocation_base; - - var call_builder = new RemoteCallBuilder (loader_base, saved_regs); + GPRegs regs = saved_regs; + regs.stack_pointer = bres.allocated_stack.stack_root; + var call_builder = new RemoteCallBuilder (loader_base, regs); call_builder.add_argument (loader_base + loader_layout.ctx_offset); RemoteCall loader_call = call_builder.build (this); RemoteCallResult loader_result = yield loader_call.execute (cancellable); @@ -1076,8 +1077,10 @@ namespace Frida { unowned uint8[] bootstrapper_code = Frida.Data.HelperBackend.get_bootstrapper_bin_blob ().data; size_t bootstrapper_size = round_size_to_page_size (bootstrapper_code.length); + size_t stack_size = 64 * 1024; + uint64 allocation_base = 0; - size_t allocation_size = size_t.max (bootstrapper_size, loader_size); + size_t allocation_size = size_t.max (bootstrapper_size, loader_size) + stack_size; uint64 remote_mmap = 0; uint64 remote_munmap = 0; @@ -1117,10 +1120,12 @@ namespace Frida { Memory.copy (&bootstrap_ctx, output_context, output_context.length); allocation_base = (uintptr) bootstrap_ctx.allocation_base; - code_swap.revert (); } + result.allocated_stack.stack_base = (void *) (allocation_base + allocation_size - stack_size); + result.allocated_stack.stack_size = stack_size; + try { write_memory (allocation_base, bootstrapper_code); maybe_fixup_helper_code (allocation_base, bootstrapper_code); @@ -1129,7 +1134,9 @@ namespace Frida { HelperBootstrapStatus status = SUCCESS; do { - var call_builder = new RemoteCallBuilder (code_start, saved_regs); + GPRegs regs = saved_regs; + regs.stack_pointer = result.allocated_stack.stack_root; + var call_builder = new RemoteCallBuilder (code_start, regs); unowned uint8[] fallback_ld_data = fallback_ld.data; unowned uint8[] fallback_libc_data = fallback_libc.data; @@ -1416,14 +1423,28 @@ namespace Frida { } } + private struct AllocatedStack { + public void * stack_base; + public size_t stack_size; + + public uint64 stack_root { + get { + return (uint64) stack_base + (uint64) stack_size; + } + } + } + + private class BootstrapResult { public HelperBootstrapContext context; public HelperLibcApi libc; + public AllocatedStack allocated_stack; public BootstrapResult clone () { var res = new BootstrapResult (); res.context = context; res.libc = libc; + res.allocated_stack = allocated_stack; return res; } }