19 Commits
v0.34 ... v0.35

Author SHA1 Message Date
30842dd9c0 release: bump to v0.35 2018-02-16 10:35:49 +01:00
b4ac5fcbe3 feat(variant2): better explanation when kernel supports IBRS but CPU does not 2018-02-16 10:34:01 +01:00
fef380d66f feat(readme): add quick run section 2018-02-15 21:19:49 +01:00
55a6fd3911 feat(variant1): better detection for Red Hat/Ubuntu patch 2018-02-15 21:19:49 +01:00
35c8a63de6 Remove the color in the title 2018-02-15 20:21:00 +01:00
5f914e555e fix(xen): declare Xen's PTI patch as a valid mitigation for variant3 2018-02-14 14:24:55 +01:00
66dce2c158 fix(ucode): update blacklisted ucodes list from latest Intel info 2018-02-14 14:14:16 +01:00
155cac2102 Teach checker how to find kernels installed by systemd kernel-install 2018-02-10 20:51:33 +01:00
22cae605e1 fix(retpoline): remove the "retpoline enabled" test
This test worked for some early versions of the retpoline
implementation in vanilla kernels, but the corresponding
flag has been removed from /proc/cpuinfo in latest kernels.
The full information is available in /sys instead, which
was already implemented in the script.
2018-02-09 20:12:33 +01:00
eb75e51975 fix(ucode): update list of blacklisted ucodes from 2018-02-08 Intel document
Removed 2 ucodes and added 2 other ones
2018-02-09 19:56:27 +01:00
253e180807 Update spectre-meltdown-checker.sh
Dots better than colon for indicating waiting.
2018-02-06 19:02:56 +01:00
5d6102a00e enh: show kernel version in offline mode 2018-02-02 11:27:04 +01:00
a2dfca671e feat: detect disrepancy between found kernel image and running kernel 2018-02-02 11:13:54 +01:00
36bd80d75f enh: speedup by not decompressing kernel on --sysfs-only 2018-02-02 11:13:31 +01:00
1834dd6201 feat: add skylake era cpu detection routine 2018-02-02 11:12:10 +01:00
3d765bc703 enh: lazy loading of cpu informations 2018-02-02 11:11:51 +01:00
07afd95b63 feat: better cleanup routine on exit & interrupt 2018-02-02 11:09:36 +01:00
b7a10126d1 fix: ARM CPU display name & detection
Fix ARM CPU display name, and properly
detect known vulnerable ARM CPUs when
multiple different model cores are
present (mostly Android phones)
2018-02-02 11:00:23 +01:00
6346a0deaa fix: --no-color workaround for android's sed 2018-02-02 10:59:49 +01:00
2 changed files with 161 additions and 94 deletions

View File

@ -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

View File

@ -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"