From a4a9a6f7c6e9cd9e219c56d08434a04bc2f395ff Mon Sep 17 00:00:00 2001 From: Sergey Bugaev Date: Sat, 19 Dec 2020 21:00:22 +0300 Subject: [PATCH] virt: detect Docker and Podman containers Docker doesn't set $container, so it cannot be detected that way. Instead, we check for presence of /.dockerinit, which it creates. Podman does set $container, but some Red Hat images (in particular, Fedora images) override $container to equal "oci". So to correctly detect Podman containers, we check for presence of /run/.containerenv, which is created by Podman and is now the official way to get information about the container from within the container. Fixes https://github.com/systemd/systemd/issues/15393 --- src/basic/virt.c | 50 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/src/basic/virt.c b/src/basic/virt.c index 02e7fbf1f72..f625328e58d 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -453,6 +453,34 @@ static const char *const container_table[_VIRTUALIZATION_MAX] = { DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(container, int); +static int detect_container_files(void) { + unsigned i; + + static const struct { + const char *file_path; + int id; + } container_file_table[] = { + /* https://github.com/containers/podman/issues/6192 */ + /* https://github.com/containers/podman/issues/3586#issuecomment-661918679 */ + { "/run/.containerenv", VIRTUALIZATION_PODMAN }, + /* https://github.com/moby/moby/issues/18355 */ + /* Docker must be the last in this table, see below. */ + { "/.dockerenv", VIRTUALIZATION_DOCKER }, + }; + + for (i = 0; i < ELEMENTSOF(container_file_table); i++) { + if (access(container_file_table[i].file_path, F_OK) >= 0) + return container_file_table[i].id; + + if (errno != ENOENT) + log_debug_errno(errno, + "Checking if %s exists failed, ignoring: %m", + container_file_table[i].file_path); + } + + return VIRTUALIZATION_NONE; +} + int detect_container(void) { static thread_local int cached_found = _VIRTUALIZATION_INVALID; _cleanup_free_ char *m = NULL, *o = NULL, *p = NULL; @@ -530,7 +558,7 @@ int detect_container(void) { */ e = getenv("container"); if (!e) - goto none; + goto check_files; if (isempty(e)) { r = VIRTUALIZATION_NONE; goto finish; @@ -558,12 +586,28 @@ int detect_container(void) { if (r < 0) /* This only works if we have CAP_SYS_PTRACE, hence let's better ignore failures here */ log_debug_errno(r, "Failed to read $container of PID 1, ignoring: %m"); -none: - /* If that didn't work, give up, assume no container manager. */ +check_files: + /* Check for existence of some well-known files. We only do this after checking + * for other specific container managers, otherwise we risk mistaking another + * container manager for Docker: the /.dockerenv file could inadvertently end up + * in a file system image. */ + r = detect_container_files(); + if (r) + goto finish; + + /* If none of that worked, give up, assume no container manager. */ r = VIRTUALIZATION_NONE; goto finish; translate_name: + if (streq(e, "oci")) { + /* Some images hardcode container=oci, but OCI is not a specific container manager. + * Try to detect one based on well-known files. */ + r = detect_container_files(); + if (!r) + r = VIRTUALIZATION_CONTAINER_OTHER; + goto finish; + } r = container_from_string(e); if (r < 0) r = VIRTUALIZATION_CONTAINER_OTHER;