From bc00a8152669a649d55a4a1d19bd3f10c8cecc62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lesimple?= Date: Thu, 30 Jul 2026 15:51:23 +0200 Subject: [PATCH] fix: xen: consider Xen dom0 as non-guest (#343 continued) --- src/libs/360_cpu_smt.sh | 14 ++++++++++++-- src/libs/370_hw_vmm.sh | 9 ++++++++- src/vulns-helpers/check_mds.sh | 20 +++++++++++++++----- src/vulns-helpers/check_mmio.sh | 20 +++++++++++++++----- src/vulns/CVE-2019-11135.sh | 16 ++++++++++++---- 5 files changed, 62 insertions(+), 17 deletions(-) diff --git a/src/libs/360_cpu_smt.sh b/src/libs/360_cpu_smt.sh index e7f9d31..36d4e7d 100644 --- a/src/libs/360_cpu_smt.sh +++ b/src/libs/360_cpu_smt.sh @@ -46,8 +46,18 @@ is_arm_cpu() { # Check whether SMT (HyperThreading) is enabled on the system # Returns: 0 if SMT enabled, 1 otherwise is_cpu_smt_enabled() { - local siblings cpucores - # SMT / HyperThreading is enabled if siblings != cpucores + local siblings cpucores smt_active + # Most reliable: /sys/devices/system/cpu/smt/active mirrors the kernel's + # sched_smt_active() (1=SMT active, 0=not), which is exactly what the kernel + # itself uses to derive the "SMT (disabled|vulnerable)" vulnerability strings. + if [ -r /sys/devices/system/cpu/smt/active ]; then + smt_active=$(cat /sys/devices/system/cpu/smt/active 2>/dev/null) + case "$smt_active" in + 1) return 0 ;; + 0) return 1 ;; + esac + fi + # Fallback: SMT / HyperThreading is enabled if siblings != cpucores if [ -e "$g_procfs/cpuinfo" ]; then siblings=$(awk '/^siblings/ {print $3;exit}' "$g_procfs/cpuinfo") cpucores=$(awk '/^cpu cores/ {print $4;exit}' "$g_procfs/cpuinfo") diff --git a/src/libs/370_hw_vmm.sh b/src/libs/370_hw_vmm.sh index 0d44b09..6c96d64 100644 --- a/src/libs/370_hw_vmm.sh +++ b/src/libs/370_hw_vmm.sh @@ -127,7 +127,14 @@ is_running_as_guest() { if [ "${g_is_guest_vm_cached:-0}" != 1 ]; then g_is_guest_vm=0 g_is_guest_vm_reason='' - if [ -e "$g_procfs/cpuinfo" ] && grep -qw 'hypervisor' "$g_procfs/cpuinfo" 2>/dev/null; then + # A Xen dom0 runs on top of the hypervisor and therefore also has the + # 'hypervisor' CPUID flag set, but it's the privileged control domain: + # it has direct hardware access and a truthful view of the host CPU + # topology, so it must not be classified as a guest (#343). Check it + # before the cpuinfo probe below, which would otherwise match. + if is_xen_dom0; then + g_is_guest_vm=0 + elif [ -e "$g_procfs/cpuinfo" ] && grep -qw 'hypervisor' "$g_procfs/cpuinfo" 2>/dev/null; then g_is_guest_vm=1 g_is_guest_vm_reason="'hypervisor' flag in $g_procfs/cpuinfo" fi diff --git a/src/vulns-helpers/check_mds.sh b/src/vulns-helpers/check_mds.sh index 5bdba1f..031d0ea 100644 --- a/src/vulns-helpers/check_mds.sh +++ b/src/vulns-helpers/check_mds.sh @@ -175,11 +175,21 @@ check_mds_linux() { mds_smt_mitigated=1 pstatus green YES elif echo "$ret_sys_interface_check_fullmsg" | grep -q 'SMT Host state unknown'; then - # The kernel appends "SMT Host state unknown" when running under - # a hypervisor (X86_FEATURE_HYPERVISOR): the host controls SMT - # scheduling, so it can't be determined from inside the guest (#343). - mds_smt_mitigated=2 - pstatus yellow UNKNOWN "running in a VM guest, the hypervisor host controls SMT" + # The kernel appends "SMT Host state unknown" whenever the + # HYPERVISOR CPUID bit is set. That's true both inside a guest + # AND on a Xen dom0 (#343). In a guest we genuinely can't see + # the host's SMT scheduling; on dom0/bare metal the local SMT + # state is authoritative, so trust it there. + if is_running_as_guest; then + mds_smt_mitigated=2 + pstatus yellow UNKNOWN "running in a VM guest, the hypervisor host controls SMT" + elif is_cpu_smt_enabled; then + mds_smt_mitigated=0 + pstatus yellow NO + else + mds_smt_mitigated=1 + pstatus green YES + fi else mds_smt_mitigated=0 pstatus yellow NO diff --git a/src/vulns-helpers/check_mmio.sh b/src/vulns-helpers/check_mmio.sh index 7b5bfd6..f755683 100644 --- a/src/vulns-helpers/check_mmio.sh +++ b/src/vulns-helpers/check_mmio.sh @@ -233,11 +233,21 @@ check_mmio_linux() { mmio_smt_mitigated=1 pstatus green YES elif echo "$ret_sys_interface_check_fullmsg" | grep -q 'SMT Host state unknown'; then - # The kernel appends "SMT Host state unknown" when running under - # a hypervisor (X86_FEATURE_HYPERVISOR): the host controls SMT - # scheduling, so it can't be determined from inside the guest (#343). - mmio_smt_mitigated=2 - pstatus yellow UNKNOWN "running in a VM guest, the hypervisor host controls SMT" + # The kernel appends "SMT Host state unknown" whenever the + # HYPERVISOR CPUID bit is set. That's true both inside a guest + # AND on a Xen dom0 (#343). In a guest we genuinely can't see + # the host's SMT scheduling; on dom0/bare metal the local SMT + # state is authoritative, so trust it there. + if is_running_as_guest; then + mmio_smt_mitigated=2 + pstatus yellow UNKNOWN "running in a VM guest, the hypervisor host controls SMT" + elif is_cpu_smt_enabled; then + mmio_smt_mitigated=0 + pstatus yellow NO + else + mmio_smt_mitigated=1 + pstatus green YES + fi else mmio_smt_mitigated=0 pstatus yellow NO diff --git a/src/vulns/CVE-2019-11135.sh b/src/vulns/CVE-2019-11135.sh index eb85a1a..dcb0e76 100644 --- a/src/vulns/CVE-2019-11135.sh +++ b/src/vulns/CVE-2019-11135.sh @@ -87,10 +87,18 @@ check_CVE_2019_11135_linux() { elif echo "$ret_sys_interface_check_fullmsg" | grep -qF 'SMT vulnerable'; then pvulnstatus "$cve" VULN "SMT (HyperThreading) must be disabled for full mitigation" elif echo "$ret_sys_interface_check_fullmsg" | grep -qF 'SMT Host state unknown'; then - # The kernel appends "SMT Host state unknown" when running under a - # hypervisor (X86_FEATURE_HYPERVISOR): the host controls SMT - # scheduling, so it can't be determined from inside the guest (#343). - pvulnstatus "$cve" UNK "TAA is mitigated and TSX is disabled, but SMT (Hyper-Threading) cross-thread protection can't be verified from inside a VM guest: it depends on the hypervisor host's SMT/core-scheduling configuration" + # "SMT Host state unknown" is emitted whenever the HYPERVISOR + # CPUID bit is set -- true both inside a guest AND on a Xen dom0 + # (#343). In a guest we can't see the host's SMT scheduling; on + # dom0/bare metal the local SMT state is authoritative, so trust + # it there. + if is_running_as_guest; then + pvulnstatus "$cve" UNK "TAA is mitigated and TSX is disabled, but SMT (Hyper-Threading) cross-thread protection can't be verified from inside a VM guest: it depends on the hypervisor host's SMT/core-scheduling configuration" + elif is_cpu_smt_enabled; then + pvulnstatus "$cve" VULN "SMT (HyperThreading) must be disabled for full mitigation" + else + pvulnstatus "$cve" "$status" "$msg" + fi else pvulnstatus "$cve" "$status" "$msg" fi