Hello again!
What you're describing seems feasible to me, except for one part I'll get to
later on (so please read to the end before going too deep into testing it).
The way Docker and other container tools like Podman work is through a lower-
level component called the "OCI runtime interface". When you start a container
using Docker or Podman or any other such tool, what is happening behind the
scenes is that the tool will generate an "OCI runtime configuration", which is
a JSON configuration describing the workload that needs to be executed
(command-line, environment, user, permissions, mount volumes, etc.), and which
also points to a rootfs directory where the root filesystem of the container is
present.
gVisor provides a binary called "runsc" which implements this OCI runtime
interface. It accepts this JSON config format and can execute the workload
inside a gVisor sandbox, using the provided rootfs directory as root
filesystem. So it seems like it would work for your use-case, so long as you
can create this OCI runtime config.
To get started on this, the best way is probably to first get an OCI runtime
configuration template that works on a Linux desktop or VM but that you can
later try inside termux on an Android device. Running this in regular non-
Android Linux successfully first will make it easy to determine whether any
problems that come up are termux/Android-specific, as opposed to problems with
the OCI configuration itself.
You can start by creating the following directory structure:
/some/path
/some/path/gvisor-testing
/some/path/gvisor-testing/state
/some/path/gvisor-testing/bundle
/some/path/gvisor-testing/bundle/rootfs
Put your rootfs files under "/some/path/gvisor-testing/bundle/rootfs" (for
example, you should have an empty directory at "/some/path/gvisor-testing/
bundle/rootfs/proc", and you should have a whole /usr-like tree under "/some/
path/gvisor-testing/bundle/usr".
Once you have this, run this:
$ runsc spec --bundle=/some/path/gvisor-testing/bundle -- /bin/echo 'Hello
world'
(Notice that this is pointing to the directory that contains 'rootfs', not to
'rootfs' itself).
This will create a file at /some/path/gvisor-testing/bundle/config.json which is
an OCI runtime config JSON. You can edit this as you wish. Notice that the
command (in this case `/bin/echo 'Hello world'`) is inside the `process.args`
part of the config, and the rootfs is under `root.path`. You can replace this
with an absolute path to the rootfs directory if you want. You could add
something like the `/sdcard` volume inside the `mounts` array, but I would
recommend not doing this before you can confirm that a simple "Hello world"
command works on Android.
Once you have this config set up, you should be able to run:
$ sudo runsc --root=/some/path/gvisor-testing/state run --bundle=/some/path/
gvisor-testing/bundle hello-world
And if all works well you should see "Hello world".
If it does not work, try adding debug logging to see what's wrong:
$ sudo runsc --root=/some/path/gvisor-testing/state --debug-log=/dev/stderr
run --bundle=/some/path/gvisor-testing/bundle hello-world
If running without `sudo`, you may need to add `--rootless=true`, and probably
`--network=none` or `--network=host`. Depending on your host configuration, you
may also need `--ignore-cgroups=true`. These flags need to go before the `run`
positional argument to `runsc`.
If any of the above fails (I typed the above commands by hand without testing
them so it's likely I missed some flag or something), try following the gVisor
OCI tutorial:
https://gvisor.dev/docs/user_guide/quick_start/oci/ which also walks through
creating a valid rootfs. And if that tutorial still doesn't work, please open
a bug about it.
Once you have a working OCI bundle (config.json + rootfs) on your Linux
desktop, then you can copy that directory structure over to your Android
device, and try to run it there.
What I expect you will run into at this point is that some Android kernels
lack essential namespace features that container runtimes require. This
discussion suggest that it may be a problem:
https://github.com/containers/podman/discussions/17717
These kernel features are not strictly essential for gVisor to function as a
userspace kernel, but they are used by gVisor as second-layer defenses in
order to strengthen its security. You can read more about this at
https://gvisor.dev/docs/
So while it is technically feasible to remove these extra security measures
from gVisor's code (so that it would run without needing namespaces support
from the Android kernel), doing so would weaken its security for gVisor's
intended primary use-case of being a _secure_ container runtime. Therefore,
this cannot be its main mode of operation, and there would need to be a good
reason for supporting such an alternative mode.
Anyway, if you do want to give it a shot, check if the above works or if you
run into the namespace support issue. If it works, then I think you now have
all the pieces necessary to build such a `gvisor-chroot` tool.
Cheers,
- E.