mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2025-07-15 23:31:22 +02:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
30842dd9c0 | |||
b4ac5fcbe3 | |||
fef380d66f | |||
55a6fd3911 | |||
35c8a63de6 | |||
5f914e555e | |||
66dce2c158 | |||
155cac2102 | |||
22cae605e1 | |||
eb75e51975 | |||
253e180807 | |||
5d6102a00e | |||
a2dfca671e | |||
36bd80d75f | |||
1834dd6201 | |||
3d765bc703 | |||
07afd95b63 | |||
b7a10126d1 | |||
6346a0deaa |
22
README.md
22
README.md
@ -8,6 +8,28 @@ You can also specify a kernel image on the command line, if you'd like to inspec
|
|||||||
|
|
||||||
The script will do its best to detect mitigations, including backported non-vanilla patches, regardless of the advertised kernel version number.
|
The script will do its best to detect mitigations, including backported non-vanilla patches, regardless of the advertised kernel version number.
|
||||||
|
|
||||||
|
## Easy way to run the script
|
||||||
|
|
||||||
|
- Get the latest version of the script using `curl` *or* `wget`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -L meltdown.ovh -o spectre-meltdown-checker.sh
|
||||||
|
wget meltdown.ovh -O spectre-meltdown-checker.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- Inspect the script. You never blindly run scripts you downloaded from the Internet, do you?
|
||||||
|
|
||||||
|
```bash
|
||||||
|
vim spectre-meltdown-checker.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
- When you're ready, run the script as root
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x spectre-meltdown-checker.sh
|
||||||
|
sudo ./spectre-meltdown-checker.sh
|
||||||
|
```
|
||||||
|
|
||||||
## 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
|
||||||
|
@ -4,11 +4,24 @@
|
|||||||
# Check for the latest version at:
|
# Check for the latest version at:
|
||||||
# https://github.com/speed47/spectre-meltdown-checker
|
# https://github.com/speed47/spectre-meltdown-checker
|
||||||
# git clone https://github.com/speed47/spectre-meltdown-checker.git
|
# git clone https://github.com/speed47/spectre-meltdown-checker.git
|
||||||
# or wget https://raw.githubusercontent.com/speed47/spectre-meltdown-checker/master/spectre-meltdown-checker.sh
|
# or wget meltdown.ovh -O spectre-meltdown-checker.sh
|
||||||
|
# or curl -L meltdown.ovh -o spectre-meltdown-checker.sh
|
||||||
#
|
#
|
||||||
# Stephane Lesimple
|
# Stephane Lesimple
|
||||||
#
|
#
|
||||||
VERSION='0.34'
|
VERSION='0.35'
|
||||||
|
|
||||||
|
trap 'exit_cleanup' EXIT
|
||||||
|
trap '_warn "interrupted, cleaning up..."; exit_cleanup; exit 1' INT
|
||||||
|
exit_cleanup()
|
||||||
|
{
|
||||||
|
# cleanup the temp decompressed config & kernel image
|
||||||
|
[ -n "$dumped_config" ] && [ -f "$dumped_config" ] && rm -f "$dumped_config"
|
||||||
|
[ -n "$vmlinuxtmp" ] && [ -f "$vmlinuxtmp" ] && rm -f "$vmlinuxtmp"
|
||||||
|
[ "$mounted_debugfs" = 1 ] && umount /sys/kernel/debug 2>/dev/null
|
||||||
|
[ "$insmod_cpuid" = 1 ] && rmmod cpuid 2>/dev/null
|
||||||
|
[ "$insmod_msr" = 1 ] && rmmod msr 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
show_usage()
|
show_usage()
|
||||||
{
|
{
|
||||||
@ -123,7 +136,10 @@ __echo()
|
|||||||
|
|
||||||
if [ "$opt_no_color" = 1 ] ; then
|
if [ "$opt_no_color" = 1 ] ; then
|
||||||
# strip ANSI color codes
|
# strip ANSI color codes
|
||||||
_msg=$($echo_cmd -e "$_msg" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")
|
# some sed versions (i.e. toybox) can't seem to handle
|
||||||
|
# \033 aka \x1B correctly, so do it for them.
|
||||||
|
_ctrlchar=$($echo_cmd -e "\033")
|
||||||
|
_msg=$($echo_cmd -e "$_msg" | sed -r "s/$_ctrlchar\[([0-9][0-9]?(;[0-9][0-9]?)?)?m//g")
|
||||||
fi
|
fi
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
$echo_cmd $opt -e "$_msg"
|
$echo_cmd $opt -e "$_msg"
|
||||||
@ -240,7 +256,9 @@ is_cpu_vulnerable()
|
|||||||
for cpupart in $cpu_part_list
|
for cpupart in $cpu_part_list
|
||||||
do
|
do
|
||||||
i=$(( i + 1 ))
|
i=$(( i + 1 ))
|
||||||
cpuarch=$(echo "$cpu_arch_list" | awk '{ print $'$i' }')
|
# do NOT quote $cpu_arch_list below
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
cpuarch=$(echo $cpu_arch_list | awk '{ print $'$i' }')
|
||||||
_debug "checking cpu$i: <$cpupart> <$cpuarch>"
|
_debug "checking cpu$i: <$cpupart> <$cpuarch>"
|
||||||
# some kernels report AArch64 instead of 8
|
# some kernels report AArch64 instead of 8
|
||||||
[ "$cpuarch" = "AArch64" ] && cpuarch=8
|
[ "$cpuarch" = "AArch64" ] && cpuarch=8
|
||||||
@ -306,7 +324,7 @@ is_cpu_specex_free()
|
|||||||
# { X86_VENDOR_INTEL, 5 },
|
# { X86_VENDOR_INTEL, 5 },
|
||||||
# { X86_VENDOR_NSC, 5 },
|
# { X86_VENDOR_NSC, 5 },
|
||||||
# { X86_VENDOR_ANY, 4 },
|
# { X86_VENDOR_ANY, 4 },
|
||||||
set -u
|
parse_cpu_details
|
||||||
if [ "$cpu_vendor" = GenuineIntel ]; then
|
if [ "$cpu_vendor" = GenuineIntel ]; then
|
||||||
if [ "$cpu_family" = 6 ]; then
|
if [ "$cpu_family" = 6 ]; then
|
||||||
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_CEDARVIEW" ] || \
|
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_CEDARVIEW" ] || \
|
||||||
@ -314,22 +332,19 @@ is_cpu_specex_free()
|
|||||||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_LINCROFT" ] || \
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_LINCROFT" ] || \
|
||||||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_PENWELL" ] || \
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_PENWELL" ] || \
|
||||||
[ "$cpu_model" = "$INTEL_FAM6_ATOM_PINEVIEW" ]; then
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_PINEVIEW" ]; then
|
||||||
set +u
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
elif [ "$cpu_family" = 5 ]; then
|
elif [ "$cpu_family" = 5 ]; then
|
||||||
set +u
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
set +u
|
|
||||||
[ "$cpu_family" -eq 4 ] && return 0
|
[ "$cpu_family" -eq 4 ] && return 0
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
show_header()
|
show_header()
|
||||||
{
|
{
|
||||||
_info "\033[1;34mSpectre and Meltdown mitigation detection tool v$VERSION\033[0m"
|
_info "Spectre and Meltdown mitigation detection tool v$VERSION"
|
||||||
_info
|
_info
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,8 +587,6 @@ extract_vmlinux()
|
|||||||
[ -n "$1" ] || return 1
|
[ -n "$1" ] || return 1
|
||||||
# Prepare temp files:
|
# Prepare temp files:
|
||||||
vmlinuxtmp="$(mktemp /tmp/vmlinux-XXXXXX)"
|
vmlinuxtmp="$(mktemp /tmp/vmlinux-XXXXXX)"
|
||||||
# single quotes in trap cmd: will be expanded when signalled
|
|
||||||
trap 'rm -f $vmlinuxtmp' EXIT INT
|
|
||||||
|
|
||||||
# Initial attempt for uncompressed images or objects:
|
# Initial attempt for uncompressed images or objects:
|
||||||
if check_vmlinux "$1"; then
|
if check_vmlinux "$1"; then
|
||||||
@ -602,44 +615,18 @@ mount_debugfs()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
umount_debugfs()
|
|
||||||
{
|
|
||||||
if [ "$mounted_debugfs" = 1 ]; then
|
|
||||||
# umount debugfs if we did mount it ourselves
|
|
||||||
umount /sys/kernel/debug
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
load_msr()
|
load_msr()
|
||||||
{
|
{
|
||||||
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_msr()
|
|
||||||
{
|
|
||||||
if [ "$insmod_msr" = 1 ]; then
|
|
||||||
# if we used modprobe ourselves, rmmod the module
|
|
||||||
rmmod msr 2>/dev/null
|
|
||||||
_debug "attempted to unload module msr, ret=$?"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
load_cpuid()
|
load_cpuid()
|
||||||
{
|
{
|
||||||
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
unload_cpuid()
|
|
||||||
{
|
|
||||||
if [ "$insmod_cpuid" = 1 ]; then
|
|
||||||
# if we used modprobe ourselves, rmmod the module
|
|
||||||
rmmod cpuid 2>/dev/null
|
|
||||||
_debug "attempted to unload module cpuid, ret=$?"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
read_cpuid()
|
read_cpuid()
|
||||||
{
|
{
|
||||||
_leaf="$1"
|
_leaf="$1"
|
||||||
@ -694,6 +681,7 @@ is_coreos()
|
|||||||
|
|
||||||
parse_cpu_details()
|
parse_cpu_details()
|
||||||
{
|
{
|
||||||
|
[ "$parse_cpu_details_done" = 1 ] && return 0
|
||||||
cpu_vendor=$( grep '^vendor_id' /proc/cpuinfo | awk '{print $3}' | head -1)
|
cpu_vendor=$( grep '^vendor_id' /proc/cpuinfo | awk '{print $3}' | head -1)
|
||||||
cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//')
|
cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//')
|
||||||
# special case for ARM follows
|
# special case for ARM follows
|
||||||
@ -703,9 +691,11 @@ parse_cpu_details()
|
|||||||
# an example is "bigLITTLE", so we need to store the whole list, this is needed for is_cpu_vulnerable
|
# an example is "bigLITTLE", so we need to store the whole list, this is needed for is_cpu_vulnerable
|
||||||
cpu_part_list=$(awk '/CPU part/ {print $4}' /proc/cpuinfo)
|
cpu_part_list=$(awk '/CPU part/ {print $4}' /proc/cpuinfo)
|
||||||
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' /proc/cpuinfo)
|
cpu_arch_list=$(awk '/CPU architecture/ {print $3}' /proc/cpuinfo)
|
||||||
# take the first one to fill the friendly name
|
# take the first one to fill the friendly name, do NOT quote the vars below
|
||||||
cpu_arch=$(echo "$cpu_arch_list" | awk '{ print $1 }')
|
# shellcheck disable=SC2086
|
||||||
cpu_part=$(echo "$cpu_part_list" | awk '{ print $1 }')
|
cpu_arch=$(echo $cpu_arch_list | awk '{ print $1 }')
|
||||||
|
# shellcheck disable=SC2086
|
||||||
|
cpu_part=$(echo $cpu_part_list | awk '{ print $1 }')
|
||||||
[ "$cpu_arch" = "AArch64" ] && cpu_arch=8
|
[ "$cpu_arch" = "AArch64" ] && cpu_arch=8
|
||||||
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"
|
||||||
@ -716,7 +706,6 @@ parse_cpu_details()
|
|||||||
cpu_model=$( grep '^model' /proc/cpuinfo | awk '{print $3}' | grep -E '^[0-9]+$' | head -1)
|
cpu_model=$( grep '^model' /proc/cpuinfo | awk '{print $3}' | grep -E '^[0-9]+$' | head -1)
|
||||||
cpu_stepping=$(grep '^stepping' /proc/cpuinfo | awk '{print $3}' | grep -E '^[0-9]+$' | head -1)
|
cpu_stepping=$(grep '^stepping' /proc/cpuinfo | awk '{print $3}' | grep -E '^[0-9]+$' | head -1)
|
||||||
cpu_ucode=$( grep '^microcode' /proc/cpuinfo | awk '{print $3}' | head -1)
|
cpu_ucode=$( grep '^microcode' /proc/cpuinfo | awk '{print $3}' | head -1)
|
||||||
cpu_friendly_name=$(grep '^model name' /proc/cpuinfo | cut -d: -f2- | head -1 | sed -e 's/^ *//')
|
|
||||||
|
|
||||||
# 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
|
||||||
@ -780,33 +769,36 @@ parse_cpu_details()
|
|||||||
INTEL_FAM6_XEON_PHI_KNL=$(( 0x57 ))
|
INTEL_FAM6_XEON_PHI_KNL=$(( 0x57 ))
|
||||||
INTEL_FAM6_XEON_PHI_KNM=$(( 0x85 ))
|
INTEL_FAM6_XEON_PHI_KNM=$(( 0x85 ))
|
||||||
}
|
}
|
||||||
|
parse_cpu_details_done=1
|
||||||
}
|
}
|
||||||
|
|
||||||
is_ucode_blacklisted()
|
is_ucode_blacklisted()
|
||||||
{
|
{
|
||||||
|
parse_cpu_details
|
||||||
# if it's not an Intel, don't bother: it's not blacklisted
|
# if it's not an Intel, don't bother: it's not blacklisted
|
||||||
[ "$cpu_vendor" = GenuineIntel ] || return 1
|
[ "$cpu_vendor" = GenuineIntel ] || return 1
|
||||||
# it also needs to be family=6
|
# it also needs to be family=6
|
||||||
[ "$cpu_family" = 6 ] || return 1
|
[ "$cpu_family" = 6 ] || return 1
|
||||||
# now, check each known bad microcode
|
# now, check each known bad microcode
|
||||||
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/intel.c#n105
|
# source: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/cpu/intel.c#n105
|
||||||
|
# 2018-02-08 update: https://newsroom.intel.com/wp-content/uploads/sites/11/2018/02/microcode-update-guidance.pdf
|
||||||
# model,stepping,microcode
|
# model,stepping,microcode
|
||||||
ucode_found="model $cpu_model stepping $cpu_stepping ucode $cpu_ucode"
|
ucode_found="model $cpu_model stepping $cpu_stepping ucode $cpu_ucode"
|
||||||
set -u
|
|
||||||
for tuple in \
|
for tuple in \
|
||||||
$INTEL_FAM6_KABYLAKE_DESKTOP,0x0B,0x84 \
|
$INTEL_FAM6_KABYLAKE_DESKTOP,0x0B,0x80 \
|
||||||
$INTEL_FAM6_KABYLAKE_DESKTOP,0x0A,0x84 \
|
$INTEL_FAM6_KABYLAKE_DESKTOP,0x0A,0x80 \
|
||||||
$INTEL_FAM6_KABYLAKE_DESKTOP,0x09,0x84 \
|
$INTEL_FAM6_KABYLAKE_DESKTOP,0x09,0x80 \
|
||||||
$INTEL_FAM6_KABYLAKE_MOBILE,0x0A,0x84 \
|
$INTEL_FAM6_KABYLAKE_MOBILE,0x0A,0x80 \
|
||||||
$INTEL_FAM6_KABYLAKE_MOBILE,0x09,0x84 \
|
$INTEL_FAM6_KABYLAKE_MOBILE,0x09,0x80 \
|
||||||
$INTEL_FAM6_SKYLAKE_X,0x03,0x0100013e \
|
$INTEL_FAM6_SKYLAKE_X,0x03,0x0100013e \
|
||||||
|
$INTEL_FAM6_SKYLAKE_X,0x04,0x02000036 \
|
||||||
|
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003a \
|
||||||
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003c \
|
$INTEL_FAM6_SKYLAKE_X,0x04,0x0200003c \
|
||||||
$INTEL_FAM6_SKYLAKE_MOBILE,0x03,0xc2 \
|
|
||||||
$INTEL_FAM6_SKYLAKE_DESKTOP,0x03,0xc2 \
|
|
||||||
$INTEL_FAM6_BROADWELL_CORE,0x04,0x28 \
|
$INTEL_FAM6_BROADWELL_CORE,0x04,0x28 \
|
||||||
$INTEL_FAM6_BROADWELL_GT3E,0x01,0x1b \
|
$INTEL_FAM6_BROADWELL_GT3E,0x01,0x1b \
|
||||||
$INTEL_FAM6_BROADWELL_XEON_D,0x02,0x14 \
|
$INTEL_FAM6_BROADWELL_XEON_D,0x02,0x14 \
|
||||||
$INTEL_FAM6_BROADWELL_XEON_D,0x03,0x07000011 \
|
$INTEL_FAM6_BROADWELL_XEON_D,0x03,0x07000011 \
|
||||||
|
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000023 \
|
||||||
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000025 \
|
$INTEL_FAM6_BROADWELL_X,0x01,0x0b000025 \
|
||||||
$INTEL_FAM6_HASWELL_ULT,0x01,0x21 \
|
$INTEL_FAM6_HASWELL_ULT,0x01,0x21 \
|
||||||
$INTEL_FAM6_HASWELL_GT3E,0x01,0x18 \
|
$INTEL_FAM6_HASWELL_GT3E,0x01,0x18 \
|
||||||
@ -814,7 +806,6 @@ is_ucode_blacklisted()
|
|||||||
$INTEL_FAM6_HASWELL_X,0x02,0x3b \
|
$INTEL_FAM6_HASWELL_X,0x02,0x3b \
|
||||||
$INTEL_FAM6_HASWELL_X,0x04,0x10 \
|
$INTEL_FAM6_HASWELL_X,0x04,0x10 \
|
||||||
$INTEL_FAM6_IVYBRIDGE_X,0x04,0x42a \
|
$INTEL_FAM6_IVYBRIDGE_X,0x04,0x42a \
|
||||||
$INTEL_FAM6_ATOM_GEMINI_LAKE,0x01,0x22 \
|
|
||||||
$INTEL_FAM6_SANDYBRIDGE_X,0x06,0x61b \
|
$INTEL_FAM6_SANDYBRIDGE_X,0x06,0x61b \
|
||||||
$INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712
|
$INTEL_FAM6_SANDYBRIDGE_X,0x07,0x712
|
||||||
do
|
do
|
||||||
@ -823,15 +814,39 @@ is_ucode_blacklisted()
|
|||||||
ucode=$(echo $tuple | cut -d, -f3)
|
ucode=$(echo $tuple | cut -d, -f3)
|
||||||
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ] && echo "$cpu_ucode" | grep -qi "^$ucode$"; then
|
if [ "$cpu_model" = "$model" ] && [ "$cpu_stepping" = "$stepping" ] && echo "$cpu_ucode" | grep -qi "^$ucode$"; then
|
||||||
_debug "is_ucode_blacklisted: we have a match! ($cpu_model/$cpu_stepping/$cpu_ucode)"
|
_debug "is_ucode_blacklisted: we have a match! ($cpu_model/$cpu_stepping/$cpu_ucode)"
|
||||||
set +u
|
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
set +u
|
|
||||||
_debug "is_ucode_blacklisted: no ($cpu_model/$cpu_stepping/$cpu_ucode)"
|
_debug "is_ucode_blacklisted: no ($cpu_model/$cpu_stepping/$cpu_ucode)"
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is_skylake_cpu()
|
||||||
|
{
|
||||||
|
# is this a skylake cpu?
|
||||||
|
# return 0 if yes, 1 otherwise
|
||||||
|
#if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL &&
|
||||||
|
# boot_cpu_data.x86 == 6) {
|
||||||
|
# switch (boot_cpu_data.x86_model) {
|
||||||
|
# case INTEL_FAM6_SKYLAKE_MOBILE:
|
||||||
|
# case INTEL_FAM6_SKYLAKE_DESKTOP:
|
||||||
|
# case INTEL_FAM6_SKYLAKE_X:
|
||||||
|
# case INTEL_FAM6_KABYLAKE_MOBILE:
|
||||||
|
# case INTEL_FAM6_KABYLAKE_DESKTOP:
|
||||||
|
# return true;
|
||||||
|
parse_cpu_details
|
||||||
|
[ "$cpu_vendor" = GenuineIntel ] || return 1
|
||||||
|
[ "$cpu_family" = 6 ] || return 1
|
||||||
|
if [ "$cpu_model" = $INTEL_FAM6_SKYLAKE_MOBILE ] || \
|
||||||
|
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_DESKTOP ] || \
|
||||||
|
[ "$cpu_model" = $INTEL_FAM6_SKYLAKE_X ] || \
|
||||||
|
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_MOBILE ] || \
|
||||||
|
[ "$cpu_model" = $INTEL_FAM6_KABYLAKE_DESKTOP ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
# check for mode selection inconsistency
|
# check for mode selection inconsistency
|
||||||
if [ "$opt_live_explicit" = 1 ]; then
|
if [ "$opt_live_explicit" = 1 ]; then
|
||||||
if [ -n "$opt_kernel" ] || [ -n "$opt_config" ] || [ -n "$opt_map" ]; then
|
if [ -n "$opt_kernel" ] || [ -n "$opt_config" ] || [ -n "$opt_map" ]; then
|
||||||
@ -853,9 +868,6 @@ if [ "$opt_coreos" = 1 ]; then
|
|||||||
mount_debugfs
|
mount_debugfs
|
||||||
toolbox --ephemeral --bind-ro /dev/cpu:/dev/cpu -- sh -c "dnf install -y binutils which && /media/root$PWD/$0 $* --coreos-within-toolbox"
|
toolbox --ephemeral --bind-ro /dev/cpu:/dev/cpu -- sh -c "dnf install -y binutils which && /media/root$PWD/$0 $* --coreos-within-toolbox"
|
||||||
exitcode=$?
|
exitcode=$?
|
||||||
mount_debugfs
|
|
||||||
unload_cpuid
|
|
||||||
unload_msr
|
|
||||||
exit $exitcode
|
exit $exitcode
|
||||||
else
|
else
|
||||||
if is_coreos; then
|
if is_coreos; then
|
||||||
@ -864,10 +876,9 @@ else
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# root check (only for live mode, for offline mode, we already checked if we could read the files)
|
|
||||||
|
|
||||||
parse_cpu_details
|
parse_cpu_details
|
||||||
if [ "$opt_live" = 1 ]; then
|
if [ "$opt_live" = 1 ]; then
|
||||||
|
# root check (only for live mode, for offline mode, we already checked if we could read the files)
|
||||||
if [ "$(id -u)" -ne 0 ]; then
|
if [ "$(id -u)" -ne 0 ]; then
|
||||||
_warn "Note that you should launch this script with root privileges to get accurate information."
|
_warn "Note that you should launch this script with root privileges to get accurate information."
|
||||||
_warn "We'll proceed but you might see permission denied errors."
|
_warn "We'll proceed but you might see permission denied errors."
|
||||||
@ -909,6 +920,8 @@ if [ "$opt_live" = 1 ]; then
|
|||||||
[ -e "/boot/kernel-genkernel-$(uname -m)-$(uname -r)" ] && opt_kernel="/boot/kernel-genkernel-$(uname -m)-$(uname -r)"
|
[ -e "/boot/kernel-genkernel-$(uname -m)-$(uname -r)" ] && opt_kernel="/boot/kernel-genkernel-$(uname -m)-$(uname -r)"
|
||||||
# NixOS:
|
# NixOS:
|
||||||
[ -e "/run/booted-system/kernel" ] && opt_kernel="/run/booted-system/kernel"
|
[ -e "/run/booted-system/kernel" ] && opt_kernel="/run/booted-system/kernel"
|
||||||
|
# systemd kernel-install:
|
||||||
|
[ -e "/etc/machine-id" ] && [ -e "/boot/$(cat /etc/machine-id)/$(uname -r)/linux" ] && opt_kernel="/boot/$(cat /etc/machine-id)/$(uname -r)/linux"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# system.map
|
# system.map
|
||||||
@ -933,6 +946,7 @@ if [ "$opt_live" = 1 ]; then
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
_info "Checking for vulnerabilities against specified kernel"
|
_info "Checking for vulnerabilities against specified kernel"
|
||||||
|
_info "CPU is \033[35m$cpu_friendly_name\033[0m"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -n "$opt_kernel" ]; then
|
if [ -n "$opt_kernel" ]; then
|
||||||
@ -972,6 +986,8 @@ if [ -e "$opt_kernel" ]; then
|
|||||||
if ! which readelf >/dev/null 2>&1; then
|
if ! which readelf >/dev/null 2>&1; then
|
||||||
_debug "readelf not found"
|
_debug "readelf not found"
|
||||||
vmlinux_err="missing 'readelf' tool, please install it, usually it's in the 'binutils' package"
|
vmlinux_err="missing 'readelf' tool, please install it, usually it's in the 'binutils' package"
|
||||||
|
elif [ "$opt_sysfs_only" = 1 ]; then
|
||||||
|
vmlinux_err='kernel image decompression skipped'
|
||||||
else
|
else
|
||||||
extract_vmlinux "$opt_kernel"
|
extract_vmlinux "$opt_kernel"
|
||||||
fi
|
fi
|
||||||
@ -981,6 +997,20 @@ else
|
|||||||
fi
|
fi
|
||||||
if [ -z "$vmlinux" ] || [ ! -r "$vmlinux" ]; then
|
if [ -z "$vmlinux" ] || [ ! -r "$vmlinux" ]; then
|
||||||
[ -z "$vmlinux_err" ] && vmlinux_err="couldn't extract your kernel from $opt_kernel"
|
[ -z "$vmlinux_err" ] && vmlinux_err="couldn't extract your kernel from $opt_kernel"
|
||||||
|
else
|
||||||
|
vmlinux_version=$(strings "$vmlinux" 2>/dev/null | grep '^Linux version ' | head -1)
|
||||||
|
if [ -n "$vmlinux_version" ]; then
|
||||||
|
# in live mode, check if the img we found is the correct one
|
||||||
|
if [ "$opt_live" = 1 ]; then
|
||||||
|
_verbose "Kernel image is \033[35m$vmlinux_version"
|
||||||
|
if ! echo "$vmlinux_version" | grep -qF "$(uname -r)" || \
|
||||||
|
! echo "$vmlinux_version" | grep -qF "$(uname -v)"; then
|
||||||
|
_warn "Possible disrepancy between your running kernel and the image we found ($opt_kernel), results might be incorrect"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
_info "Kernel image is \033[35m$vmlinux_version"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info
|
_info
|
||||||
@ -1194,7 +1224,7 @@ check_cpu()
|
|||||||
_warn "the mitigations for Spectre), or upgrade to a newer one if available."
|
_warn "the mitigations for Spectre), or upgrade to a newer one if available."
|
||||||
_warn
|
_warn
|
||||||
else
|
else
|
||||||
pstatus green NO "$ucode_found"
|
pstatus blue NO "$ucode_found"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info "* CPU vulnerability to the three speculative execution attacks variants"
|
_info "* CPU vulnerability to the three speculative execution attacks variants"
|
||||||
@ -1210,6 +1240,28 @@ check_cpu()
|
|||||||
_info
|
_info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
check_redhat_canonical_spectre()
|
||||||
|
{
|
||||||
|
# if we were already called, don't do it again
|
||||||
|
[ -n "$redhat_canonical_spectre" ] && return
|
||||||
|
|
||||||
|
if ! which strings >/dev/null 2>&1; then
|
||||||
|
redhat_canonical_spectre=-1
|
||||||
|
else
|
||||||
|
# Red Hat / Ubuntu specific variant1 patch is difficult to detect,
|
||||||
|
# let's use the same way than the official Red Hat detection script,
|
||||||
|
# and detect their specific variant2 patch. If it's present, it means
|
||||||
|
# that the variant1 patch is also present (both were merged at the same time)
|
||||||
|
if strings "$vmlinux" | grep -qw noibrs && strings "$vmlinux" | grep -qw noibpb; then
|
||||||
|
_debug "found redhat/canonical version of the variant2 patch (implies variant1)"
|
||||||
|
redhat_canonical_spectre=1
|
||||||
|
else
|
||||||
|
redhat_canonical_spectre=0
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
###################
|
###################
|
||||||
# SPECTRE VARIANT 1
|
# SPECTRE VARIANT 1
|
||||||
check_variant1()
|
check_variant1()
|
||||||
@ -1260,10 +1312,20 @@ check_variant1()
|
|||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$opt_verbose" -ge 2 ] || [ "$v1_mask_nospec" != 1 ]; then
|
_info_nol "* Kernel has the Red Hat/Ubuntu patch: "
|
||||||
|
check_redhat_canonical_spectre
|
||||||
|
if [ "$redhat_canonical_spectre" = -1 ]; then
|
||||||
|
pstatus yellow UNKNOWN "missing 'strings' tool, please install it, usually it's in the binutils package"
|
||||||
|
elif [ "$redhat_canonical_spectre" = 1 ]; then
|
||||||
|
pstatus green YES
|
||||||
|
else
|
||||||
|
pstatus red NO
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$opt_verbose" -ge 2 ] || ( [ "$v1_mask_nospec" != 1 ] && [ "$redhat_canonical_spectre" != 1 ] ); 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
|
||||||
_info_nol "* Checking count of LFENCE instructions following a jump in kernel: "
|
_info_nol "* Checking count of LFENCE instructions following a jump in kernel... "
|
||||||
if [ -n "$vmlinux_err" ]; then
|
if [ -n "$vmlinux_err" ]; then
|
||||||
pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)"
|
pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)"
|
||||||
else
|
else
|
||||||
@ -1303,6 +1365,8 @@ check_variant1()
|
|||||||
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
||||||
if [ "$v1_mask_nospec" = 1 ]; then
|
if [ "$v1_mask_nospec" = 1 ]; then
|
||||||
pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (array_index_mask_nospec)"
|
pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (array_index_mask_nospec)"
|
||||||
|
elif [ "$redhat_canonical_spectre" = 1 ]; then
|
||||||
|
pvulnstatus $cve OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)"
|
||||||
elif [ "$v1_lfence" = 1 ]; then
|
elif [ "$v1_lfence" = 1 ]; then
|
||||||
pvulnstatus $cve OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)"
|
pvulnstatus $cve OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)"
|
||||||
elif [ "$vmlinux_err" ]; then
|
elif [ "$vmlinux_err" ]; then
|
||||||
@ -1348,7 +1412,7 @@ check_variant2()
|
|||||||
if [ -e "$dir/ibrs_enabled" ]; then
|
if [ -e "$dir/ibrs_enabled" ]; then
|
||||||
# if the file is there, we have IBRS compiled-in
|
# if the file is there, we have IBRS compiled-in
|
||||||
# /sys/kernel/debug/ibrs_enabled: vanilla
|
# /sys/kernel/debug/ibrs_enabled: vanilla
|
||||||
# /sys/kernel/debug/x86/ibrs_enabled: RedHat (see https://access.redhat.com/articles/3311301)
|
# /sys/kernel/debug/x86/ibrs_enabled: Red Hat (see https://access.redhat.com/articles/3311301)
|
||||||
# /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed
|
# /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed
|
||||||
pstatus green YES
|
pstatus green YES
|
||||||
ibrs_knob_dir=$dir
|
ibrs_knob_dir=$dir
|
||||||
@ -1389,6 +1453,13 @@ check_variant2()
|
|||||||
_debug "ibrs: found '*spec_ctrl*' symbol in $opt_map"
|
_debug "ibrs: found '*spec_ctrl*' symbol in $opt_map"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
if [ "$ibrs_supported" != 1 ]; then
|
||||||
|
check_redhat_canonical_spectre
|
||||||
|
if [ "$redhat_canonical_spectre" = 1 ]; then
|
||||||
|
pstatus green YES "Red Hat/Ubuntu patch"
|
||||||
|
ibrs_supported=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
if [ "$ibrs_supported" != 1 ]; then
|
if [ "$ibrs_supported" != 1 ]; then
|
||||||
if [ "$ibrs_can_tell" = 1 ]; then
|
if [ "$ibrs_can_tell" = 1 ]; then
|
||||||
pstatus red NO
|
pstatus red NO
|
||||||
@ -1418,9 +1489,7 @@ check_variant2()
|
|||||||
;;
|
;;
|
||||||
0)
|
0)
|
||||||
pstatus red NO
|
pstatus red NO
|
||||||
if [ "$opt_verbose" -ge 2 ]; then
|
_verbose " - To enable, \`echo 1 > $ibrs_knob_dir/ibrs_enabled' as root. If you don't have hardware support, you'll get an error."
|
||||||
_info " - To enable, \`echo 1 > $ibrs_knob_dir/ibrs_enabled' as root. If you don't have hardware support, you'll get an error."
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
1 | 2) pstatus green YES;;
|
1 | 2) pstatus green YES;;
|
||||||
*) pstatus yellow UNKNOWN;;
|
*) pstatus yellow UNKNOWN;;
|
||||||
@ -1446,9 +1515,7 @@ check_variant2()
|
|||||||
;;
|
;;
|
||||||
0 | 1)
|
0 | 1)
|
||||||
pstatus red NO
|
pstatus red NO
|
||||||
if [ "$opt_verbose" -ge 2 ]; then
|
_verbose " - To enable, \`echo 2 > $ibrs_knob_dir/ibrs_enabled' as root. If you don't have hardware support, you'll get an error."
|
||||||
_info " - To enable, \`echo 2 > $ibrs_knob_dir/ibrs_enabled' as root. If you don't have hardware support, you'll get an error."
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
2) pstatus green YES;;
|
2) pstatus green YES;;
|
||||||
*) pstatus yellow UNKNOWN;;
|
*) pstatus yellow UNKNOWN;;
|
||||||
@ -1470,9 +1537,7 @@ check_variant2()
|
|||||||
;;
|
;;
|
||||||
0)
|
0)
|
||||||
pstatus red NO
|
pstatus red NO
|
||||||
if [ "$opt_verbose" -ge 2 ]; then
|
_verbose " - To enable, \`echo 1 > $ibrs_knob_dir/ibpb_enabled' as root. If you don't have hardware support, you'll get an error."
|
||||||
_info " - To enable, \`echo 1 > $ibrs_knob_dir/ibpb_enabled' as root. If you don't have hardware support, you'll get an error."
|
|
||||||
fi
|
|
||||||
;;
|
;;
|
||||||
1) pstatus green YES;;
|
1) pstatus green YES;;
|
||||||
2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints";;
|
2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints";;
|
||||||
@ -1562,19 +1627,6 @@ check_variant2()
|
|||||||
pstatus red NO
|
pstatus red NO
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
_info_nol " * Retpoline enabled: "
|
|
||||||
if [ "$opt_live" = 1 ]; then
|
|
||||||
# kernel adds this flag when retpoline is supported and enabled,
|
|
||||||
# regardless of the fact that it's minimal / full and generic / amd
|
|
||||||
if grep -qw retpoline /proc/cpuinfo; then
|
|
||||||
pstatus green YES
|
|
||||||
else
|
|
||||||
pstatus red NO
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
pstatus blue N/A "can't check this in offline mode"
|
|
||||||
fi
|
|
||||||
elif [ "$sys_interface_available" = 0 ]; then
|
elif [ "$sys_interface_available" = 0 ]; then
|
||||||
# we have no sysfs but were asked to use it only!
|
# we have no sysfs but were asked to use it only!
|
||||||
msg="/sys vulnerability interface use forced, but it's not available!"
|
msg="/sys vulnerability interface use forced, but it's not available!"
|
||||||
@ -1597,6 +1649,8 @@ check_variant2()
|
|||||||
pvulnstatus $cve OK "IBRS is mitigating the vulnerability"
|
pvulnstatus $cve OK "IBRS is mitigating the vulnerability"
|
||||||
elif [ "$ibpb_enabled" = 2 ]; then
|
elif [ "$ibpb_enabled" = 2 ]; then
|
||||||
pvulnstatus $cve OK "Full IBPB is mitigating the vulnerability"
|
pvulnstatus $cve OK "Full IBPB is mitigating the vulnerability"
|
||||||
|
elif [ "$ibrs_supported" = 1 ] && [ "$cpuid_spec_ctrl" != 1 ]; then
|
||||||
|
pvulnstatus $cve VULN "Your kernel is compiled with IBRS but your CPU microcode is lacking support to successfully mitigate the vulnerability"
|
||||||
else
|
else
|
||||||
pvulnstatus $cve VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
|
pvulnstatus $cve VULN "IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability"
|
||||||
fi
|
fi
|
||||||
@ -1686,7 +1740,7 @@ check_variant3()
|
|||||||
_debug "kpti_enabled: found 'kaiser' flag in /proc/cpuinfo"
|
_debug "kpti_enabled: found 'kaiser' flag in /proc/cpuinfo"
|
||||||
kpti_enabled=1
|
kpti_enabled=1
|
||||||
elif [ -e /sys/kernel/debug/x86/pti_enabled ]; then
|
elif [ -e /sys/kernel/debug/x86/pti_enabled ]; then
|
||||||
# RedHat Backport creates a dedicated file, see https://access.redhat.com/articles/3311301
|
# Red Hat Backport creates a dedicated file, see https://access.redhat.com/articles/3311301
|
||||||
kpti_enabled=$(cat /sys/kernel/debug/x86/pti_enabled 2>/dev/null)
|
kpti_enabled=$(cat /sys/kernel/debug/x86/pti_enabled 2>/dev/null)
|
||||||
_debug "kpti_enabled: file /sys/kernel/debug/x86/pti_enabled exists and says: $kpti_enabled"
|
_debug "kpti_enabled: file /sys/kernel/debug/x86/pti_enabled exists and says: $kpti_enabled"
|
||||||
fi
|
fi
|
||||||
@ -1781,7 +1835,7 @@ check_variant3()
|
|||||||
elif [ "$xen_pv_domo" = 1 ]; then
|
elif [ "$xen_pv_domo" = 1 ]; then
|
||||||
pvulnstatus $cve OK "Xen Dom0s are safe and do not require PTI"
|
pvulnstatus $cve OK "Xen Dom0s are safe and do not require PTI"
|
||||||
elif [ "$xen_pv_domu" = 1 ]; then
|
elif [ "$xen_pv_domu" = 1 ]; then
|
||||||
pvulnstatus $cve VULN "Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM or PVH mode"
|
pvulnstatus $cve VULN "Xen PV DomUs are vulnerable and need to be run in HVM, PVHVM, PVH mode, or the Xen hypervisor must have the Xen's own PTI patch"
|
||||||
else
|
else
|
||||||
pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability"
|
pvulnstatus $cve VULN "PTI is needed to mitigate the vulnerability"
|
||||||
fi
|
fi
|
||||||
@ -1834,15 +1888,6 @@ 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"
|
||||||
|
|
||||||
# this'll umount only if we mounted debugfs ourselves
|
|
||||||
umount_debugfs
|
|
||||||
# same for modules
|
|
||||||
unload_msr
|
|
||||||
unload_cpuid
|
|
||||||
|
|
||||||
# cleanup the temp decompressed config
|
|
||||||
[ -n "$dumped_config" ] && [ -f "$dumped_config" ] && rm -f "$dumped_config"
|
|
||||||
|
|
||||||
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "nrpe" ]; then
|
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "nrpe" ]; then
|
||||||
if [ ! -z "$nrpe_vuln" ]; then
|
if [ ! -z "$nrpe_vuln" ]; then
|
||||||
echo "Vulnerable:$nrpe_vuln"
|
echo "Vulnerable:$nrpe_vuln"
|
||||||
|
Reference in New Issue
Block a user