]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
virt: Fix Xen PV detection when nested inside another hypervisor
authorBogdan Seniuc <bogdan@bogdan.site>
Sat, 9 Oct 2021 12:00:36 +0000 (15:00 +0300)
committerLennart Poettering <lennart@poettering.net>
Mon, 11 Oct 2021 13:10:46 +0000 (15:10 +0200)
Currently, when Xen PV domains are nested within a hypervisor which is
detected through CPUID (such as VMware), the detected hypervisor might
not be Xen, because we don't check for Xen until after the CPUID check.

This change moves the Xen check before CPUID checks to fix the issue,
and moves Dom0 checking to detect_vm_xen so that we keep ignoring Xen
when we are in Dom0.

src/basic/virt.c

index c9c4416ef78c8759eb85a8cb120ac9a8a6737b5e..745a8557795b8614d268b7f74a5e84a1a51f36b4 100644 (file)
@@ -276,19 +276,6 @@ static int detect_vm_dmi(void) {
 #endif
 }
 
-static int detect_vm_xen(void) {
-
-        /* Check for Dom0 will be executed later in detect_vm_xen_dom0
-           The presence of /proc/xen indicates some form of a Xen domain */
-        if (access("/proc/xen", F_OK) < 0) {
-                log_debug("Virtualization XEN not found, /proc/xen does not exist");
-                return VIRTUALIZATION_NONE;
-        }
-
-        log_debug("Virtualization XEN found (/proc/xen exists)");
-        return VIRTUALIZATION_XEN;
-}
-
 #define XENFEAT_dom0 11 /* xen/include/public/features.h */
 #define PATH_FEATURES "/sys/hypervisor/properties/features"
 /* Returns -errno, or 0 for domU, or 1 for dom0 */
@@ -342,6 +329,26 @@ static int detect_vm_xen_dom0(void) {
         }
 }
 
+static int detect_vm_xen(void) {
+        int r;
+
+        /* The presence of /proc/xen indicates some form of a Xen domain */
+        if (access("/proc/xen", F_OK) < 0) {
+                log_debug("Virtualization XEN not found, /proc/xen does not exist");
+                return VIRTUALIZATION_NONE;
+        }
+        log_debug("Virtualization XEN found (/proc/xen exists)");
+
+        /* Ignore the Xen hypervisor if we are in Dom0 */
+        r = detect_vm_xen_dom0();
+        if (r < 0)
+                return r;
+        if (r > 0)
+                return VIRTUALIZATION_NONE;
+
+        return VIRTUALIZATION_XEN;
+}
+
 static int detect_vm_hypervisor(void) {
         _cleanup_free_ char *hvtype = NULL;
         int r;
@@ -435,7 +442,8 @@ int detect_vm(void) {
          *
          * → First, try to detect Oracle Virtualbox and Amazon EC2 Nitro, 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.
+         *   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 info in DMI is
          *   overwritten.
@@ -457,6 +465,15 @@ int detect_vm(void) {
         else if (r != VIRTUALIZATION_NONE)
                 goto finish;
 
+        /* Detect Xen */
+        r = detect_vm_xen();
+        if (r < 0)
+                return r;
+        if (r == VIRTUALIZATION_VM_OTHER)
+                other = true;
+        else if (r != VIRTUALIZATION_NONE)
+                goto finish;
+
         /* Detect from CPUID */
         r = detect_vm_cpuid();
         if (r < 0)
@@ -476,20 +493,7 @@ int detect_vm(void) {
                 goto finish;
         }
 
-        /* x86 xen will most likely be detected by cpuid. If not (most likely
-         * because we're not an x86 guest), then we should try the /proc/xen
-         * directory next. If that's not found, then we check for the high-level
-         * hypervisor sysfs file.
-         */
-
-        r = detect_vm_xen();
-        if (r < 0)
-                return r;
-        if (r == VIRTUALIZATION_VM_OTHER)
-                other = true;
-        else if (r != VIRTUALIZATION_NONE)
-                goto finish;
-
+        /* Check high-level hypervisor sysfs file */
         r = detect_vm_hypervisor();
         if (r < 0)
                 return r;
@@ -511,18 +515,7 @@ int detect_vm(void) {
                 return r;
 
 finish:
-        /* x86 xen Dom0 is detected as XEN in hypervisor and maybe others.
-         * In order to detect the Dom0 as not virtualization we need to
-         * double-check it */
-        if (r == VIRTUALIZATION_XEN) {
-                int dom0;
-
-                dom0 = detect_vm_xen_dom0();
-                if (dom0 < 0)
-                        return dom0;
-                if (dom0 > 0)
-                        r = VIRTUALIZATION_NONE;
-        } else if (r == VIRTUALIZATION_NONE && other)
+        if (r == VIRTUALIZATION_NONE && other)
                 r = VIRTUALIZATION_VM_OTHER;
 
         cached_found = r;