LibAFL
LibAFL copied to clipboard
fork() is not safe with tokio
The launcher uses fork by default to start new children, however tokio is known to not working well with fork. I'm getting hangs for using Runtime created before fork() while the Runtime created after fork() seems working well.
https://github.com/AFLplusplus/LibAFL/blob/3625e881a3d7a838021046948fe710eab44ece69/libafl/src/events/launcher.rs#L189
Therefore fork() looks not that "general safe" in rust.
I want to open a discussion here for possible solutions while I haven't tried all:
- Disable
forkfeature, meaning starting processes via command line: This works a bit, but only for fuzzers without initial setup because the code beforeforkwill be executed multiple times. - Make sure
Runtimeare created afterfork(): My current workaround, but seems no document. - Restrict the threads of
Runtimeto 1: Promissing workaround, no ducment either.
More context:
- https://github.com/tokio-rs/tokio/issues/1541
- https://stackoverflow.com/questions/60686516/why-cant-i-communicate-with-a-forked-child-process-using-tokio-unixstream
Note I have no idea about the safety with reqwest but from the documents reqwest seems maintaining a connection pool and internally uses tokio.
First of all, the other threads die, and hence it deadlocks - but AFAIK these deadlocks are still considered safe in rust(?)
I don't know if using a single thread as tokio runtime will work, it may also spawn one second thread that would not survive forking.
In general I fear there is nothing we can do? It's a target-specific (or usage-specific) problem in this case, right? A lot of targets won't work with fork - for these you need to disable the fork feature, which is supported by LibAFL already.
Do you suggest to add documentation somewhere?
I suggest either adding more documents or propagating unsafe to the launcher API like launch() instead of simply marking fork() as safe.
The root cause is that tokio don’t have handy function like gevent.reinit which setups everything again in a child. I will report this to tokio later.
It's not unsafe - it's safe. It just deadlocks after fork, right? No memory corruption or similar
/edit: see https://doc.rust-lang.org/reference/behavior-not-considered-unsafe.html?highlight=deadloc#behavior-not-considered-unsafe
It's not
unsafe- it's safe. It just deadlocks after fork, right? No memory corruption or similar/edit: see https://doc.rust-lang.org/reference/behavior-not-considered-unsafe.html?highlight=deadloc#behavior-not-considered-unsafe
Okay, make sense. I will report this to tokio.
Regarding documents, could you just add the link of this issue in launcher.rs before fork is called? I think that's pretty enough for users to understand the possible side effects.
Feel free to open a docs PR :P It's an issue for all things that fork, like browsers, etc. It's kinda documented in 4) here: https://github.com/AFLplusplus/LibAFL/blob/7f0a4f1d7eb382c8e06ed14a5123a6eaab24bfa0/docs/src/message_passing/spawn_instances.md#automated-with-launcher
I agree it's pretty hidden, feel free to add more docu and send a PR along :)
There is not much we can do here, closing for now.