X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fbasic%2Fvirt.c;h=20effaf4ca5e90cbb67fd0f7b4e4dd51cb3a2776;hb=f082899f180431f04553e4ee3b0968020ef59188;hp=7a2b9e9bd607b81f584818e8f53ffbe30e220404;hpb=70cec624a0e54f3c35aff781645b07452fc32596;p=elogind.git diff --git a/src/basic/virt.c b/src/basic/virt.c index 7a2b9e9bd..20effaf4c 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -48,7 +48,7 @@ static int detect_vm_cpuid(void) { { "KVMKVMKVM", VIRTUALIZATION_KVM }, /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ { "VMwareVMware", VIRTUALIZATION_VMWARE }, - /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ + /* https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs */ { "Microsoft Hv", VIRTUALIZATION_MICROSOFT }, /* https://wiki.freebsd.org/bhyve */ { "bhyve bhyve ", VIRTUALIZATION_BHYVE }, @@ -409,8 +409,7 @@ int detect_container(void) { if (cached_found >= 0) return cached_found; - /* /proc/vz exists in container and outside of the container, - * /proc/bc only outside of the container. */ + /* /proc/vz exists in container and outside of the container, /proc/bc only outside of the container. */ if (access("/proc/vz", F_OK) >= 0 && access("/proc/bc", F_OK) < 0) { r = VIRTUALIZATION_OPENVZ; @@ -418,50 +417,58 @@ int detect_container(void) { } if (getpid() == 1) { - /* If we are PID 1 we can just check our own - * environment variable */ + /* If we are PID 1 we can just check our own environment variable, and that's authoritative. */ e = getenv("container"); if (isempty(e)) { r = VIRTUALIZATION_NONE; goto finish; } - } else { - - /* Otherwise, PID 1 dropped this information into a - * file in /run. This is better than accessing - * /proc/1/environ, since we don't need CAP_SYS_PTRACE - * for that. */ - - r = read_one_line_file("/run/systemd/container", &m); - if (r == -ENOENT) { - - /* Fallback for cases where PID 1 was not - * systemd (for example, cases where - * init=/bin/sh is used. */ - - r = getenv_for_pid(1, "container", &m); - if (r <= 0) { - - /* If that didn't work, give up, - * assume no container manager. - * - * Note: This means we still cannot - * detect containers if init=/bin/sh - * is passed but privileges dropped, - * as /proc/1/environ is only readable - * with privileges. */ - - r = VIRTUALIZATION_NONE; - goto finish; - } - } - if (r < 0) - return r; + goto translate_name; + } + + /* Otherwise, PID 1 might have dropped this information into a file in /run. This is better than accessing + * /proc/1/environ, since we don't need CAP_SYS_PTRACE for that. */ + r = read_one_line_file("/run/systemd/container", &m); + if (r >= 0) { + e = m; + goto translate_name; + } + if (r != -ENOENT) + return log_debug_errno(r, "Failed to read /run/systemd/container: %m"); + + /* Fallback for cases where PID 1 was not systemd (for example, cases where init=/bin/sh is used. */ + r = getenv_for_pid(1, "container", &m); + if (r > 0) { e = m; + goto translate_name; } + 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"); + + /* Interestingly /proc/1/sched actually shows the host's PID for what we see as PID 1. Hence, if the PID shown + * there is not 1, we know we are in a PID namespace. and hence a container. */ + r = read_one_line_file("/proc/1/sched", &m); + if (r >= 0) { + const char *t; + + t = strrchr(m, '('); + if (!t) + return -EIO; + + if (!startswith(t, "(1,")) { + r = VIRTUALIZATION_CONTAINER_OTHER; + goto finish; + } + } else if (r != -ENOENT) + return r; + + /* If that didn't work, give up, assume no container manager. */ + r = VIRTUALIZATION_NONE; + goto finish; +translate_name: for (j = 0; j < ELEMENTSOF(value_table); j++) if (streq(e, value_table[j].value)) { r = value_table[j].id; @@ -471,7 +478,7 @@ int detect_container(void) { r = VIRTUALIZATION_CONTAINER_OTHER; finish: - log_debug("Found container virtualization %s", virtualization_to_string(r)); + log_debug("Found container virtualization %s.", virtualization_to_string(r)); cached_found = r; return r; } @@ -486,7 +493,6 @@ int detect_virtualization(void) { return r; } -#endif // 0 static int userns_has_mapping(const char *name) { _cleanup_fclose_ FILE *f = NULL; @@ -499,7 +505,7 @@ static int userns_has_mapping(const char *name) { f = fopen(name, "re"); if (!f) { log_debug_errno(errno, "Failed to open %s: %m", name); - return errno == -ENOENT ? false : -errno; + return errno == ENOENT ? false : -errno; } n = getline(&buf, &n_allocated, f); @@ -557,18 +563,35 @@ int running_in_userns(void) { log_debug("/proc/self/setgroups contains \"%s\", %s user namespace", line, r ? "in" : "not in"); return r; } +#endif // 0 int running_in_chroot(void) { - int ret; + _cleanup_free_ char *self_mnt = NULL, *pid1_mnt = NULL; + int r; + + /* Try to detect whether we are running in a chroot() environment. Specifically, check whether we have a + * different root directory than PID 1, even though we live in the same mount namespace as it. */ +#if 0 /// elogind does not allow to ignore chroots, we are never init! if (getenv_bool("SYSTEMD_IGNORE_CHROOT") > 0) return 0; +#endif // 0 + + r = files_same("/proc/1/root", "/"); + if (r < 0) + return r; + if (r > 0) + return 0; - ret = files_same("/proc/1/root", "/"); - if (ret < 0) - return ret; + r = readlink_malloc("/proc/self/ns/mnt", &self_mnt); + if (r < 0) + return r; + + r = readlink_malloc("/proc/1/ns/mnt", &pid1_mnt); + if (r < 0) + return r; - return ret == 0; + return streq(self_mnt, pid1_mnt); /* Only if we live in the same namespace! */ } static const char *const virtualization_table[_VIRTUALIZATION_MAX] = {