mirror of
https://github.com/speed47/spectre-meltdown-checker
synced 2024-11-08 15:13:39 +01:00
feat(cpu) add STIBP, RDCL_NO, IBRS_ALL checks
Move all the CPU checks to their own section, for clarity. We now check for IBRS, IBPB, STIBP, RDCL_NO and IBRS_ALL. We also show whether the system CPU is vulnerable to the three variants, regardless of the fact that mitigations are in place or not, which is determined in each vuln- specific section.
This commit is contained in:
parent
b45e40bec8
commit
acf12a6d2d
@ -199,6 +199,8 @@ is_cpu_vulnerable()
|
|||||||
variant3=''
|
variant3=''
|
||||||
# we also set a friendly name for the CPU to be used in the script if needed
|
# we also set a friendly name for the CPU to be used in the script if needed
|
||||||
cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//')
|
cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//')
|
||||||
|
# variant 0 is just for us to fill the cpu_friendly_name var
|
||||||
|
[ "$1" = 0 ] && return 0
|
||||||
|
|
||||||
if grep -q GenuineIntel /proc/cpuinfo; then
|
if grep -q GenuineIntel /proc/cpuinfo; then
|
||||||
# Intel
|
# Intel
|
||||||
@ -217,6 +219,13 @@ is_cpu_vulnerable()
|
|||||||
[ -z "$variant2" ] && variant2=immune
|
[ -z "$variant2" ] && variant2=immune
|
||||||
[ -z "$variant3" ] && variant3=immune
|
[ -z "$variant3" ] && variant3=immune
|
||||||
fi
|
fi
|
||||||
|
if [ "$capabilities_rdcl_no" = 1 ]; then
|
||||||
|
# capability bit for future Intel processor that will explicitly state
|
||||||
|
# that they're not vulnerable to Meltdown
|
||||||
|
# this var is set in check_cpu()
|
||||||
|
[ -z "$variant3" ] && variant3=immune
|
||||||
|
_debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown"
|
||||||
|
fi
|
||||||
elif grep -q AuthenticAMD /proc/cpuinfo; then
|
elif grep -q AuthenticAMD /proc/cpuinfo; then
|
||||||
# AMD revised their statement about variant2 => vulnerable
|
# AMD revised their statement about variant2 => vulnerable
|
||||||
# https://www.amd.com/en/corporate/speculative-execution
|
# https://www.amd.com/en/corporate/speculative-execution
|
||||||
@ -664,7 +673,7 @@ if [ "$opt_live" = 1 ]; then
|
|||||||
_info "Checking for vulnerabilities on current system"
|
_info "Checking for vulnerabilities on current system"
|
||||||
_info "Kernel is \033[35m"$(uname -s) $(uname -r) $(uname -v) $(uname -m)"\033[0m"
|
_info "Kernel is \033[35m"$(uname -s) $(uname -r) $(uname -v) $(uname -m)"\033[0m"
|
||||||
# call is_cpu_vulnerable to fill the cpu_friendly_name var
|
# call is_cpu_vulnerable to fill the cpu_friendly_name var
|
||||||
is_cpu_vulnerable 1
|
is_cpu_vulnerable 0
|
||||||
_info "CPU is \033[35m$cpu_friendly_name\033[0m"
|
_info "CPU is \033[35m$cpu_friendly_name\033[0m"
|
||||||
|
|
||||||
# try to find the image of the current running kernel
|
# try to find the image of the current running kernel
|
||||||
@ -804,80 +813,11 @@ sys_interface_check()
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
###################
|
check_cpu()
|
||||||
# SPECTRE VARIANT 1
|
|
||||||
check_variant1()
|
|
||||||
{
|
{
|
||||||
_info "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m"
|
_info "\033[1;34mHardware check\033[0m"
|
||||||
|
|
||||||
status=UNK
|
_info "* Hardware support (CPU microcode) for mitigation techniques"
|
||||||
sys_interface_available=0
|
|
||||||
msg=''
|
|
||||||
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then
|
|
||||||
# this kernel has the /sys interface, trust it over everything
|
|
||||||
sys_interface_available=1
|
|
||||||
elif [ "$opt_sysfs_only" != 1 ]; then
|
|
||||||
# no /sys interface (or offline mode), fallback to our own ways
|
|
||||||
_info_nol "* Checking count of LFENCE opcodes in kernel: "
|
|
||||||
if [ -n "$vmlinux_err" ]; then
|
|
||||||
msg="couldn't check ($vmlinux_err)"
|
|
||||||
status=UNK
|
|
||||||
pstatus yellow UNKNOWN
|
|
||||||
else
|
|
||||||
if ! which objdump >/dev/null 2>&1; then
|
|
||||||
msg="missing 'objdump' tool, please install it, usually it's in the binutils package"
|
|
||||||
status=UNK
|
|
||||||
pstatus yellow UNKNOWN
|
|
||||||
else
|
|
||||||
# here we disassemble the kernel and count the number of occurrences of the LFENCE opcode
|
|
||||||
# in non-patched kernels, this has been empirically determined as being around 40-50
|
|
||||||
# in patched kernels, this is more around 70-80, sometimes way higher (100+)
|
|
||||||
# v0.13: 68 found in a 3.10.23-xxxx-std-ipv6-64 (with lots of modules compiled-in directly), which doesn't have the LFENCE patches,
|
|
||||||
# so let's push the threshold to 70.
|
|
||||||
nb_lfence=$(objdump -d "$vmlinux" | grep -wc lfence)
|
|
||||||
if [ "$nb_lfence" -lt 70 ]; then
|
|
||||||
msg="only $nb_lfence opcodes found, should be >= 70, heuristic to be improved when official patches become available"
|
|
||||||
status=VULN
|
|
||||||
pstatus red NO
|
|
||||||
else
|
|
||||||
msg="$nb_lfence opcodes found, which is >= 70, heuristic to be improved when official patches become available"
|
|
||||||
status=OK
|
|
||||||
pstatus green YES
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
# 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_vulnerable 1; then
|
|
||||||
# override status & msg in case CPU is not vulnerable after all
|
|
||||||
msg="your CPU vendor reported your CPU model as not vulnerable"
|
|
||||||
status=OK
|
|
||||||
fi
|
|
||||||
|
|
||||||
# report status
|
|
||||||
pvulnstatus CVE-2017-5753 "$status" "$msg"
|
|
||||||
}
|
|
||||||
|
|
||||||
###################
|
|
||||||
# SPECTRE VARIANT 2
|
|
||||||
check_variant2()
|
|
||||||
{
|
|
||||||
_info "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m"
|
|
||||||
|
|
||||||
status=UNK
|
|
||||||
sys_interface_available=0
|
|
||||||
msg=''
|
|
||||||
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then
|
|
||||||
# this kernel has the /sys interface, trust it over everything
|
|
||||||
sys_interface_available=1
|
|
||||||
fi
|
|
||||||
if [ "$opt_sysfs_only" != 1 ]; then
|
|
||||||
_info "* Mitigation 1"
|
|
||||||
_info " * Hardware support (CPU microcode)"
|
|
||||||
_info " * Indirect Branch Restricted Speculation (IBRS)"
|
_info " * Indirect Branch Restricted Speculation (IBRS)"
|
||||||
_info_nol " * SPEC_CTRL MSR is available: "
|
_info_nol " * SPEC_CTRL MSR is available: "
|
||||||
if [ ! -e /dev/cpu/0/msr ]; then
|
if [ ! -e /dev/cpu/0/msr ]; then
|
||||||
@ -966,7 +906,7 @@ check_variant2()
|
|||||||
|
|
||||||
_info_nol " * CPU indicates IBPB capability: "
|
_info_nol " * CPU indicates IBPB capability: "
|
||||||
if [ ! -e /dev/cpu/0/cpuid ]; then
|
if [ ! -e /dev/cpu/0/cpuid ]; then
|
||||||
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuidr, is cpuid support enabled in your kernel?"
|
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
||||||
else
|
else
|
||||||
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
|
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
|
||||||
if [ "$opt_verbose" -ge 3 ]; then
|
if [ "$opt_verbose" -ge 3 ]; then
|
||||||
@ -1003,7 +943,7 @@ check_variant2()
|
|||||||
|
|
||||||
_info_nol " * CPU indicates STIBP capability: "
|
_info_nol " * CPU indicates STIBP capability: "
|
||||||
if [ ! -e /dev/cpu/0/cpuid ]; then
|
if [ ! -e /dev/cpu/0/cpuid ]; then
|
||||||
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuidr, is cpuid support enabled in your kernel?"
|
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
||||||
else
|
else
|
||||||
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
|
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
|
||||||
if [ "$opt_verbose" -ge 3 ]; then
|
if [ "$opt_verbose" -ge 3 ]; then
|
||||||
@ -1018,13 +958,158 @@ check_variant2()
|
|||||||
edx_bit27=$(( edx_hb & 8 ))
|
edx_bit27=$(( edx_hb & 8 ))
|
||||||
_debug "cpuid: edx_bit27=$edx_bit27"
|
_debug "cpuid: edx_bit27=$edx_bit27"
|
||||||
if [ "$edx_bit27" -eq 8 ]; then
|
if [ "$edx_bit27" -eq 8 ]; then
|
||||||
pstatus green YES "STIBP feature bit"
|
pstatus green YES
|
||||||
cpuid_stibp=1
|
cpuid_stibp=1
|
||||||
else
|
else
|
||||||
pstatus red NO
|
pstatus red NO
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_info " * Enhanced IBRS (IBRS_ALL)"
|
||||||
|
_info_nol " * CPU indicates ARCH_CAPABILITIES MSR availability: "
|
||||||
|
if [ ! -e /dev/cpu/0/cpuid ]; then
|
||||||
|
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/cpuid, is cpuid support enabled in your kernel?"
|
||||||
|
else
|
||||||
|
# A processor supports STIBP if it enumerates CPUID (EAX=7H,ECX=0):EDX[27] as 1
|
||||||
|
if [ "$opt_verbose" -ge 3 ]; then
|
||||||
|
dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 >/dev/null 2>/dev/null
|
||||||
|
_debug "cpuid: reading leaf7 of cpuid on cpu0, ret=$?"
|
||||||
|
_debug "cpuid: leaf7 eax-ebx-ecx-edx: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | od -x -A n)
|
||||||
|
_debug "cpuid: leaf7 edx higher byte is: "$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=15 count=1 2>/dev/null | od -x -A n)
|
||||||
|
fi
|
||||||
|
# getting high byte of edx on leaf7 of cpuinfo in decimal
|
||||||
|
edx_hb=$(dd if=/dev/cpu/0/cpuid bs=16 skip=7 iflag=skip_bytes count=1 2>/dev/null | dd bs=1 skip=15 count=1 2>/dev/null | od -t u -A n | awk '{print $1}')
|
||||||
|
_debug "cpuid: leaf7 edx higher byte: $edx_hb (decimal)"
|
||||||
|
edx_bit29=$(( edx_hb & 32 ))
|
||||||
|
_debug "cpuid: edx_bit29=$edx_bit29"
|
||||||
|
if [ "$edx_bit27" -eq 32 ]; then
|
||||||
|
pstatus green YES
|
||||||
|
cpuid_arch_capabilities=1
|
||||||
|
else
|
||||||
|
pstatus red NO
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info_nol " * ARCH_CAPABILITIES MSR advertises IBRS_ALL capability: "
|
||||||
|
if [ "$cpuid_arch_capabilities" != 1 ]; then
|
||||||
|
pstatus red NO
|
||||||
|
elif [ ! -e /dev/cpu/0/msr ]; then
|
||||||
|
spec_ctrl_msr=-1
|
||||||
|
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
|
||||||
|
else
|
||||||
|
# the new MSR 'ARCH_CAPABILITIES' is at offset 0x10a
|
||||||
|
# here we use dd, it's the same as using 'rdmsr 0x10a' but without needing the rdmsr tool
|
||||||
|
# if we get a read error, the MSR is not there. bs has to be 8 for msr
|
||||||
|
capabilities=$(dd if=/dev/cpu/0/msr bs=8 count=1 skip=266 iflag=skip_bytes 2>/dev/null | od -t u1 -A n | awk '{print $8}')
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
_debug "capabilities MSR lower byte is $capabilities (decimal)"
|
||||||
|
capabilities_rdcl_no=0
|
||||||
|
[ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1
|
||||||
|
[ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1
|
||||||
|
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all"
|
||||||
|
if [ "$capabilities_ibrs_all" = 1 ]; then
|
||||||
|
pstatus green YES
|
||||||
|
else
|
||||||
|
pstatus red NO
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
pstatus yellow UNKNOWN
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info_nol " * CPU explicitly indicates not being vulnerable to Meltdown (RDCL_NO): "
|
||||||
|
if [ "$capabilities_rdcl_no" = 1 ]; then
|
||||||
|
pstatus green YES
|
||||||
|
else
|
||||||
|
pstatus blue NO
|
||||||
|
fi
|
||||||
|
|
||||||
|
_info "* CPU vulnerability to the three speculative execution attacks variants"
|
||||||
|
for v in 1 2 3; do
|
||||||
|
_info_nol " * Vulnerable to Variant $v: "
|
||||||
|
if is_cpu_vulnerable $v; then
|
||||||
|
pstatus red YES
|
||||||
|
else
|
||||||
|
pstatus green NO
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
_info
|
||||||
|
}
|
||||||
|
|
||||||
|
###################
|
||||||
|
# SPECTRE VARIANT 1
|
||||||
|
check_variant1()
|
||||||
|
{
|
||||||
|
_info "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m"
|
||||||
|
|
||||||
|
status=UNK
|
||||||
|
sys_interface_available=0
|
||||||
|
msg=''
|
||||||
|
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then
|
||||||
|
# this kernel has the /sys interface, trust it over everything
|
||||||
|
sys_interface_available=1
|
||||||
|
elif [ "$opt_sysfs_only" != 1 ]; then
|
||||||
|
# no /sys interface (or offline mode), fallback to our own ways
|
||||||
|
_info_nol "* Checking count of LFENCE opcodes in kernel: "
|
||||||
|
if [ -n "$vmlinux_err" ]; then
|
||||||
|
msg="couldn't check ($vmlinux_err)"
|
||||||
|
status=UNK
|
||||||
|
pstatus yellow UNKNOWN
|
||||||
|
else
|
||||||
|
if ! which objdump >/dev/null 2>&1; then
|
||||||
|
msg="missing 'objdump' tool, please install it, usually it's in the binutils package"
|
||||||
|
status=UNK
|
||||||
|
pstatus yellow UNKNOWN
|
||||||
|
else
|
||||||
|
# here we disassemble the kernel and count the number of occurrences of the LFENCE opcode
|
||||||
|
# in non-patched kernels, this has been empirically determined as being around 40-50
|
||||||
|
# in patched kernels, this is more around 70-80, sometimes way higher (100+)
|
||||||
|
# v0.13: 68 found in a 3.10.23-xxxx-std-ipv6-64 (with lots of modules compiled-in directly), which doesn't have the LFENCE patches,
|
||||||
|
# so let's push the threshold to 70.
|
||||||
|
nb_lfence=$(objdump -d "$vmlinux" | grep -wc lfence)
|
||||||
|
if [ "$nb_lfence" -lt 70 ]; then
|
||||||
|
msg="only $nb_lfence opcodes found, should be >= 70, heuristic to be improved when official patches become available"
|
||||||
|
status=VULN
|
||||||
|
pstatus red NO
|
||||||
|
else
|
||||||
|
msg="$nb_lfence opcodes found, which is >= 70, heuristic to be improved when official patches become available"
|
||||||
|
status=OK
|
||||||
|
pstatus green YES
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
# 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_vulnerable 1; then
|
||||||
|
# override status & msg in case CPU is not vulnerable after all
|
||||||
|
msg="your CPU vendor reported your CPU model as not vulnerable"
|
||||||
|
status=OK
|
||||||
|
fi
|
||||||
|
|
||||||
|
# report status
|
||||||
|
pvulnstatus CVE-2017-5753 "$status" "$msg"
|
||||||
|
}
|
||||||
|
|
||||||
|
###################
|
||||||
|
# SPECTRE VARIANT 2
|
||||||
|
check_variant2()
|
||||||
|
{
|
||||||
|
_info "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m"
|
||||||
|
|
||||||
|
status=UNK
|
||||||
|
sys_interface_available=0
|
||||||
|
msg=''
|
||||||
|
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then
|
||||||
|
# this kernel has the /sys interface, trust it over everything
|
||||||
|
sys_interface_available=1
|
||||||
|
fi
|
||||||
|
if [ "$opt_sysfs_only" != 1 ]; then
|
||||||
|
_info "* Mitigation 1"
|
||||||
_info_nol " * Kernel is compiled with IBRS/IBPB support: "
|
_info_nol " * Kernel is compiled with IBRS/IBPB support: "
|
||||||
ibrs_can_tell=0
|
ibrs_can_tell=0
|
||||||
|
|
||||||
@ -1429,6 +1514,7 @@ check_variant3()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_cpu
|
||||||
# now run the checks the user asked for
|
# now run the checks the user asked for
|
||||||
if [ "$opt_variant1" = 1 -o "$opt_allvariants" = 1 ]; then
|
if [ "$opt_variant1" = 1 -o "$opt_allvariants" = 1 ]; then
|
||||||
check_variant1
|
check_variant1
|
||||||
|
Loading…
Reference in New Issue
Block a user