diff --git a/src/libs/001_core_header.sh b/src/libs/001_core_header.sh index d09a997..2723c25 100644 --- a/src/libs/001_core_header.sh +++ b/src/libs/001_core_header.sh @@ -17,7 +17,8 @@ VERSION='1.0.0' # --- Common paths and basedirs --- readonly VULN_SYSFS_BASE="/sys/devices/system/cpu/vulnerabilities" -readonly DEBUGFS_BASE="/sys/kernel/debug" +readonly SYSKERNEL_BASE="/sys/kernel" +readonly DEBUGFS_BASE="$SYSKERNEL_BASE/debug" readonly SYS_MODULE_BASE="/sys/module" readonly CPU_DEV_BASE="/dev/cpu" readonly BSD_CPUCTL_DEV_BASE="/dev/cpuctl" diff --git a/src/libs/340_cpu_msr.sh b/src/libs/340_cpu_msr.sh index 51ef6d1..067c972 100644 --- a/src/libs/340_cpu_msr.sh +++ b/src/libs/340_cpu_msr.sh @@ -58,6 +58,19 @@ write_msr_one_core() { return "$(eval echo \$$mockvarname)" fi + # proactive lockdown detection via sysfs (vanilla 5.4+, CentOS 8+, Rocky 9+): + # if the kernel lockdown is set to integrity or confidentiality, MSR writes will be denied, + # so we can skip the write attempt entirely and avoid relying on dmesg parsing + if [ -e "$SYSKERNEL_BASE/security/lockdown" ]; then + if grep -qE '\[integrity\]|\[confidentiality\]' "$SYSKERNEL_BASE/security/lockdown" 2>/dev/null; then + pr_debug "write_msr: kernel lockdown detected via $SYSKERNEL_BASE/security/lockdown" + g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_WRMSR_${msr}_RET=$WRITE_MSR_RET_LOCKDOWN") + g_msr_locked_down=1 + ret_write_msr_msg="your kernel is locked down, please reboot with lockdown=none in the kernel cmdline and retry" + return $WRITE_MSR_RET_LOCKDOWN + fi + fi + if [ ! -e $CPU_DEV_BASE/0/msr ] && [ ! -e ${BSD_CPUCTL_DEV_BASE}0 ]; then # try to load the module ourselves (and remember it so we can rmmod it afterwards) load_msr @@ -231,6 +244,19 @@ read_msr_one_core() { return "$(eval echo \$$mockvarname)" fi + # proactive lockdown detection via sysfs (vanilla 5.4+, CentOS 8+, Rocky 9+): + # if the kernel lockdown is set to integrity or confidentiality, MSR writes will be denied, + # so we can skip the write attempt entirely and avoid relying on dmesg parsing + if [ -e "$SYSKERNEL_BASE/security/lockdown" ]; then + if grep -qE '\[integrity\]|\[confidentiality\]' "$SYSKERNEL_BASE/security/lockdown" 2>/dev/null; then + pr_debug "write_msr: kernel lockdown detected via $SYSKERNEL_BASE/security/lockdown" + g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_WRMSR_${msr}_RET=$WRITE_MSR_RET_LOCKDOWN") + g_msr_locked_down=1 + ret_write_msr_msg="your kernel is locked down, please reboot with lockdown=none in the kernel cmdline and retry" + return $WRITE_MSR_RET_LOCKDOWN + fi + fi + if [ ! -e $CPU_DEV_BASE/0/msr ] && [ ! -e ${BSD_CPUCTL_DEV_BASE}0 ]; then # try to load the module ourselves (and remember it so we can rmmod it afterwards) load_msr diff --git a/src/libs/400_hw_check.sh b/src/libs/400_hw_check.sh index ab90713..5ea9273 100644 --- a/src/libs/400_hw_check.sh +++ b/src/libs/400_hw_check.sh @@ -626,17 +626,16 @@ check_cpu() { if [ "$opt_allow_msr_write" = 1 ]; then pr_info_nol " * FLUSH_CMD MSR is available: " # the new MSR 'FLUSH_CMD' is at offset 0x10b, write-only + # this is probed for informational purposes only, the CPUID L1D flush bit + # (cap_l1df) is the authoritative indicator per Intel guidance write_msr 0x10b ret=$? if [ $ret = $WRITE_MSR_RET_OK ]; then pstatus green YES - cap_flush_cmd=1 elif [ $ret = $WRITE_MSR_RET_KO ]; then pstatus yellow NO - cap_flush_cmd=0 else pstatus yellow UNKNOWN "$ret_write_msr_msg" - cap_flush_cmd=-1 fi fi @@ -655,12 +654,6 @@ check_cpu() { cap_l1df=-1 fi - # if we weren't allowed to probe the write-only MSR but the CPUID - # bit says that it shoul be there, make the assumption that it is - if [ "$opt_allow_msr_write" != 1 ]; then - cap_flush_cmd=$cap_l1df - fi - if is_intel; then pr_info " * Microarchitectural Data Sampling" pr_info_nol " * VERW instruction is available: " diff --git a/src/vulns/CVE-2018-3615.sh b/src/vulns/CVE-2018-3615.sh index 6db32df..fb07763 100644 --- a/src/vulns/CVE-2018-3615.sh +++ b/src/vulns/CVE-2018-3615.sh @@ -8,15 +8,10 @@ check_CVE_2018_3615() { pr_info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" pr_info_nol "* CPU microcode mitigates the vulnerability: " - if { [ "$cap_flush_cmd" = 1 ] || { [ "$g_msr_locked_down" = 1 ] && [ "$cap_l1df" = 1 ]; }; } && [ "$cap_sgx" = 1 ]; then - # no easy way to detect a fixed SGX but we know that - # microcodes that have the FLUSH_CMD MSR also have the - # fixed SGX (for CPUs that support it), because Intel - # delivered fixed microcodes for both issues at the same time - # - # if the system we're running on is locked down (no way to write MSRs), - # make the assumption that if the L1D flush CPUID bit is set, probably - # that FLUSH_CMD MSR is here too + if [ "$cap_l1df" = 1 ] && [ "$cap_sgx" = 1 ]; then + # the L1D flush CPUID bit indicates that the microcode supports L1D flushing, + # and microcodes that have this also have the fixed SGX (for CPUs that support it), + # because Intel delivered fixed microcodes for both issues at the same time pstatus green YES elif [ "$cap_sgx" = 1 ]; then pstatus red NO @@ -27,7 +22,7 @@ check_CVE_2018_3615() { 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 [ "$cap_flush_cmd" = 1 ] || { [ "$g_msr_locked_down" = 1 ] && [ "$cap_l1df" = 1 ]; }; then + elif [ "$cap_l1df" = 1 ]; then pvulnstatus "$cve" OK "your CPU microcode mitigates the vulnerability" else pvulnstatus "$cve" VULN "your CPU supports SGX and the microcode is not up to date"