Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

get_device() stuck in python child process #176

Open
DayChan opened this issue Feb 4, 2021 · 3 comments
Open

get_device() stuck in python child process #176

DayChan opened this issue Feb 4, 2021 · 3 comments

Comments

@DayChan
Copy link

DayChan commented Feb 4, 2021

Use get_device() in child thread is fine, however, if I call it in child process, it will be stuck without any log.

@tux-mind
Copy link

👍

Minimum reproducible example:

import frida
import logging

from multiprocessing import Process
from threading import Thread

logging.basicConfig(level=logging.INFO, format='%(processName)s %(threadName)s %(message)s')

def list_devs():
    logging.info("listing devices...")
    logging.info("got these devices: %s", frida.enumerate_devices())
	
list_devs()

p = Process(target=list_devs, name="ChildProcess")
p.start()

t = Thread(target=list_devs, name="ChildThread")
t.start()

t.join()
logging.info("thread joined")

p.join()
loggin.info("process joined")

output:

MainProcess MainThread listing devices...
MainProcess MainThread got these devices: [Device(id="local", name="Local System", type='local'), Device(id="socket", name="Local Socket", type='remote'), Device(id="**redacted**", name="iOS Device", type='usb')]
MainProcess ChildThread listing devices...
ChildProcess MainThread listing devices...
MainProcess ChildThread got these devices: [Device(id="local", name="Local System", type='local'), Device(id="socket", name="Local Socket", type='remote'), Device(id="**redacted**", name="iOS Device", type='usb')]
MainProcess MainThread thread joined

$ pip show frida says Version: 15.1.22. Also tested on Version: 16.0.8

@tux-mind
Copy link

tux-mind commented Jan 25, 2023

I managed to get the stack trace of the hung process on 14.0.0:

#1  0x00007ffff7296087 in g_cond_wait (cond=0xad0138, mutex=0xad0130) at ../../../glib/glib/gthread-posix.c:1637
#2  0x00007ffff4175b35 in frida_async_task_execute (self=self@entry=0xad0160, cancellable=cancellable@entry=0x0, error=error@entry=0x7fffffffc1d0) at ../../../frida-core/src/frida.vala:2591
#3  0x00007ffff417664b in frida_device_manager_enumerate_devices_sync (self=<optimized out>, cancellable=0x0, error=0x7fffffffc220) at ../../../frida-core/src/frida.vala:202
#4  0x00007ffff4145bc2 in PyDeviceManager_enumerate_devices (self=0x7ffff374c090) at ../../../frida-python/src/_frida.c:2002

Maybe the AsyncTask class isn't meant to be shared among processes but only threads.

EDIT
Frida uses Vala and GLib. It extensively uses GLib's MainLoop and MainContext, with mutexes and threads.
Those mutexes and threads get copied to the new process, messing everything up.
ref: https://stackoverflow.com/questions/4223553/c-does-exec-have-to-immediately-follow-fork-in-a-multi-threaded-process

I think the "solution" here is to specify in the documentation that, as Frida is a multi-thread library, forking is not supported.

@zenitraM
Copy link

zenitraM commented May 12, 2024

A (likely nasty) workaround for those getting here like me and finding they can't use Frida from a Python thread/process - even if you aren't doing any sort of multi-threaded work with it (i.e sharing Frida objects/devices/etc across threads).

It seems what makes things break here is that import frida already initiates internal state at import time, and therefore you can't share/call the imported module from a different thread.
This will make things fail if you import a file on the main thread that itself imports Frida, yet you call the method that does all the Frida work from a children thread.

So if you do the import frida within the method that is running on your thread instead, it will work as this global state will then not be shared.

So instead of:

import frida

def threaded_function():
   device = frida.get_usb_device()

do:

def threaded_function():
   import frida
   device = frida.get_usb_device()

I haven't dug more on why this happens, if my theory is correct sounds like a fix for this could be to make a way for the bindings to not have this global state initiated implicitly on the import, but rather expose a way of initializing the "Frida context" separately somehow.

Caveat emptor, this only enabled my use of running a single Frida invocation within a thread of a single script, which I'd argue is not really multi-threaded usage from Frida's perspective as all of my Frida usage is happening from the same thread.
It's likely more complex usecases, or even importing multiple times, will still break in fun ways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants