summaryrefslogtreecommitdiffstats
path: root/src/basic/virt.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/basic/virt.c51
1 files changed, 30 insertions, 21 deletions
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;
}