mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-03 05:37:11 +02:00
Downfall: - added `--kernel-config` support for all three Kconfig variants seen over all kernel versions up to now - added `--kernel-map` support for `gds_select_mitigation` in `System.map` - fixed the `--sysfs-only` mode - added verbose information about remediation when `--explain` is used - implemented `--paranoid mode`, requiring `GDS_MITIGATION_LOCKED` so that mitigation can't be disabled at runtime - fixed offline mode (was wrongly looking at the system `dmesg`) - better microcode status reporting (enabled, disabled, unsupported, unknown) - fixed unknown (EOL) AVX-capable Intel family 6 CPUs now defaulting to affected - fixed 2 missing known affected CPU models: INTEL_FAM6_SKYLAKE_L and INTEL_FAM6_SKYLAKE - fixed case when we're running in a VM and the hypervisor doesn't let us read the MSR Spectre V2: - fix: affected_cpu: added Centaur family 7 (CentaurHauls) and Zhaoxin family 7 (Shanghai) as immune - fix: added Centaur family 5 (CentaurHauls) and NSC family 5 (Geode by NSC) to is_cpu_specex_free() - enh: offline mode: added detection logic by probing System.map and Kconfig
1250 lines
64 KiB
Bash
1250 lines
64 KiB
Bash
# vim: set ts=4 sw=4 sts=4 et:
|
|
###############################
|
|
# CVE-2017-5715, Spectre V2, Branch Target Injection
|
|
|
|
# Sets: vulnstatus
|
|
check_CVE_2017_5715() {
|
|
check_cve 'CVE-2017-5715'
|
|
}
|
|
|
|
# Sets: g_ibrs_can_tell, g_ibrs_supported, g_ibrs_enabled, g_ibrs_fw_enabled,
|
|
# g_ibpb_can_tell, g_ibpb_supported, g_ibpb_enabled, g_specex_knob_dir
|
|
check_CVE_2017_5715_linux() {
|
|
local status sys_interface_available msg dir bp_harden_can_tell bp_harden retpoline retpoline_compiler retpoline_compiler_reason retp_enabled rsb_filling
|
|
local v2_base_mode v2_stibp_status v2_pbrsb_status v2_bhi_status v2_ibpb_mode v2_vuln_module v2_is_autoibrs smt_enabled
|
|
status=UNK
|
|
sys_interface_available=0
|
|
msg=''
|
|
if sys_interface_check "$VULN_SYSFS_BASE/spectre_v2"; then
|
|
sys_interface_available=1
|
|
status=$ret_sys_interface_check_status
|
|
#
|
|
# Complete sysfs message inventory for spectre_v2, traced via git blame
|
|
# on mainline (~/linux) and stable (~/linux-stable):
|
|
#
|
|
# all versions:
|
|
# "Not affected" (cpu_show_common, 61dc0f555b5c)
|
|
# "Vulnerable" (cpu_show_common fallthrough / spectre_v2_strings[NONE], 61dc0f555b5c)
|
|
#
|
|
# The output is a composite string: <base>[<ibpb>][<ibrs_fw>][<stibp>][<rsb>][<pbrsb>][<bhi>][<module>]
|
|
# where <base> comes from spectre_v2_strings[] (or an early-return override),
|
|
# and the remaining fields are appended by helper functions.
|
|
# Before v6.9-rc4 (0cd01ac5dcb1), fields were separated by ", ".
|
|
# From v6.9-rc4 onward, fields are separated by "; ".
|
|
#
|
|
# --- base string (spectre_v2_strings[]) ---
|
|
#
|
|
# da285121560e (v4.15, initial spectre_v2 sysfs):
|
|
# "Vulnerable"
|
|
# "Mitigation: None" (documented in spectre.rst 5ad3eb113245,
|
|
# not found in code but listed as a possible value; treat as vulnerable / sysfs override)
|
|
# "Vulnerable: Minimal generic ASM retpoline"
|
|
# "Vulnerable: Minimal AMD ASM retpoline"
|
|
# "Mitigation: Full generic retpoline"
|
|
# "Mitigation: Full AMD retpoline"
|
|
# 706d51681d63 (v4.19, added Enhanced IBRS):
|
|
# + "Mitigation: Enhanced IBRS"
|
|
# ef014aae8f1c (v4.20-rc5, removed minimal retpoline):
|
|
# - "Vulnerable: Minimal generic ASM retpoline"
|
|
# - "Vulnerable: Minimal AMD ASM retpoline"
|
|
# d45476d98324 (v5.17-rc8, renamed retpoline variants):
|
|
# "Mitigation: Full generic retpoline" -> "Mitigation: Retpolines"
|
|
# "Mitigation: Full AMD retpoline" -> "Mitigation: LFENCE" (in array)
|
|
# NOTE: "Mitigation: LFENCE" was the actual sysfs output for a brief window
|
|
# (between d45476d98324 and eafd987d4a82, both in v5.17-rc8) before the
|
|
# show_state override reclassified it as "Vulnerable: LFENCE". LFENCE alone
|
|
# is now considered an insufficient mitigation for Spectre v2. Any kernel
|
|
# reporting "Mitigation: LFENCE" is from this narrow window and should be
|
|
# treated as vulnerable.
|
|
# 1e19da8522c8 (v5.17-rc8, split Enhanced IBRS into 3 modes):
|
|
# "Mitigation: Enhanced IBRS" -> "Mitigation: Enhanced IBRS" (EIBRS alone)
|
|
# + "Mitigation: Enhanced IBRS + LFENCE"
|
|
# + "Mitigation: Enhanced IBRS + Retpolines"
|
|
# 7c693f54c873 (v5.19-rc7, added kernel IBRS):
|
|
# + "Mitigation: IBRS"
|
|
# e7862eda309e (v6.3-rc1, AMD Automatic IBRS):
|
|
# "Mitigation: Enhanced IBRS" -> "Mitigation: Enhanced / Automatic IBRS"
|
|
# "Mitigation: Enhanced IBRS + LFENCE" -> "Mitigation: Enhanced / Automatic IBRS + LFENCE"
|
|
# "Mitigation: Enhanced IBRS + Retpolines" -> "Mitigation: Enhanced / Automatic IBRS + Retpolines"
|
|
# d1cc1baef67a (v6.18-rc1, fixed LFENCE in array):
|
|
# "Mitigation: LFENCE" -> "Vulnerable: LFENCE" (in array, matching the
|
|
# show_state override that had been correcting the sysfs output since v5.17)
|
|
#
|
|
# --- early-return overrides in spectre_v2_show_state() ---
|
|
#
|
|
# These bypass the base string + suffix format entirely.
|
|
#
|
|
# eafd987d4a82 (v5.17-rc8, LFENCE override):
|
|
# "Vulnerable: LFENCE"
|
|
# (overrode the array's "Mitigation: LFENCE"; removed in v6.18-rc1 when the array
|
|
# was fixed to say "Vulnerable: LFENCE" directly)
|
|
# 44a3918c8245 (v5.17-rc8, created spectre_v2_show_state, eIBRS+eBPF):
|
|
# "Vulnerable: Unprivileged eBPF enabled"
|
|
# (immediately renamed below)
|
|
# 0de05d056afd (v5.17-rc8, renamed + added eIBRS+LFENCE case):
|
|
# "Vulnerable: Unprivileged eBPF enabled" -> "Vulnerable: eIBRS with unprivileged eBPF"
|
|
# + "Vulnerable: eIBRS+LFENCE with unprivileged eBPF and SMT"
|
|
#
|
|
# --- <ibpb> suffix (ibpb_state()) ---
|
|
#
|
|
# 20ffa1caecca (v4.16-rc1, initial IBPB):
|
|
# ", IBPB" (present/absent)
|
|
# a8f76ae41cd6 (v4.20-rc5, extracted ibpb_state()):
|
|
# ", IBPB: disabled" | ", IBPB: always-on"
|
|
# 7cc765a67d8e (v4.20-rc5, conditional IBPB):
|
|
# + ", IBPB: conditional"
|
|
# 0cd01ac5dcb1 (v6.9-rc4, separator change):
|
|
# ", IBPB: ..." -> "; IBPB: ..."
|
|
#
|
|
# --- <ibrs_fw> suffix ---
|
|
#
|
|
# dd84441a7971 (v4.16-rc4):
|
|
# ", IBRS_FW" (present/absent)
|
|
# 0cd01ac5dcb1 (v6.9-rc4, separator change):
|
|
# ", IBRS_FW" -> "; IBRS_FW"
|
|
#
|
|
# --- <stibp> suffix (stibp_state()) ---
|
|
#
|
|
# 53c613fe6349 (v4.20-rc1, initial STIBP):
|
|
# ", STIBP" (present/absent)
|
|
# a8f76ae41cd6 (v4.20-rc5, extracted stibp_state()):
|
|
# ", STIBP: disabled" | ", STIBP: forced"
|
|
# 9137bb27e60e (v4.20-rc5, added prctl):
|
|
# + ", STIBP: conditional" (when prctl/seccomp + switch_to_cond_stibp)
|
|
# 20c3a2c33e9f (v5.0-rc1, added always-on preferred):
|
|
# + ", STIBP: always-on"
|
|
# 34bce7c9690b (v4.20-rc5, eIBRS suppresses STIBP):
|
|
# returns "" when eIBRS is in use
|
|
# fd470a8beed8 (v6.5-rc4, AutoIBRS exception):
|
|
# returns "" only when eIBRS AND not AutoIBRS (AutoIBRS shows STIBP)
|
|
# 0cd01ac5dcb1 (v6.9-rc4, separator change):
|
|
# ", STIBP: ..." -> "; STIBP: ..."
|
|
#
|
|
# --- <rsb> suffix ---
|
|
#
|
|
# bb4b3b776273 (v4.20-rc1):
|
|
# ", RSB filling" (present/absent)
|
|
# 53c613fe6349 (v4.20-rc1, temporarily removed, re-added in a8f76ae41cd6)
|
|
# 0cd01ac5dcb1 (v6.9-rc4, separator change):
|
|
# ", RSB filling" -> "; RSB filling"
|
|
#
|
|
# --- <pbrsb> suffix (pbrsb_eibrs_state()) ---
|
|
#
|
|
# 2b1299322016 (v6.0-rc1):
|
|
# ", PBRSB-eIBRS: Not affected" | ", PBRSB-eIBRS: SW sequence" | ", PBRSB-eIBRS: Vulnerable"
|
|
# 0cd01ac5dcb1 (v6.9-rc4, separator change):
|
|
# ", PBRSB-eIBRS: ..." -> "; PBRSB-eIBRS: ..."
|
|
#
|
|
# --- <bhi> suffix (spectre_bhi_state()) ---
|
|
#
|
|
# ec9404e40e8f (v6.9-rc4):
|
|
# "; BHI: Not affected" | "; BHI: BHI_DIS_S" | "; BHI: SW loop, KVM: SW loop"
|
|
# | "; BHI: Retpoline" | "; BHI: Vulnerable"
|
|
# 95a6ccbdc719 (v6.9-rc4, KVM default):
|
|
# + "; BHI: Vulnerable, KVM: SW loop"
|
|
# 5f882f3b0a8b (v6.9-rc4, clarified syscall hardening):
|
|
# removed "; BHI: Vulnerable (Syscall hardening enabled)"
|
|
# removed "; BHI: Syscall hardening, KVM: SW loop"
|
|
# (both replaced by "; BHI: Vulnerable" / "; BHI: Vulnerable, KVM: SW loop")
|
|
#
|
|
# --- <module> suffix (spectre_v2_module_string()) ---
|
|
#
|
|
# caf7501a1b4e (v4.16-rc1):
|
|
# " - vulnerable module loaded" (present/absent)
|
|
#
|
|
# --- stable backports ---
|
|
#
|
|
# 3.2.y: old-style base strings ("Full generic/AMD retpoline", "Minimal generic/AMD
|
|
# ASM retpoline"). Suffixes: ", IBPB" only (no STIBP/IBRS_FW/RSB). Format: %s%s\n.
|
|
# Has "Mitigation: Enhanced IBRS" (no "/ Automatic") in later releases.
|
|
# 3.16.y, 4.4.y: old-style base strings. ibpb_state()/stibp_state()/IBRS_FW/RSB filling.
|
|
# 3.16.y lacks STIBP "always-on". Comma separators.
|
|
# Both have "Mitigation: Enhanced IBRS" (no "/ Automatic"). No LFENCE/EIBRS modes.
|
|
# 4.9.y: has spectre_v2_show_state() with LFENCE override ("Vulnerable: LFENCE"),
|
|
# eIBRS+eBPF overrides. "Mitigation: Enhanced IBRS" (no "/ Automatic").
|
|
# No SPECTRE_V2_IBRS. No pbrsb or BHI. Comma separators.
|
|
# 4.14.y: like 4.9.y but also has SPECTRE_V2_IBRS and pbrsb_eibrs_state().
|
|
# "Mitigation: Enhanced IBRS" (no "/ Automatic"). No BHI. Comma separators.
|
|
# 4.19.y: like 4.14.y but has "Enhanced / Automatic IBRS". No BHI. Comma separators.
|
|
# 5.4.y, 5.10.y: like 4.19.y. No BHI. Comma separators.
|
|
# 5.15.y, 6.1.y, 6.6.y, 6.12.y: match mainline (semicolons, BHI, all fields).
|
|
#
|
|
# --- Red Hat / CentOS / Rocky kernels ---
|
|
#
|
|
# Red Hat kernels carry their own spectre_v2 mitigation implementation that differs
|
|
# significantly from mainline. The following strings are unique to Red Hat kernels:
|
|
#
|
|
# centos6 (RHEL 6, kernel 2.6.32): base strings are a superset of mainline v4.15:
|
|
# "Vulnerable: Minimal ASM retpoline" (no "generic" qualifier)
|
|
# "Vulnerable: Minimal AMD ASM retpoline"
|
|
# "Vulnerable: Retpoline without IBPB"
|
|
# "Vulnerable: Retpoline on Skylake+" (removed in later centos6 releases)
|
|
# "Vulnerable: Retpoline with unsafe module(s)"
|
|
# "Mitigation: Full AMD retpoline"
|
|
# "Mitigation: Full retpoline" (no "generic" qualifier)
|
|
# "Mitigation: Full retpoline and IBRS (user space)"
|
|
# "Mitigation: IBRS (kernel)"
|
|
# "Mitigation: IBRS (kernel and user space)"
|
|
# "Mitigation: IBP disabled"
|
|
# Suffixes: ", IBPB" only. Format: %s%s\n.
|
|
#
|
|
# centos7 (RHEL 7, kernel 3.10): early releases have all centos6 strings plus
|
|
# "Vulnerable: Retpoline on Skylake+". Later releases removed Skylake+ and
|
|
# Minimal AMD, and changed AMD retpoline to:
|
|
# "Vulnerable: AMD retpoline (LFENCE/JMP)"
|
|
# Added "Mitigation: Enhanced IBRS". Suffixes: ibpb_state() + stibp_state()
|
|
# with simple ", IBPB" / ", STIBP" strings. No IBRS_FW/RSB/pbrsb/BHI.
|
|
#
|
|
# centos8 (RHEL 8, kernel 4.18): uses mainline v5.17+ style enum names
|
|
# (RETPOLINE/LFENCE/EIBRS) but retains RHEL-specific entries:
|
|
# "Mitigation: IBRS (kernel)" (SPECTRE_V2_IBRS)
|
|
# "Mitigation: Full retpoline and IBRS (user space)" (SPECTRE_V2_RETPOLINE_IBRS_USER)
|
|
# "Mitigation: IBRS (kernel and user space)" (SPECTRE_V2_IBRS_ALWAYS)
|
|
# "Mitigation: Enhanced IBRS" (no "/ Automatic"). spectre_v2_show_state() with
|
|
# LFENCE/eIBRS+eBPF overrides. Comma separators. No pbrsb/BHI.
|
|
#
|
|
# rocky9 (RHEL 9, kernel 5.14): matches mainline. Semicolons, BHI, all fields.
|
|
# rocky10 (RHEL 10, kernel 6.12): matches mainline.
|
|
#
|
|
#
|
|
# --- Kconfig symbols ---
|
|
# 76b043848fd2 (v4.15-rc8): CONFIG_RETPOLINE
|
|
# f43b9876e857 (v5.19-rc7): CONFIG_CPU_IBRS_ENTRY (kernel IBRS on entry)
|
|
# aefb2f2e619b (v6.9-rc1): renamed CONFIG_RETPOLINE => CONFIG_MITIGATION_RETPOLINE
|
|
# 1da8d2172ce5 (v6.9-rc1): renamed CONFIG_CPU_IBRS_ENTRY => CONFIG_MITIGATION_IBRS_ENTRY
|
|
# ec9404e40e8f (v6.9-rc4): CONFIG_SPECTRE_BHI_ON / CONFIG_SPECTRE_BHI_OFF
|
|
# 4f511739c54b (v6.9-rc4): replaced by CONFIG_MITIGATION_SPECTRE_BHI
|
|
# 72c70f480a70 (v6.12-rc1): CONFIG_MITIGATION_SPECTRE_V2 (top-level on/off)
|
|
# 8754e67ad4ac (v6.15-rc7): CONFIG_MITIGATION_ITS (indirect target selection)
|
|
# stable 5.4.y-6.6.y: CONFIG_RETPOLINE (pre-rename)
|
|
# stable 6.12.y: CONFIG_MITIGATION_RETPOLINE, CONFIG_MITIGATION_SPECTRE_V2
|
|
#
|
|
# --- kernel functions (for $opt_map / System.map) ---
|
|
# da285121560e (v4.15-rc8): spectre_v2_select_mitigation(),
|
|
# spectre_v2_parse_cmdline(), nospectre_v2_parse_cmdline()
|
|
# 20ffa1caecca (v4.16-rc1): spectre_v2_module_string(), retpoline_module_ok()
|
|
# a8f76ae41cd6 (v4.20-rc5): spectre_v2_user_select_mitigation(),
|
|
# spectre_v2_user_parse_cmdline()
|
|
# 7c693f54c873 (v5.19-rc7): spectre_v2_in_ibrs_mode(), spectre_v2_in_eibrs_mode()
|
|
# 44a3918c8245 (v5.17-rc8): spectre_v2_show_state()
|
|
# 480e803dacf8 (v6.16-rc1): split into spectre_v2_select_mitigation() +
|
|
# spectre_v2_apply_mitigation() + spectre_v2_update_mitigation() +
|
|
# spectre_v2_user_apply_mitigation() + spectre_v2_user_update_mitigation()
|
|
#
|
|
# --- CPU affection logic (for is_cpu_affected) ---
|
|
# X86_BUG_SPECTRE_V2 is set for ALL x86 CPUs except:
|
|
# - CPUs matching NO_SPECULATION: family 4 (all vendors), Centaur/Intel/NSC/Vortex
|
|
# family 5, Intel Atom Bonnell/Saltwell
|
|
# - CPUs matching NO_SPECTRE_V2: Centaur family 7, Zhaoxin family 7
|
|
# 99c6fa2511d8 (v4.15-rc8): unconditional for all x86 CPUs
|
|
# 1e41a766c98b (v5.6-rc1): added NO_SPECTRE_V2 exemption for Centaur/Zhaoxin
|
|
# 98c7a713db91 (v6.15-rc1): added X86_BUG_SPECTRE_V2_USER as separate bit
|
|
# No MSR/CPUID immunity bits — purely whitelist-based.
|
|
# vendor scope: all x86 vendors affected (Intel, AMD, Hygon, etc.)
|
|
# except Centaur family 7 and Zhaoxin family 7.
|
|
#
|
|
# all messages start with either "Not affected", "Mitigation", or "Vulnerable"
|
|
fi
|
|
if [ "$opt_sysfs_only" != 1 ]; then
|
|
check_has_vmm
|
|
|
|
v2_base_mode=''
|
|
v2_stibp_status=''
|
|
v2_pbrsb_status=''
|
|
v2_bhi_status=''
|
|
v2_ibpb_mode=''
|
|
v2_vuln_module=''
|
|
v2_is_autoibrs=0
|
|
|
|
pr_info "* Mitigation 1"
|
|
|
|
g_ibrs_can_tell=0
|
|
g_ibrs_supported=''
|
|
g_ibrs_enabled=''
|
|
g_ibpb_can_tell=0
|
|
g_ibpb_supported=''
|
|
g_ibpb_enabled=''
|
|
|
|
if [ "$opt_live" = 1 ]; then
|
|
# in live mode, we can check for the ibrs_enabled file in debugfs
|
|
# all versions of the patches have it (NOT the case of IBPB or KPTI)
|
|
g_ibrs_can_tell=1
|
|
mount_debugfs
|
|
for dir in \
|
|
$DEBUGFS_BASE \
|
|
$DEBUGFS_BASE/x86 \
|
|
"$g_procfs/sys/kernel"; do
|
|
if [ -e "$dir/ibrs_enabled" ]; then
|
|
# if the file is there, we have IBRS compiled-in
|
|
# $DEBUGFS_BASE/ibrs_enabled: vanilla
|
|
# $DEBUGFS_BASE/x86/ibrs_enabled: Red Hat (see https://access.redhat.com/articles/3311301)
|
|
# /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed
|
|
g_specex_knob_dir=$dir
|
|
g_ibrs_supported="$dir/ibrs_enabled exists"
|
|
g_ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null)
|
|
pr_debug "ibrs: found $dir/ibrs_enabled=$g_ibrs_enabled"
|
|
# if ibrs_enabled is there, ibpb_enabled will be in the same dir
|
|
if [ -e "$dir/ibpb_enabled" ]; then
|
|
# if the file is there, we have IBPB compiled-in (see note above for IBRS)
|
|
g_ibpb_supported="$dir/ibpb_enabled exists"
|
|
g_ibpb_enabled=$(cat "$dir/ibpb_enabled" 2>/dev/null)
|
|
pr_debug "ibpb: found $dir/ibpb_enabled=$g_ibpb_enabled"
|
|
else
|
|
pr_debug "ibpb: $dir/ibpb_enabled file doesn't exist"
|
|
fi
|
|
break
|
|
else
|
|
pr_debug "ibrs: $dir/ibrs_enabled file doesn't exist"
|
|
fi
|
|
done
|
|
# on some newer kernels, the spec_ctrl_ibrs flag in "$g_procfs/cpuinfo"
|
|
# is set when ibrs has been administratively enabled (usually from cmdline)
|
|
# which in that case means ibrs is supported *and* enabled for kernel & user
|
|
# as per the ibrs patch series v3
|
|
if [ -z "$g_ibrs_supported" ]; then
|
|
if grep ^flags "$g_procfs/cpuinfo" | grep -qw spec_ctrl_ibrs; then
|
|
pr_debug "ibrs: found spec_ctrl_ibrs flag in $g_procfs/cpuinfo"
|
|
g_ibrs_supported="spec_ctrl_ibrs flag in $g_procfs/cpuinfo"
|
|
# enabled=2 -> kernel & user
|
|
g_ibrs_enabled=2
|
|
# XXX and what about ibpb ?
|
|
fi
|
|
fi
|
|
if [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
# when IBPB is enabled on 4.15+, we can see it in sysfs
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -q 'IBPB'; then
|
|
pr_debug "ibpb: found enabled in sysfs"
|
|
[ -z "$g_ibpb_supported" ] && g_ibpb_supported='IBPB found enabled in sysfs'
|
|
[ -z "$g_ibpb_enabled" ] && g_ibpb_enabled=1
|
|
fi
|
|
# when IBRS_FW is enabled on 4.15+, we can see it in sysfs
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -q '[,;] IBRS_FW'; then
|
|
pr_debug "ibrs: found IBRS_FW in sysfs"
|
|
[ -z "$g_ibrs_supported" ] && g_ibrs_supported='found IBRS_FW in sysfs'
|
|
g_ibrs_fw_enabled=1
|
|
fi
|
|
# when IBRS is enabled on 4.15+, we can see it in sysfs
|
|
# on a more recent kernel, classic "IBRS" is not even longer an option, because of the performance impact.
|
|
# only "Enhanced IBRS" is available (on CPUs with the IBRS_ALL flag)
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -q -e '\<IBRS\>' -e 'Indirect Branch Restricted Speculation'; then
|
|
pr_debug "ibrs: found IBRS in sysfs"
|
|
[ -z "$g_ibrs_supported" ] && g_ibrs_supported='found IBRS in sysfs'
|
|
[ -z "$g_ibrs_enabled" ] && g_ibrs_enabled=3
|
|
fi
|
|
# checking for 'Enhanced IBRS' in sysfs, enabled on CPUs with IBRS_ALL
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -q -e 'Enhanced IBRS'; then
|
|
[ -z "$g_ibrs_supported" ] && g_ibrs_supported='found Enhanced IBRS in sysfs'
|
|
# 4 isn't actually a valid value of the now extinct "g_ibrs_enabled" flag file,
|
|
# that only went from 0 to 3, so we use 4 as "enhanced ibrs is enabled"
|
|
g_ibrs_enabled=4
|
|
fi
|
|
fi
|
|
# in live mode, if ibrs or ibpb is supported and we didn't find these are enabled, then they are not
|
|
[ -n "$g_ibrs_supported" ] && [ -z "$g_ibrs_enabled" ] && g_ibrs_enabled=0
|
|
[ -n "$g_ibpb_supported" ] && [ -z "$g_ibpb_enabled" ] && g_ibpb_enabled=0
|
|
fi
|
|
if [ -z "$g_ibrs_supported" ]; then
|
|
check_redhat_canonical_spectre
|
|
if [ "$g_redhat_canonical_spectre" = 1 ]; then
|
|
g_ibrs_supported="Red Hat/Ubuntu variant"
|
|
g_ibpb_supported="Red Hat/Ubuntu variant"
|
|
fi
|
|
fi
|
|
if [ -z "$g_ibrs_supported" ] && [ -n "$g_kernel" ]; then
|
|
if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then
|
|
:
|
|
else
|
|
g_ibrs_can_tell=1
|
|
g_ibrs_supported=$("${opt_arch_prefix}strings" "$g_kernel" | grep -Fw -e '[,;] IBRS_FW' | head -n1)
|
|
if [ -n "$g_ibrs_supported" ]; then
|
|
pr_debug "ibrs: found ibrs evidence in kernel image ($g_ibrs_supported)"
|
|
g_ibrs_supported="found '$g_ibrs_supported' in kernel image"
|
|
fi
|
|
fi
|
|
fi
|
|
if [ -z "$g_ibrs_supported" ] && [ -n "$opt_map" ]; then
|
|
g_ibrs_can_tell=1
|
|
if grep -q spec_ctrl "$opt_map"; then
|
|
g_ibrs_supported="found spec_ctrl in symbols file"
|
|
pr_debug "ibrs: found '*spec_ctrl*' symbol in $opt_map"
|
|
elif grep -q -e spectre_v2_select_mitigation -e spectre_v2_apply_mitigation "$opt_map"; then
|
|
# spectre_v2_select_mitigation exists since v4.15; split into
|
|
# spectre_v2_select_mitigation + spectre_v2_apply_mitigation in v6.16
|
|
g_ibrs_supported="found spectre_v2 mitigation function in symbols file"
|
|
pr_debug "ibrs: found spectre_v2_*_mitigation symbol in $opt_map"
|
|
fi
|
|
fi
|
|
# CONFIG_CPU_IBRS_ENTRY (v5.19) / CONFIG_MITIGATION_IBRS_ENTRY (v6.9): kernel IBRS on entry
|
|
if [ -z "$g_ibrs_supported" ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then
|
|
g_ibrs_can_tell=1
|
|
if grep -q '^CONFIG_\(CPU_\|MITIGATION_\)IBRS_ENTRY=y' "$opt_config"; then
|
|
g_ibrs_supported="CONFIG_CPU_IBRS_ENTRY/CONFIG_MITIGATION_IBRS_ENTRY found in kernel config"
|
|
pr_debug "ibrs: found IBRS entry config option in $opt_config"
|
|
fi
|
|
fi
|
|
# recent (4.15) vanilla kernels have IBPB but not IBRS, and without the debugfs tunables of Red Hat
|
|
# we can detect it directly in the image
|
|
if [ -z "$g_ibpb_supported" ] && [ -n "$g_kernel" ]; then
|
|
if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then
|
|
:
|
|
else
|
|
g_ibpb_can_tell=1
|
|
g_ibpb_supported=$("${opt_arch_prefix}strings" "$g_kernel" | grep -Fw -e 'ibpb' -e ', IBPB' | head -n1)
|
|
if [ -n "$g_ibpb_supported" ]; then
|
|
pr_debug "ibpb: found ibpb evidence in kernel image ($g_ibpb_supported)"
|
|
g_ibpb_supported="found '$g_ibpb_supported' in kernel image"
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
pr_info_nol " * Kernel is compiled with IBRS support: "
|
|
if [ -z "$g_ibrs_supported" ]; then
|
|
if [ "$g_ibrs_can_tell" = 1 ]; then
|
|
pstatus yellow NO
|
|
else
|
|
# problem obtaining/inspecting kernel or strings not installed, but if the later is true,
|
|
# then readelf is not installed either (both in binutils) which makes the former true, so
|
|
# either way g_kernel_err should be set
|
|
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
|
fi
|
|
else
|
|
if [ "$opt_verbose" -ge 2 ]; then
|
|
pstatus green YES "$g_ibrs_supported"
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
fi
|
|
|
|
pr_info_nol " * IBRS enabled and active: "
|
|
if [ "$opt_live" = 1 ]; then
|
|
if [ "$g_ibpb_enabled" = 2 ]; then
|
|
# if ibpb=2, ibrs is forcefully=0
|
|
pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints"
|
|
else
|
|
# 0 means disabled
|
|
# 1 is enabled only for kernel space
|
|
# 2 is enabled for kernel and user space
|
|
# 3 is enabled
|
|
# 4 is enhanced ibrs enabled
|
|
case "$g_ibrs_enabled" in
|
|
0)
|
|
if [ "$g_ibrs_fw_enabled" = 1 ]; then
|
|
pstatus blue YES "for firmware code only"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
;;
|
|
1) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel space and firmware code"; else pstatus green YES "for kernel space"; fi ;;
|
|
2) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel, user space, and firmware code"; else pstatus green YES "for both kernel and user space"; fi ;;
|
|
3) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel and firmware code"; else pstatus green YES; fi ;;
|
|
4) pstatus green YES "Enhanced flavor, performance impact will be greatly reduced" ;;
|
|
*) if [ "$cap_ibrs" != 'SPEC_CTRL' ] && [ "$cap_ibrs" != 'IBRS_SUPPORT' ] && [ "$cap_spec_ctrl" != -1 ]; then
|
|
pstatus yellow NO
|
|
pr_debug "ibrs: known cpu not supporting SPEC-CTRL or IBRS"
|
|
else
|
|
pstatus yellow UNKNOWN
|
|
fi ;;
|
|
esac
|
|
fi
|
|
else
|
|
pstatus blue N/A "not testable in offline mode"
|
|
fi
|
|
|
|
pr_info_nol " * Kernel is compiled with IBPB support: "
|
|
if [ -z "$g_ibpb_supported" ]; then
|
|
if [ "$g_ibpb_can_tell" = 1 ]; then
|
|
pstatus yellow NO
|
|
else
|
|
# if we're in offline mode without System.map, we can't really know
|
|
pstatus yellow UNKNOWN "in offline mode, we need the kernel image to be able to tell"
|
|
fi
|
|
else
|
|
if [ "$opt_verbose" -ge 2 ]; then
|
|
pstatus green YES "$g_ibpb_supported"
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
fi
|
|
|
|
pr_info_nol " * IBPB enabled and active: "
|
|
if [ "$opt_live" = 1 ]; then
|
|
case "$g_ibpb_enabled" in
|
|
"")
|
|
if [ "$g_ibrs_supported" = 1 ]; then
|
|
pstatus yellow UNKNOWN
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
;;
|
|
0)
|
|
pstatus yellow NO
|
|
;;
|
|
1) pstatus green YES ;;
|
|
2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints" ;;
|
|
*) pstatus yellow UNKNOWN ;;
|
|
esac
|
|
else
|
|
pstatus blue N/A "not testable in offline mode"
|
|
fi
|
|
|
|
pr_info "* Mitigation 2"
|
|
pr_info_nol " * Kernel has branch predictor hardening (arm): "
|
|
bp_harden_can_tell=0
|
|
bp_harden=''
|
|
if [ -r "$opt_config" ]; then
|
|
bp_harden_can_tell=1
|
|
bp_harden=$(grep -w 'CONFIG_HARDEN_BRANCH_PREDICTOR=y' "$opt_config")
|
|
if [ -n "$bp_harden" ]; then
|
|
pstatus green YES
|
|
pr_debug "bp_harden: found '$bp_harden' in $opt_config"
|
|
fi
|
|
fi
|
|
if [ -z "$bp_harden" ] && [ -n "$opt_map" ]; then
|
|
bp_harden_can_tell=1
|
|
bp_harden=$(grep -w bp_hardening_data "$opt_map")
|
|
if [ -n "$bp_harden" ]; then
|
|
pstatus green YES
|
|
pr_debug "bp_harden: found '$bp_harden' in $opt_map"
|
|
fi
|
|
fi
|
|
if [ -z "$bp_harden" ]; then
|
|
if [ "$bp_harden_can_tell" = 1 ]; then
|
|
pstatus yellow NO
|
|
else
|
|
pstatus yellow UNKNOWN
|
|
fi
|
|
fi
|
|
|
|
pr_info_nol " * Kernel compiled with retpoline option: "
|
|
# We check the RETPOLINE kernel options
|
|
retpoline=0
|
|
if [ -r "$opt_config" ]; then
|
|
if grep -q '^CONFIG_\(MITIGATION_\)\?RETPOLINE=y' "$opt_config"; then
|
|
pstatus green YES
|
|
retpoline=1
|
|
# shellcheck disable=SC2046
|
|
pr_debug 'retpoline: found '$(grep '^CONFIG_\(MITIGATION_\)\?RETPOLINE' "$opt_config")" in $opt_config"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
else
|
|
pstatus yellow UNKNOWN "couldn't read your kernel configuration"
|
|
fi
|
|
|
|
if [ "$retpoline" = 1 ]; then
|
|
# Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm
|
|
# For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles)
|
|
# See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79
|
|
# In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_MITIGATION_RETPOLINE is set
|
|
# *AND* if the compiler is retpoline-compliant, so look for that symbol. The name of this kernel config
|
|
# option before version 6.9-rc1 is CONFIG_RETPOLINE.
|
|
#
|
|
# if there is "retpoline" in the file and NOT "minimal", then it's full retpoline
|
|
# (works for vanilla and Red Hat variants)
|
|
#
|
|
# since 5.15.28, this is now "Retpolines" as the implementation was switched to a generic one,
|
|
# so we look for both "retpoline" and "retpolines"
|
|
if [ "$opt_live" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -qwi -e retpoline -e retpolines; then
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -qwi minimal; then
|
|
retpoline_compiler=0
|
|
retpoline_compiler_reason="kernel reports minimal retpoline compilation"
|
|
else
|
|
retpoline_compiler=1
|
|
retpoline_compiler_reason="kernel reports full retpoline compilation"
|
|
fi
|
|
fi
|
|
elif [ -n "$opt_map" ]; then
|
|
# look for the symbol
|
|
if grep -qw noretpoline_setup "$opt_map"; then
|
|
retpoline_compiler=1
|
|
retpoline_compiler_reason="noretpoline_setup symbol found in System.map"
|
|
fi
|
|
elif [ -n "$g_kernel" ]; then
|
|
# look for the symbol
|
|
if command -v "${opt_arch_prefix}nm" >/dev/null 2>&1; then
|
|
# the proper way: use nm and look for the symbol
|
|
if "${opt_arch_prefix}nm" "$g_kernel" 2>/dev/null | grep -qw 'noretpoline_setup'; then
|
|
retpoline_compiler=1
|
|
retpoline_compiler_reason="noretpoline_setup found in kernel symbols"
|
|
fi
|
|
elif grep -q noretpoline_setup "$g_kernel"; then
|
|
# if we don't have nm, nevermind, the symbol name is long enough to not have
|
|
# any false positive using good old grep directly on the binary
|
|
retpoline_compiler=1
|
|
retpoline_compiler_reason="noretpoline_setup found in kernel"
|
|
fi
|
|
fi
|
|
if [ -n "$retpoline_compiler" ]; then
|
|
pr_info_nol " * Kernel compiled with a retpoline-aware compiler: "
|
|
if [ "$retpoline_compiler" = 1 ]; then
|
|
if [ -n "$retpoline_compiler_reason" ]; then
|
|
pstatus green YES "$retpoline_compiler_reason"
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
else
|
|
if [ -n "$retpoline_compiler_reason" ]; then
|
|
pstatus red NO "$retpoline_compiler_reason"
|
|
else
|
|
pstatus red NO
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# only Red Hat has a tunable to disable it on runtime
|
|
retp_enabled=-1
|
|
if [ "$opt_live" = 1 ]; then
|
|
if [ -e "$g_specex_knob_dir/retp_enabled" ]; then
|
|
retp_enabled=$(cat "$g_specex_knob_dir/retp_enabled" 2>/dev/null)
|
|
pr_debug "retpoline: found $g_specex_knob_dir/retp_enabled=$retp_enabled"
|
|
pr_info_nol " * Retpoline is enabled: "
|
|
if [ "$retp_enabled" = 1 ]; then
|
|
pstatus green YES
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# only for information, in verbose mode
|
|
if [ "$opt_verbose" -ge 2 ]; then
|
|
pr_info_nol " * Local gcc is retpoline-aware: "
|
|
if command -v gcc >/dev/null 2>&1; then
|
|
if [ -n "$(gcc -mindirect-branch=thunk-extern --version 2>&1 >/dev/null)" ]; then
|
|
pstatus blue NO
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
else
|
|
pstatus blue NO "gcc is not installed"
|
|
fi
|
|
fi
|
|
|
|
if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then
|
|
pr_info_nol " * Kernel supports RSB filling: "
|
|
rsb_filling=0
|
|
if [ "$opt_live" = 1 ] && [ "$opt_no_sysfs" != 1 ]; then
|
|
# if we're live and we aren't denied looking into /sys, let's do it
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -qw RSB; then
|
|
rsb_filling=1
|
|
pstatus green YES
|
|
fi
|
|
fi
|
|
if [ "$rsb_filling" = 0 ]; then
|
|
if [ -n "$g_kernel_err" ]; then
|
|
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
|
else
|
|
if grep -qw -e 'Filling RSB on context switch' "$g_kernel"; then
|
|
rsb_filling=1
|
|
pstatus green YES
|
|
else
|
|
rsb_filling=0
|
|
pstatus yellow NO
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Mitigation 3: derive structured mitigation variables for the verdict.
|
|
# These are set from sysfs fields (when available) with hardware fallbacks.
|
|
pr_info "* Mitigation 3 (sub-mitigations)"
|
|
|
|
# --- v2_base_mode: which base Spectre v2 mitigation is active ---
|
|
pr_info_nol " * Base Spectre v2 mitigation mode: "
|
|
if [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
# Parse from sysfs (handle all mainline, stable, and RHEL variants)
|
|
case "$ret_sys_interface_check_fullmsg" in
|
|
*"Enhanced / Automatic IBRS + LFENCE"* | *"Enhanced IBRS + LFENCE"*) v2_base_mode=eibrs_lfence ;;
|
|
*"Enhanced / Automatic IBRS + Retpolines"* | *"Enhanced IBRS + Retpolines"*) v2_base_mode=eibrs_retpoline ;;
|
|
*"Enhanced / Automatic IBRS"* | *"Enhanced IBRS"*) v2_base_mode=eibrs ;;
|
|
*"Mitigation: IBRS (kernel and user space)"*) v2_base_mode=ibrs ;;
|
|
*"Mitigation: IBRS (kernel)"*) v2_base_mode=ibrs ;;
|
|
*"Mitigation: IBRS"*) v2_base_mode=ibrs ;;
|
|
*"Mitigation: Retpolines"* | *"Full generic retpoline"* | *"Full retpoline"* | *"Full AMD retpoline"*) v2_base_mode=retpoline ;;
|
|
*"Vulnerable: LFENCE"* | *"Mitigation: LFENCE"*) v2_base_mode=lfence ;;
|
|
*"Vulnerable"*) v2_base_mode=none ;;
|
|
*) v2_base_mode=unknown ;;
|
|
esac
|
|
fi
|
|
# Fallback to existing variables if sysfs didn't provide a base mode
|
|
if [ -z "$v2_base_mode" ] || [ "$v2_base_mode" = "unknown" ]; then
|
|
if [ "$g_ibrs_enabled" = 4 ]; then
|
|
v2_base_mode=eibrs
|
|
elif [ -n "$g_ibrs_enabled" ] && [ "$g_ibrs_enabled" -ge 1 ] 2>/dev/null; then
|
|
v2_base_mode=ibrs
|
|
elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ]; then
|
|
v2_base_mode=retpoline
|
|
elif [ "$retpoline" = 1 ]; then
|
|
v2_base_mode=retpoline
|
|
fi
|
|
fi
|
|
case "$v2_base_mode" in
|
|
eibrs) pstatus green "Enhanced / Automatic IBRS" ;;
|
|
eibrs_lfence) pstatus green "Enhanced / Automatic IBRS + LFENCE" ;;
|
|
eibrs_retpoline) pstatus green "Enhanced / Automatic IBRS + Retpolines" ;;
|
|
ibrs) pstatus green "IBRS" ;;
|
|
retpoline) pstatus green "Retpolines" ;;
|
|
lfence) pstatus red "LFENCE (insufficient)" ;;
|
|
none) pstatus yellow "None" ;;
|
|
*) pstatus yellow UNKNOWN ;;
|
|
esac
|
|
|
|
# --- v2_is_autoibrs: AMD AutoIBRS vs Intel eIBRS ---
|
|
case "$v2_base_mode" in
|
|
eibrs | eibrs_lfence | eibrs_retpoline)
|
|
if [ "$cap_autoibrs" = 1 ] || { (is_amd || is_hygon) && [ "$cap_ibrs_all" != 1 ]; }; then
|
|
v2_is_autoibrs=1
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
# --- v2_ibpb_mode ---
|
|
pr_info_nol " * IBPB mode: "
|
|
if [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
case "$ret_sys_interface_check_fullmsg" in
|
|
*"IBPB: always-on"*) v2_ibpb_mode=always-on ;;
|
|
*"IBPB: conditional"*) v2_ibpb_mode=conditional ;;
|
|
*"IBPB: disabled"*) v2_ibpb_mode=disabled ;;
|
|
*", IBPB"* | *"; IBPB"*) v2_ibpb_mode=conditional ;;
|
|
*) v2_ibpb_mode=disabled ;;
|
|
esac
|
|
elif [ "$opt_live" = 1 ]; then
|
|
case "$g_ibpb_enabled" in
|
|
2) v2_ibpb_mode=always-on ;;
|
|
1) v2_ibpb_mode=conditional ;;
|
|
0) v2_ibpb_mode=disabled ;;
|
|
*) v2_ibpb_mode=unknown ;;
|
|
esac
|
|
else
|
|
v2_ibpb_mode=unknown
|
|
fi
|
|
case "$v2_ibpb_mode" in
|
|
always-on) pstatus green YES "always-on" ;;
|
|
conditional) pstatus green YES "conditional" ;;
|
|
disabled) pstatus yellow NO "disabled" ;;
|
|
*) pstatus yellow UNKNOWN ;;
|
|
esac
|
|
|
|
# --- SMT state (used in STIBP inference and verdict) ---
|
|
is_cpu_smt_enabled
|
|
smt_enabled=$?
|
|
# smt_enabled: 0=enabled, 1=disabled, 2=unknown
|
|
|
|
# --- v2_stibp_status ---
|
|
pr_info_nol " * STIBP status: "
|
|
if [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
case "$ret_sys_interface_check_fullmsg" in
|
|
*"STIBP: always-on"*) v2_stibp_status=always-on ;;
|
|
*"STIBP: forced"*) v2_stibp_status=forced ;;
|
|
*"STIBP: conditional"*) v2_stibp_status=conditional ;;
|
|
*"STIBP: disabled"*) v2_stibp_status=disabled ;;
|
|
*", STIBP"* | *"; STIBP"*) v2_stibp_status=forced ;;
|
|
*)
|
|
# No STIBP field: Intel eIBRS suppresses it (implicit cross-thread protection)
|
|
case "$v2_base_mode" in
|
|
eibrs | eibrs_lfence | eibrs_retpoline)
|
|
if [ "$v2_is_autoibrs" != 1 ]; then
|
|
v2_stibp_status=eibrs-implicit
|
|
else
|
|
v2_stibp_status=unknown
|
|
fi
|
|
;;
|
|
*) v2_stibp_status=unknown ;;
|
|
esac
|
|
;;
|
|
esac
|
|
else
|
|
# No sysfs: use hardware capability + context to infer STIBP status
|
|
if [ "$smt_enabled" != 0 ]; then
|
|
# SMT disabled or unknown: STIBP is not needed
|
|
v2_stibp_status=not-needed
|
|
else
|
|
case "$v2_base_mode" in
|
|
eibrs | eibrs_lfence | eibrs_retpoline)
|
|
if [ "$v2_is_autoibrs" != 1 ]; then
|
|
# Intel eIBRS provides implicit cross-thread protection
|
|
v2_stibp_status=eibrs-implicit
|
|
elif [ -n "$cap_stibp" ]; then
|
|
# AMD AutoIBRS: CPU supports STIBP but can't confirm runtime state
|
|
v2_stibp_status=unknown
|
|
else
|
|
# No STIBP support on this CPU
|
|
v2_stibp_status=unavailable
|
|
fi
|
|
;;
|
|
*)
|
|
if [ -n "$cap_stibp" ]; then
|
|
# CPU supports STIBP but can't confirm runtime state without sysfs
|
|
v2_stibp_status=unknown
|
|
else
|
|
# CPU does not support STIBP at all
|
|
v2_stibp_status=unavailable
|
|
fi
|
|
;;
|
|
esac
|
|
fi
|
|
fi
|
|
case "$v2_stibp_status" in
|
|
always-on) pstatus green YES "always-on" ;;
|
|
forced) pstatus green YES "forced" ;;
|
|
conditional) pstatus green YES "conditional" ;;
|
|
eibrs-implicit) pstatus green YES "implicit via eIBRS" ;;
|
|
not-needed) pstatus green YES "not needed (SMT disabled)" ;;
|
|
unavailable) pstatus red NO "CPU does not support STIBP" ;;
|
|
disabled) pstatus yellow NO "disabled" ;;
|
|
*) pstatus yellow UNKNOWN ;;
|
|
esac
|
|
|
|
# --- v2_pbrsb_status (only relevant for eIBRS) ---
|
|
case "$v2_base_mode" in
|
|
eibrs | eibrs_lfence | eibrs_retpoline)
|
|
pr_info_nol " * PBRSB-eIBRS mitigation: "
|
|
if [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
case "$ret_sys_interface_check_fullmsg" in
|
|
*"PBRSB-eIBRS: Not affected"*) v2_pbrsb_status=not-affected ;;
|
|
*"PBRSB-eIBRS: SW sequence"*) v2_pbrsb_status=sw-sequence ;;
|
|
*"PBRSB-eIBRS: Vulnerable"*) v2_pbrsb_status=vulnerable ;;
|
|
*) v2_pbrsb_status=unknown ;;
|
|
esac
|
|
elif [ "$opt_live" != 1 ] && [ -n "$g_kernel" ]; then
|
|
if grep -q 'PBRSB-eIBRS' "$g_kernel" 2>/dev/null; then
|
|
v2_pbrsb_status=sw-sequence
|
|
else
|
|
v2_pbrsb_status=unknown
|
|
fi
|
|
else
|
|
v2_pbrsb_status=unknown
|
|
fi
|
|
case "$v2_pbrsb_status" in
|
|
not-affected) pstatus green "Not affected" ;;
|
|
sw-sequence) pstatus green "SW sequence" ;;
|
|
vulnerable) pstatus red "Vulnerable" ;;
|
|
*) pstatus yellow UNKNOWN ;;
|
|
esac
|
|
;;
|
|
*) v2_pbrsb_status=n/a ;;
|
|
esac
|
|
|
|
# --- v2_bhi_status ---
|
|
pr_info_nol " * BHI mitigation: "
|
|
if [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
case "$ret_sys_interface_check_fullmsg" in
|
|
*"BHI: Not affected"*) v2_bhi_status=not-affected ;;
|
|
*"BHI: BHI_DIS_S"*) v2_bhi_status=bhi_dis_s ;;
|
|
*"BHI: SW loop"*) v2_bhi_status=sw-loop ;;
|
|
*"BHI: Retpoline"*) v2_bhi_status=retpoline ;;
|
|
*"BHI: Vulnerable, KVM: SW loop"*) v2_bhi_status=vuln-kvm-loop ;;
|
|
*"BHI: Vulnerable"*) v2_bhi_status=vulnerable ;;
|
|
*) v2_bhi_status=unknown ;;
|
|
esac
|
|
elif [ "$opt_live" != 1 ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then
|
|
if grep -q '^CONFIG_\(MITIGATION_\)\?SPECTRE_BHI' "$opt_config"; then
|
|
if [ "$cap_bhi" = 1 ]; then
|
|
v2_bhi_status=bhi_dis_s
|
|
else
|
|
v2_bhi_status=sw-loop
|
|
fi
|
|
else
|
|
v2_bhi_status=unknown
|
|
fi
|
|
else
|
|
v2_bhi_status=unknown
|
|
fi
|
|
case "$v2_bhi_status" in
|
|
not-affected) pstatus green "Not affected" ;;
|
|
bhi_dis_s) pstatus green "BHI_DIS_S (hardware)" ;;
|
|
sw-loop) pstatus green "SW loop" ;;
|
|
retpoline) pstatus green "Retpoline" ;;
|
|
vuln-kvm-loop) pstatus yellow "Vulnerable (KVM: SW loop)" ;;
|
|
vulnerable) pstatus red "Vulnerable" ;;
|
|
*) pstatus yellow UNKNOWN ;;
|
|
esac
|
|
|
|
# --- v2_vuln_module ---
|
|
if [ "$opt_live" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then
|
|
pr_info_nol " * Non-retpoline module loaded: "
|
|
if echo "$ret_sys_interface_check_fullmsg" | grep -q 'vulnerable module loaded'; then
|
|
v2_vuln_module=1
|
|
pstatus red YES
|
|
else
|
|
v2_vuln_module=0
|
|
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 [ "$opt_sysfs_only" != 1 ]; then
|
|
# --- own logic using Phase 2 variables ---
|
|
# Helper: collect caveats for the verdict message
|
|
_v2_caveats=''
|
|
# Append a caveat string to the _v2_caveats list
|
|
# Callers: check_CVE_2017_5715_linux (eIBRS, IBRS, retpoline verdict paths)
|
|
_v2_add_caveat() { _v2_caveats="${_v2_caveats:+$_v2_caveats; }$1"; }
|
|
|
|
# ARM branch predictor hardening (unchanged)
|
|
if [ -n "$bp_harden" ]; then
|
|
pvulnstatus "$cve" OK "Branch predictor hardening mitigates the vulnerability"
|
|
elif [ -z "$bp_harden" ] && [ "$cpu_vendor" = ARM ]; then
|
|
pvulnstatus "$cve" VULN "Branch predictor hardening is needed to mitigate the vulnerability"
|
|
explain "Your kernel has not been compiled with the CONFIG_UNMAP_KERNEL_AT_EL0 option, recompile it with this option enabled."
|
|
|
|
# LFENCE-only is always VULN (reclassified in v5.17)
|
|
elif [ "$v2_base_mode" = "lfence" ]; then
|
|
pvulnstatus "$cve" VULN "LFENCE alone is not a sufficient Spectre v2 mitigation"
|
|
explain "LFENCE-based indirect branch mitigation was reclassified as vulnerable starting with Linux v5.17. Use retpoline (spectre_v2=retpoline) or IBRS-based mitigations (spectre_v2=eibrs or spectre_v2=ibrs) instead. If your CPU supports Enhanced IBRS, that is the preferred option."
|
|
|
|
# eIBRS paths (eibrs / eibrs_lfence / eibrs_retpoline)
|
|
elif [ "$v2_base_mode" = "eibrs" ] || [ "$v2_base_mode" = "eibrs_lfence" ] || [ "$v2_base_mode" = "eibrs_retpoline" ]; then
|
|
_v2_caveats=''
|
|
_v2_ok=1
|
|
|
|
# BHI check: eIBRS alone doesn't protect against BHI
|
|
if [ "$v2_bhi_status" = "vulnerable" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "BHI vulnerable"
|
|
elif [ "$v2_bhi_status" = "unknown" ] && is_intel; then
|
|
if [ "$cap_bhi" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "BHI vulnerable (no BHI_DIS_S hardware support, no kernel mitigation detected)"
|
|
elif [ "$cap_rrsba" != 0 ]; then
|
|
_v2_add_caveat "BHI status unknown (kernel may lack BHI mitigation)"
|
|
fi
|
|
fi
|
|
|
|
# PBRSB check (only matters for VMM hosts)
|
|
if [ "$v2_pbrsb_status" = "vulnerable" ]; then
|
|
if [ "$g_has_vmm" != 0 ] || [ "$opt_paranoid" = 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "PBRSB-eIBRS vulnerable"
|
|
fi
|
|
fi
|
|
|
|
# AutoIBRS: needs explicit STIBP (does NOT provide implicit cross-thread protection)
|
|
if [ "$v2_is_autoibrs" = 1 ] && [ "$smt_enabled" = 0 ]; then
|
|
if [ "$v2_stibp_status" = "disabled" ] || [ "$v2_stibp_status" = "unavailable" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "STIBP not active with SMT on AMD AutoIBRS"
|
|
fi
|
|
fi
|
|
|
|
# Vulnerable module check
|
|
if [ "$v2_vuln_module" = 1 ]; then
|
|
_v2_add_caveat "non-retpoline module loaded"
|
|
fi
|
|
|
|
# Paranoid mode
|
|
if [ "$opt_paranoid" = 1 ]; then
|
|
if [ "$v2_ibpb_mode" != "always-on" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "IBPB not always-on"
|
|
fi
|
|
if [ "$smt_enabled" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "SMT enabled"
|
|
fi
|
|
fi
|
|
|
|
# eBPF caveat: eIBRS without retpoline is insufficient when unprivileged eBPF is enabled
|
|
_ebpf_disabled=''
|
|
if [ "$v2_base_mode" = "eibrs" ] || [ "$v2_base_mode" = "eibrs_lfence" ]; then
|
|
# shellcheck disable=SC2154
|
|
if [ -n "${SMC_MOCK_UNPRIVILEGED_BPF_DISABLED:-}" ]; then
|
|
_ebpf_disabled="$SMC_MOCK_UNPRIVILEGED_BPF_DISABLED"
|
|
g_mocked=1
|
|
elif [ "$opt_live" = 1 ] && [ -r "$g_procfs/sys/kernel/unprivileged_bpf_disabled" ]; then
|
|
_ebpf_disabled=$(cat "$g_procfs/sys/kernel/unprivileged_bpf_disabled" 2>/dev/null)
|
|
g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_UNPRIVILEGED_BPF_DISABLED='$_ebpf_disabled'")
|
|
fi
|
|
# In paranoid mode, enabled unprivileged eBPF makes eIBRS insufficient
|
|
if [ "$_v2_ok" = 1 ] && [ "$_ebpf_disabled" = 0 ] && [ "$opt_paranoid" = 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "unprivileged eBPF enabled (eIBRS insufficient)"
|
|
fi
|
|
fi
|
|
|
|
# Build the base description
|
|
case "$v2_base_mode" in
|
|
eibrs) _v2_desc="Enhanced / Automatic IBRS" ;;
|
|
eibrs_lfence) _v2_desc="Enhanced / Automatic IBRS + LFENCE" ;;
|
|
eibrs_retpoline) _v2_desc="Enhanced / Automatic IBRS + Retpolines" ;;
|
|
esac
|
|
|
|
if [ "$_v2_ok" = 1 ]; then
|
|
if [ -n "$_v2_caveats" ]; then
|
|
pvulnstatus "$cve" OK "$_v2_desc mitigates the vulnerability ($_v2_caveats)"
|
|
else
|
|
pvulnstatus "$cve" OK "$_v2_desc mitigates the vulnerability"
|
|
fi
|
|
if [ "$v2_base_mode" = "eibrs" ] || [ "$v2_base_mode" = "eibrs_lfence" ]; then
|
|
pr_info " NOTE: eIBRS is considered vulnerable by the kernel when unprivileged eBPF is enabled."
|
|
if [ "$_ebpf_disabled" = 0 ]; then
|
|
pr_info " Unprivileged eBPF is currently ENABLED (kernel.unprivileged_bpf_disabled=0): this system may be vulnerable!"
|
|
elif [ "$_ebpf_disabled" = 1 ] || [ "$_ebpf_disabled" = 2 ]; then
|
|
pr_info " Unprivileged eBPF is currently disabled (kernel.unprivileged_bpf_disabled=$_ebpf_disabled): eIBRS is sufficient."
|
|
else
|
|
pr_info " Could not read kernel.unprivileged_bpf_disabled, check it manually with \`sysctl kernel.unprivileged_bpf_disabled\`."
|
|
fi
|
|
fi
|
|
else
|
|
pvulnstatus "$cve" VULN "$_v2_desc active but insufficient: $_v2_caveats"
|
|
explain "Your system uses $_v2_desc but has gaps in sub-mitigations: $_v2_caveats. Update your kernel and microcode to the latest versions. If BHI is vulnerable, a kernel with CONFIG_MITIGATION_SPECTRE_BHI or BHI_DIS_S microcode support is needed. If PBRSB-eIBRS is vulnerable, update the kernel for RSB VM exit mitigation. If STIBP is disabled on AMD AutoIBRS with SMT, add \`spectre_v2_user=on\` or disable SMT with \`nosmt\`. If unprivileged eBPF is enabled, disable it with \`sysctl -w kernel.unprivileged_bpf_disabled=1\`. In paranoid mode, disable SMT with \`nosmt\` and set \`spectre_v2_user=on\` for IBPB always-on."
|
|
fi
|
|
|
|
# Kernel IBRS path
|
|
elif [ "$v2_base_mode" = "ibrs" ]; then
|
|
_v2_caveats=''
|
|
_v2_ok=1
|
|
|
|
# IBRS needs IBPB for cross-process protection
|
|
if [ "$v2_ibpb_mode" = "disabled" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "IBPB disabled"
|
|
fi
|
|
|
|
# IBRS needs STIBP or SMT-off for cross-thread protection
|
|
if [ "$smt_enabled" = 0 ] && { [ "$v2_stibp_status" = "disabled" ] || [ "$v2_stibp_status" = "unavailable" ]; }; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "STIBP not active with SMT enabled"
|
|
fi
|
|
|
|
# RSB filling on Skylake+
|
|
if is_vulnerable_to_empty_rsb && [ "$rsb_filling" != 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "RSB filling missing on Skylake+"
|
|
fi
|
|
|
|
# BHI check
|
|
if [ "$v2_bhi_status" = "vulnerable" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "BHI vulnerable"
|
|
elif [ "$v2_bhi_status" = "unknown" ] && is_intel && [ "$cap_bhi" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "BHI vulnerable (no BHI_DIS_S hardware support, no kernel mitigation detected)"
|
|
fi
|
|
|
|
# Vulnerable module check
|
|
if [ "$v2_vuln_module" = 1 ]; then
|
|
_v2_add_caveat "non-retpoline module loaded"
|
|
fi
|
|
|
|
# Paranoid mode
|
|
if [ "$opt_paranoid" = 1 ]; then
|
|
if [ "$v2_ibpb_mode" != "always-on" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "IBPB not always-on"
|
|
fi
|
|
if [ "$smt_enabled" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "SMT enabled"
|
|
fi
|
|
fi
|
|
|
|
if [ "$_v2_ok" = 1 ]; then
|
|
pvulnstatus "$cve" OK "IBRS mitigates the vulnerability"
|
|
else
|
|
pvulnstatus "$cve" VULN "IBRS active but insufficient: $_v2_caveats"
|
|
explain "Your system uses kernel IBRS but has gaps: $_v2_caveats. Ensure IBPB is enabled (spectre_v2_user=on or spectre_v2_user=prctl,ibpb). If STIBP is disabled with SMT, add spectre_v2_user=on or disable SMT with \`nosmt\`. If RSB filling is missing, update the kernel. If BHI is vulnerable, update kernel/microcode for BHI mitigation."
|
|
fi
|
|
|
|
# Retpoline path
|
|
elif [ "$v2_base_mode" = "retpoline" ]; then
|
|
_v2_caveats=''
|
|
_v2_ok=1
|
|
|
|
# Retpoline compiler check
|
|
if [ "$retpoline_compiler" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "not compiled with retpoline-aware compiler"
|
|
fi
|
|
|
|
# Red Hat runtime disable check
|
|
if [ "$retp_enabled" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "retpoline disabled at runtime"
|
|
fi
|
|
|
|
# RSB filling on Skylake+ (empty RSB falls back to BTB)
|
|
if is_vulnerable_to_empty_rsb && [ "$rsb_filling" != 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "RSB filling missing on Skylake+"
|
|
fi
|
|
|
|
# BHI: retpoline only mitigates BHI if RRSBA is disabled
|
|
if [ "$v2_bhi_status" = "vulnerable" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "BHI vulnerable"
|
|
elif [ "$v2_bhi_status" = "unknown" ] && is_intel; then
|
|
if [ "$cap_bhi" = 0 ] && [ "$cap_rrsba" = 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "BHI vulnerable (no BHI_DIS_S hardware support, RRSBA bypasses retpoline)"
|
|
elif [ "$cap_rrsba" = 1 ]; then
|
|
_v2_add_caveat "BHI status unknown with RRSBA"
|
|
fi
|
|
fi
|
|
|
|
# Vulnerable module
|
|
if [ "$v2_vuln_module" = 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "non-retpoline module loaded"
|
|
fi
|
|
|
|
# IBPB check: retpoline without IBPB is weaker
|
|
if [ "$v2_ibpb_mode" = "disabled" ] || { [ -z "$g_ibpb_enabled" ] || [ "$g_ibpb_enabled" = 0 ]; }; then
|
|
if [ "$opt_paranoid" = 1 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "IBPB disabled"
|
|
else
|
|
_v2_add_caveat "IBPB disabled (recommended)"
|
|
fi
|
|
fi
|
|
|
|
# Paranoid mode: require SMT off, IBPB always-on
|
|
if [ "$opt_paranoid" = 1 ]; then
|
|
if [ "$v2_ibpb_mode" != "always-on" ] && [ "$v2_ibpb_mode" != "disabled" ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "IBPB not always-on"
|
|
fi
|
|
if [ "$smt_enabled" = 0 ]; then
|
|
_v2_ok=0
|
|
_v2_add_caveat "SMT enabled"
|
|
fi
|
|
fi
|
|
|
|
if [ "$_v2_ok" = 1 ]; then
|
|
if [ -n "$_v2_caveats" ]; then
|
|
pvulnstatus "$cve" OK "Retpolines mitigate the vulnerability ($_v2_caveats)"
|
|
if echo "$_v2_caveats" | grep -q 'IBPB'; then
|
|
if [ -n "$cap_ibpb" ]; then
|
|
pr_warn "You should enable IBPB to complete retpoline as a Variant 2 mitigation"
|
|
else
|
|
pr_warn "IBPB is considered as a good addition to retpoline for Variant 2 mitigation, but your CPU microcode doesn't support it"
|
|
fi
|
|
fi
|
|
else
|
|
pvulnstatus "$cve" OK "Retpolines + IBPB mitigate the vulnerability"
|
|
fi
|
|
else
|
|
pvulnstatus "$cve" VULN "Retpoline active but insufficient: $_v2_caveats"
|
|
explain "Your system uses retpoline but has gaps: $_v2_caveats. Ensure the kernel was compiled with a retpoline-aware compiler. Enable IBPB (spectre_v2_user=on). If RSB filling is missing on Skylake+, update the kernel. If BHI is vulnerable, update kernel/microcode. In paranoid mode, disable SMT with \`nosmt\` and set \`spectre_v2_user=on\`."
|
|
fi
|
|
|
|
# Legacy fallback: IBRS+IBPB from debugfs on old systems without sysfs
|
|
elif [ -n "$g_ibrs_enabled" ] && [ "$g_ibrs_enabled" -ge 1 ] 2>/dev/null && [ -n "$g_ibpb_enabled" ] && [ "$g_ibpb_enabled" -ge 1 ] 2>/dev/null; then
|
|
if [ "$g_ibrs_enabled" = 4 ]; then
|
|
pvulnstatus "$cve" OK "Enhanced IBRS + IBPB are mitigating the vulnerability"
|
|
else
|
|
pvulnstatus "$cve" OK "IBRS + IBPB are mitigating the vulnerability"
|
|
fi
|
|
elif [ "$g_ibpb_enabled" = 2 ] && [ "$smt_enabled" != 0 ]; then
|
|
pvulnstatus "$cve" OK "Full IBPB is mitigating the vulnerability"
|
|
|
|
# Offline mode fallback
|
|
elif [ "$opt_live" != 1 ]; then
|
|
if [ "$retpoline" = 1 ] && [ -n "$g_ibpb_supported" ]; then
|
|
pvulnstatus "$cve" OK "offline mode: kernel supports retpoline + IBPB to mitigate the vulnerability"
|
|
elif [ -n "$g_ibrs_supported" ] && [ -n "$g_ibpb_supported" ]; then
|
|
pvulnstatus "$cve" OK "offline mode: kernel supports IBRS + IBPB to mitigate the vulnerability"
|
|
elif [ "$cap_ibrs_all" = 1 ] || [ "$cap_autoibrs" = 1 ]; then
|
|
pvulnstatus "$cve" OK "offline mode: CPU supports Enhanced / Automatic IBRS"
|
|
# CONFIG_MITIGATION_SPECTRE_V2 (v6.12+): top-level on/off for all Spectre V2 mitigations
|
|
elif [ -n "$opt_config" ] && [ -r "$opt_config" ] && grep -q '^CONFIG_MITIGATION_SPECTRE_V2=y' "$opt_config"; then
|
|
pvulnstatus "$cve" OK "offline mode: kernel has Spectre V2 mitigation framework enabled (CONFIG_MITIGATION_SPECTRE_V2)"
|
|
elif [ "$g_ibrs_can_tell" != 1 ]; then
|
|
pvulnstatus "$cve" UNK "offline 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
|
|
|
|
# Catch-all: if no verdict was reached above, it's VULN
|
|
if [ "$g_pvulnstatus_last_cve" != "$cve" ]; then
|
|
if is_intel || is_amd || is_hygon; then
|
|
pvulnstatus "$cve" VULN "Your CPU is affected and no sufficient mitigation was detected"
|
|
explain "To mitigate this vulnerability, you need one of: (1) Enhanced IBRS / Automatic IBRS (eIBRS) -- requires CPU microcode support; preferred for modern CPUs. (2) Kernel IBRS (spectre_v2=ibrs) + IBPB -- requires IBRS-capable microcode. (3) Retpoline (spectre_v2=retpoline) + IBPB -- requires a retpoline-aware compiler and IBPB-capable microcode. For Skylake+ CPUs, options 1 or 2 are preferred as retpoline needs RSB filling. Update your kernel and CPU microcode to the latest versions."
|
|
else
|
|
if [ "$sys_interface_available" = 1 ]; then
|
|
pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
|
|
else
|
|
pvulnstatus "$cve" VULN "no known mitigation exists for your CPU vendor ($cpu_vendor)"
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
# --sysfs-only: Phase 2 variables are unset, fall back to the
|
|
# raw sysfs result (status + fullmsg were set in Phase 1).
|
|
pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
|
|
fi
|
|
else
|
|
# msg was explicitly set by the "sysfs not available" elif above.
|
|
pvulnstatus "$cve" "$status" "$msg"
|
|
fi
|
|
}
|
|
|
|
# Sets: vulnstatus
|
|
check_CVE_2017_5715_bsd() {
|
|
local ibrs_disabled ibrs_active retpoline nb_thunks
|
|
pr_info "* Mitigation 1"
|
|
pr_info_nol " * Kernel supports IBRS: "
|
|
ibrs_disabled=$(sysctl -n hw.ibrs_disable 2>/dev/null)
|
|
if [ -z "$ibrs_disabled" ]; then
|
|
pstatus yellow NO
|
|
else
|
|
pstatus green YES
|
|
fi
|
|
|
|
pr_info_nol " * IBRS enabled and active: "
|
|
ibrs_active=$(sysctl -n hw.ibrs_active 2>/dev/null)
|
|
if [ "$ibrs_active" = 1 ]; then
|
|
pstatus green YES
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
|
|
pr_info "* Mitigation 2"
|
|
pr_info_nol " * Kernel compiled with RETPOLINE: "
|
|
retpoline=0
|
|
if [ -n "$g_kernel_err" ]; then
|
|
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
|
else
|
|
if ! command -v "${opt_arch_prefix}readelf" >/dev/null 2>&1; then
|
|
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}readelf' tool, please install it, usually it's in the binutils package"
|
|
else
|
|
nb_thunks=$("${opt_arch_prefix}readelf" -s "$g_kernel" | grep -c -e __llvm_retpoline_ -e __llvm_external_retpoline_ -e __x86_indirect_thunk_)
|
|
if [ "$nb_thunks" -gt 0 ]; then
|
|
retpoline=1
|
|
pstatus green YES "found $nb_thunks thunk(s)"
|
|
else
|
|
pstatus yellow NO
|
|
fi
|
|
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 [ "$retpoline" = 1 ]; then
|
|
pvulnstatus "$cve" OK "Retpoline mitigates the vulnerability"
|
|
elif [ "$ibrs_active" = 1 ]; then
|
|
pvulnstatus "$cve" OK "IBRS mitigates the vulnerability"
|
|
elif [ "$ibrs_disabled" = 0 ]; then
|
|
pvulnstatus "$cve" VULN "IBRS is supported by your kernel but your CPU microcode lacks support"
|
|
explain "The microcode of your CPU needs to be upgraded to be able to use IBRS. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section). To do a microcode update, you can search the ports for the \`cpupdate\` tool. Microcode updates done this way are not reboot-proof, so be sure to do it every time the system boots up."
|
|
elif [ "$ibrs_disabled" = 1 ]; then
|
|
pvulnstatus "$cve" VULN "IBRS is supported but administratively disabled on your system"
|
|
explain "To enable IBRS, use \`sysctl hw.ibrs_disable=0\`"
|
|
else
|
|
pvulnstatus "$cve" VULN "IBRS is needed to mitigate the vulnerability but your kernel is missing support"
|
|
explain "You need to either upgrade your kernel or recompile yourself a more recent version having IBRS support"
|
|
fi
|
|
}
|