]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
virt: detect Docker and Podman containers
authorSergey Bugaev <bugaevc@gmail.com>
Sat, 19 Dec 2020 18:00:22 +0000 (21:00 +0300)
committerSergey Bugaev <bugaevc@gmail.com>
Wed, 10 Feb 2021 19:25:04 +0000 (22:25 +0300)
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

index 02e7fbf1f72fe7456645d5259610f86e138e5dc7..f625328e58dfb20a4b06640dd6a01c0c1e0bf0ea 100644 (file)
@@ -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;