kmaork / pyinjector

Inject shared libraries into running processes
MIT License
86 stars 16 forks source link

Support chrooted/contained processes #37

Open cakemanny opened 2 months ago

cakemanny commented 2 months ago

This adds support for injecting libraries into processes in containers. Which is needed for https://github.com/kmaork/hypno/issues/18.

It's draft right now for a few reasons. I've not hooked the tests into the github actions workflows. In fact I'm not sure if I've gone in the right direction with the tests, i.e. using docker compose ? It looks a bit ugly but I suspect it's less awkward than trying to control containers from within the pytest tests.

~/src/third-party/pyinjector/integration (support-chrooted-processes) % make test
docker compose up --abort-on-container-failure
[+] Running 2/0
 ✔ Container integration-target-1    C...                                  0.0s 
 ✔ Container integration-injector-1  Created                               0.0s 
Attaching to injector-1, target-1
target-1    | started
injector-1  | Processing /src
injector-1  |   Installing build dependencies: started
injector-1  |   Installing build dependencies: finished with status 'done'
injector-1  |   Getting requirements to build wheel: started
injector-1  |   Getting requirements to build wheel: finished with status 'done'
injector-1  |   Preparing metadata (pyproject.toml): started
injector-1  |   Preparing metadata (pyproject.toml): finished with status 'done'
injector-1  | Building wheels for collected packages: pyinjector
injector-1  |   Building wheel for pyinjector (pyproject.toml): started
injector-1  |   Building wheel for pyinjector (pyproject.toml): finished with status 'done'
injector-1  |   Created wheel for pyinjector: filename=pyinjector-1.3.0-cp311-cp311-linux_aarch64.whl size=53781 sha256=f385d0a19b69cca7fa0a965f3432e15fcd28c4cd876eb4bd211281dccede6619
injector-1  |   Stored in directory: /tmp/pip-ephem-wheel-cache-d6s_wou4/wheels/a0/a1/77/062e875f5b546d9255c4403d3277b732c25c5e17cdbf8d14d3
injector-1  | Successfully built pyinjector
injector-1  | Installing collected packages: pyinjector
injector-1  |   Attempting uninstall: pyinjector
injector-1  |     Found existing installation: pyinjector 1.3.0
injector-1  |     Uninstalling pyinjector-1.3.0:
injector-1  |       Successfully uninstalled pyinjector-1.3.0
injector-1  | Successfully installed pyinjector-1.3.0
injector-1  | 
injector-1  | [notice] A new release of pip is available: 24.0 -> 24.1.2
injector-1  | [notice] To update, run: pip install --upgrade pip
injector-1  | sopath="/proc/28976/root/app/libcontainer-injection.so"
injector-1  | pid="28976"
target-1    | Injected!
injector-1  | pyinjector failed to inject: Injector failed with -1 calling injector_inject: The target process unexpectedly terminated with exit code 0.
target-1 exited with code 0
injector-1 exited with code 0

Secondly, I've not yet tried incorporating your suggestion

but I think that it'd also be useful to always check for existence of the shared library in the target process' fs (again using /proc/pid/root) by default.

I think that it shouldn't be too hard to iterate on with the tests set up though.

Also, if you like some of this and dislike other bits I'm completely unattached to it.

kmaork commented 2 months ago

Thank you for contributing! I will hopefully have more time to look at it soon, but one note about testing - it would be better if everything could be done directly from python. If possible, it would be better not to depend on make and docker-compose. For example, I'd consider spawning a container with subprocess.run(["docker", "run"..., But I think that an even leaner approach which doesn't depend on docker would be to just use nsenter without actually spwaning a container and relying on docker. For example, running the regular test program inside a filesystem namespace (and maybe others).

cakemanny commented 2 months ago

Hi, just to give you an update, I think I'm unlikely to continue working on this. I think I want something a bit safer than what is guaranteed by kubo/injector. So I'm focusing rather on trying out other ideas.

Regarding the suggestions for the tests. I investigated a little. Using nsenter with a root filesystem change requires running the tests as the root user and in order to run a process there the binary needs to be statically linked (or all shared libraries need to be copied/linked in, I guess). I imagine the docker approach may be simpler but I recall finding managing docker containers from a test to be rather flakey. Though perhaps the testcontainers library would be helpful in this case.

You're free to take what you like and delete the parts that you don't, in case any of this was useful.