40 Commits
v0.37 ... v0.38

Author SHA1 Message Date
21af561148 bump to v0.38 2018-08-07 10:55:50 +02:00
cb740397f3 feat(arm32): add spectrev1 mitigation detection 2018-08-07 10:42:03 +02:00
84195689af change: default to --no-explain, use --explain to get detailed mitigation help 2018-08-04 16:31:41 +02:00
b637681fa8 fix: debug output: msg inaccuracy for ARM checks 2018-08-04 16:19:54 +02:00
9316c30577 fix: armv8: models < 0xd07 are not vulnerable 2018-08-04 16:19:54 +02:00
f9dd9d8cb9 add guess for archlinuxarm aarch64 kernel image on raspberry pi 3 (#222) 2018-08-01 00:15:52 +02:00
0f0d103a89 fix: correctly init capabilities_ssb_no var in all cases 2018-07-26 10:18:14 +02:00
b262c40541 fix: remove spurious character after an else statement 2018-07-25 21:55:50 +02:00
cc2910fbbc fix: read_cpuid: don't use iflag=skip_bytes for compat with old dd versions
This closes #215 #199 #193
2018-07-23 09:12:30 +02:00
30c4a1f6d2 arm64: cavium: Add CPU Implementer Cavium (#216)
This patch adds 0x43 check for cavium implementor id in function
parse_cpu_details. Also adds that Cavium Soc is not vulnerable to variant 3/3a

Signed-off-by: Manish Jaggi <manish.jagg@cavium.com>
2018-07-22 19:06:19 +02:00
cf06636a3f fix: prometheus output: use printf for proper \n interpretation (#204) 2018-06-21 23:35:51 +02:00
60077c8d12 fix(arm): rewrite vuln logic from latest arm statement for Cortex A8 to A76 2018-06-21 23:24:18 +02:00
c181978d7c fix(arm): Updated arm cortex status (#209)
* Cortex A8 Vulnerable

Arm Cortex A8 is vulnerable to variants 1 & 2  (https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability)

Part number is 0xc08 (https://developer.arm.com/docs/ddi0344/b/system-control-coprocessor/system-control-coprocessorregisters/c0-main-id-register)

False negative reported by @V10lator in #206

* ARM Cortex A12 Vulnerable to 1&2

https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability

* A76 vulnerable to variant 4

All arch 8 cortex A57-A76 are vulnerable to variant 4.

https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability

* Whitelist variant4 nonvuln Arms

* ARM Cortex Whitelist & Cumulative Blacklist

Applies all information about vulnerabilities of ARM Cortex processors (from https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability).

Whitelist & blacklist approach, using both vulnerable and non vulnerable status for each identified CPU, with vulnerabilities tracked cumulatively for multi CPU systems.
2018-06-16 12:14:39 +02:00
Jan
9a6406a9a2 chore: add docker support (#203) 2018-06-14 20:25:35 +02:00
5962d20ba7 fix(variant4): whitelist from common.c::cpu_no_spec_store_bypass (#202)
* variant4 from common.c::cpu_no_spec_store_bypass

Variant 4 - Add function to 'whitelist' the hand-full of CPUs unaffected by speculative store bypass. 

This would allow improved determination of variant 4 status ( #189 ) of immune CPUs while waiting for the 4.17/stable patches to be backported to distro kernels.

Source of cpu list : https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n945)
Modeled after is_cpu_specex_free()

* amd families fix

amd families are reported by parse_cpu_details() in decimal

* remove duplicates

Only list processors which speculate and are immune to variant 4.
Avoids duplication with non-speculating CPUs listed in is_cpu_specex_free()
2018-05-27 15:14:29 +02:00
17a3488505 fix(help): add missing references to variants 3a & 4 (#201) 2018-05-24 16:35:57 +02:00
e54e8b3e84 chore: remove warning in README, fix display indentation 2018-05-24 16:32:53 +02:00
39c778e3ac fix(amd): AMD families 0x15-0x17 non-arch MSRs are a valid way to control SSB 2018-05-23 23:08:07 +02:00
2cde6e4649 feat(ssbd): add detection of proper CPUID bits on AMD 2018-05-23 22:50:52 +02:00
f4d51e7e53 fix(variant4): add another detection way for Red Hat kernel 2018-05-23 22:47:54 +02:00
85d46b2799 feat(variant4): add more detailed explanations 2018-05-23 21:08:58 +02:00
61e02abd0c feat(variant3a): detect up to date microcode 2018-05-23 21:08:08 +02:00
114756fab7 fix(amd): not vulnerable to variant3a 2018-05-23 20:38:43 +02:00
ea75969eb7 fix(help): Update variant options in usage message (#200) 2018-05-22 15:54:25 +02:00
ca391cbfc9 fix(variant2): correctly detect IBRS/IBPB in SLES kernels 2018-05-22 12:06:46 +02:00
68af5c5f92 feat(variant4): detect SSBD-aware kernel 2018-05-22 12:05:46 +02:00
19be8f79eb doc: update README with some info about variant3 and variant4 2018-05-22 09:43:29 +02:00
f75cc0bb6f feat(variant4): add sysfs mitigation hint and some explanation about the vuln 2018-05-22 09:39:11 +02:00
f33d65ff71 feat(variant3a): add information about microcode-sufficient mitigation 2018-05-22 09:38:29 +02:00
725eaa8bf5 feat(arm): adjust vulnerable ARM CPUs for variant3a and variant4 2018-05-22 09:19:29 +02:00
c6ee0358d1 feat(variant4): report SSB_NO CPUs as not vulnerable 2018-05-22 09:18:30 +02:00
22d0b203da fix(ssb_no): rename ssbd_no to ssb_no and fix shift 2018-05-22 00:38:31 +02:00
3062a8416a fix(msg): add missing words 2018-05-22 00:10:08 +02:00
6a4318addf feat(variant3a/4): initial support for 2 new CVEs 2018-05-22 00:06:56 +02:00
c19986188f fix(variant2): adjust detection for SLES kernels 2018-05-19 09:53:12 +02:00
7e4899bcb8 ibrs can't be enabled on no ibrs cpu (#195)
* ibrs can't be enabled on no ibrs cpu

If the cpu is identified, and does not support SPEC_CTRL or IBRS, then ibrs can't be enabled, even if supported by the kernel.
Instead of reporting IBRS enabled and active UNKNOWN, report IBRS enabled and active NO.
2018-05-17 15:39:48 +02:00
5cc77741af Update spectre-meltdown-checker.sh 2018-05-05 13:00:44 +02:00
1c0f6d9580 cpuid and msr module check
This adds a check before loading the cpuid and msr modules under linux, ensuring they are not unloaded in exit_cleanup() if they were initially present.
2018-05-05 13:00:44 +02:00
4acd0f647a Suggestion to change VM to a CPU with IBRS capability 2018-04-20 20:35:12 +02:00
fb52dbe7bf set master branch to v0.37+ 2018-04-20 20:34:42 +02:00
3 changed files with 426 additions and 73 deletions

7
Dockerfile Normal file
View File

@ -0,0 +1,7 @@
FROM alpine:3.7
RUN apk --update --no-cache add kmod binutils grep perl
COPY . /check
ENTRYPOINT ["/check/spectre-meltdown-checker.sh"]

View File

@ -1,7 +1,12 @@
Spectre & Meltdown Checker Spectre & Meltdown Checker
========================== ==========================
A shell script to tell if your system is vulnerable against the 3 "speculative execution" CVEs that were made public early 2018. A shell script to tell if your system is vulnerable against the several "speculative execution" CVEs that were made public in 2018.
- CVE-2017-5753 aka Spectre Variant 1
- CVE-2017-5715 aka Spectre Variant 2
- CVE-2017-5754 aka Meltdown or Variant 3
- CVE-2018-3640 aka Variant 3a
- CVE-2018-3639 aka Variant 4
Supported operating systems: Supported operating systems:
- Linux (all versions, flavors and distros) - Linux (all versions, flavors and distros)
@ -39,6 +44,13 @@ chmod +x spectre-meltdown-checker.sh
sudo ./spectre-meltdown-checker.sh sudo ./spectre-meltdown-checker.sh
``` ```
### Run the script in a docker container
```shell
docker build -t spectre-meltdown-checker .
docker run --rm --privileged -v /boot:/boot:ro -v /lib/modules:/lib/modules:ro -v /dev/cpu:/dev/cpu:ro spectre-meltdown-checker
```
## Example of script output ## Example of script output
- Intel Haswell CPU running under Ubuntu 16.04 LTS - Intel Haswell CPU running under Ubuntu 16.04 LTS
@ -74,7 +86,19 @@ sudo ./spectre-meltdown-checker.sh
- Mitigation: updated kernel (with PTI/KPTI patches), updating the kernel is enough - Mitigation: updated kernel (with PTI/KPTI patches), updating the kernel is enough
- Performance impact of the mitigation: low to medium - Performance impact of the mitigation: low to medium
## Disclaimer **CVE-2018-3640** rogue system register read (Variant 3a)
- Impact: TBC
- Mitigation: microcode update only
- Performance impact of the mitigation: negligible
**CVE-2018-3639** speculative store bypass (Variant 4)
- Impact: software using JIT (no known exploitation against kernel)
- Mitigation: microcode update + kernel update making possible for affected software to protect itself
- Performance impact of the mitigation: low to medium
## Understanding what this script does and doesn't
This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place. This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the collectively named "speculative execution" vulnerabilities. It doesn't attempt to run any kind of exploit, and can't guarantee that your system is secure, but rather helps you verifying whether your system has the known correct mitigations in place.
However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels). However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels).

View File

@ -9,7 +9,7 @@
# #
# Stephane Lesimple # Stephane Lesimple
# #
VERSION='0.37' VERSION='0.38'
trap 'exit_cleanup' EXIT trap 'exit_cleanup' EXIT
trap '_warn "interrupted, cleaning up..."; exit_cleanup; exit 1' INT trap '_warn "interrupted, cleaning up..."; exit_cleanup; exit 1' INT
@ -50,7 +50,7 @@ show_usage()
Options: Options:
--no-color don't use color codes --no-color don't use color codes
--verbose, -v increase verbosity level, possibly several times --verbose, -v increase verbosity level, possibly several times
--no-explain don't produce a human-readable explanation of actions to take to mitigate a vulnerability --explain produce an additional human-readable explanation of actions to take to mitigate a vulnerability
--paranoid require IBPB to deem Variant 2 as mitigated --paranoid require IBPB to deem Variant 2 as mitigated
--no-sysfs don't use the /sys interface even if present [Linux] --no-sysfs don't use the /sys interface even if present [Linux]
@ -64,7 +64,7 @@ show_usage()
--batch nrpe produce machine readable output formatted for NRPE --batch nrpe produce machine readable output formatted for NRPE
--batch prometheus produce output for consumption by prometheus-node-exporter --batch prometheus produce output for consumption by prometheus-node-exporter
--variant [1,2,3] specify which variant you'd like to check, by default all variants are checked, --variant [1,2,3,3a,4] specify which variant you'd like to check, by default all variants are checked,
can be specified multiple times (e.g. --variant 2 --variant 3) can be specified multiple times (e.g. --variant 2 --variant 3)
--hw-only only check for CPU information, don't check for any variant --hw-only only check for CPU information, don't check for any variant
--no-hw skip CPU information and checks, if you're inspecting a kernel not to be run on this host --no-hw skip CPU information and checks, if you're inspecting a kernel not to be run on this host
@ -124,6 +124,8 @@ opt_verbose=1
opt_variant1=0 opt_variant1=0
opt_variant2=0 opt_variant2=0
opt_variant3=0 opt_variant3=0
opt_variant3a=0
opt_variant4=0
opt_allvariants=1 opt_allvariants=1
opt_no_sysfs=0 opt_no_sysfs=0
opt_sysfs_only=0 opt_sysfs_only=0
@ -131,7 +133,7 @@ opt_coreos=0
opt_arch_prefix='' opt_arch_prefix=''
opt_hw_only=0 opt_hw_only=0
opt_no_hw=0 opt_no_hw=0
opt_no_explain=0 opt_explain=0
opt_paranoid=0 opt_paranoid=0
global_critical=0 global_critical=0
@ -233,7 +235,7 @@ _debug()
explain() explain()
{ {
if [ "$opt_no_explain" != 1 ] ; then if [ "$opt_explain" = 1 ] ; then
_info '' _info ''
_info "> \033[41m\033[30mHow to fix:\033[0m $*" _info "> \033[41m\033[30mHow to fix:\033[0m $*"
fi fi
@ -248,13 +250,17 @@ _is_cpu_vulnerable_cached()
[ "$1" = 2 ] && return $variant2 [ "$1" = 2 ] && return $variant2
# shellcheck disable=SC2086 # shellcheck disable=SC2086
[ "$1" = 3 ] && return $variant3 [ "$1" = 3 ] && return $variant3
# shellcheck disable=SC2086
[ "$1" = 3a ] && return $variant3a
# shellcheck disable=SC2086
[ "$1" = 4 ] && return $variant4
echo "$0: error: invalid variant '$1' passed to is_cpu_vulnerable()" >&2 echo "$0: error: invalid variant '$1' passed to is_cpu_vulnerable()" >&2
exit 255 exit 255
} }
is_cpu_vulnerable() is_cpu_vulnerable()
{ {
# param: 1, 2 or 3 (variant) # param: 1, 2, 3, 3a or 4 (variant)
# returns 0 if vulnerable, 1 if not vulnerable # returns 0 if vulnerable, 1 if not vulnerable
# (note that in shell, a return of 0 is success) # (note that in shell, a return of 0 is success)
# by default, everything is vulnerable, we work in a "whitelist" logic here. # by default, everything is vulnerable, we work in a "whitelist" logic here.
@ -267,11 +273,15 @@ is_cpu_vulnerable()
variant1='' variant1=''
variant2='' variant2=''
variant3='' variant3=''
variant3a=''
variant4=''
if is_cpu_specex_free; then if is_cpu_specex_free; then
variant1=immune variant1=immune
variant2=immune variant2=immune
variant3=immune variant3=immune
variant3a=immune
variant4=immune
elif is_intel; then elif is_intel; then
# Intel # Intel
# https://github.com/crozone/SpectrePoC/issues/1 ^F E5200 => spectre 2 not vulnerable # https://github.com/crozone/SpectrePoC/issues/1 ^F E5200 => spectre 2 not vulnerable
@ -289,12 +299,33 @@ is_cpu_vulnerable()
variant3=immune variant3=immune
_debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown" _debug "is_cpu_vulnerable: RDCL_NO is set so not vuln to meltdown"
fi fi
if [ "$capabilities_ssb_no" = 1 ]; then
# capability bit for future Intel processor that will explicitly state
# that they're not vulnerable to Variant 4
# this var is set in check_cpu()
variant4=immune
_debug "is_cpu_vulnerable: SSB_NO is set so not vuln to variant4"
fi
if is_cpu_ssb_free; then
[ -z "$variant4" ] && variant4=immune
_debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4"
fi
elif is_amd; then elif is_amd; 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
variant1=vuln variant1=vuln
variant2=vuln variant2=vuln
[ -z "$variant3" ] && variant3=immune [ -z "$variant3" ] && variant3=immune
# https://www.amd.com/en/corporate/security-updates
# "We have not identified any AMD x86 products susceptible to the Variant 3a vulnerability in our analysis to-date."
[ -z "$variant3a" ] && variant3a=immune
if is_cpu_ssb_free; then
[ -z "$variant4" ] && variant4=immune
_debug "is_cpu_vulnerable: cpu not affected by speculative store bypass so not vuln to variant4"
fi
elif [ "$cpu_vendor" = CAVIUM ]; then
variant3=immune
variant3a=immune
elif [ "$cpu_vendor" = ARM ]; then elif [ "$cpu_vendor" = ARM ]; then
# ARM # ARM
# reference: https://developer.arm.com/support/security-update # reference: https://developer.arm.com/support/security-update
@ -313,46 +344,83 @@ is_cpu_vulnerable()
if [ -n "$cpupart" ] && [ -n "$cpuarch" ]; then if [ -n "$cpupart" ] && [ -n "$cpuarch" ]; then
# Cortex-R7 and Cortex-R8 are real-time and only used in medical devices or such # Cortex-R7 and Cortex-R8 are real-time and only used in medical devices or such
# I can't find their CPU part number, but it's probably not that useful anyway # I can't find their CPU part number, but it's probably not that useful anyway
# model R7 R8 A9 A15 A17 A57 A72 A73 A75 # model R7 R8 A8 A9 A12 A15 A17 A57 A72 A73 A75 A76
# part ? ? 0xc09 0xc0f 0xc0e 0xd07 0xd08 0xd09 0xd0a # part ? ? c08 c09 c0d c0f c0e d07 d08 d09 d0a d0b?
# arch 7? 7? 7 7 7 8 8 8 8 # arch 7? 7? 7 7 7 7 7 8 8 8 8 8
# #
# variant 1 & variant 2 # Whitelist identified non-vulnerable processors, use vulnerability information from
if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -Eq '^0x(c09|c0f|c0e)$'; then # https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
# armv7 vulnerable chips #
_debug "checking cpu$i: this armv7 vulnerable to spectre 1 & 2" # Maintain cumulative check of vulnerabilities -
# if at least one of the cpu is vulnerable, then the system is vulnerable
if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc08 -e 0xc09 -e 0xc0d -e 0xc0e; then
variant1=vuln variant1=vuln
variant2=vuln variant2=vuln
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -Eq '^0x(d07|d08|d09|d0a)$'; then [ -z "$variant3" ] && variant3=immune
# armv8 vulnerable chips [ -z "$variant3a" ] && variant3a=immune
_debug "checking cpu$i: this armv8 vulnerable to spectre 1 & 2" [ -z "$variant4" ] && variant4=immune
_debug "checking cpu$i: armv7 A8/A9/A12/A17 non vulnerable to variants 3, 3a & 4"
elif [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc0f; then
variant1=vuln variant1=vuln
variant2=vuln variant2=vuln
else [ -z "$variant3" ] && variant3=immune
_debug "checking cpu$i: this arm non vulnerable to 1 & 2" variant3a=vuln
# others are not vulnerable [ -z "$variant4" ] && variant4=immune
_debug "checking cpu$i: armv7 A15 non vulnerable to variants 3 & 4"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd07 -e 0xd08; then
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
variant3a=vuln
variant4=vuln
_debug "checking cpu$i: armv8 A57/A72 non vulnerable to variants 3"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd09; then
variant1=vuln
variant2=vuln
[ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
variant4=vuln
_debug "checking cpu$i: armv8 A73 non vulnerable to variants 3 & 3a"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0a; then
variant1=vuln
variant2=vuln
variant3=vuln
[ -z "$variant3a" ] && variant3a=immune
variant4=vuln
_debug "checking cpu$i: armv8 A75 non vulnerable to variant 3a"
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0b; then
variant1=vuln
[ -z "$variant2" ] && variant2=immune
[ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
variant4=vuln
_debug "checking cpu$i: armv8 A76 non vulnerable to variant 2, 3 & 3a"
elif [ "$cpuarch" -le 7 ] || ( [ "$cpuarch" = 8 ] && [ $(( cpupart )) -lt $(( 0xd07 )) ] ) ; then
[ -z "$variant1" ] && variant1=immune [ -z "$variant1" ] && variant1=immune
[ -z "$variant2" ] && variant2=immune [ -z "$variant2" ] && variant2=immune
fi
# for variant3, only A75 is vulnerable
if [ "$cpuarch" = 8 ] && [ "$cpupart" = 0xd0a ]; then
_debug "checking cpu$i: arm A75 vulnerable to meltdown"
variant3=vuln
else
_debug "checking cpu$i: this arm non vulnerable to meltdown"
[ -z "$variant3" ] && variant3=immune [ -z "$variant3" ] && variant3=immune
[ -z "$variant3a" ] && variant3a=immune
[ -z "$variant4" ] && variant4=immune
_debug "checking cpu$i: arm arch$cpuarch, all immune (v7 or v8 and model < 0xd07)"
else
variant1=vuln
variant2=vuln
variant3=vuln
variant3a=vuln
variant4=vuln
_debug "checking cpu$i: arm unknown arch$cpuarch part$cpupart, considering vuln"
fi fi
fi fi
_debug "is_cpu_vulnerable: for cpu$i and so far, we have <$variant1> <$variant2> <$variant3>" _debug "is_cpu_vulnerable: for cpu$i and so far, we have <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4>"
done done
fi fi
_debug "is_cpu_vulnerable: temp results are <$variant1> <$variant2> <$variant3>" _debug "is_cpu_vulnerable: temp results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4>"
# if at least one of the cpu is vulnerable, then the system is vulnerable
[ "$variant1" = "immune" ] && variant1=1 || variant1=0 [ "$variant1" = "immune" ] && variant1=1 || variant1=0
[ "$variant2" = "immune" ] && variant2=1 || variant2=0 [ "$variant2" = "immune" ] && variant2=1 || variant2=0
[ "$variant3" = "immune" ] && variant3=1 || variant3=0 [ "$variant3" = "immune" ] && variant3=1 || variant3=0
_debug "is_cpu_vulnerable: final results are <$variant1> <$variant2> <$variant3>" [ "$variant3a" = "immune" ] && variant3a=1 || variant3a=0
[ "$variant4" = "immune" ] && variant4=1 || variant4=0
_debug "is_cpu_vulnerable: final results are <$variant1> <$variant2> <$variant3> <$variant3a> <$variant4>"
is_cpu_vulnerable_cached=1 is_cpu_vulnerable_cached=1
_is_cpu_vulnerable_cached "$1" _is_cpu_vulnerable_cached "$1"
return $? return $?
@ -390,6 +458,51 @@ is_cpu_specex_free()
return 1 return 1
} }
is_cpu_ssb_free()
{
# return true (0) if the CPU isn't affected by speculative store bypass, false (1) if it does.
# if it's not in the list we know, return false (1).
# source1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/common.c#n945
# source2: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git/tree/arch/x86/kernel/cpu/common.c
# Only list CPUs that speculate but are immune, to avoid duplication of cpus listed in is_cpu_specex_free()
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT1 },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_AIRMONT },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_SILVERMONT2 },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ATOM_MERRIFIELD },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_CORE_YONAH },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNL },
#{ X86_VENDOR_INTEL, 6, INTEL_FAM6_XEON_PHI_KNM },
#{ X86_VENDOR_AMD, 0x12, },
#{ X86_VENDOR_AMD, 0x11, },
#{ X86_VENDOR_AMD, 0x10, },
#{ X86_VENDOR_AMD, 0xf, },
parse_cpu_details
if is_intel; then
if [ "$cpu_family" = 6 ]; then
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT1" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT2" ] || \
[ "$cpu_model" = "$INTEL_FAM6_ATOM_MERRIFIELD" ]; then
return 0
elif [ "$cpu_model" = "$INTEL_FAM6_CORE_YONAH" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || \
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
return 0
fi
fi
fi
if is_amd; then
if [ "$cpu_family" = "18" ] || \
[ "$cpu_family" = "17" ] || \
[ "$cpu_family" = "16" ] || \
[ "$cpu_family" = "15" ]; then
return 0
fi
fi
[ "$cpu_family" = 4 ] && return 0
return 1
}
show_header() show_header()
{ {
_info "Spectre and Meltdown mitigation detection tool v$VERSION" _info "Spectre and Meltdown mitigation detection tool v$VERSION"
@ -471,7 +584,11 @@ while [ -n "$1" ]; do
opt_no_hw=1 opt_no_hw=1
shift shift
elif [ "$1" = "--no-explain" ]; then elif [ "$1" = "--no-explain" ]; then
opt_no_explain=1 # deprecated, kept for compatibility
opt_explain=0
shift
elif [ "$1" = "--explain" ]; then
opt_explain=1
shift shift
elif [ "$1" = "--batch" ]; then elif [ "$1" = "--batch" ]; then
opt_batch=1 opt_batch=1
@ -492,15 +609,17 @@ while [ -n "$1" ]; do
shift shift
elif [ "$1" = "--variant" ]; then elif [ "$1" = "--variant" ]; then
if [ -z "$2" ]; then if [ -z "$2" ]; then
echo "$0: error: option --variant expects a parameter (1, 2 or 3)" >&2 echo "$0: error: option --variant expects a parameter (1, 2, 3, 3a or 4)" >&2
exit 255 exit 255
fi fi
case "$2" in case "$2" in
1) opt_variant1=1; opt_allvariants=0;; 1) opt_variant1=1; opt_allvariants=0;;
2) opt_variant2=1; opt_allvariants=0;; 2) opt_variant2=1; opt_allvariants=0;;
3) opt_variant3=1; opt_allvariants=0;; 3) opt_variant3=1; opt_allvariants=0;;
3a) opt_variant3a=1; opt_allvariants=0;;
4) opt_variant4=1; opt_allvariants=0;;
*) *)
echo "$0: error: invalid parameter '$2' for --variant, expected either 1, 2 or 3" >&2; echo "$0: error: invalid parameter '$2' for --variant, expected either 1, 2, 3, 3a or 4" >&2;
exit 255 exit 255
;; ;;
esac esac
@ -567,6 +686,8 @@ pvulnstatus()
CVE-2017-5753) aka="SPECTRE VARIANT 1";; CVE-2017-5753) aka="SPECTRE VARIANT 1";;
CVE-2017-5715) aka="SPECTRE VARIANT 2";; CVE-2017-5715) aka="SPECTRE VARIANT 2";;
CVE-2017-5754) aka="MELTDOWN";; CVE-2017-5754) aka="MELTDOWN";;
CVE-2018-3640) aka="VARIANT 3A";;
CVE-2018-3639) aka="VARIANT 4";;
esac esac
case "$opt_batch_format" in case "$opt_batch_format" in
@ -732,8 +853,12 @@ mount_debugfs()
load_msr() load_msr()
{ {
if [ "$os" = Linux ]; then if [ "$os" = Linux ]; then
if ! grep -e msr /proc/modules 2>/dev/null; then
modprobe msr 2>/dev/null && insmod_msr=1 modprobe msr 2>/dev/null && insmod_msr=1
_debug "attempted to load module msr, insmod_msr=$insmod_msr" _debug "attempted to load module msr, insmod_msr=$insmod_msr"
else
_debug "msr module already loaded"
fi
else else
if ! kldstat -q -m cpuctl; then if ! kldstat -q -m cpuctl; then
kldload cpuctl 2>/dev/null && kldload_cpuctl=1 kldload cpuctl 2>/dev/null && kldload_cpuctl=1
@ -747,8 +872,12 @@ load_msr()
load_cpuid() load_cpuid()
{ {
if [ "$os" = Linux ]; then if [ "$os" = Linux ]; then
if ! grep -e cpuid /proc/modules 2>/dev/null; then
modprobe cpuid 2>/dev/null && insmod_cpuid=1 modprobe cpuid 2>/dev/null && insmod_cpuid=1
_debug "attempted to load module cpuid, insmod_cpuid=$insmod_cpuid" _debug "attempted to load module cpuid, insmod_cpuid=$insmod_cpuid"
else
_debug "cpuid module already loaded"
fi
else else
if ! kldstat -q -m cpuctl; then if ! kldstat -q -m cpuctl; then
kldload cpuctl 2>/dev/null && kldload_cpuctl=1 kldload cpuctl 2>/dev/null && kldload_cpuctl=1
@ -787,7 +916,10 @@ read_cpuid()
# Linux # Linux
# we need _leaf to be converted to decimal for dd # we need _leaf to be converted to decimal for dd
_leaf=$(( _leaf )) _leaf=$(( _leaf ))
_cpuid=$(dd if=/dev/cpu/0/cpuid bs=16 skip="$_leaf" iflag=skip_bytes count=1 2>/dev/null | od -A n -t u4) # to avoid using iflag=skip_bytes, which doesn't exist on old versions of dd, seek to the closer multiple-of-16
_ddskip=$(( _leaf / 16 ))
_odskip=$(( _leaf - _ddskip * 16 ))
_cpuid=$(dd if=/dev/cpu/0/cpuid bs=16 skip=$_ddskip count=$((_odskip + 1)) 2>/dev/null | od -j $((_odskip * 16)) -A n -t u4)
elif [ -e /dev/cpuctl0 ]; then elif [ -e /dev/cpuctl0 ]; then
# BSD # BSD
_cpuid=$(cpucontrol -i "$_leaf" /dev/cpuctl0 2>/dev/null | awk '{print $4,$5,$6,$7}') _cpuid=$(cpucontrol -i "$_leaf" /dev/cpuctl0 2>/dev/null | awk '{print $4,$5,$6,$7}')
@ -867,6 +999,9 @@ parse_cpu_details()
cpu_friendly_name="ARM" cpu_friendly_name="ARM"
[ -n "$cpu_arch" ] && cpu_friendly_name="$cpu_friendly_name v$cpu_arch" [ -n "$cpu_arch" ] && cpu_friendly_name="$cpu_friendly_name v$cpu_arch"
[ -n "$cpu_part" ] && cpu_friendly_name="$cpu_friendly_name model $cpu_part" [ -n "$cpu_part" ] && cpu_friendly_name="$cpu_friendly_name model $cpu_part"
elif grep -qi 'CPU implementer[[:space:]]*:[[:space:]]*0x43' "$procfs/cpuinfo"; then
cpu_vendor='CAVIUM'
fi fi
cpu_family=$( grep '^cpu family' "$procfs/cpuinfo" | awk '{print $4}' | grep -E '^[0-9]+$' | head -1) cpu_family=$( grep '^cpu family' "$procfs/cpuinfo" | awk '{print $4}' | grep -E '^[0-9]+$' | head -1)
@ -880,6 +1015,7 @@ parse_cpu_details()
# get raw cpuid, it's always useful (referenced in the Intel doc for firmware updates for example) # get raw cpuid, it's always useful (referenced in the Intel doc for firmware updates for example)
if read_cpuid 0x1 $EAX 0 0xFFFFFFFF; then if read_cpuid 0x1 $EAX 0 0xFFFFFFFF; then
cpuid="$read_cpuid_value" cpuid="$read_cpuid_value"
#cpuid_hex=$(printf "%X" "$cpuid")
fi fi
# under BSD, linprocfs often doesn't export ucode information, so fetch it ourselves the good old way # under BSD, linprocfs often doesn't export ucode information, so fetch it ourselves the good old way
@ -900,7 +1036,7 @@ parse_cpu_details()
fi fi
echo "$cpu_ucode" | grep -q ^0x && cpu_ucode_decimal=$(( cpu_ucode )) echo "$cpu_ucode" | grep -q ^0x && cpu_ucode_decimal=$(( cpu_ucode ))
ucode_found="model $cpu_model stepping $cpu_stepping ucode $cpu_ucode cpuid "$(printf "0x%x" "$cpuid") ucode_found=$(printf "model 0x%x family 0x%x stepping 0x%x ucode 0x%x cpuid 0x%x" "$cpu_model" "$cpu_family" "$cpu_stepping" "$cpu_ucode" "$cpuid")
# also define those that we will need in other funcs # also define those that we will need in other funcs
# taken from ttps://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/intel-family.h # taken from ttps://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/include/asm/intel-family.h
@ -1189,6 +1325,8 @@ if [ "$opt_live" = 1 ]; then
[ -e "/boot/vmlinuz" ] && opt_kernel="/boot/vmlinuz" [ -e "/boot/vmlinuz" ] && opt_kernel="/boot/vmlinuz"
# Arch: # Arch:
[ -e "/boot/vmlinuz-linux" ] && opt_kernel="/boot/vmlinuz-linux" [ -e "/boot/vmlinuz-linux" ] && opt_kernel="/boot/vmlinuz-linux"
# Arch aarch64:
[ -e "/boot/Image" ] && opt_kernel="/boot/Image"
# Linux-Libre: # Linux-Libre:
[ -e "/boot/vmlinuz-linux-libre" ] && opt_kernel="/boot/vmlinuz-linux-libre" [ -e "/boot/vmlinuz-linux-libre" ] && opt_kernel="/boot/vmlinuz-linux-libre"
# pine64 # pine64
@ -1403,7 +1541,6 @@ read_msr()
return 0 return 0
} }
check_cpu() check_cpu()
{ {
_info "\033[1;34mHardware check\033[0m" _info "\033[1;34mHardware check\033[0m"
@ -1619,6 +1756,46 @@ check_cpu()
fi fi
fi fi
# variant 4
if is_intel; then
_info " * Speculative Store Bypass Disable (SSBD)"
_info_nol " * CPU indicates SSBD capability: "
read_cpuid 0x7 $EDX 31 1 1; ret=$?
if [ $ret -eq 0 ]; then
cpuid_ssbd='Intel SSBD'
fi
elif is_amd; then
_info " * Speculative Store Bypass Disable (SSBD)"
_info_nol " * CPU indicates SSBD capability: "
read_cpuid 0x80000008 $EBX 24 1 1; ret24=$?
read_cpuid 0x80000008 $EBX 25 1 1; ret25=$?
if [ $ret24 -eq 0 ]; then
cpuid_ssbd='AMD SSBD in SPEC_CTRL'
#cpuid_ssbd_spec_ctrl=1
elif [ $ret25 -eq 0 ]; then
cpuid_ssbd='AMD SSBD in VIRT_SPEC_CTRL'
#cpuid_ssbd_virt_spec_ctrl=1
elif [ "$cpu_family" -ge 21 ] && [ "$cpu_family" -le 23 ]; then
cpuid_ssbd='AMD non-architectural MSR'
fi
fi
if [ -n "$cpuid_ssbd" ]; then
pstatus green YES "$cpuid_ssbd"
elif [ "$ret24" = 2 ] && [ "$ret25" = 2 ]; then
pstatus yellow UNKNOWN "is cpuid kernel module available?"
else
pstatus yellow NO
fi
if is_amd; then
# similar to SSB_NO for intel
read_cpuid 0x80000008 $EBX 26 1 1; ret=$?
if [ $ret -eq 0 ]; then
amd_ssb_no=1
fi
fi
if is_intel; then if is_intel; then
_info " * Enhanced IBRS (IBRS_ALL)" _info " * Enhanced IBRS (IBRS_ALL)"
_info_nol " * CPU indicates ARCH_CAPABILITIES MSR availability: " _info_nol " * CPU indicates ARCH_CAPABILITIES MSR availability: "
@ -1638,11 +1815,13 @@ check_cpu()
_info_nol " * ARCH_CAPABILITIES MSR advertises IBRS_ALL capability: " _info_nol " * ARCH_CAPABILITIES MSR advertises IBRS_ALL capability: "
capabilities_rdcl_no=-1 capabilities_rdcl_no=-1
capabilities_ibrs_all=-1 capabilities_ibrs_all=-1
capabilities_ssb_no=-1
if [ "$cpuid_arch_capabilities" = -1 ]; then if [ "$cpuid_arch_capabilities" = -1 ]; then
pstatus yellow UNKNOWN pstatus yellow UNKNOWN
elif [ "$cpuid_arch_capabilities" != 1 ]; then elif [ "$cpuid_arch_capabilities" != 1 ]; then
capabilities_rdcl_no=0 capabilities_rdcl_no=0
capabilities_ibrs_all=0 capabilities_ibrs_all=0
capabilities_ssb_no=0
pstatus yellow NO pstatus yellow NO
elif [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then elif [ ! -e /dev/cpu/0/msr ] && [ ! -e /dev/cpuctl0 ]; then
spec_ctrl_msr=-1 spec_ctrl_msr=-1
@ -1672,15 +1851,17 @@ check_cpu()
capabilities=$val_cap_msr capabilities=$val_cap_msr
capabilities_rdcl_no=0 capabilities_rdcl_no=0
capabilities_ibrs_all=0 capabilities_ibrs_all=0
capabilities_ssb_no=0
if [ $val -eq 0 ]; then if [ $val -eq 0 ]; then
_debug "capabilities MSR lower byte is $capabilities (decimal)" _debug "capabilities MSR lower byte is $capabilities (decimal)"
[ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1 [ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1
[ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1 [ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all" [ $(( capabilities & 16 )) -eq 16 ] && capabilities_ssb_no=1
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all ssb_no=$capabilities_ssb_no"
if [ "$capabilities_ibrs_all" = 1 ]; then if [ "$capabilities_ibrs_all" = 1 ]; then
if [ $cpu_mismatch -eq 0 ]; then if [ $cpu_mismatch -eq 0 ]; then
pstatus green YES pstatus green YES
else: else
pstatus green YES "But not in all CPUs" pstatus green YES "But not in all CPUs"
fi fi
else else
@ -1703,6 +1884,15 @@ check_cpu()
fi fi
fi fi
_info_nol " * CPU explicitly indicates not being vulnerable to Variant 4 (SSB_NO): "
if [ "$capabilities_ssb_no" = -1 ]; then
pstatus yellow UNKNOWN
elif [ "$capabilities_ssb_no" = 1 ] || [ "$amd_ssb_no" = 1 ]; then
pstatus green YES
else
pstatus yellow NO
fi
_info_nol " * CPU microcode is known to cause stability problems: " _info_nol " * CPU microcode is known to cause stability problems: "
if is_ucode_blacklisted; then if is_ucode_blacklisted; then
pstatus red YES "$ucode_found" pstatus red YES "$ucode_found"
@ -1719,8 +1909,8 @@ check_cpu()
check_cpu_vulnerabilities() check_cpu_vulnerabilities()
{ {
_info "* CPU vulnerability to the three speculative execution attack variants" _info "* CPU vulnerability to the speculative execution attack variants"
for v in 1 2 3; do for v in 1 2 3 3a 4; do
_info_nol " * Vulnerable to Variant $v: " _info_nol " * Vulnerable to Variant $v: "
if is_cpu_vulnerable $v; then if is_cpu_vulnerable $v; then
pstatus yellow YES pstatus yellow YES
@ -1787,7 +1977,7 @@ check_variant1_linux()
fi fi
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
# no /sys interface (or offline mode), fallback to our own ways # no /sys interface (or offline mode), fallback to our own ways
_info_nol "* Kernel has array_index_mask_nospec (x86): " _info_nol "* Kernel has array_index_mask_nospec: "
# vanilla: look for the Linus' mask aka array_index_mask_nospec() # vanilla: look for the Linus' mask aka array_index_mask_nospec()
# that is inlined at least in raw_copy_from_user (__get_user_X symbols) # that is inlined at least in raw_copy_from_user (__get_user_X symbols)
#mov PER_CPU_VAR(current_task), %_ASM_DX #mov PER_CPU_VAR(current_task), %_ASM_DX
@ -1799,6 +1989,22 @@ check_variant1_linux()
#ASM_STAC #ASM_STAC
# x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0) # x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0)
# x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0) # x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0)
#
# arm32
##ifdef CONFIG_THUMB2_KERNEL
##define CSDB ".inst.w 0xf3af8014"
##else
##define CSDB ".inst 0xe320f014" e320f014
##endif
#asm volatile(
# "cmp %1, %2\n" e1500003
#" sbc %0, %1, %1\n" e0c03000
#CSDB
#: "=r" (mask)
#: "r" (idx), "Ir" (sz)
#: "cc");
#
# http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855
if [ -n "$kernel_err" ]; then if [ -n "$kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($kernel_err)" pstatus yellow UNKNOWN "couldn't check ($kernel_err)"
elif ! which perl >/dev/null 2>&1; then elif ! which perl >/dev/null 2>&1; then
@ -1806,18 +2012,24 @@ check_variant1_linux()
else else
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$kernel"; ret=$? perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$kernel"; ret=$?
if [ $ret -gt 0 ]; then if [ $ret -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of 64 bits array_index_mask_nospec()" pstatus green YES "$ret occurrence(s) found of x86 64 bits array_index_mask_nospec()"
v1_mask_nospec="64 bits array_index_mask_nospec" v1_mask_nospec="x86 64 bits array_index_mask_nospec"
else else
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$kernel"; ret=$? perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$kernel"; ret=$?
if [ $ret -gt 0 ]; then if [ $ret -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of 32 bits array_index_mask_nospec()" pstatus green YES "$ret occurrence(s) found of x86 32 bits array_index_mask_nospec()"
v1_mask_nospec="32 bits array_index_mask_nospec" v1_mask_nospec="x86 32 bits array_index_mask_nospec"
else
ret=$("${opt_arch_prefix}objdump" -d "$kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp)
if [ "$ret" -gt 0 ]; then
pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
v1_mask_nospec="arm 32 bits array_index_mask_nospec"
else else
pstatus yellow NO pstatus yellow NO
fi fi
fi fi
fi fi
fi
_info_nol "* Kernel has the Red Hat/Ubuntu patch: " _info_nol "* Kernel has the Red Hat/Ubuntu patch: "
check_redhat_canonical_spectre check_redhat_canonical_spectre
@ -1833,7 +2045,7 @@ check_variant1_linux()
pstatus yellow NO pstatus yellow NO
fi fi
_info_nol "* Kernel has mask_nospec64 (arm): " _info_nol "* Kernel has mask_nospec64 (arm64): "
#.macro mask_nospec64, idx, limit, tmp #.macro mask_nospec64, idx, limit, tmp
#sub \tmp, \idx, \limit #sub \tmp, \idx, \limit
#bic \tmp, \tmp, \idx #bic \tmp, \tmp, \idx
@ -1860,13 +2072,12 @@ check_variant1_linux()
"${opt_arch_prefix}objdump" -d "$kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\ssub\s+(x\d+)/ && $r[1]=~/\sbic\s+$1,\s+$1,/ && $r[2]=~/\sand\s/ && exit(9); shift @r if @r>3'; ret=$? "${opt_arch_prefix}objdump" -d "$kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\ssub\s+(x\d+)/ && $r[1]=~/\sbic\s+$1,\s+$1,/ && $r[2]=~/\sand\s/ && exit(9); shift @r if @r>3'; ret=$?
if [ "$ret" -eq 9 ]; then if [ "$ret" -eq 9 ]; then
pstatus green YES "mask_nospec64 macro is present and used" pstatus green YES "mask_nospec64 macro is present and used"
v1_mask_nospec="arm mask_nospec64" v1_mask_nospec="arm64 mask_nospec64"
else else
pstatus yellow NO pstatus yellow NO
fi fi
fi fi
if [ "$opt_verbose" -ge 2 ] || ( [ -z "$v1_mask_nospec" ] && [ "$redhat_canonical_spectre" != 1 ] && [ "$redhat_canonical_spectre" != 2 ] ); then if [ "$opt_verbose" -ge 2 ] || ( [ -z "$v1_mask_nospec" ] && [ "$redhat_canonical_spectre" != 1 ] && [ "$redhat_canonical_spectre" != 2 ] ); then
# this is a slow heuristic and we don't need it if we already know the kernel is patched # this is a slow heuristic and we don't need it if we already know the kernel is patched
# but still show it in verbose mode # but still show it in verbose mode
@ -2029,7 +2240,7 @@ check_variant2_linux()
fi fi
if [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then if [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then
# when IBPB is enabled on 4.15+, we can see it in sysfs # when IBPB is enabled on 4.15+, we can see it in sysfs
if grep -q ', IBPB' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then if grep -q 'IBPB' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then
_debug "ibpb: found enabled in sysfs" _debug "ibpb: found enabled in sysfs"
[ -z "$ibpb_supported" ] && ibpb_supported='IBPB found enabled in sysfs' [ -z "$ibpb_supported" ] && ibpb_supported='IBPB found enabled in sysfs'
[ -z "$ibpb_enabled" ] && ibpb_enabled=1 [ -z "$ibpb_enabled" ] && ibpb_enabled=1
@ -2041,7 +2252,7 @@ check_variant2_linux()
ibrs_fw_enabled=1 ibrs_fw_enabled=1
fi fi
# when IBRS is enabled on 4.15+, we can see it in sysfs # when IBRS is enabled on 4.15+, we can see it in sysfs
if grep -q 'Indirect Branch Restricted Speculation' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then if grep -q -e 'IBRS' -e 'Indirect Branch Restricted Speculation' "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then
_debug "ibrs: found IBRS in sysfs" _debug "ibrs: found IBRS in sysfs"
[ -z "$ibrs_supported" ] && ibrs_supported='found IBRS in sysfs' [ -z "$ibrs_supported" ] && ibrs_supported='found IBRS in sysfs'
[ -z "$ibrs_enabled" ] && ibrs_enabled=3 [ -z "$ibrs_enabled" ] && ibrs_enabled=3
@ -2129,7 +2340,10 @@ check_variant2_linux()
1) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel space and firmware code"; else pstatus green YES "for kernel space"; fi;; 1) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel space and firmware code"; else pstatus green YES "for kernel space"; fi;;
2) if [ "$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;; 2) if [ "$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 [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel and firmware code"; else pstatus green YES; fi;; 3) if [ "$ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel and firmware code"; else pstatus green YES; fi;;
*) pstatus yellow UNKNOWN;; *) if [ "$cpuid_ibrs" != 'SPEC_CTRL' ] && [ "$cpuid_ibrs" != 'IBRS_SUPPORT' ] && [ "$cpuid_spec_ctrl" != -1 ];
then pstatus yellow NO; _debug "ibrs: known cpu not supporting SPEC-CTRL or IBRS";
else
pstatus yellow UNKNOWN; fi;;
esac esac
fi fi
else else
@ -2381,7 +2595,7 @@ check_variant2_linux()
# if we are in live mode, we can check for a lot more stuff and explain further # if we are in live mode, we can check for a lot more stuff and explain further
if [ "$opt_live" = 1 ] && [ "$vulnstatus" != "OK" ]; then 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 an 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." _explain_hypervisor="An updated CPU microcode will have IBRS/IBPB capabilities indicated in the Hardware Check section above. If you're running under an 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) # IBPB (amd & intel)
if ( [ -z "$ibpb_enabled" ] || [ "$ibpb_enabled" = 0 ] ) && ( is_intel || is_amd ); then if ( [ -z "$ibpb_enabled" ] || [ "$ibpb_enabled" = 0 ] ) && ( is_intel || is_amd ); then
if [ -z "$cpuid_ibpb" ]; then if [ -z "$cpuid_ibpb" ]; then
@ -2806,6 +3020,102 @@ check_variant3_bsd()
fi fi
} }
check_variant3a()
{
_info "\033[1;34mCVE-2018-3640 [rogue system register read] aka 'Variant 3a'\033[0m"
status=UNK
sys_interface_available=0
msg=''
_info_nol "* CPU microcode mitigates the vulnerability: "
if [ -n "$cpuid_ssbd" ]; then
# microcodes that ship with SSBD are known to also fix variant3a
# there is no specific cpuid bit as far as we know
pstatus green YES
else
pstatus yellow NO
fi
cve='CVE-2018-3640'
if ! is_cpu_vulnerable 3a; then
# override status & msg in case CPU is not vulnerable after all
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
elif [ -n "$cpuid_ssbd" ]; then
pvulnstatus $cve OK "your CPU microcode mitigates the vulnerability"
else
pvulnstatus $cve VULN "an up-to-date CPU microcode is needed to mitigate this vulnerability"
explain "The microcode of your CPU needs to be upgraded to mitigate this vulnerability. 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). The microcode update is enough, there is no additional OS, kernel or software change needed."
fi
}
check_variant4()
{
_info "\033[1;34mCVE-2018-3639 [speculative store bypass] aka 'Variant 4'\033[0m"
status=UNK
sys_interface_available=0
msg=''
if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spec_store_bypass"; then
# this kernel has the /sys interface, trust it over everything
sys_interface_available=1
fi
if [ "$opt_sysfs_only" != 1 ]; then
_info_nol "* Kernel supports speculation store bypass: "
if [ "$opt_live" = 1 ]; then
if grep -Eq 'Speculation.?Store.?Bypass:' /proc/self/status 2>/dev/null; then
kernel_ssb='found in /proc/self/status'
_debug "found Speculation.Store.Bypass: in /proc/self/status"
fi
fi
if [ -z "$kernel_ssb" ] && [ -n "$kernel" ]; then
kernel_ssb=$("${opt_arch_prefix}strings" "$kernel" | grep spec_store_bypass | head -n1);
[ -n "$kernel_ssb" ] && _debug "found $kernel_ssb in kernel"
fi
if [ -z "$kernel_ssb" ] && [ -n "$opt_map" ]; then
kernel_ssb=$(grep spec_store_bypass "$opt_map" | head -n1)
[ -n "$kernel_ssb" ] && _debug "found $kernel_ssb in System.map"
fi
if [ -n "$kernel_ssb" ]; then
pstatus green YES "$kernel_ssb"
else
pstatus yellow NO
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
cve='CVE-2018-3639'
if ! is_cpu_vulnerable 4; then
# override status & msg in case CPU is not vulnerable after all
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
elif [ -z "$msg" ] || [ "$msg" = "Vulnerable" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test
if [ -n "$cpuid_ssbd" ]; then
if [ -n "$kernel_ssb" ]; then
pvulnstatus $cve OK "your system provides the necessary tools for software mitigation"
else
pvulnstatus $cve VULN "your kernel needs to be updated"
explain "You have a recent-enough CPU microcode but your kernel is too old to use the new features exported by your CPU's microcode. If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel from recent-enough sources."
fi
else
if [ -n "$kernel_ssb" ]; then
pvulnstatus $cve VULN "Your CPU doesn't support SSBD"
explain "Your kernel is recent enough to use the CPU microcode features for mitigation, but your CPU microcode doesn't actually provide the necessary features for the kernel to use. The microcode of your CPU hence needs to be upgraded. 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)."
else
pvulnstatus $cve VULN "Neither your CPU nor your kernel support SSBD"
explain "Both your CPU microcode and your kernel are lacking support for mitigation. If you're using a distro kernel, upgrade your distro to get the latest kernel available. Otherwise, recompile the kernel from recent-enough sources. The microcode of your CPU also needs to be upgraded. 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)."
fi
fi
else
pvulnstatus $cve "$status" "$msg"
fi
}
if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then if [ "$opt_no_hw" = 0 ] && [ -z "$opt_arch_prefix" ]; then
check_cpu check_cpu
check_cpu_vulnerabilities check_cpu_vulnerabilities
@ -2825,10 +3135,22 @@ if [ "$opt_variant3" = 1 ] || [ "$opt_allvariants" = 1 ]; then
check_variant3 check_variant3
_info _info
fi fi
if [ "$opt_variant3a" = 1 ] || [ "$opt_allvariants" = 1 ]; then
check_variant3a
_info
fi
if [ "$opt_variant4" = 1 ] || [ "$opt_allvariants" = 1 ]; then
check_variant4
_info
fi
_vars=$(set | grep -Ev '^[A-Z_[:space:]]' | sort | tr "\n" '|') _vars=$(set | grep -Ev '^[A-Z_[:space:]]' | sort | tr "\n" '|')
_debug "variables at end of script: $_vars" _debug "variables at end of script: $_vars"
if [ "$opt_explain" = 0 ]; then
_info "Need more detailed information about mitigation options? Use --explain"
fi
_info "A false sense of security is worse than no security at all, see --disclaimer" _info "A false sense of security is worse than no security at all, see --disclaimer"
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "nrpe" ]; then if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "nrpe" ]; then
@ -2846,7 +3168,7 @@ fi
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "prometheus" ]; then
echo "# TYPE specex_vuln_status untyped" echo "# TYPE specex_vuln_status untyped"
echo "# HELP specex_vuln_status Exposure of system to speculative execution vulnerabilities" echo "# HELP specex_vuln_status Exposure of system to speculative execution vulnerabilities"
echo "$prometheus_output" printf "%b\n" "$prometheus_output"
fi fi
# exit with the proper exit code # exit with the proper exit code