diff --git a/src/darwin/frida-helper-backend-glue.m b/src/darwin/frida-helper-backend-glue.m index 91c27f639..889f8d9d4 100644 --- a/src/darwin/frida-helper-backend-glue.m +++ b/src/darwin/frida-helper-backend-glue.m @@ -376,7 +376,7 @@ }; static FridaSpawnInstance * frida_spawn_instance_new (FridaDarwinHelperBackend * backend); -static void frida_spawn_instance_free (FridaSpawnInstance * instance); +static void frida_spawn_instance_close (FridaSpawnInstance * instance); static void frida_spawn_instance_resume (FridaSpawnInstance * self); static void frida_spawn_instance_on_server_cancel (void * context); @@ -410,7 +410,7 @@ static FridaInjectInstance * frida_inject_instance_new (FridaDarwinHelperBackend * backend, guint id, guint pid); static FridaInjectInstance * frida_inject_instance_clone (const FridaInjectInstance * instance, guint id); -static void frida_inject_instance_free (FridaInjectInstance * instance); +static void frida_inject_instance_close (FridaInjectInstance * instance); static gboolean frida_inject_instance_task_did_not_exec (FridaInjectInstance * instance); static gboolean frida_inject_instance_start_thread (FridaInjectInstance * self, GError ** error); @@ -934,7 +934,7 @@ static kern_return_t frida_convert_thread_state (mach_port_t thread, FridaConver { if (instance->pid != 0) kill (instance->pid, SIGKILL); - frida_spawn_instance_free (instance); + frida_spawn_instance_close (instance); pid = 0; @@ -2200,9 +2200,9 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier } void -_frida_darwin_helper_backend_free_spawn_instance (FridaDarwinHelperBackend * self, void * instance) +_frida_darwin_helper_backend_close_spawn_instance (FridaDarwinHelperBackend * self, void * instance) { - frida_spawn_instance_free (instance); + frida_spawn_instance_close (instance); } guint @@ -2489,7 +2489,7 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier } failure: { - frida_inject_instance_free (instance); + frida_inject_instance_close (instance); goto beach; } beach: @@ -2646,7 +2646,7 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier FridaInjectInstance * self = context; dispatch_release (g_steal_pointer (&self->thread_monitor_source)); - frida_inject_instance_free (self); + frida_inject_instance_close (self); } static void @@ -2738,9 +2738,9 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier } void -_frida_darwin_helper_backend_free_inject_instance (FridaDarwinHelperBackend * self, void * instance) +_frida_darwin_helper_backend_close_inject_instance (FridaDarwinHelperBackend * self, void * instance) { - frida_inject_instance_free (instance); + frida_inject_instance_close (instance); } static FridaSpawnInstance * @@ -2750,7 +2750,7 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier guint i; instance = g_slice_new0 (FridaSpawnInstance); - instance->backend = backend; + instance->backend = g_object_ref (backend); instance->thread = MACH_PORT_NULL; instance->server_port = MACH_PORT_NULL; @@ -2773,11 +2773,13 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier instance->page_pool[i].scratch_page = 0; } + _frida_darwin_helper_backend_on_instance_created (backend, instance); + return instance; } static void -frida_spawn_instance_free (FridaSpawnInstance * instance) +frida_spawn_instance_close (FridaSpawnInstance * instance) { task_t self_task; FridaExceptionPortSet * previous_ports; @@ -2816,6 +2818,9 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier if (instance->dyld != NULL) g_object_unref (instance->dyld); + _frida_darwin_helper_backend_on_instance_destroyed (instance->backend, instance); + g_object_unref (instance->backend); + g_slice_free (FridaSpawnInstance, instance); } @@ -2858,7 +2863,7 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier FridaSpawnInstance * self = context; dispatch_release (g_steal_pointer (&self->server_recv_source)); - frida_spawn_instance_free (self); + frida_spawn_instance_close (self); } static void @@ -4114,6 +4119,8 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier instance->backend = g_object_ref (backend); + _frida_darwin_helper_backend_on_instance_created (backend, instance); + return instance; } @@ -4143,11 +4150,13 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier g_object_ref (clone->backend); + _frida_darwin_helper_backend_on_instance_created (clone->backend, clone); + return clone; } static void -frida_inject_instance_free (FridaInjectInstance * instance) +frida_inject_instance_close (FridaInjectInstance * instance) { FridaAgentContext * agent_context = instance->agent_context; task_t self_task; @@ -4187,6 +4196,7 @@ static void frida_darwin_helper_backend_launch_using_lsaw (NSString * identifier if (instance->task != MACH_PORT_NULL) mach_port_deallocate (self_task, instance->task); + _frida_darwin_helper_backend_on_instance_destroyed (instance->backend, instance); g_object_unref (instance->backend); g_slice_free (FridaInjectInstance, instance); diff --git a/src/darwin/frida-helper-backend.vala b/src/darwin/frida-helper-backend.vala index d1e31b709..8fc9951fa 100644 --- a/src/darwin/frida-helper-backend.vala +++ b/src/darwin/frida-helper-backend.vala @@ -33,6 +33,9 @@ namespace Frida { private Gee.HashMap inject_cleaner_by_instance = new Gee.HashMap (); private Gee.HashMap inject_expiry_timers = new Gee.HashMap (); + private Gee.Set instances = new Gee.HashSet (); + private SourceFunc? on_last_instance_destroyed = null; + public uint next_id = 1; private PolicySoftener policy_softener; @@ -65,10 +68,6 @@ namespace Frida { } ~DarwinHelperBackend () { - foreach (var instance in spawn_instances.values) - _free_spawn_instance (instance); - foreach (var instance in inject_instances.values) - _free_inject_instance (instance); _destroy_dispatch_context (); } @@ -79,11 +78,24 @@ namespace Frida { pending.complete (); foreach (var entry in inject_cleaner_by_instance.entries) { - _free_inject_instance (entry.key); + _close_inject_instance (entry.key); Source.remove (entry.value); } inject_cleaner_by_instance.clear (); + foreach (var instance in spawn_instances.values) + _close_spawn_instance (instance); + spawn_instances.clear (); + + bool any_pending = false; + lock (instances) { + any_pending = !instances.is_empty; + if (any_pending) + on_last_instance_destroyed = close.callback; + } + if (any_pending) + yield; + if (dtrace_agent != null) { dtrace_agent.spawn_added.disconnect (on_dtrace_agent_spawn_added); dtrace_agent.spawn_removed.disconnect (on_dtrace_agent_spawn_removed); @@ -189,7 +201,7 @@ namespace Frida { inject_cleaner_by_instance.unset (instance, out source_id); Source.remove (source_id); - _free_inject_instance (instance); + _close_inject_instance (instance); } policy_softener.forget (pid); @@ -207,7 +219,7 @@ namespace Frida { void * instance; if (spawn_instances.unset (pid, out instance)) - _free_spawn_instance (instance); + _close_spawn_instance (instance); child_dead (pid); } @@ -295,7 +307,7 @@ namespace Frida { void * instance; if (spawn_instances.unset (pid, out instance)) { _resume_spawn_instance (instance); - _free_spawn_instance (instance); + _close_spawn_instance (instance); } else { resume_with_validation (pid); } @@ -414,7 +426,7 @@ namespace Frida { } catch (GLib.Error e) { if (instance_created_here) { spawn_instances.unset (pid); - _free_spawn_instance (spawn_instance); + _close_spawn_instance (spawn_instance); } throw_api_error (e); @@ -547,7 +559,7 @@ namespace Frida { private void schedule_inject_instance_cleanup (void * instance) { var cleanup_source = new TimeoutSource (50); cleanup_source.set_callback (() => { - _free_inject_instance (instance); + _close_inject_instance (instance); var removed = inject_cleaner_by_instance.unset (instance); assert (removed); @@ -603,6 +615,19 @@ namespace Frida { policy_softener.forget (pid); } + public void _on_instance_created (void * instance) { + lock (instances) + instances.add (instance); + } + + public void _on_instance_destroyed (void * instance) { + lock (instances) { + instances.remove (instance); + if (on_last_instance_destroyed != null && instances.is_empty) + schedule_on_frida_thread ((owned) on_last_instance_destroyed); + } + } + private void on_dtrace_agent_spawn_added (HostSpawnInfo info) { spawn_added (info); } @@ -650,7 +675,7 @@ namespace Frida { protected extern void * _create_spawn_instance (uint pid); protected extern void _prepare_spawn_instance_for_injection (void * instance, uint task) throws Error; protected extern void _resume_spawn_instance (void * instance); - protected extern void _free_spawn_instance (void * instance); + protected extern void _close_spawn_instance (void * instance); protected extern uint _inject_into_task (uint pid, uint task, string path_or_name, MappedLibraryBlob? blob, string entrypoint, string data) throws Error; protected extern void _demonitor (void * instance); @@ -658,7 +683,7 @@ namespace Frida { protected extern void _recreate_injectee_thread (void * instance, uint pid, uint task) throws Error; protected extern void _join_inject_instance_posix_thread (void * instance, void * posix_thread); protected extern uint _get_pid_of_inject_instance (void * instance); - protected extern void _free_inject_instance (void * instance); + protected extern void _close_inject_instance (void * instance); } public class DTraceAgent : Object {