mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2025-07-15 15:21:23 +02:00
Compare commits
49 Commits
Author | SHA1 | Date | |
---|---|---|---|
360be7b35f | |||
5f59257826 | |||
92d59cbdc1 | |||
4747b932e7 | |||
860023a806 | |||
ab67a9221d | |||
f4592bf3a8 | |||
be15e47671 | |||
d3481d9524 | |||
21af561148 | |||
cb740397f3 | |||
84195689af | |||
b637681fa8 | |||
9316c30577 | |||
f9dd9d8cb9 | |||
0f0d103a89 | |||
b262c40541 | |||
cc2910fbbc | |||
30c4a1f6d2 | |||
cf06636a3f | |||
60077c8d12 | |||
c181978d7c | |||
9a6406a9a2 | |||
5962d20ba7 | |||
17a3488505 | |||
e54e8b3e84 | |||
39c778e3ac | |||
2cde6e4649 | |||
f4d51e7e53 | |||
85d46b2799 | |||
61e02abd0c | |||
114756fab7 | |||
ea75969eb7 | |||
ca391cbfc9 | |||
68af5c5f92 | |||
19be8f79eb | |||
f75cc0bb6f | |||
f33d65ff71 | |||
725eaa8bf5 | |||
c6ee0358d1 | |||
22d0b203da | |||
3062a8416a | |||
6a4318addf | |||
c19986188f | |||
7e4899bcb8 | |||
5cc77741af | |||
1c0f6d9580 | |||
4acd0f647a | |||
fb52dbe7bf |
7
Dockerfile
Normal file
7
Dockerfile
Normal 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"]
|
28
README.md
28
README.md
@ -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).
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
#
|
#
|
||||||
# Stephane Lesimple
|
# Stephane Lesimple
|
||||||
#
|
#
|
||||||
VERSION='0.37'
|
VERSION='0.39'
|
||||||
|
|
||||||
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
|
||||||
@ -148,12 +150,12 @@ if which printf >/dev/null 2>&1; then
|
|||||||
elif which echo >/dev/null 2>&1; then
|
elif which echo >/dev/null 2>&1; then
|
||||||
echo_cmd=$(which echo)
|
echo_cmd=$(which echo)
|
||||||
else
|
else
|
||||||
# which command is broken?
|
# maybe the `which` command is broken?
|
||||||
[ -x /bin/echo ] && echo_cmd=/bin/echo
|
[ -x /bin/echo ] && echo_cmd=/bin/echo
|
||||||
# for Android
|
# for Android
|
||||||
[ -x /system/bin/echo ] && echo_cmd=/system/bin/echo
|
[ -x /system/bin/echo ] && echo_cmd=/system/bin/echo
|
||||||
fi
|
fi
|
||||||
# still empty ? fallback to builtin
|
# still empty? fallback to builtin
|
||||||
[ -z "$echo_cmd" ] && echo_cmd=echo
|
[ -z "$echo_cmd" ] && echo_cmd=echo
|
||||||
__echo()
|
__echo()
|
||||||
{
|
{
|
||||||
@ -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
|
||||||
@ -243,18 +245,20 @@ is_cpu_vulnerable_cached=0
|
|||||||
_is_cpu_vulnerable_cached()
|
_is_cpu_vulnerable_cached()
|
||||||
{
|
{
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
[ "$1" = 1 ] && return $variant1
|
{
|
||||||
# shellcheck disable=SC2086
|
[ "$1" = 1 ] && return $variant1
|
||||||
[ "$1" = 2 ] && return $variant2
|
[ "$1" = 2 ] && return $variant2
|
||||||
# shellcheck disable=SC2086
|
[ "$1" = 3 ] && return $variant3
|
||||||
[ "$1" = 3 ] && return $variant3
|
[ "$1" = 3a ] && return $variant3a
|
||||||
|
[ "$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 +271,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 +297,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 +342,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
|
[ "$variant3a" = "immune" ] && variant3a=1 || variant3a=0
|
||||||
_debug "is_cpu_vulnerable: final results are <$variant1> <$variant2> <$variant3>"
|
[ "$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 +456,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 +582,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 +607,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 +684,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 +851,12 @@ mount_debugfs()
|
|||||||
load_msr()
|
load_msr()
|
||||||
{
|
{
|
||||||
if [ "$os" = Linux ]; then
|
if [ "$os" = Linux ]; then
|
||||||
modprobe msr 2>/dev/null && insmod_msr=1
|
if ! grep -e msr /proc/modules 2>/dev/null; then
|
||||||
_debug "attempted to load module msr, insmod_msr=$insmod_msr"
|
modprobe msr 2>/dev/null && insmod_msr=1
|
||||||
|
_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 +870,12 @@ load_msr()
|
|||||||
load_cpuid()
|
load_cpuid()
|
||||||
{
|
{
|
||||||
if [ "$os" = Linux ]; then
|
if [ "$os" = Linux ]; then
|
||||||
modprobe cpuid 2>/dev/null && insmod_cpuid=1
|
if ! grep -e cpuid /proc/modules 2>/dev/null; then
|
||||||
_debug "attempted to load module cpuid, insmod_cpuid=$insmod_cpuid"
|
modprobe cpuid 2>/dev/null && insmod_cpuid=1
|
||||||
|
_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
|
||||||
@ -760,9 +887,7 @@ load_cpuid()
|
|||||||
}
|
}
|
||||||
|
|
||||||
# shellcheck disable=SC2034
|
# shellcheck disable=SC2034
|
||||||
{
|
|
||||||
EAX=1; EBX=2; ECX=3; EDX=4;
|
EAX=1; EBX=2; ECX=3; EDX=4;
|
||||||
}
|
|
||||||
read_cpuid()
|
read_cpuid()
|
||||||
{
|
{
|
||||||
# leaf is the value of the eax register when calling the cpuid instruction:
|
# leaf is the value of the eax register when calling the cpuid instruction:
|
||||||
@ -787,7 +912,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 +995,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 +1011,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 +1032,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
|
||||||
@ -1074,6 +1206,17 @@ is_skylake_cpu()
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_vulnerable_to_empty_rsb()
|
||||||
|
{
|
||||||
|
if is_intel && [ -z "$capabilities_rsba" ]; then
|
||||||
|
_warn "is_vulnerable_to_empty_rsb() called before ARCH CAPABILITIES MSR was read"
|
||||||
|
fi
|
||||||
|
if is_skylake_cpu || [ "$capabilities_rsba" = 1 ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
is_zen_cpu()
|
is_zen_cpu()
|
||||||
{
|
{
|
||||||
# is this CPU from the AMD ZEN family ? (ryzen, epyc, ...)
|
# is this CPU from the AMD ZEN family ? (ryzen, epyc, ...)
|
||||||
@ -1111,6 +1254,8 @@ if [ "$opt_hw_only" = 1 ]; then
|
|||||||
opt_variant1=0
|
opt_variant1=0
|
||||||
opt_variant2=0
|
opt_variant2=0
|
||||||
opt_variant3=0
|
opt_variant3=0
|
||||||
|
opt_variant3a=0
|
||||||
|
opt_variant4=0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -1173,6 +1318,9 @@ if [ "$opt_live" = 1 ]; then
|
|||||||
if [ -r /proc/cmdline ] && grep -q 'BOOT_IMAGE=' /proc/cmdline; then
|
if [ -r /proc/cmdline ] && grep -q 'BOOT_IMAGE=' /proc/cmdline; then
|
||||||
opt_kernel=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
|
opt_kernel=$(grep -Eo 'BOOT_IMAGE=[^ ]+' /proc/cmdline | cut -d= -f2)
|
||||||
_debug "found opt_kernel=$opt_kernel in /proc/cmdline"
|
_debug "found opt_kernel=$opt_kernel in /proc/cmdline"
|
||||||
|
# if the boot partition is within a btrfs subvolume, strip the subvolume name
|
||||||
|
# if /boot is a separate subvolume, the remainder of the code in this section should handle it
|
||||||
|
if echo "$opt_kernel" | grep -q "^/@"; then opt_kernel=$(echo "$opt_kernel" | sed "s:/@[^/]*::"); fi
|
||||||
# if we have a dedicated /boot partition, our bootloader might have just called it /
|
# if we have a dedicated /boot partition, our bootloader might have just called it /
|
||||||
# so try to prepend /boot and see if we find anything
|
# so try to prepend /boot and see if we find anything
|
||||||
[ -e "/boot/$opt_kernel" ] && opt_kernel="/boot/$opt_kernel"
|
[ -e "/boot/$opt_kernel" ] && opt_kernel="/boot/$opt_kernel"
|
||||||
@ -1189,6 +1337,10 @@ 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"
|
||||||
|
# Arch armv5/armv7:
|
||||||
|
[ -e "/boot/zImage" ] && opt_kernel="/boot/zImage"
|
||||||
# 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
|
||||||
@ -1356,18 +1508,39 @@ number_of_cpus()
|
|||||||
# $2 - cpu index
|
# $2 - cpu index
|
||||||
write_msr()
|
write_msr()
|
||||||
{
|
{
|
||||||
|
# _msr must be in hex, in the form 0x1234:
|
||||||
|
_msr="$1"
|
||||||
|
# cpu index, starting from 0:
|
||||||
|
_cpu="$2"
|
||||||
if [ "$os" != Linux ]; then
|
if [ "$os" != Linux ]; then
|
||||||
cpucontrol -m "$1=0" "/dev/cpuctl$2" >/dev/null 2>&1; ret=$?
|
cpucontrol -m "$_msr=0" "/dev/cpuctl$_cpu" >/dev/null 2>&1; ret=$?
|
||||||
else
|
else
|
||||||
|
# for Linux
|
||||||
# convert to decimal
|
# convert to decimal
|
||||||
_msrindex=$(( $1 ))
|
_msr=$(( _msr ))
|
||||||
if [ ! -w /dev/cpu/"$2"/msr ]; then
|
if [ ! -w /dev/cpu/"$_cpu"/msr ]; then
|
||||||
ret=200 # permission error
|
ret=200 # permission error
|
||||||
|
# if wrmsr is available, use it
|
||||||
|
elif which wrmsr >/dev/null 2>&1 && [ "$SMC_NO_WRMSR" != 1 ]; then
|
||||||
|
_debug "write_msr: using wrmsr"
|
||||||
|
wrmsr $_msr 0 2>/dev/null; ret=$?
|
||||||
|
# or if we have perl, use it, any 5.x version will work
|
||||||
|
elif which perl >/dev/null 2>&1 && [ "$SMC_NO_PERL" != 1 ]; then
|
||||||
|
_debug "write_msr: using perl"
|
||||||
|
ret=1
|
||||||
|
perl -e "open(M,'>','/dev/cpu/$_cpu/msr') and seek(M,$_msr,0) and exit(syswrite(M,pack('H16',0)))"; [ $? -eq 8 ] && ret=0
|
||||||
|
# fallback to dd if it supports seek_bytes
|
||||||
|
elif dd if=/dev/null of=/dev/null bs=8 count=1 seek="$_msr" oflag=seek_bytes 2>/dev/null; then
|
||||||
|
_debug "write_msr: using dd"
|
||||||
|
dd if=/dev/zero of=/dev/cpu/"$_cpu"/msr bs=8 count=1 seek="$_msr" oflag=seek_bytes 2>/dev/null; ret=$?
|
||||||
else
|
else
|
||||||
dd if=/dev/zero of=/dev/cpu/"$2"/msr bs=8 count=1 seek="$_msrindex" oflag=seek_bytes 2>/dev/null; ret=$?
|
_debug "write_msr: got no wrmsr, perl or recent enough dd!"
|
||||||
|
return 201 # missing tool error
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
_debug "write_msr: for cpu $2 on msr $1 ($_msrindex), ret=$ret"
|
# normalize ret
|
||||||
|
[ "$ret" != 0 ] && ret=1
|
||||||
|
_debug "write_msr: for cpu $_cpu on msr $_msr, ret=$ret"
|
||||||
return $ret
|
return $ret
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1388,12 +1561,27 @@ read_msr()
|
|||||||
_msr_l="$(( _msr_l >> 24 & 0xFF )) $(( _msr_l >> 16 & 0xFF )) $(( _msr_l >> 8 & 0xFF )) $(( _msr_l & 0xFF ))"
|
_msr_l="$(( _msr_l >> 24 & 0xFF )) $(( _msr_l >> 16 & 0xFF )) $(( _msr_l >> 8 & 0xFF )) $(( _msr_l & 0xFF ))"
|
||||||
read_msr_value="$_msr_h $_msr_l"
|
read_msr_value="$_msr_h $_msr_l"
|
||||||
else
|
else
|
||||||
|
# for Linux
|
||||||
# convert to decimal
|
# convert to decimal
|
||||||
_msr=$(( _msr ))
|
_msr=$(( _msr ))
|
||||||
if [ ! -r /dev/cpu/"$_cpu"/msr ]; then
|
if [ ! -r /dev/cpu/"$_cpu"/msr ]; then
|
||||||
return 200 # permission error
|
return 200 # permission error
|
||||||
|
# if rdmsr is available, use it
|
||||||
|
elif which rdmsr >/dev/null 2>&1 && [ "$SMC_NO_RDMSR" != 1 ]; then
|
||||||
|
_debug "read_msr: using rdmsr"
|
||||||
|
read_msr_value=$(rdmsr -r $_msr 2>/dev/null | od -t u8 -A n)
|
||||||
|
# or if we have perl, use it, any 5.x version will work
|
||||||
|
elif which perl >/dev/null 2>&1 && [ "$SMC_NO_PERL" != 1 ]; then
|
||||||
|
_debug "read_msr: using perl"
|
||||||
|
read_msr_value=$(perl -e "open(M,'<','/dev/cpu/$_cpu/msr') and seek(M,$_msr,0) and read(M,\$_,8) and print" | od -t u8 -A n)
|
||||||
|
# fallback to dd if it supports skip_bytes
|
||||||
|
elif dd if=/dev/null of=/dev/null bs=8 count=1 skip="$_msr" iflag=skip_bytes 2>/dev/null; then
|
||||||
|
_debug "read_msr: using dd"
|
||||||
|
read_msr_value=$(dd if=/dev/cpu/"$_cpu"/msr bs=8 count=1 skip="$_msr" iflag=skip_bytes 2>/dev/null | od -t u8 -A n)
|
||||||
|
else
|
||||||
|
_debug "read_msr: got no rdmsr, perl or recent enough dd!"
|
||||||
|
return 201 # missing tool error
|
||||||
fi
|
fi
|
||||||
read_msr_value=$(dd if=/dev/cpu/"$_cpu"/msr bs=8 count=1 skip="$_msr" iflag=skip_bytes 2>/dev/null | od -t u1 -A n)
|
|
||||||
if [ -z "$read_msr_value" ]; then
|
if [ -z "$read_msr_value" ]; then
|
||||||
# MSR doesn't exist, don't check for $? because some versions of dd still return 0!
|
# MSR doesn't exist, don't check for $? because some versions of dd still return 0!
|
||||||
return 1
|
return 1
|
||||||
@ -1403,7 +1591,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"
|
||||||
@ -1427,9 +1614,7 @@ check_cpu()
|
|||||||
pstatus yellow UNKNOWN "is msr kernel module available?"
|
pstatus yellow UNKNOWN "is msr kernel module available?"
|
||||||
else
|
else
|
||||||
# the new MSR 'SPEC_CTRL' is at offset 0x48
|
# the new MSR 'SPEC_CTRL' is at offset 0x48
|
||||||
# here we use dd, it's the same as using 'rdmsr 0x48' but without needing the rdmsr tool
|
# we check if we have it for all cpus
|
||||||
# if we get a read error, the MSR is not there. bs has to be 8 for msr
|
|
||||||
# skip=9 because 8*9=72=0x48
|
|
||||||
val=0
|
val=0
|
||||||
cpu_mismatch=0
|
cpu_mismatch=0
|
||||||
for i in $(seq 0 "$idx_max_cpu")
|
for i in $(seq 0 "$idx_max_cpu")
|
||||||
@ -1456,6 +1641,9 @@ check_cpu()
|
|||||||
elif [ $val -eq 200 ]; then
|
elif [ $val -eq 200 ]; then
|
||||||
pstatus yellow UNKNOWN "is msr kernel module available?"
|
pstatus yellow UNKNOWN "is msr kernel module available?"
|
||||||
spec_ctrl_msr=-1
|
spec_ctrl_msr=-1
|
||||||
|
elif [ $val -eq 201 ]; then
|
||||||
|
pstatus yellow UNKNOWN "missing tool, install either msr-tools or perl"
|
||||||
|
spec_ctrl_msr=-1
|
||||||
else
|
else
|
||||||
spec_ctrl_msr=0
|
spec_ctrl_msr=0
|
||||||
pstatus yellow NO
|
pstatus yellow NO
|
||||||
@ -1517,8 +1705,7 @@ check_cpu()
|
|||||||
pstatus yellow UNKNOWN "is msr kernel module available?"
|
pstatus yellow UNKNOWN "is msr kernel module available?"
|
||||||
else
|
else
|
||||||
# the new MSR 'PRED_CTRL' is at offset 0x49, write-only
|
# the new MSR 'PRED_CTRL' is at offset 0x49, write-only
|
||||||
# here we use dd, it's the same as using 'wrmsr 0x49 0' but without needing the wrmsr tool
|
# we test if of all cpus
|
||||||
# if we get a write error, the MSR is not there
|
|
||||||
val=0
|
val=0
|
||||||
cpu_mismatch=0
|
cpu_mismatch=0
|
||||||
for i in $(seq 0 "$idx_max_cpu")
|
for i in $(seq 0 "$idx_max_cpu")
|
||||||
@ -1619,6 +1806,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,26 +1865,29 @@ 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
|
||||||
|
capabilities_rsba=-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
|
||||||
|
capabilities_rsba=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
|
||||||
pstatus yellow UNKNOWN "is msr kernel module available?"
|
pstatus yellow UNKNOWN "is msr kernel module available?"
|
||||||
else
|
else
|
||||||
# the new MSR 'ARCH_CAPABILITIES' is at offset 0x10a
|
# 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
|
# we check if we have it for all cpus
|
||||||
# if we get a read error, the MSR is not there. bs has to be 8 for msr
|
|
||||||
val=0
|
val=0
|
||||||
val_cap_msr=0
|
val_cap_msr=0
|
||||||
cpu_mismatch=0
|
cpu_mismatch=0
|
||||||
for i in $(seq 0 "$idx_max_cpu")
|
for i in $(seq 0 "$idx_max_cpu")
|
||||||
do
|
do
|
||||||
read_msr 0x10a "$i"; ret=$?
|
read_msr 0x10a "$i"; ret=$?
|
||||||
capabilities=$(echo "$read_msr_value" | awk '{print $8}')
|
capabilities=$read_msr_value
|
||||||
if [ "$i" -eq 0 ]; then
|
if [ "$i" -eq 0 ]; then
|
||||||
val=$ret
|
val=$ret
|
||||||
val_cap_msr=$capabilities
|
val_cap_msr=$capabilities
|
||||||
@ -1672,15 +1902,19 @@ 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
|
||||||
|
capabilities_rsba=0
|
||||||
if [ $val -eq 0 ]; then
|
if [ $val -eq 0 ]; then
|
||||||
_debug "capabilities MSR lower byte is $capabilities (decimal)"
|
_debug "capabilities MSR is $capabilities (decimal)"
|
||||||
[ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1
|
[ $(( capabilities >> 0 & 1 )) -eq 1 ] && capabilities_rdcl_no=1
|
||||||
[ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1
|
[ $(( capabilities >> 1 & 1 )) -eq 1 ] && capabilities_ibrs_all=1
|
||||||
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all"
|
[ $(( capabilities >> 2 & 1 )) -eq 1 ] && capabilities_rsba=1
|
||||||
|
[ $(( capabilities >> 4 & 1 )) -eq 1 ] && capabilities_ssb_no=1
|
||||||
|
_debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all ssb_no=$capabilities_ssb_no rsba=$capabilities_rsba"
|
||||||
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
|
||||||
@ -1688,6 +1922,8 @@ check_cpu()
|
|||||||
fi
|
fi
|
||||||
elif [ $val -eq 200 ]; then
|
elif [ $val -eq 200 ]; then
|
||||||
pstatus yellow UNKNOWN "is msr kernel module available?"
|
pstatus yellow UNKNOWN "is msr kernel module available?"
|
||||||
|
elif [ $val -eq 201 ]; then
|
||||||
|
pstatus yellow UNKNOWN "missing tool, install either msr-tools or perl"
|
||||||
else
|
else
|
||||||
pstatus yellow NO
|
pstatus yellow NO
|
||||||
fi
|
fi
|
||||||
@ -1703,6 +1939,24 @@ 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 " * Hypervisor indicates host CPU might be vulnerable to RSB underflow (RSBA): "
|
||||||
|
if [ "$capabilities_rsba" = -1 ]; then
|
||||||
|
pstatus yellow UNKNOWN
|
||||||
|
elif [ "$capabilities_rsba" = 1 ]; then
|
||||||
|
pstatus yellow YES
|
||||||
|
else
|
||||||
|
pstatus blue 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 +1973,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 +2041,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 +2053,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,15 +2076,21 @@ 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
|
else
|
||||||
pstatus yellow NO
|
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
|
||||||
|
pstatus yellow NO
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
@ -1833,7 +2109,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 +2136,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 +2304,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 +2316,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 +2404,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
|
||||||
@ -2300,7 +2578,7 @@ check_variant2_linux()
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if is_skylake_cpu || [ "$opt_verbose" -ge 2 ]; then
|
if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then
|
||||||
_info_nol " * Kernel supports RSB filling: "
|
_info_nol " * Kernel supports RSB filling: "
|
||||||
if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then
|
if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then
|
||||||
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package"
|
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package"
|
||||||
@ -2327,9 +2605,9 @@ check_variant2_linux()
|
|||||||
# override status & msg in case CPU is not vulnerable after all
|
# override status & msg in case CPU is not vulnerable after all
|
||||||
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
|
pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable"
|
||||||
else
|
else
|
||||||
if [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ -n "$ibpb_enabled" ] && [ "$ibpb_enabled" -ge 1 ] && ( ! is_skylake_cpu || [ -n "$rsb_filling" ] ); then
|
if [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ -n "$ibpb_enabled" ] && [ "$ibpb_enabled" -ge 1 ] && ( ! is_vulnerable_to_empty_rsb || [ -n "$rsb_filling" ] ); then
|
||||||
pvulnstatus $cve OK "Full retpoline + IBPB are mitigating the vulnerability"
|
pvulnstatus $cve OK "Full retpoline + IBPB are mitigating the vulnerability"
|
||||||
elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ "$opt_paranoid" = 0 ] && ( ! is_skylake_cpu || [ -n "$rsb_filling" ] ); then
|
elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ] && [ "$retp_enabled" != 0 ] && [ "$opt_paranoid" = 0 ] && ( ! is_vulnerable_to_empty_rsb || [ -n "$rsb_filling" ] ); then
|
||||||
pvulnstatus $cve OK "Full retpoline is mitigating the vulnerability"
|
pvulnstatus $cve OK "Full retpoline is mitigating the vulnerability"
|
||||||
if [ -n "$cpuid_ibpb" ]; then
|
if [ -n "$cpuid_ibpb" ]; then
|
||||||
_warn "You should enable IBPB to complete retpoline as a Variant 2 mitigation"
|
_warn "You should enable IBPB to complete retpoline as a Variant 2 mitigation"
|
||||||
@ -2359,7 +2637,7 @@ check_variant2_linux()
|
|||||||
# if we arrive here and didn't already call pvulnstatus, then it's VULN, let's explain why
|
# if we arrive here and didn't already call pvulnstatus, then it's VULN, let's explain why
|
||||||
if [ "$pvulnstatus_last_cve" != "$cve" ]; then
|
if [ "$pvulnstatus_last_cve" != "$cve" ]; then
|
||||||
# explain what's needed for this CPU
|
# explain what's needed for this CPU
|
||||||
if is_skylake_cpu; then
|
if is_vulnerable_to_empty_rsb; then
|
||||||
pvulnstatus $cve VULN "IBRS+IBPB or retpoline+IBPB+RBS filling, is needed to mitigate the vulnerability"
|
pvulnstatus $cve VULN "IBRS+IBPB or retpoline+IBPB+RBS 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."
|
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; then
|
elif is_zen_cpu; then
|
||||||
@ -2381,7 +2659,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 +3084,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 +3199,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 +3232,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
|
||||||
|
Reference in New Issue
Block a user