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

Support chrooted/contained processes #37

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

cakemanny
Copy link

This adds support for injecting libraries into processes in containers. Which is needed for kmaork/hypno#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.

static void init()
{
write(1, message, strlen(message));
exit(0);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's probably better to pipe the output of the process through grep -F "Injected", but it requires rethinking how to find the PID. I think I ought to do that.

Although an advantage is that it ends the test as soon as the injection is done.

@kmaork
Copy link
Owner

kmaork commented Jul 27, 2024

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
Copy link
Author

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.

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

Successfully merging this pull request may close these issues.

2 participants