mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-05 16:23:19 +02:00
255 lines
12 KiB
Bash
255 lines
12 KiB
Bash
# vim: set ts=4 sw=4 sts=4 et:
|
|
###############################
|
|
# CVE-2022-29900, Retbleed (AMD), Arbitrary Speculative Code Execution with Return Instructions
|
|
|
|
check_CVE_2022_29900() {
|
|
check_cve 'CVE-2022-29900'
|
|
}
|
|
|
|
check_CVE_2022_29900_linux() {
|
|
local status sys_interface_available msg kernel_retbleed kernel_retbleed_err kernel_unret kernel_ibpb_entry smt_enabled
|
|
status=UNK
|
|
sys_interface_available=0
|
|
msg=''
|
|
|
|
#
|
|
# Kernel source inventory for retbleed (CVE-2022-29900 / CVE-2022-29901)
|
|
#
|
|
# --- sysfs messages ---
|
|
# all versions:
|
|
# "Not affected" (cpu_show_common, pre-existing)
|
|
#
|
|
# --- mainline ---
|
|
# 6b80b59b3555 (v5.19-rc7, initial retbleed sysfs):
|
|
# "Vulnerable\n" (hardcoded, no enum yet)
|
|
# 7fbf47c7ce50 (v5.19-rc7, retbleed= boot parameter):
|
|
# "Vulnerable" (RETBLEED_MITIGATION_NONE)
|
|
# "Mitigation: untrained return thunk" (RETBLEED_MITIGATION_UNRET)
|
|
# "Vulnerable: untrained return thunk on non-Zen uarch" (UNRET on non-AMD/Hygon)
|
|
# 6ad0ad2bf8a6 (v5.19-rc7, Intel mitigations):
|
|
# "Mitigation: IBRS" (RETBLEED_MITIGATION_IBRS)
|
|
# "Mitigation: Enhanced IBRS" (RETBLEED_MITIGATION_EIBRS)
|
|
# 3ebc17006888 (v5.19-rc7, retbleed=ibpb):
|
|
# "Mitigation: IBPB" (RETBLEED_MITIGATION_IBPB)
|
|
# e8ec1b6e08a2 (v5.19-rc7, STIBP for JMP2RET):
|
|
# UNRET now appends SMT status:
|
|
# "Mitigation: untrained return thunk; SMT disabled"
|
|
# "Mitigation: untrained return thunk; SMT enabled with STIBP protection"
|
|
# "Mitigation: untrained return thunk; SMT vulnerable"
|
|
# e6cfcdda8cbe (v6.0-rc1, STIBP for IBPB):
|
|
# IBPB now appends SMT status, non-AMD message changed:
|
|
# "Vulnerable: untrained return thunk / IBPB on non-AMD based uarch"
|
|
# "Mitigation: IBPB; SMT disabled"
|
|
# "Mitigation: IBPB; SMT enabled with STIBP protection"
|
|
# "Mitigation: IBPB; SMT vulnerable"
|
|
# d82a0345cf21 (v6.2-rc1, call depth tracking):
|
|
# "Mitigation: Stuffing" (RETBLEED_MITIGATION_STUFF)
|
|
# e3b78a7ad5ea (v6.16-rc1, restructure):
|
|
# added RETBLEED_MITIGATION_AUTO (internal, resolved before display)
|
|
# no new sysfs strings
|
|
#
|
|
# all messages start with either "Not affected", "Vulnerable", or "Mitigation"
|
|
#
|
|
# --- stable backports ---
|
|
# 4.14.y, 4.19.y, 5.4.y: Intel-only mitigations (IBRS, eIBRS); no UNRET, IBPB, STUFF;
|
|
# no SMT status display; simplified retbleed_show_state().
|
|
# 5.10.y, 5.15.y, 6.1.y: full mitigations (NONE, UNRET, IBPB, IBRS, EIBRS);
|
|
# SMT status appended for UNRET/IBPB; no STUFF.
|
|
# 6.6.y, 6.12.y: adds STUFF (call depth tracking). 6.12.y uses INTEL_ model prefix.
|
|
# all stable: single retbleed_select_mitigation() (no update/apply split).
|
|
#
|
|
# --- RHEL/CentOS ---
|
|
# centos7 (~4.18): NONE, UNRET, IBPB, IBRS, EIBRS; no STUFF; SMT status for UNRET;
|
|
# no Hygon check; no UNRET_ENTRY/IBPB_ENTRY/IBRS_ENTRY Kconfig symbols;
|
|
# unique cpu_in_retbleed_whitelist() function for Intel.
|
|
# rocky8 (~4.18/5.14): NONE, UNRET, IBPB, IBRS, EIBRS; no STUFF;
|
|
# CONFIG_CPU_UNRET_ENTRY, CONFIG_CPU_IBPB_ENTRY, CONFIG_CPU_IBRS_ENTRY (old names).
|
|
# rocky9 (~6.x): same as mainline; CONFIG_MITIGATION_* names; has STUFF.
|
|
# rocky10 (~6.12+): same as mainline; has select/update/apply split.
|
|
#
|
|
# --- Kconfig symbols ---
|
|
# f43b9876e857 (v5.19-rc7): CONFIG_CPU_UNRET_ENTRY, CONFIG_CPU_IBPB_ENTRY,
|
|
# CONFIG_CPU_IBRS_ENTRY
|
|
# 80e4c1cd42ff (v6.2-rc1): CONFIG_CALL_DEPTH_TRACKING
|
|
# ac61d43983a4 (v6.9-rc1): renamed to CONFIG_MITIGATION_UNRET_ENTRY,
|
|
# CONFIG_MITIGATION_IBPB_ENTRY, CONFIG_MITIGATION_IBRS_ENTRY,
|
|
# CONFIG_MITIGATION_CALL_DEPTH_TRACKING
|
|
# 894e28857c11 (v6.12-rc1): CONFIG_MITIGATION_RETBLEED (master switch)
|
|
#
|
|
# --- kernel functions (for $opt_map / System.map) ---
|
|
# 7fbf47c7ce50 (v5.19-rc7): retbleed_select_mitigation()
|
|
# e3b78a7ad5ea (v6.16-rc1): split into retbleed_select_mitigation() +
|
|
# retbleed_update_mitigation() + retbleed_apply_mitigation()
|
|
# vendor kernels: centos7/rocky8/rocky9 have retbleed_select_mitigation() only;
|
|
# rocky10 has the full split.
|
|
#
|
|
# --- CPU affection logic (for is_cpu_affected) ---
|
|
# X86_BUG_RETBLEED is set when X86_FEATURE_BTC_NO is NOT set AND either:
|
|
# (a) CPU matches cpu_vuln_blacklist[] RETBLEED entries, OR
|
|
# (b) ARCH_CAP_RSBA is set in IA32_ARCH_CAPABILITIES MSR
|
|
# 6b80b59b3555 (v5.19-rc7, initial AMD):
|
|
# AMD: family 0x15, 0x16, 0x17; Hygon: family 0x18
|
|
# 6ad0ad2bf8a6 (v5.19-rc7, Intel):
|
|
# Intel: SKYLAKE_L, SKYLAKE, SKYLAKE_X, KABYLAKE_L, KABYLAKE,
|
|
# ICELAKE_L, COMETLAKE, COMETLAKE_L, LAKEFIELD, ROCKETLAKE
|
|
# + any Intel with ARCH_CAP_RSBA set
|
|
# 26aae8ccbc19 (v5.19-rc7, BTC_NO):
|
|
# AMD Zen 3+ with BTC_NO are excluded
|
|
# f54d45372c6a (post-v5.19, Cannon Lake):
|
|
# Intel: + CANNONLAKE_L
|
|
# immunity: X86_FEATURE_BTC_NO (AMD) — Zen 3+ declare not affected
|
|
# vendor scope: AMD (0x15-0x17), Hygon (0x18), Intel (Skylake through Rocket Lake + RSBA)
|
|
#
|
|
|
|
if sys_interface_check "$VULN_SYSFS_BASE/retbleed"; 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 mitigation: "
|
|
if [ -n "$g_kernel_err" ]; then
|
|
kernel_retbleed_err="$g_kernel_err"
|
|
elif grep -q 'retbleed' "$g_kernel"; then
|
|
kernel_retbleed="found retbleed mitigation logic in kernel image"
|
|
fi
|
|
if [ -z "$kernel_retbleed" ] && [ -n "$opt_map" ]; then
|
|
if grep -q 'retbleed_select_mitigation' "$opt_map"; then
|
|
kernel_retbleed="found retbleed_select_mitigation in System.map"
|
|
fi
|
|
fi
|
|
if [ -n "$kernel_retbleed" ]; then
|
|
pstatus green YES "$kernel_retbleed"
|
|
elif [ -n "$kernel_retbleed_err" ]; then
|
|
pstatus yellow UNKNOWN "$kernel_retbleed_err"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
|
|
pr_info_nol "* Kernel compiled with UNRET_ENTRY support (untrained return thunk): "
|
|
if [ -r "$opt_config" ]; then
|
|
# CONFIG_CPU_UNRET_ENTRY: Linux < 6.9
|
|
# CONFIG_MITIGATION_UNRET_ENTRY: Linux >= 6.9
|
|
if grep -Eq '^CONFIG_(CPU|MITIGATION)_UNRET_ENTRY=y' "$opt_config"; then
|
|
pstatus green YES
|
|
kernel_unret="CONFIG_(CPU|MITIGATION)_UNRET_ENTRY=y found in kernel config"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
else
|
|
if [ -n "$g_kernel_err" ]; then
|
|
pstatus yellow UNKNOWN "$g_kernel_err"
|
|
elif [ -n "$kernel_retbleed" ]; then
|
|
# if the kernel has retbleed logic, assume UNRET_ENTRY is likely compiled in
|
|
# (we can't tell for certain without the config)
|
|
kernel_unret="retbleed mitigation logic present in kernel (UNRET_ENTRY status unknown)"
|
|
pstatus yellow UNKNOWN "kernel has retbleed mitigation but config not available to verify"
|
|
else
|
|
pstatus yellow NO "your kernel is too old and doesn't have the retbleed mitigation logic"
|
|
fi
|
|
fi
|
|
|
|
pr_info_nol "* Kernel compiled with IBPB_ENTRY support: "
|
|
if [ -r "$opt_config" ]; then
|
|
# CONFIG_CPU_IBPB_ENTRY: Linux < 6.9
|
|
# CONFIG_MITIGATION_IBPB_ENTRY: Linux >= 6.9
|
|
if grep -Eq '^CONFIG_(CPU|MITIGATION)_IBPB_ENTRY=y' "$opt_config"; then
|
|
pstatus green YES
|
|
kernel_ibpb_entry="CONFIG_(CPU|MITIGATION)_IBPB_ENTRY=y found in kernel config"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
else
|
|
if [ -n "$g_kernel_err" ]; then
|
|
pstatus yellow UNKNOWN "$g_kernel_err"
|
|
elif [ -n "$kernel_retbleed" ]; then
|
|
kernel_ibpb_entry="retbleed mitigation logic present in kernel (IBPB_ENTRY status unknown)"
|
|
pstatus yellow UNKNOWN "kernel has retbleed mitigation but config not available to verify"
|
|
else
|
|
pstatus yellow NO "your kernel is too old and doesn't have the retbleed mitigation logic"
|
|
fi
|
|
fi
|
|
|
|
# Zen/Zen+/Zen2: check IBPB microcode support and SMT
|
|
if [ "$cpu_family" = $((0x17)) ]; then
|
|
pr_info_nol "* CPU supports IBPB: "
|
|
if [ "$opt_live" = 1 ]; then
|
|
if [ -n "$cap_ibpb" ]; then
|
|
pstatus green YES "$cap_ibpb"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
else
|
|
pstatus blue N/A "not testable in offline mode"
|
|
fi
|
|
|
|
pr_info_nol "* Hyper-Threading (SMT) is enabled: "
|
|
is_cpu_smt_enabled
|
|
smt_enabled=$?
|
|
if [ "$smt_enabled" = 0 ]; then
|
|
pstatus yellow YES
|
|
else
|
|
pstatus green NO
|
|
fi
|
|
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
|
|
if [ "$opt_sysfs_only" != 1 ]; then
|
|
if [ "$cpu_family" = $((0x17)) ]; then
|
|
# Zen/Zen+/Zen2
|
|
if [ -z "$kernel_retbleed" ]; then
|
|
pvulnstatus "$cve" VULN "Your kernel is too old and doesn't have the retbleed mitigation logic"
|
|
elif [ "$opt_paranoid" = 1 ] && [ "$smt_enabled" = 0 ]; then
|
|
pvulnstatus "$cve" VULN "SMT is enabled, which weakens the IBPB-based mitigation"
|
|
explain "For Zen/Zen+/Zen2 CPUs in paranoid mode, proper mitigation needs SMT to be disabled\n" \
|
|
"(this can be done by adding \`nosmt\` to your kernel command line), because IBPB alone\n" \
|
|
"doesn't fully protect cross-thread speculation."
|
|
elif [ -z "$kernel_unret" ] && [ -z "$kernel_ibpb_entry" ]; then
|
|
pvulnstatus "$cve" VULN "Your kernel doesn't have either UNRET_ENTRY or IBPB_ENTRY compiled-in"
|
|
elif [ "$smt_enabled" = 0 ] && [ -z "$cap_ibpb" ] && [ "$opt_live" = 1 ]; then
|
|
pvulnstatus "$cve" VULN "SMT is enabled and your microcode doesn't support IBPB"
|
|
explain "Update your CPU microcode to get IBPB support, or disable SMT by adding\n" \
|
|
"\`nosmt\` to your kernel command line."
|
|
else
|
|
pvulnstatus "$cve" OK "Your kernel and CPU support mitigation"
|
|
fi
|
|
elif [ "$cpu_family" = $((0x15)) ] || [ "$cpu_family" = $((0x16)) ]; then
|
|
# older AMD families: basic mitigation check
|
|
if [ -z "$kernel_retbleed" ]; then
|
|
pvulnstatus "$cve" VULN "Your kernel is too old and doesn't have the retbleed mitigation logic"
|
|
elif [ -n "$kernel_unret" ] || [ -n "$kernel_ibpb_entry" ]; then
|
|
pvulnstatus "$cve" OK "Your kernel supports mitigation"
|
|
else
|
|
pvulnstatus "$cve" VULN "Your kernel doesn't have UNRET_ENTRY or IBPB_ENTRY compiled-in"
|
|
fi
|
|
else
|
|
# not supposed to happen
|
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
|
fi
|
|
else
|
|
pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
|
|
fi
|
|
else
|
|
pvulnstatus "$cve" "$status" "$msg"
|
|
fi
|
|
}
|
|
|
|
check_CVE_2022_29900_bsd() {
|
|
if ! is_cpu_affected "$cve"; then
|
|
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
|
else
|
|
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
|
|
fi
|
|
}
|