From efeb864cb547a2cbf96dc0053a8bdb4d9190b364 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 12 Jun 2024 05:50:45 +0200 Subject: Merging upstream version 256. Signed-off-by: Daniel Baumann --- src/basic/virt.c | 51 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 21 deletions(-) (limited to 'src/basic/virt.c') diff --git a/src/basic/virt.c b/src/basic/virt.c index 88357a9..0970350 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -21,6 +21,7 @@ #include "stat-util.h" #include "string-table.h" #include "string-util.h" +#include "uid-range.h" #include "virt.h" enum { @@ -446,7 +447,7 @@ static Virtualization detect_vm_zvm(void) { /* Returns a short identifier for the various VM implementations */ Virtualization detect_vm(void) { static thread_local Virtualization cached_found = _VIRTUALIZATION_INVALID; - bool other = false; + bool other = false, hyperv = false; int xen_dom0 = 0; Virtualization v, dmi; @@ -455,12 +456,12 @@ Virtualization detect_vm(void) { /* We have to use the correct order here: * - * → First, try to detect Oracle Virtualbox, Amazon EC2 Nitro, Parallels, and Google Compute Engine, even if they use KVM, - * as well as Xen even if it cloaks as Microsoft Hyper-V. Attempt to detect uml at this stage also - * since it runs as a user-process nested inside other VMs. Also check for Xen now, because Xen PV - * mode does not override CPUID when nested inside another hypervisor. + * → First, try to detect Oracle Virtualbox, Amazon EC2 Nitro, Parallels, and Google Compute Engine, + * even if they use KVM, as well as Xen, even if it cloaks as Microsoft Hyper-V. Attempt to detect + * UML at this stage too, since it runs as a user-process nested inside other VMs. Also check for + * Xen now, because Xen PV mode does not override CPUID when nested inside another hypervisor. * - * → Second, try to detect from CPUID, this will report KVM for whatever software is used even if + * → Second, try to detect from CPUID. This will report KVM for whatever software is used even if * info in DMI is overwritten. * * → Third, try to detect from DMI. */ @@ -503,7 +504,12 @@ Virtualization detect_vm(void) { v = detect_vm_cpuid(); if (v < 0) return v; - if (v == VIRTUALIZATION_VM_OTHER) + if (v == VIRTUALIZATION_MICROSOFT) + /* QEMU sets the CPUID string to hyperv's, in case it provides hyperv enlightenments. Let's + * hence not return Microsoft here but just use the other mechanisms first to make a better + * decision. */ + hyperv = true; + else if (v == VIRTUALIZATION_VM_OTHER) other = true; else if (v != VIRTUALIZATION_NONE) goto finish; @@ -544,8 +550,15 @@ Virtualization detect_vm(void) { return v; finish: - if (v == VIRTUALIZATION_NONE && other) - v = VIRTUALIZATION_VM_OTHER; + /* None of the checks above gave us a clear answer, hence let's now use fallback logic: if hyperv + * enlightenments are available but the VMM wasn't recognized as anything yet, it's probably + * Microsoft. */ + if (v == VIRTUALIZATION_NONE) { + if (hyperv) + v = VIRTUALIZATION_MICROSOFT; + else if (other) + v = VIRTUALIZATION_VM_OTHER; + } cached_found = v; log_debug("Found VM virtualization %s", virtualization_to_string(v)); @@ -818,7 +831,7 @@ Virtualization detect_virtualization(void) { static int userns_has_mapping(const char *name) { _cleanup_fclose_ FILE *f = NULL; - uid_t a, b, c; + uid_t base, shift, range; int r; f = fopen(name, "re"); @@ -827,26 +840,22 @@ static int userns_has_mapping(const char *name) { return errno == ENOENT ? false : -errno; } - errno = 0; - r = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &a, &b, &c); - if (r == EOF) { - if (ferror(f)) - return log_debug_errno(errno_or_else(EIO), "Failed to read %s: %m", name); - - log_debug("%s is empty, we're in an uninitialized user namespace", name); + r = uid_map_read_one(f, &base, &shift, &range); + if (r == -ENOMSG) { + log_debug("%s is empty, we're in an uninitialized user namespace.", name); return true; } - if (r != 3) - return log_debug_errno(SYNTHETIC_ERRNO(EBADMSG), "Failed to parse %s: %m", name); + if (r < 0) + return log_debug_errno(r, "Failed to read %s: %m", name); - if (a == 0 && b == 0 && c == UINT32_MAX) { + if (base == 0 && shift == 0 && range == UINT32_MAX) { /* The kernel calls mappings_overlap() and does not allow overlaps */ log_debug("%s has a full 1:1 mapping", name); return false; } /* Anything else implies that we are in a user namespace */ - log_debug("Mapping found in %s, we're in a user namespace", name); + log_debug("Mapping found in %s, we're in a user namespace.", name); return true; } -- cgit v1.2.3