Skip to content

Commit

Permalink
darwin(x86/arm64): Initialize TLV area on loading
Browse files Browse the repository at this point in the history
Dyld's tlv_get_addr function retrieves the thread local storage by
using a descriptor's key to index into the thread local storage held in
gsbase on x86 or TPIDRRO_EL0 on arm64 to retrieve a thread- and module-
specific data area to offset into.

If this offset-specific area pointer is NULL, it will be lazily
allocated by tlv_get_addr through a call to
RuntimeState::_instantiateTLVs. This allocates the area, using a size
stored in a Dyld-private vector _tlvInfos, and copies over intial data.
When a module is loaded through Dyld, it stores the nesseary size along
with the key in _tlvInfos.

Since we don't have a way to insert our newly generated key into
this array through public (and hence stable) APIs, we pre-allocate and
initialize the per-thread area for the initial thread in the runtime.
  • Loading branch information
fabianfreyer committed Sep 2, 2023
1 parent 5ec3456 commit 03de284
Showing 1 changed file with 42 additions and 0 deletions.
42 changes: 42 additions & 0 deletions gum/backend-darwin/gumdarwinmapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ struct _GumDarwinMapper
GumAddress chained_symbols_vector;
GumAddress tlv_get_addrAddr;
GumDarwinModule * libsystem_pthread;
GumAddress tlv_address;
GumAddress pthread_key;
GumAddress pthread_key_create;
GumAddress pthread_key_delete;
Expand Down Expand Up @@ -707,6 +708,8 @@ gum_darwin_mapper_map (GumDarwinMapper * self,
GumDarwinModule * module = self->module;
mach_port_t task = self->resolver->task;
GumDarwinModule * libdyld;
guint32 tlv_data_offset;
guint64 tlv_data_size, tlv_bss_size;
guint i;
mach_vm_address_t mapped_address;
vm_prot_t cur_protection, max_protection;
Expand Down Expand Up @@ -763,6 +766,22 @@ gum_darwin_mapper_map (GumDarwinMapper * self,
if (!ctx.success)
goto beach;

gum_darwin_module_get_tlv_init (module, &tlv_data_offset, &tlv_data_size,
&tlv_bss_size);
self->tlv_address = (GumAddress) 0;

kr = mach_vm_allocate (task, &self->tlv_address,
tlv_data_size + tlv_bss_size, VM_FLAGS_ANYWHERE);
GUM_CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "mach_vm_allocate(tlv)");

kr = mach_vm_protect (task, self->tlv_address, tlv_data_size + tlv_bss_size,
FALSE, VM_PROT_READ | VM_PROT_WRITE);
GUM_CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "mach_vm_protect(tlv)");

kr = mach_vm_write (task, self->tlv_address,
(vm_offset_t) self->image->data + tlv_data_offset, tlv_data_size);
GUM_CHECK_MACH_RESULT (kr, ==, KERN_SUCCESS, "mach_vm_write(tlv)");

gum_darwin_mapper_alloc_and_emit_runtime (self, base_address, total_vm_size);

for (i = 0; i != module->segments->len; i++)
Expand Down Expand Up @@ -1321,6 +1340,15 @@ gum_emit_x86_tlv_init_code (GumEmitX86Context * ctx)
GUM_ARG_ADDRESS, GUM_ADDRESS (self->pthread_key),
GUM_ARG_ADDRESS, GUM_ADDRESS (0) /* destructor */);

gum_x86_writer_put_mov_reg_address (cw, GUM_X86_XAX,
GUM_ADDRESS (self->pthread_key));
gum_x86_writer_put_mov_reg_reg_ptr (cw, GUM_X86_XAX, GUM_X86_XAX);
gum_x86_writer_put_shl_reg_u8 (cw, GUM_X86_XAX,
self->module->pointer_size == 8 ? 3 : 2);
gum_x86_writer_put_mov_reg_address (cw, GUM_X86_XBX,
GUM_ADDRESS (self->tlv_address));
gum_x86_writer_put_mov_gs_reg_ptr_reg (cw, GUM_X86_XAX, GUM_X86_XBX);

GumAddress tlv_section = self->module->base_address
+ gum_darwin_module_get_tlv_descriptors_file_offset (module);

Expand Down Expand Up @@ -1921,6 +1949,20 @@ static void gum_emit_arm64_tlv_init_code (GumEmitArm64Context * ctx)
GUM_ARG_ADDRESS, GUM_ADDRESS (self->pthread_key),
GUM_ARG_ADDRESS, GUM_ADDRESS (0) /* destructor */);

gum_arm64_writer_put_ldr_reg_address (aw, ARM64_REG_X19,
GUM_ADDRESS (self->pthread_key));
gum_arm64_writer_put_ldr_reg_reg (aw, ARM64_REG_X19, ARM64_REG_X19);
gum_arm64_writer_put_lsl_reg_imm (aw, ARM64_REG_X19,
self->module->pointer_size == 8 ? 3 : 2);
gum_arm64_writer_put_mrs (aw, ARM64_REG_X20, GUM_ARM64_SYSREG_TPIDRRO_EL0);
gum_arm64_writer_put_and_reg_reg_imm (aw, ARM64_REG_X20, ARM64_REG_X20,
(guint64) -8);
gum_arm64_writer_put_add_reg_reg_reg (aw, ARM64_REG_X19, ARM64_REG_X19,
ARM64_REG_X20);
gum_arm64_writer_put_ldr_reg_address (aw, ARM64_REG_X20,
GUM_ADDRESS (self->tlv_address));
gum_arm64_writer_put_str_reg_reg (aw, ARM64_REG_X19, ARM64_REG_X20);

gum_arm64_writer_put_ldr_reg_u64 (aw, ARM64_REG_X20,
GUM_ADDRESS (tlv_section));

Expand Down

0 comments on commit 03de284

Please sign in to comment.