From 1e43af915fcb29bf0a06706c973a1f1919e53d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ole=20Andr=C3=A9=20Vadla=20Ravn=C3=A5s?= Date: Mon, 21 Oct 2024 13:42:40 +0200 Subject: [PATCH] linux: Allocate stack for 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. # Conflicts: # src/linux/helpers/bootstrapper-arm.bin # src/linux/helpers/bootstrapper-mips.bin # src/linux/helpers/bootstrapper-mips64.bin # src/linux/helpers/bootstrapper-mips64el.bin # src/linux/helpers/bootstrapper-mipsel.bin # src/linux/helpers/bootstrapper-x86.bin # src/linux/helpers/bootstrapper-x86_64.bin --- src/linux/frida-helper-backend.vala | 43 ++++++++++++++++++++--- src/linux/helpers/bootstrapper-arm64.bin | Bin 7354 -> 7418 bytes src/linux/helpers/bootstrapper.c | 6 ++++ src/linux/helpers/inject-context.h | 3 ++ 4 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/linux/frida-helper-backend.vala b/src/linux/frida-helper-backend.vala index ed84fc4d6..e3ed21c92 100644 --- a/src/linux/frida-helper-backend.vala +++ b/src/linux/frida-helper-backend.vala @@ -1017,8 +1017,10 @@ 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); + // Set the stack pointer to the allocated stack root. + 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); @@ -1088,9 +1090,13 @@ namespace Frida { remote_munmap = remote_libc.base_address + munmap_offset; } + uint64 stack_base = 0; + size_t stack_size = 64 << 10; // enough for the bootstrapper if (remote_mmap != 0) { allocation_base = yield allocate_memory (remote_mmap, allocation_size, Posix.PROT_READ | Posix.PROT_WRITE | Posix.PROT_EXEC, cancellable); + stack_base = yield allocate_memory (remote_mmap, stack_size, + Posix.PROT_READ | Posix.PROT_WRITE | Posix.PROT_EXEC, cancellable); } else { var code_swap = yield new ProcessCodeSwapScope (this, bootstrapper_code, cancellable); uint64 code_start = code_swap.code_start; @@ -1104,6 +1110,7 @@ namespace Frida { var bootstrap_ctx = HelperBootstrapContext (); bootstrap_ctx.allocation_size = allocation_size; + bootstrap_ctx.stack_size = stack_size; write_memory (bootstrap_ctx_location, (uint8[]) &bootstrap_ctx); call_builder.add_argument (bootstrap_ctx_location); @@ -1117,10 +1124,13 @@ namespace Frida { Memory.copy (&bootstrap_ctx, output_context, output_context.length); allocation_base = (uintptr) bootstrap_ctx.allocation_base; - + stack_base = (uintptr) bootstrap_ctx.stack_base; code_swap.revert (); } + result.allocated_stack.stack_base = (void *)stack_base; + result.allocated_stack.stack_size = stack_size; + try { write_memory (allocation_base, bootstrapper_code); maybe_fixup_helper_code (allocation_base, bootstrapper_code); @@ -1129,7 +1139,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; @@ -1198,6 +1210,10 @@ namespace Frida { yield deallocate_memory (remote_munmap, allocation_base, allocation_size, null); } catch (GLib.Error e) { } + try { + yield deallocate_memory (remote_munmap, stack_base, stack_size, null); + } catch (GLib.Error e) { + } } throw_api_error (e); @@ -1395,6 +1411,8 @@ namespace Frida { public async void deallocate (BootstrapResult bres, Cancellable? cancellable) throws Error, IOError { yield deallocate_memory ((uintptr) bres.libc.munmap, (uintptr) bres.context.allocation_base, bres.context.allocation_size, cancellable); + yield deallocate_memory ((uintptr) bres.libc.munmap, (uintptr) bres.allocated_stack.stack_base, + bres.allocated_stack.stack_size, cancellable); } } @@ -1416,14 +1434,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; } } @@ -1717,6 +1749,9 @@ namespace Frida { bool enable_ctrlfds; int ctrlfds[2]; HelperLibcApi * libc; + + void * stack_base; + size_t stack_size; } protected struct HelperLoaderContext { diff --git a/src/linux/helpers/bootstrapper-arm64.bin b/src/linux/helpers/bootstrapper-arm64.bin index e276d5a699afc35772c297d24a52c9451db8e37f..87a333fc127bb4d1a8ad157c0ec7a28f48c301fb 100644 GIT binary patch delta 1226 zcmZ8gUuaup6hGg+?ecGH+9rWznQLzIFnV+Ir%7DblB}0X)y~PVOg5Ov9ljI`>Vtof zD$O!v)ozmG*D>ac5hnI#FOEb;S8!Pn89s_kM}0`+zq&nG+*Y|l7td#Q;baLk^Tb!#_^!?}X}vILtNgq8Mh* zd9MTuYci-Y0RO3!ZYdkBDsOb{=I^lXuBkX!pFU_E3)3|&G5#Vu(K(2UKERimDiu}! zJKHCMLwZ8s>j(Hz=_xkAFG?f1_v$$(z!%E-dd@|0?CpBa9nMcS3Lj*Rck8*;!hDv! zPa0=_(xVIf!>mC~HVfyo{S&-PP8@oEe6vwFn-$r2S9Y5(L;gDhDRUV%mFLDcCs=;+ zTSw`yRcfwLn9IT&TNTZh4w_D;@)=nTp5B5sJ`b8M$bWQWHftJZ&Sl|Q{*_!~gM79_ zeeA-P=I*q^bW^FrHzmB6-f1=>`5av0-*lXmigG2=Sz*CJY*H;?qql1hT2)5kxiK1; z7UzHNh_VC^IYuPt;l~~QBFs2AQ!8HQaW^%F5Fkj{ncS zPF%>&l@hp4+c6}_Z0i@}c#kl!W3OrW8(~$-H<(SkH;oO#`}nV}tAQ9^raG|A2g=G+ zj9+mN4I~kXDcPC1G=40q*s+62?(xisJ=gYD<~?UvAcZ=KY5+sq*ISSA$gXrSftxe+ z#iJ7VMU(eEx+N4!BVKuR*R)K7U+E4FCvXp=^qr8oMT@@$@Fj_gd3ycIISqZp>4NKO z<7z3M=m{~6KhqN$*63~^fdp3JQ94FJfheX9!}D!ZMroL zSA>V);%ywQ-Pl8i3hkQd5DSSor3O44KL3~Si zZ?qnt+dJk_4_b&_B6ou$V;>JPCPKj{z6CUAsY463>Gq;B1@ zPq9P8G;v`WGPmvcHHoR*!rBiXi;Nnoh*(0{R` IQVgo{zr3r8{{R30 delta 1117 zcmZ8gU1$_n82#={lKqQDvl;BNjk}Y5Xm<906B}b^b%=!e^B`;=DoE)_DcXu{1zRYg zbX+N>O@DIx*@w0d&4W;PLs8k4V13B46)IAwNU?>yOjaqPsKH;RC5+!S5SASn4xDrD z`R+Y)=fBZkN2jCuLm4VwFr3RisJR|+Ot6Y>5H1|m49D#O=OaI13@$9nk&5d|<)*+0 zI5!BnITlE9)r#k+U%?_f=G|7r%LfR-`x3pdG_9jH>RW^tV(w4%9je-~8 ztoli#;3FJ+r%~`nt)gA}LN^aL3X7#FoqbFmuT=~fg8y1K={U{OSNcF4i*jb`rtxLF zbV3)aZ!f%1eiy83<}q4%5th~5`0`F>6|Z<^9xT#P?9!wTZ?8-&zqPsSWpSLBwa}3j z>dDWcvJb3p=ReiU=J79eNTJkGXIcEML+k%+#dG_Rr|hRuyUsCwXQ;bu$E*T;j{eSl zk|k9SbXHj?%bPR{*tYBSM{bRgd2-Bf)MN^WJPDS@H$7XVr5^mzGaz8zgDhTs&HFlI zd7Sly-$?Lr8BUr2FCV4v7^Zebge?av>P(t1Nu)_Iyvm(U@jJvpEB8Ty|4Uqr)|;%w z`(hqr{y8PdPtgQeRg{W)Fp2m5Bk>I9q|CG`lX?Dw$ZzE~XK+toLVU}!;p(4(<4nnM zgG_aRk=2bYCGo(Tp-`GHPc%;Nk;EklRvrcnM>teFRjsZ$BvZMO^;sh0O!d%ZAnyKJ;%FAs|QHyZPWfp;5U?!z*)-3@uxr;e)4T>^BH-*L|WZP z+CZBYO`}U08isqtJ{ClVmwf3qUoyr25*Z%S@@-l@jqmqvV>vw2JEvs$G1_mm^LhKz z;y+T298LsBsH*qGNuWi!nZ@6O5hc#|w=0)2_vPV z8obyS4kh>y`JyrmUvKrC((r!YhES5fMCuIPlz&>)q=pe?14~y&llibc; FridaProcessLayout process; + if (ctx->stack_base == NULL && ctx->stack_size > 0) + { + ctx->stack_base = mmap (NULL, ctx->stack_size, PROT_READ | PROT_WRITE , MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ctx->stack_base == MAP_FAILED) + return FRIDA_BOOTSTRAP_ALLOCATION_ERROR; + } if (ctx->allocation_base == NULL) { ctx->allocation_base = mmap (NULL, ctx->allocation_size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); diff --git a/src/linux/helpers/inject-context.h b/src/linux/helpers/inject-context.h index 8fa65c069..87fc9b0a1 100644 --- a/src/linux/helpers/inject-context.h +++ b/src/linux/helpers/inject-context.h @@ -50,6 +50,9 @@ struct _FridaBootstrapContext int enable_ctrlfds; int ctrlfds[2]; FridaLibcApi * libc; + + void * stack_base; + size_t stack_size; }; struct _FridaLoaderContext