mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-03 13:47:08 +02:00
split script in multiple files, reassembled through build.sh
This commit is contained in:
603
src/vulns/CVE-2017-5715.sh
Normal file
603
src/vulns/CVE-2017-5715.sh
Normal file
@@ -0,0 +1,603 @@
|
||||
# vim: set ts=4 sw=4 sts=4 et:
|
||||
###################
|
||||
# SPECTRE 2 SECTION
|
||||
|
||||
# CVE-2017-5715 Spectre Variant 2 (branch target injection) - entry point
|
||||
check_CVE_2017_5715() {
|
||||
check_cve 'CVE-2017-5715'
|
||||
}
|
||||
|
||||
# CVE-2017-5715 Spectre Variant 2 (branch target injection) - Linux mitigation check
|
||||
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 explain_hypervisor
|
||||
status=UNK
|
||||
sys_interface_available=0
|
||||
msg=''
|
||||
if sys_interface_check "$VULN_SYSFS_BASE/spectre_v2"; 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 "* 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"
|
||||
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 "$msg" | 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
|
||||
|
||||
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"
|
||||
else
|
||||
if [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ -n "$g_ibpb_enabled" ] && [ "$g_ibpb_enabled" -ge 1 ] && (! is_vulnerable_to_empty_rsb || [ "$rsb_filling" = 1 ]); then
|
||||
pvulnstatus "$cve" OK "Full retpoline + IBPB are mitigating the vulnerability"
|
||||
elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ "$opt_paranoid" = 0 ] && (! is_vulnerable_to_empty_rsb || [ "$rsb_filling" = 1 ]); then
|
||||
pvulnstatus "$cve" OK "Full retpoline is mitigating the vulnerability"
|
||||
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
|
||||
elif [ -n "$g_ibrs_enabled" ] && [ -n "$g_ibpb_enabled" ] && [ "$g_ibrs_enabled" -ge 1 ] && [ "$g_ibpb_enabled" -ge 1 ]; 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 ] && ! is_cpu_smt_enabled; then
|
||||
pvulnstatus "$cve" OK "Full IBPB is mitigating the vulnerability"
|
||||
elif [ -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."
|
||||
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 [ "$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
|
||||
|
||||
# if we arrive here and didn't already call pvulnstatus, then it's VULN, let's explain why
|
||||
if [ "$g_pvulnstatus_last_cve" != "$cve" ]; then
|
||||
# explain what's needed for this CPU
|
||||
if is_vulnerable_to_empty_rsb; then
|
||||
pvulnstatus "$cve" VULN "IBRS+IBPB or retpoline+IBPB+RSB filling, is needed to mitigate the vulnerability"
|
||||
explain "To mitigate this vulnerability, you need either IBRS + IBPB, both requiring hardware support from your CPU microcode in addition to kernel support, or a kernel compiled with retpoline and IBPB, with retpoline requiring a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware) and IBPB requiring hardware support from your CPU microcode. You also need a recent-enough kernel that supports RSB filling if you plan to use retpoline. For Skylake+ CPUs, the IBRS + IBPB approach is generally preferred as it guarantees complete protection, and the performance impact is not as high as with older CPUs in comparison with retpoline. More information about how to enable the missing bits for those two possible mitigations on your system follow. You only need to take one of the two approaches."
|
||||
elif is_zen_cpu || is_moksha_cpu; then
|
||||
pvulnstatus "$cve" VULN "retpoline+IBPB is needed to mitigate the vulnerability"
|
||||
explain "To mitigate this vulnerability, You need a kernel compiled with retpoline + IBPB support, with retpoline requiring a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware) and IBPB requiring hardware support from your CPU microcode."
|
||||
elif is_intel || is_amd || is_hygon; then
|
||||
pvulnstatus "$cve" VULN "IBRS+IBPB or retpoline+IBPB is needed to mitigate the vulnerability"
|
||||
explain "To mitigate this vulnerability, you need either IBRS + IBPB, both requiring hardware support from your CPU microcode in addition to kernel support, or a kernel compiled with retpoline and IBPB, with retpoline requiring a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware) and IBPB requiring hardware support from your CPU microcode. The retpoline + IBPB approach is generally preferred as the performance impact is lower. More information about how to enable the missing bits for those two possible mitigations on your system follow. You only need to take one of the two approaches."
|
||||
else
|
||||
# in that case, we might want to trust sysfs if it's there
|
||||
if [ -n "$msg" ]; then
|
||||
[ "$msg" = Vulnerable ] && msg="no known mitigation exists for your CPU vendor ($cpu_vendor)"
|
||||
pvulnstatus "$cve" "$status" "$msg"
|
||||
else
|
||||
pvulnstatus "$cve" VULN "no known mitigation exists for your CPU vendor ($cpu_vendor)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# if we are in live mode, we can check for a lot more stuff and explain further
|
||||
if [ "$opt_live" = 1 ] && [ "$vulnstatus" != "OK" ]; then
|
||||
explain_hypervisor="An updated CPU microcode will have IBRS/IBPB capabilities indicated in the Hardware Check section above. If you're running under a hypervisor (KVM, Xen, VirtualBox, VMware, ...), the hypervisor needs to be up to date to be able to export the new host CPU flags to the guest. You can run this script on the host to check if the host CPU is IBRS/IBPB. If it is, and it doesn't show up in the guest, upgrade the hypervisor. You may need to reconfigure your VM to use a CPU model that has IBRS capability; in Libvirt, such CPUs are listed with an IBRS suffix."
|
||||
# IBPB (amd & intel)
|
||||
if { [ -z "$g_ibpb_enabled" ] || [ "$g_ibpb_enabled" = 0 ]; } && { is_intel || is_amd || is_hygon; }; then
|
||||
if [ -z "$cap_ibpb" ]; then
|
||||
explain "The microcode of your CPU needs to be upgraded to be able to use IBPB. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. 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). $explain_hypervisor"
|
||||
fi
|
||||
if [ -z "$g_ibpb_supported" ]; then
|
||||
explain "Your kernel doesn't have IBPB support, so you need to either upgrade your kernel (if you're using a distro) or recompiling a more recent kernel."
|
||||
fi
|
||||
if [ -n "$cap_ibpb" ] && [ -n "$g_ibpb_supported" ]; then
|
||||
if [ -e "$g_specex_knob_dir/g_ibpb_enabled" ]; then
|
||||
# newer (April 2018) Red Hat kernels have g_ibpb_enabled as ro, and automatically enables it with retpoline
|
||||
if [ ! -w "$g_specex_knob_dir/g_ibpb_enabled" ] && [ -e "$g_specex_knob_dir/retp_enabled" ]; then
|
||||
explain "Both your CPU and your kernel have IBPB support, but it is currently disabled. You kernel should enable IBPB automatically if you enable retpoline. You may enable it with \`echo 1 > $g_specex_knob_dir/retp_enabled\`."
|
||||
else
|
||||
explain "Both your CPU and your kernel have IBPB support, but it is currently disabled. You may enable it with \`echo 1 > $g_specex_knob_dir/g_ibpb_enabled\`."
|
||||
fi
|
||||
else
|
||||
explain "Both your CPU and your kernel have IBPB support, but it is currently disabled. You may enable it. Check in your distro's documentation on how to do this."
|
||||
fi
|
||||
fi
|
||||
elif [ "$g_ibpb_enabled" = 2 ] && is_cpu_smt_enabled; then
|
||||
explain "You have g_ibpb_enabled set to 2, but it only offers sufficient protection when simultaneous multi-threading (aka SMT or HyperThreading) is disabled. You should reboot your system with the kernel parameter \`nosmt\`."
|
||||
fi
|
||||
# /IBPB
|
||||
|
||||
# IBRS (amd & intel)
|
||||
if { [ -z "$g_ibrs_enabled" ] || [ "$g_ibrs_enabled" = 0 ]; } && { is_intel || is_amd || is_hygon; }; then
|
||||
if [ -z "$cap_ibrs" ]; then
|
||||
explain "The microcode of your CPU needs to be upgraded to be able to use IBRS. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. 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). $explain_hypervisor"
|
||||
fi
|
||||
if [ -z "$g_ibrs_supported" ]; then
|
||||
explain "Your kernel doesn't have IBRS support, so you need to either upgrade your kernel (if you're using a distro) or recompiling a more recent kernel."
|
||||
fi
|
||||
if [ -n "$cap_ibrs" ] && [ -n "$g_ibrs_supported" ]; then
|
||||
if [ -e "$g_specex_knob_dir/g_ibrs_enabled" ]; then
|
||||
explain "Both your CPU and your kernel have IBRS support, but it is currently disabled. You may enable it with \`echo 1 > $g_specex_knob_dir/g_ibrs_enabled\`."
|
||||
else
|
||||
explain "Both your CPU and your kernel have IBRS support, but it is currently disabled. You may enable it. Check in your distro's documentation on how to do this."
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# /IBRS
|
||||
unset explain_hypervisor
|
||||
|
||||
# RETPOLINE (amd & intel &hygon )
|
||||
if is_amd || is_intel || is_hygon; then
|
||||
if [ "$retpoline" = 0 ]; then
|
||||
explain "Your kernel is not compiled with retpoline support, so you need to either upgrade your kernel (if you're using a distro) or recompile your kernel with the CONFIG_MITIGATION_RETPOLINE option enabled (was named CONFIG_RETPOLINE before kernel 6.9-rc1). You also need to compile your kernel with a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware)."
|
||||
elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 0 ]; then
|
||||
explain "Your kernel is compiled with retpoline, but without a retpoline-aware compiler (re-run this script with -v to know if your version of gcc is retpoline-aware)."
|
||||
elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" = 0 ]; then
|
||||
explain "Your kernel has retpoline support and has been compiled with a retpoline-aware compiler, but retpoline is disabled. You should enable it with \`echo 1 > $g_specex_knob_dir/retp_enabled\`."
|
||||
fi
|
||||
fi
|
||||
# /RETPOLINE
|
||||
fi
|
||||
fi
|
||||
# sysfs msgs:
|
||||
#1 "Vulnerable"
|
||||
#2 "Vulnerable: Minimal generic ASM retpoline"
|
||||
#2 "Vulnerable: Minimal AMD ASM retpoline"
|
||||
# "Mitigation: Full generic retpoline"
|
||||
# "Mitigation: Full AMD retpoline"
|
||||
# $MITIGATION + ", IBPB"
|
||||
# $MITIGATION + ", IBRS_FW"
|
||||
#5 $MITIGATION + " - vulnerable module loaded"
|
||||
# Red Hat only:
|
||||
#2 "Vulnerable: Minimal ASM retpoline",
|
||||
#3 "Vulnerable: Retpoline without IBPB",
|
||||
#4 "Vulnerable: Retpoline on Skylake+",
|
||||
#5 "Vulnerable: Retpoline with unsafe module(s)",
|
||||
# "Mitigation: Full retpoline",
|
||||
# "Mitigation: Full retpoline and IBRS (user space)",
|
||||
# "Mitigation: IBRS (kernel)",
|
||||
# "Mitigation: IBRS (kernel and user space)",
|
||||
# "Mitigation: IBP disabled",
|
||||
}
|
||||
|
||||
# CVE-2017-5715 Spectre Variant 2 (branch target injection) - BSD mitigation check
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user