mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-06-13 18:13:29 +02:00
1211c21261
Better detect Xen guest type + add container detection CVE-2017-5754: when we see Xen but we're inside a container, /proc/xen/capabilities isn't exposed and dmesg is the host's, so dom0 vs PV DomU can't be told apart. Don't report VULN in that case, but UNKNOWN instead, and ask to rerun the script on the host.
295 lines
14 KiB
Bash
295 lines
14 KiB
Bash
# vim: set ts=4 sw=4 sts=4 et:
|
|
###############################
|
|
# CVE-2017-5754, Meltdown, Rogue Data Cache Load
|
|
|
|
# no security impact but give a hint to the user in verbose mode
|
|
# about PCID/INVPCID cpuid features that must be present to avoid
|
|
# Check whether PCID/INVPCID are available to reduce PTI performance impact
|
|
# refs:
|
|
# https://marc.info/?t=151532047900001&r=1&w=2
|
|
# https://groups.google.com/forum/m/#!topic/mechanical-sympathy/L9mHTbeQLNU
|
|
pti_performance_check() {
|
|
local ret pcid invpcid
|
|
pr_info_nol " * Reduced performance impact of PTI: "
|
|
if [ -e "$g_procfs/cpuinfo" ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw pcid; then
|
|
pcid=1
|
|
else
|
|
read_cpuid 0x1 0x0 "$ECX" 17 1 1
|
|
ret=$?
|
|
if [ "$ret" = "$READ_CPUID_RET_OK" ]; then
|
|
pcid=1
|
|
fi
|
|
fi
|
|
|
|
if [ -e "$g_procfs/cpuinfo" ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw invpcid; then
|
|
invpcid=1
|
|
else
|
|
read_cpuid 0x7 0x0 "$EBX" 10 1 1
|
|
ret=$?
|
|
if [ "$ret" = "$READ_CPUID_RET_OK" ]; then
|
|
invpcid=1
|
|
fi
|
|
fi
|
|
|
|
if [ "$invpcid" = 1 ]; then
|
|
pstatus green YES 'CPU supports INVPCID, performance impact of PTI will be greatly reduced'
|
|
elif [ "$pcid" = 1 ]; then
|
|
pstatus green YES 'CPU supports PCID, performance impact of PTI will be reduced'
|
|
else
|
|
pstatus blue NO 'PCID/INVPCID not supported, performance impact of PTI will be significant'
|
|
fi
|
|
}
|
|
|
|
check_CVE_2017_5754() {
|
|
check_cve 'CVE-2017-5754'
|
|
}
|
|
|
|
check_CVE_2017_5754_linux() {
|
|
local status sys_interface_available msg kpti_support kpti_can_tell kpti_enabled dmesg_grep pti_xen_pv_domU xen_pv_domo xen_pv_domu xen_unknown_container explain_text
|
|
status=UNK
|
|
sys_interface_available=0
|
|
msg=''
|
|
if sys_interface_check "$VULN_SYSFS_BASE/meltdown"; then
|
|
# this kernel has the /sys interface, trust it over everything
|
|
sys_interface_available=1
|
|
status=$ret_sys_interface_check_status
|
|
fi
|
|
if [ "$opt_sysfs_only" != 1 ]; then
|
|
pr_info_nol "* Kernel supports Page Table Isolation (PTI): "
|
|
kpti_support=''
|
|
kpti_can_tell=0
|
|
if [ -n "$opt_config" ]; then
|
|
kpti_can_tell=1
|
|
kpti_support=$(grep -E -w -e 'CONFIG_(MITIGATION_)?PAGE_TABLE_ISOLATION=y' -e CONFIG_KAISER=y -e CONFIG_UNMAP_KERNEL_AT_EL0=y "$opt_config")
|
|
if [ -n "$kpti_support" ]; then
|
|
pr_debug "kpti_support: found option '$kpti_support' in $opt_config"
|
|
fi
|
|
fi
|
|
if [ -z "$kpti_support" ] && [ -n "$opt_map" ]; then
|
|
# it's not an elif: some backports don't have the PTI config but still include the patch
|
|
# so we try to find an exported symbol that is part of the PTI patch in System.map
|
|
# parse_kpti: arm
|
|
kpti_can_tell=1
|
|
kpti_support=$(grep -w -e kpti_force_enabled -e parse_kpti "$opt_map")
|
|
if [ -n "$kpti_support" ]; then
|
|
pr_debug "kpti_support: found '$kpti_support' in $opt_map"
|
|
fi
|
|
fi
|
|
if [ -z "$kpti_support" ] && [ -n "$g_kernel" ]; then
|
|
# same as above but in case we don't have System.map and only kernel, look for the
|
|
# nopti option that is part of the patch (kernel command line option)
|
|
# 'kpti=': arm
|
|
kpti_can_tell=1
|
|
if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then
|
|
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package"
|
|
else
|
|
kpti_support=$("${opt_arch_prefix}strings" "$g_kernel" | grep -w -e nopti -e kpti=)
|
|
if [ -n "$kpti_support" ]; then
|
|
pr_debug "kpti_support: found '$kpti_support' in $g_kernel"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
if [ -n "$kpti_support" ]; then
|
|
if [ "$opt_verbose" -ge 2 ]; then
|
|
pstatus green YES "found '$kpti_support'"
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
elif [ "$kpti_can_tell" = 1 ]; then
|
|
pstatus yellow NO
|
|
else
|
|
pstatus yellow UNKNOWN "couldn't read your kernel configuration nor System.map file"
|
|
fi
|
|
|
|
mount_debugfs
|
|
pr_info_nol " * PTI enabled and active: "
|
|
if [ "$g_mode" = live ]; then
|
|
dmesg_grep="Kernel/User page tables isolation: enabled"
|
|
dmesg_grep="$dmesg_grep|Kernel page table isolation enabled"
|
|
dmesg_grep="$dmesg_grep|x86/pti: Unmapping kernel while in userspace"
|
|
# aarch64
|
|
dmesg_grep="$dmesg_grep|CPU features: detected( feature)?: Kernel page table isolation \(KPTI\)"
|
|
if grep ^flags "$g_procfs/cpuinfo" | grep -qw pti; then
|
|
# vanilla PTI patch sets the 'pti' flag in cpuinfo
|
|
pr_debug "kpti_enabled: found 'pti' flag in $g_procfs/cpuinfo"
|
|
kpti_enabled=1
|
|
elif grep ^flags "$g_procfs/cpuinfo" | grep -qw kaiser; then
|
|
# kernel line 4.9 sets the 'kaiser' flag in cpuinfo
|
|
pr_debug "kpti_enabled: found 'kaiser' flag in $g_procfs/cpuinfo"
|
|
kpti_enabled=1
|
|
elif [ -e "$DEBUGFS_BASE/x86/pti_enabled" ]; then
|
|
# Red Hat Backport creates a dedicated file, see https://access.redhat.com/articles/3311301
|
|
kpti_enabled=$(cat "$DEBUGFS_BASE/x86/pti_enabled" 2>/dev/null)
|
|
pr_debug "kpti_enabled: file $DEBUGFS_BASE/x86/pti_enabled exists and says: $kpti_enabled"
|
|
elif is_xen_dom0; then
|
|
pti_xen_pv_domU=$(xl dmesg 2>/dev/null | grep 'XPTI' | grep 'DomU enabled' | head -n1)
|
|
|
|
[ -n "$pti_xen_pv_domU" ] && kpti_enabled=1
|
|
fi
|
|
if [ -z "$kpti_enabled" ]; then
|
|
dmesg_grep "$dmesg_grep"
|
|
ret=$?
|
|
if [ "$ret" -eq 0 ]; then
|
|
pr_debug "kpti_enabled: found hint in dmesg: $ret_dmesg_grep_grepped"
|
|
kpti_enabled=1
|
|
elif [ "$ret" -eq 2 ]; then
|
|
pr_debug "kpti_enabled: dmesg truncated"
|
|
kpti_enabled=-1
|
|
fi
|
|
fi
|
|
if [ -z "$kpti_enabled" ]; then
|
|
pr_debug "kpti_enabled: couldn't find any hint that PTI is enabled"
|
|
kpti_enabled=0
|
|
fi
|
|
if [ "$kpti_enabled" = 1 ]; then
|
|
pstatus green YES
|
|
elif [ "$kpti_enabled" = -1 ]; then
|
|
pstatus yellow UNKNOWN "dmesg truncated, please reboot and relaunch this script"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
else
|
|
pstatus blue N/A "not testable in no-runtime mode"
|
|
fi
|
|
|
|
# PCID/INVPCID are x86-only CPU features
|
|
if is_x86_cpu; then
|
|
pti_performance_check
|
|
fi
|
|
|
|
elif [ "$sys_interface_available" = 0 ]; then
|
|
# we have no sysfs but were asked to use it only!
|
|
msg="/sys vulnerability interface use forced, but it's not available!"
|
|
status=UNK
|
|
fi
|
|
|
|
# Test if the current host is a Xen PV Dom0 / DomU
|
|
xen_pv_domo=0
|
|
xen_pv_domu=0
|
|
xen_unknown_container=0
|
|
if is_xen && ! is_xen_dom0 && is_running_in_container; then
|
|
# We can see Xen, but we're inside a container so /proc/xen/capabilities
|
|
# isn't exposed and dmesg is the host's: we can't tell a safe Dom0 from
|
|
# a vulnerable PV DomU from in here (issue #173).
|
|
xen_unknown_container=1
|
|
else
|
|
is_xen_dom0 && xen_pv_domo=1
|
|
is_xen_domU && xen_pv_domu=1
|
|
fi
|
|
|
|
if [ "$g_mode" = live ]; then
|
|
# checking whether we're running under Xen PV 64 bits. If yes, we are affected by affected_variant3
|
|
# (unless we are a Dom0)
|
|
pr_info_nol "* Running as a Xen PV DomU: "
|
|
if [ "$xen_unknown_container" = 1 ]; then
|
|
pstatus yellow UNKNOWN "running in a container, can't query Xen from here"
|
|
elif [ "$xen_pv_domu" = 1 ]; then
|
|
pstatus yellow YES
|
|
else
|
|
pstatus blue NO
|
|
fi
|
|
fi
|
|
|
|
if ! is_cpu_affected "$cve"; then
|
|
# override status & msg in case CPU is not vulnerable after all
|
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
|
elif [ -z "$msg" ]; then
|
|
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
|
if [ "$g_mode" = live ]; then
|
|
if [ "$xen_unknown_container" = 1 ]; then
|
|
pvulnstatus "$cve" UNK "running inside a container on a Xen host, can't determine if the underlying domain is a vulnerable PV DomU"
|
|
explain "This system looks like a container ($g_container_reason) running on a Xen host. Whether the underlying domain is a safe Dom0 or a vulnerable PV DomU can't be reliably determined from inside a container (/proc/xen is exposed but empty, and dmesg belongs to the host). Please re-run this script directly on the host, outside the container, to get an accurate result."
|
|
elif [ "$kpti_enabled" = 1 ]; then
|
|
pvulnstatus "$cve" OK "PTI mitigates the vulnerability"
|
|
elif [ "$xen_pv_domo" = 1 ]; then
|
|
pvulnstatus "$cve" OK "Xen Dom0s are safe and do not require PTI"
|
|
elif [ "$xen_pv_domu" = 1 ]; then
|
|
pvulnstatus "$cve" VULN "Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM, PVH mode, or the Xen hypervisor must have the Xen's own PTI patch"
|
|
explain "Go to https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ for more information"
|
|
elif [ "$kpti_enabled" = -1 ]; then
|
|
pvulnstatus "$cve" UNK "couldn't find any clue of PTI activation due to a truncated dmesg, please reboot and relaunch this script"
|
|
else
|
|
pvulnstatus "$cve" VULN "PTI is needed to mitigate the vulnerability"
|
|
if [ -n "$kpti_support" ]; then
|
|
if [ -e "$DEBUGFS_BASE/x86/pti_enabled" ]; then
|
|
explain "Your kernel supports PTI but it's disabled, you can enable it with \`echo 1 > $DEBUGFS_BASE/x86/pti_enabled\`"
|
|
elif echo "$g_kernel_cmdline" | grep -q -w -e nopti -e pti=off; then
|
|
explain "Your kernel supports PTI but it has been disabled on command-line, remove the nopti or pti=off option from your bootloader configuration"
|
|
else
|
|
explain "Your kernel supports PTI but it has been disabled, check \`dmesg\` right after boot to find clues why the system disabled it"
|
|
fi
|
|
else
|
|
explain "If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_(MITIGATION_)PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)"
|
|
fi
|
|
fi
|
|
else
|
|
if [ -n "$kpti_support" ]; then
|
|
pvulnstatus "$cve" OK "no-runtime mode: PTI will mitigate the vulnerability if enabled at runtime"
|
|
elif [ "$kpti_can_tell" = 1 ]; then
|
|
pvulnstatus "$cve" VULN "PTI is needed to mitigate the vulnerability"
|
|
explain "If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_(MITIGATION_)PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)"
|
|
else
|
|
pvulnstatus "$cve" UNK "no-runtime mode: not enough information"
|
|
explain "Re-run this script with root privileges, and give it the kernel image (--kernel), the kernel configuration (--config) and the System.map file (--map) corresponding to the kernel you would like to inspect."
|
|
fi
|
|
fi
|
|
else
|
|
if [ "$xen_pv_domo" = 1 ]; then
|
|
msg="Xen Dom0s are safe and do not require PTI"
|
|
status="OK"
|
|
elif [ "$xen_pv_domu" = 1 ]; then
|
|
msg="Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM, PVH mode, or the Xen hypervisor must have the Xen's own PTI patch"
|
|
status="VULN"
|
|
explain_text="Go to https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ for more information"
|
|
elif [ "$msg" = "Vulnerable" ]; then
|
|
msg="PTI is needed to mitigate the vulnerability"
|
|
explain_text="If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_(MITIGATION_)PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)"
|
|
fi
|
|
pvulnstatus "$cve" "$status" "$msg"
|
|
[ -z "${explain_text:-}" ] && [ "$msg" = "Vulnerable" ] && explain_text="If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel with the CONFIG_(MITIGATION_)PAGE_TABLE_ISOLATION option (named CONFIG_KAISER for some kernels), or the CONFIG_UNMAP_KERNEL_AT_EL0 option (for ARM64)"
|
|
[ -n "${explain_text:-}" ] && explain "$explain_text"
|
|
unset explain_text
|
|
fi
|
|
|
|
# Warn the user about XSA-254 recommended mitigations
|
|
if [ "$xen_pv_domo" = 1 ]; then
|
|
pr_warn
|
|
pr_warn "This host is a Xen Dom0. Please make sure that you are running your DomUs"
|
|
pr_warn "in HVM, PVHVM or PVH mode to prevent any guest-to-host / host-to-guest attacks."
|
|
pr_warn
|
|
pr_warn "See https://blog.xenproject.org/2018/01/22/xen-project-spectre-meltdown-faq-jan-22-update/ and XSA-254 for details."
|
|
fi
|
|
}
|
|
|
|
check_CVE_2017_5754_bsd() {
|
|
local kpti_enabled
|
|
pr_info_nol "* Kernel supports Page Table Isolation (PTI): "
|
|
kpti_enabled=$(sysctl -n vm.pmap.pti 2>/dev/null)
|
|
if [ -z "$kpti_enabled" ]; then
|
|
pstatus yellow NO
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
|
|
pr_info_nol " * PTI enabled and active: "
|
|
if [ "$kpti_enabled" = 1 ]; then
|
|
pstatus green YES
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
|
|
pti_performance_check
|
|
|
|
if ! is_cpu_affected "$cve"; then
|
|
# override status & msg in case CPU is not vulnerable after all
|
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
|
elif [ "$kpti_enabled" = 1 ]; then
|
|
pvulnstatus "$cve" OK "PTI mitigates the vulnerability"
|
|
elif [ -n "$kpti_enabled" ]; then
|
|
pvulnstatus "$cve" VULN "PTI is supported but disabled on your system"
|
|
else
|
|
pvulnstatus "$cve" VULN "PTI is needed to mitigate the vulnerability"
|
|
fi
|
|
}
|