virt: Detect proot virtualisation by ptrace metadata

proot provides userspace-powered emulation of chroot and mount --bind,
lending it to be used on environments without unprivileged user
namespaces, or in otherwise restricted environments like Android.

In order to achieve this, proot makes use of the kernel's ptrace()
facility, which we can use in order to detect its presence. Since it
doesn't use any kind of namespacing, including PID namespacing, we don't
need to do any tricks when trying to get the tracer's metadata.

For our purposes, proot is listed as a "container", since we mostly use
this also as the bucket for non-container-but-container-like
technologies like WSL. As such, it seems like a good fit for this
section as well.
This commit is contained in:
Chris Down 2020-04-14 18:15:04 +01:00
parent 6ab2e1178e
commit 80cc3e3eab
4 changed files with 26 additions and 0 deletions

View File

@ -167,6 +167,11 @@
<entry><varname>wsl</varname></entry>
<entry><ulink url="https://docs.microsoft.com/en-us/windows/wsl/about">Windows Subsystem for Linux</ulink></entry>
</row>
<row>
<entry><varname>proot</varname></entry>
<entry><ulink url="https://proot-me.github.io/">proot</ulink> userspace chroot/bind mount emulation</entry>
</row>
</tbody>
</tgroup>
</table>

View File

@ -1170,6 +1170,7 @@
<literal>podman</literal>,
<literal>rkt</literal>,
<literal>wsl</literal>,
<literal>proot</literal>,
<literal>acrn</literal> to test
against a specific implementation, or
<literal>private-users</literal> to check whether we are running in a user namespace. See

View File

@ -441,6 +441,7 @@ static const char *const container_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_PODMAN] = "podman",
[VIRTUALIZATION_RKT] = "rkt",
[VIRTUALIZATION_WSL] = "wsl",
[VIRTUALIZATION_PROOT] = "proot",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(container, int);
@ -449,6 +450,7 @@ int detect_container(void) {
static thread_local int cached_found = _VIRTUALIZATION_INVALID;
_cleanup_free_ char *m = NULL;
_cleanup_free_ char *o = NULL;
_cleanup_free_ char *p = NULL;
const char *e = NULL;
int r;
@ -472,6 +474,22 @@ int detect_container(void) {
goto finish;
}
/* proot doesn't use PID namespacing, so we can just check if we have a matching tracer for this
* invocation without worrying about it being elsewhere.
*/
r = get_proc_field("/proc/self/status", "TracerPid", WHITESPACE, &p);
if (r == 0 && !streq(p, "0")) {
pid_t ptrace_pid;
r = parse_pid(p, &ptrace_pid);
if (r == 0) {
const char *pf = procfs_file_alloca(ptrace_pid, "comm");
_cleanup_free_ char *ptrace_comm = NULL;
r = read_one_line_file(pf, &ptrace_comm);
if (r >= 0 && startswith(ptrace_comm, "proot"))
return VIRTUALIZATION_PROOT;
}
}
if (getpid_cached() == 1) {
/* If we are PID 1 we can just check our own environment variable, and that's authoritative.
* We distinguish three cases:
@ -660,6 +678,7 @@ static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {
[VIRTUALIZATION_PODMAN] = "podman",
[VIRTUALIZATION_RKT] = "rkt",
[VIRTUALIZATION_WSL] = "wsl",
[VIRTUALIZATION_PROOT] = "proot",
[VIRTUALIZATION_CONTAINER_OTHER] = "container-other",
};

View File

@ -34,6 +34,7 @@ enum {
VIRTUALIZATION_PODMAN,
VIRTUALIZATION_RKT,
VIRTUALIZATION_WSL,
VIRTUALIZATION_PROOT,
VIRTUALIZATION_CONTAINER_OTHER,
VIRTUALIZATION_CONTAINER_LAST = VIRTUALIZATION_CONTAINER_OTHER,