mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-09-13 14:23:27 +02:00
Zenbleed (CVE-2023-20593) is mitigated either by up-to-date CPU microcode
or by the host kernel setting FP_BACKUP_FIX (DE_CFG MSR 0xc0011029 bit 9).
Both are applied at the host level. Inside a Xen dom0/domU (or any VM
guest) the script can't read that MSR and can't trust the microcode
version the hypervisor presents, so it wrongly concluded "kernel too old
+ microcode not fixed" and reported VULN even though the host had applied
the microcode fix (passing on bare metal).
In live mode, when the verdict would be VULN and we're running as a guest,
report UNK instead, explaining the mitigation is host-level and not
observable from inside the guest. Bare metal is unchanged (still VULN),
offline analysis is unchanged, and a guest with positively-confirmed
fixed microcode still reports OK.
(cherry picked from commit 0b022ee253)
182 lines
9.0 KiB
Bash
182 lines
9.0 KiB
Bash
# vim: set ts=4 sw=4 sts=4 et:
|
|
###############################
|
|
# CVE-2023-20593, Zenbleed, Cross-Process Information Leak
|
|
|
|
check_CVE_2023_20593() {
|
|
check_cve 'CVE-2023-20593'
|
|
}
|
|
|
|
check_CVE_2023_20593_linux() {
|
|
local status sys_interface_available msg kernel_zenbleed kernel_zenbleed_err fp_backup_fix ucode_zenbleed zenbleed_print_vuln ret
|
|
status=UNK
|
|
sys_interface_available=0
|
|
msg=''
|
|
if [ "$opt_sysfs_only" != 1 ]; then
|
|
pr_info_nol "* Zenbleed mitigation is supported by kernel: "
|
|
kernel_zenbleed=''
|
|
if [ -n "$g_kernel_err" ]; then
|
|
kernel_zenbleed_err="$g_kernel_err"
|
|
# commit 522b1d69219d8f083173819fde04f994aa051a98
|
|
elif grep -q 'Zenbleed:' "$g_kernel"; then
|
|
kernel_zenbleed="found zenbleed message in kernel image"
|
|
fi
|
|
if [ -n "$kernel_zenbleed" ]; then
|
|
pstatus green YES "$kernel_zenbleed"
|
|
elif [ -n "$kernel_zenbleed_err" ]; then
|
|
pstatus yellow UNKNOWN "$kernel_zenbleed_err"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
pr_info_nol "* Zenbleed kernel mitigation enabled and active: "
|
|
if [ "$g_mode" = live ]; then
|
|
# read the DE_CFG MSR, we want to check the 9th bit
|
|
# don't do it on non-Zen2 AMD CPUs or later, aka Family 17h,
|
|
# as the behavior could be unknown on others
|
|
if is_amd && [ "$cpu_family" -ge $((0x17)) ]; then
|
|
read_msr 0xc0011029
|
|
ret=$?
|
|
if [ "$ret" = "$READ_MSR_RET_OK" ]; then
|
|
if [ $((ret_read_msr_value_lo >> 9 & 1)) -eq 1 ]; then
|
|
pstatus green YES "FP_BACKUP_FIX bit set in DE_CFG"
|
|
fp_backup_fix=1
|
|
else
|
|
pstatus yellow NO "FP_BACKUP_FIX is cleared in DE_CFG"
|
|
fp_backup_fix=0
|
|
fi
|
|
elif [ "$ret" = "$READ_MSR_RET_KO" ]; then
|
|
pstatus yellow UNKNOWN "Couldn't read the DE_CFG MSR"
|
|
else
|
|
pstatus yellow UNKNOWN "$ret_read_msr_msg"
|
|
fi
|
|
else
|
|
fp_backup_fix=0
|
|
pstatus blue N/A "CPU is incompatible"
|
|
fi
|
|
else
|
|
pstatus blue N/A "not testable in no-runtime mode"
|
|
fi
|
|
|
|
pr_info_nol "* Zenbleed mitigation is supported by CPU microcode: "
|
|
has_zenbleed_fixed_firmware
|
|
ret=$?
|
|
if [ "$ret" -eq 0 ]; then
|
|
pstatus green YES
|
|
ucode_zenbleed=1
|
|
elif [ "$ret" -eq 1 ]; then
|
|
pstatus yellow NO
|
|
ucode_zenbleed=2
|
|
else
|
|
pstatus yellow UNKNOWN
|
|
ucode_zenbleed=3
|
|
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
|
|
|
|
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
|
|
zenbleed_print_vuln=0
|
|
if [ "$g_mode" = live ]; then
|
|
if [ "$fp_backup_fix" = 1 ] && [ "$ucode_zenbleed" = 1 ]; then
|
|
# this should never happen, but if it does, it's interesting to know
|
|
pvulnstatus "$cve" OK "Both your CPU microcode and kernel are mitigating Zenbleed"
|
|
elif [ "$ucode_zenbleed" = 1 ]; then
|
|
pvulnstatus "$cve" OK "Your CPU microcode mitigates Zenbleed"
|
|
elif [ "$fp_backup_fix" = 1 ]; then
|
|
pvulnstatus "$cve" OK "Your kernel mitigates Zenbleed"
|
|
else
|
|
zenbleed_print_vuln=1
|
|
fi
|
|
else
|
|
if [ "$ucode_zenbleed" = 1 ]; then
|
|
pvulnstatus "$cve" OK "Your CPU microcode mitigates Zenbleed"
|
|
elif [ -n "$kernel_zenbleed" ]; then
|
|
pvulnstatus "$cve" OK "Your kernel mitigates Zenbleed"
|
|
else
|
|
zenbleed_print_vuln=1
|
|
fi
|
|
fi
|
|
if [ "$zenbleed_print_vuln" = 1 ]; then
|
|
if [ "$g_mode" = live ] && is_running_as_guest; then
|
|
# Both Zenbleed mitigations are applied at the host level: an
|
|
# up-to-date microcode, or the host kernel setting FP_BACKUP_FIX
|
|
# in DE_CFG. From inside a guest we can't read that MSR and can't
|
|
# trust the microcode version the hypervisor presents, so we can't
|
|
# confirm or deny the mitigation -- don't cry VULN (#488).
|
|
pvulnstatus "$cve" UNK "Zenbleed mitigation can't be verified from inside a VM guest ($g_is_guest_vm_reason): it may be applied by the hypervisor host, but that isn't observable from here"
|
|
explain "Zenbleed is mitigated either by an up-to-date CPU microcode or by the host kernel setting the FP_BACKUP_FIX bit (DE_CFG MSR 0xc0011029 bit 9). Both are host-level: a guest can neither read that MSR nor trust the microcode version the hypervisor presents (see the VM note in the hardware section above). Re-run this script on the hypervisor host to get an accurate result."
|
|
else
|
|
pvulnstatus "$cve" VULN "Your kernel is too old to mitigate Zenbleed and your CPU microcode doesn't mitigate it either"
|
|
explain "Your CPU vendor may have a new microcode for your CPU model that mitigates this issue (refer to the hardware section above).\n " \
|
|
"Otherwise, the Linux kernel is able to mitigate this issue regardless of the microcode version you have, but in this case\n " \
|
|
"your kernel is too old to support this, your Linux distribution vendor might have a more recent version you should upgrade to.\n " \
|
|
"Note that either having an up to date microcode OR an up to date kernel is enough to mitigate this issue.\n " \
|
|
"To manually mitigate the issue right now, you may use the following command: \`wrmsr -a 0xc0011029 \$((\$(rdmsr -c 0xc0011029) | (1<<9)))\`,\n " \
|
|
"however note that this manual mitigation will only be active until the next reboot."
|
|
fi
|
|
fi
|
|
unset zenbleed_print_vuln
|
|
else
|
|
pvulnstatus "$cve" "$status" "$msg"
|
|
fi
|
|
}
|
|
|
|
check_CVE_2023_20593_bsd() {
|
|
local zenbleed_enable zenbleed_state kernel_zenbleed
|
|
pr_info_nol "* Kernel supports Zenbleed mitigation (machdep.mitigations.zenbleed.enable): "
|
|
zenbleed_enable=$(sysctl -n machdep.mitigations.zenbleed.enable 2>/dev/null)
|
|
if [ -n "$zenbleed_enable" ]; then
|
|
kernel_zenbleed=1
|
|
case "$zenbleed_enable" in
|
|
0) pstatus yellow YES "force disabled" ;;
|
|
1) pstatus green YES "force enabled" ;;
|
|
2) pstatus green YES "automatic (default)" ;;
|
|
*) pstatus yellow YES "unknown value: $zenbleed_enable" ;;
|
|
esac
|
|
else
|
|
kernel_zenbleed=0
|
|
pstatus yellow NO
|
|
fi
|
|
|
|
pr_info_nol "* Zenbleed mitigation state: "
|
|
zenbleed_state=$(sysctl -n machdep.mitigations.zenbleed.state 2>/dev/null)
|
|
if [ -n "$zenbleed_state" ]; then
|
|
if echo "$zenbleed_state" | grep -qi 'not.applicable\|mitigation.enabled'; then
|
|
pstatus green YES "$zenbleed_state"
|
|
elif echo "$zenbleed_state" | grep -qi 'mitigation.disabled'; then
|
|
pstatus yellow NO "$zenbleed_state"
|
|
else
|
|
pstatus yellow UNKNOWN "$zenbleed_state"
|
|
fi
|
|
else
|
|
pstatus yellow NO "sysctl not available"
|
|
fi
|
|
|
|
if ! is_cpu_affected "$cve"; then
|
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
|
elif [ "$kernel_zenbleed" = 1 ] && [ "$zenbleed_enable" != 0 ]; then
|
|
if [ -n "$zenbleed_state" ] && echo "$zenbleed_state" | grep -qi 'mitigation.enabled'; then
|
|
pvulnstatus "$cve" OK "Zenbleed mitigation is enabled ($zenbleed_state)"
|
|
elif [ -n "$zenbleed_state" ] && echo "$zenbleed_state" | grep -qi 'not.applicable'; then
|
|
pvulnstatus "$cve" OK "Zenbleed mitigation not applicable to this CPU ($zenbleed_state)"
|
|
else
|
|
pvulnstatus "$cve" OK "Zenbleed mitigation is enabled"
|
|
fi
|
|
elif [ "$kernel_zenbleed" = 1 ] && [ "$zenbleed_enable" = 0 ]; then
|
|
pvulnstatus "$cve" VULN "Zenbleed mitigation is supported but force disabled"
|
|
explain "To re-enable Zenbleed mitigation, run \`sysctl machdep.mitigations.zenbleed.enable=2' for automatic mode.\n " \
|
|
"To make this persistent, add 'machdep.mitigations.zenbleed.enable=2' to /etc/sysctl.conf."
|
|
else
|
|
pvulnstatus "$cve" VULN "your kernel doesn't support Zenbleed mitigation, update it"
|
|
explain "Your CPU vendor may also have a new microcode for your CPU model that mitigates this issue.\n " \
|
|
"Updating to FreeBSD 14.0 or later will provide kernel-level Zenbleed mitigation via the\n " \
|
|
"machdep.mitigations.zenbleed sysctl."
|
|
fi
|
|
}
|