12 Commits
v0.07 ... v0.11

Author SHA1 Message Date
12bdd0e412 root check is now more visible 2018-01-08 11:31:19 +01:00
89f9bef577 Merge pull request #4 from dguglielmi/add-genkernel-support
Add support for Gentoo genkernel image path
2018-01-08 11:24:07 +01:00
bf056ae73d Add support for Gentoo genkernel image path 2018-01-08 11:08:53 +01:00
623e180ae1 Merge pull request #3 from TheHendla/arch_boot_img
add arch linux bootimage path
2018-01-08 10:51:59 +01:00
40a9d43c44 add arch linux bootimage path 2018-01-08 10:36:29 +01:00
c1004d5171 fix extract-vmlinux for non-gzip 2018-01-08 09:56:29 +01:00
fa0850466e add some comments, enhance pti detection 2018-01-08 09:37:54 +01:00
5c14384e15 Merge pull request #1 from t-nelis/root-check
Improve "running as root" check
2018-01-08 08:58:21 +01:00
1aaca63dcf Improve "running as root" check
Small issue with the USER environment variable:

  $ echo $USER
  thib
  $ sudo sh -c 'echo $USER'
  thib
  $ sudo -i sh -c 'echo $USER'
  root

Rather than recommending users to use sudo --login / -i, use the (very
widespread/portable) id program to retrieve the effective user ID
instead and don't change the recommendation.

  $ id -u
  1000
  $ sudo id -u
  0
  $ sudo -i id -u
  0
2018-01-08 01:22:14 +01:00
96dfa03c00 fix for uncompressed vmlinux case 2018-01-08 00:45:12 +01:00
05c79425ab detect kpti directly in vmlinux if option is not there 2018-01-07 22:47:41 +01:00
9def0c949a update readme 2018-01-07 20:13:10 +01:00
2 changed files with 103 additions and 48 deletions

View File

@ -28,24 +28,24 @@ Example of the output of the script:
``` ```
$ sudo ./spectre-meltdown-checker.sh $ sudo ./spectre-meltdown-checker.sh
Spectre and Meltdown mitigation detection tool v0.02 Spectre and Meltdown mitigation detection tool v0.07
CVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1' CVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'
* Kernel compiled with LFENCE opcode inserted at the proper places: NO (only 38 opcodes found, should be >= 60) * Kernel compiled with LFENCE opcode inserted at the proper places: NO (only 38 opcodes found, should be >= 60)
> STATUS: VULNERABLE > STATUS: VULNERABLE
CVE-2017-5715 [branch target injection] aka 'Spectre Variant 2' CVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'
* Mitigation 1 * Mitigation 1
* Hardware (CPU microcode) support for mitigation: NO * Hardware (CPU microcode) support for mitigation: NO
* Kernel support for IBRS: NO * Kernel support for IBRS: NO
* IBRS enabled for Kernel space: NO * IBRS enabled for Kernel space: NO
* IBRS enabled for User space: NO * IBRS enabled for User space: NO
* Mitigation 2 * Mitigation 2
* Kernel recompiled with retpolines: UNKNOWN (check not yet implemented) * Kernel compiled with retpolines: NO
> STATUS: VULNERABLE (IBRS hardware + kernel support OR retpolines-compiled kernel are needed to mitigate the vulnerability) > STATUS: VULNERABLE (IBRS hardware + kernel support OR kernel with retpolines are needed to mitigate the vulnerability)
CVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3' CVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3'
* Kernel supports Page Table Isolation (PTI): YES * Kernel supports Page Table Isolation (PTI): YES
* PTI enabled and active: YES * PTI enabled and active: YES
> STATUS: NOT VULNERABLE (PTI mitigates the vulnerability) > STATUS: NOT VULNERABLE (PTI mitigates the vulnerability)
``` ```

View File

@ -1,8 +1,9 @@
#! /bin/sh #! /bin/sh
# Spectre & Meltdown checker # Spectre & Meltdown checker
# Stephane Lesimple # Stephane Lesimple
VERSION=0.07 VERSION=0.11
# print status function
pstatus() pstatus()
{ {
case "$1" in case "$1" in
@ -16,6 +17,11 @@ pstatus()
/bin/echo /bin/echo
} }
# The 3 below functions are taken from the extract-linux script, available here:
# https://github.com/torvalds/linux/blob/master/scripts/extract-vmlinux
# The functions have been modified for better integration to this script
# The original header of the file has been retained below
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
# extract-vmlinux - Extract uncompressed vmlinux from a kernel image # extract-vmlinux - Extract uncompressed vmlinux from a kernel image
# #
@ -39,54 +45,76 @@ try_decompress()
# "grep" that report the byte offset of the line instead of the pattern. # "grep" that report the byte offset of the line instead of the pattern.
# Try to find the header ($1) and decompress from here # Try to find the header ($1) and decompress from here
for pos in `tr "$1\n$2" "\n$2=" < "$img" | grep -abo "^$2"` for pos in `tr "$1\n$2" "\n$2=" < "$4" | grep -abo "^$2"`
do do
pos=${pos%%:*} pos=${pos%%:*}
tail -c+$pos "$img" | $3 > $vmlinuxtmp 2> /dev/null tail -c+$pos "$4" | $3 > $vmlinuxtmp 2> /dev/null
check_vmlinux $vmlinuxtmp && echo $vmlinuxtmp || rm -f $vmlinuxtmp check_vmlinux "$vmlinuxtmp" && echo "$vmlinuxtmp" && return 0
done done
return 1
} }
extract_vmlinux() extract_vmlinux()
{ {
img="$1" [ -n "$1" ] || return 1
# Prepare temp files: # Prepare temp files:
vmlinuxtmp=$(mktemp /tmp/vmlinux-XXX) vmlinuxtmp="$(mktemp /tmp/vmlinux-XXX)"
# Initial attempt for uncompressed images or objects: # Initial attempt for uncompressed images or objects:
check_vmlinux $img if check_vmlinux "$1"; then
cat "$1" > "$vmlinuxtmp"
echo "$vmlinuxtmp"
return 0
fi
# That didn't work, so retry after decompression. # That didn't work, so retry after decompression.
try_decompress '\037\213\010' xy gunzip || \ try_decompress '\037\213\010' xy gunzip "$1" && return 0
try_decompress '\3757zXZ\000' abcde unxz || \ try_decompress '\3757zXZ\000' abcde unxz "$1" && return 0
try_decompress 'BZh' xy bunzip2 || \ try_decompress 'BZh' xy bunzip2 "$1" && return 0
try_decompress '\135\0\0\0' xxx unlzma || \ try_decompress '\135\0\0\0' xxx unlzma "$1" && return 0
try_decompress '\211\114\132' xy 'lzop -d' try_decompress '\211\114\132' xy 'lzop -d' "$1" && return 0
return 1
} }
# end of extract-vmlinux functions
/bin/echo "Spectre and Meltdown mitigation detection tool v$VERSION" /bin/echo -e "\033[1;34mSpectre and Meltdown mitigation detection tool v$VERSION\033[0m"
/bin/echo /bin/echo
# root check
if [ "$(id -u)" -ne 0 ]; then
/bin/echo -e "\033[31mNote that you should launch this script with root privileges to get accurate information."
/bin/echo -e "\033[31mWe'll proceed but you might see permission denied errors."
/bin/echo -e "\033[31mTo run it as root, you can try the following command: sudo $0"
/bin/echo
fi
###########
# SPECTRE 1 # SPECTRE 1
/bin/echo -e "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m" /bin/echo -e "\033[1;34mCVE-2017-5753 [bounds check bypass] aka 'Spectre Variant 1'\033[0m"
/bin/echo -n "* Kernel compiled with LFENCE opcode inserted at the proper places: " /bin/echo -n "* Kernel compiled with LFENCE opcode inserted at the proper places: "
status=0 status=0
img='' img=''
# try to find the image of the current running kernel
[ -e /boot/vmlinuz-linux ] && img=/boot/vmlinuz-linux
[ -e /boot/vmlinuz-$(uname -r) ] && img=/boot/vmlinuz-$(uname -r) [ -e /boot/vmlinuz-$(uname -r) ] && img=/boot/vmlinuz-$(uname -r)
[ -e /boot/vmlinux-$(uname -r) ] && img=/boot/vmlinux-$(uname -r) [ -e /boot/kernel-$( uname -r) ] && img=/boot/kernel-$( uname -r)
[ -e /boot/bzImage-$(uname -r) ] && img=/boot/bzImage-$(uname -r) [ -e /boot/bzImage-$(uname -r) ] && img=/boot/bzImage-$(uname -r)
[ -e /boot/kernel-genkernel-$(uname -m)-$(uname -r) ] && img=/boot/kernel-genkernel-$(uname -m)-$(uname -r)
if [ -z "$img" ]; then if [ -z "$img" ]; then
pstatus yellow UNKNOWN "couldn't find your kernel image in /boot" pstatus yellow UNKNOWN "couldn't find your kernel image in /boot, if you used netboot, this is normal"
else else
vmlinux=$(extract_vmlinux $img) vmlinux=$(extract_vmlinux $img)
if [ -z "$vmlinux" -o ! -r "$vmlinux" ]; then if [ -z "$vmlinux" -o ! -r "$vmlinux" ]; then
pstatus yellow UNKNOWN "couldn't extract your kernel" pstatus yellow UNKNOWN "couldn't extract your kernel from $img"
elif ! which objdump >/dev/null 2>&1; then elif ! which objdump >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'objdump' tool, please install it, usually it's in the binutils package" pstatus yellow UNKNOWN "missing 'objdump' tool, please install it, usually it's in the binutils package"
else else
# here we disassemble the kernel and count the number of occurences of the LFENCE opcode
# in non-patched kernels, this has been empirically determined as being around 40-50
# in patched kernels, this is more around 70-80
nb_lfence=$(objdump -D "$vmlinux" | grep -wc lfence) nb_lfence=$(objdump -D "$vmlinux" | grep -wc lfence)
if [ "$nb_lfence" -lt 60 ]; then if [ "$nb_lfence" -lt 60 ]; then
pstatus red NO "only $nb_lfence opcodes found, should be >= 60" pstatus red NO "only $nb_lfence opcodes found, should be >= 60"
@ -95,7 +123,6 @@ else
pstatus green YES "$nb_lfence opcodes found, which is >= 60" pstatus green YES "$nb_lfence opcodes found, which is >= 60"
status=2 status=2
fi fi
rm -f $vmlinux
fi fi
fi fi
@ -104,19 +131,22 @@ fi
[ "$status" = 1 ] && pstatus red VULNERABLE [ "$status" = 1 ] && pstatus red VULNERABLE
[ "$status" = 2 ] && pstatus green 'NOT VULNERABLE' [ "$status" = 2 ] && pstatus green 'NOT VULNERABLE'
###########
# VARIANT 2 # VARIANT 2
/bin/echo /bin/echo
/bin/echo -e "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m" /bin/echo -e "\033[1;34mCVE-2017-5715 [branch target injection] aka 'Spectre Variant 2'\033[0m"
/bin/echo "* Mitigation 1" /bin/echo "* Mitigation 1"
/bin/echo -n "* Hardware (CPU microcode) support for mitigation: " /bin/echo -n "* Hardware (CPU microcode) support for mitigation: "
if [ ! -e /dev/cpu/0/msr ]; then if [ ! -e /dev/cpu/0/msr ]; then
# try to load the module ourselves (and remember it so we can rmmod it afterwards)
modprobe msr 2>/dev/null && insmod_msr=1 modprobe msr 2>/dev/null && insmod_msr=1
fi fi
if [ ! -e /dev/cpu/0/msr ]; then if [ ! -e /dev/cpu/0/msr ]; then
pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?" pstatus yellow UNKNOWN "couldn't read /dev/cpu/0/msr, is msr support enabled in your kernel?"
else else
# same that rdmsr 0x48 but without needing the rdmsr tool # 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
# if we get a read error, the MSR is not there
dd if=/dev/cpu/0/msr of=/dev/null bs=8 count=1 skip=9 2>/dev/null dd if=/dev/cpu/0/msr of=/dev/null bs=8 count=1 skip=9 2>/dev/null
if [ $? -eq 0 ]; then if [ $? -eq 0 ]; then
pstatus green YES pstatus green YES
@ -126,14 +156,17 @@ else
fi fi
if [ "$insmod_msr" = 1 ]; then if [ "$insmod_msr" = 1 ]; then
# if we used modprobe ourselves, rmmod the module
rmmod msr 2>/dev/null rmmod msr 2>/dev/null
fi fi
/bin/echo -n "* Kernel support for IBRS: " /bin/echo -n "* Kernel support for IBRS: "
if [ -e /sys/kernel/debug/sched_features ]; then if [ -e /sys/kernel/debug/sched_features ]; then
# try to mount the debugfs hierarchy ourselves and remember it to umount afterwards
mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null && mounted_debugfs=1 mount -t debugfs debugfs /sys/kernel/debug 2>/dev/null && mounted_debugfs=1
fi fi
if [ -e /sys/kernel/debug/ibrs_enabled ]; then if [ -e /sys/kernel/debug/ibrs_enabled ]; then
# if the file is there, we have IBRS compiled-in
pstatus green YES pstatus green YES
ibrs_supported=1 ibrs_supported=1
else else
@ -142,6 +175,9 @@ fi
ibrs_enabled=$(cat /sys/kernel/debug/ibrs_enabled 2>/dev/null) ibrs_enabled=$(cat /sys/kernel/debug/ibrs_enabled 2>/dev/null)
/bin/echo -n "* IBRS enabled for Kernel space: " /bin/echo -n "* IBRS enabled for Kernel space: "
# 0 means disabled
# 1 is enabled only for kernel space
# 2 is enabled for kernel and user space
case "$ibrs_enabled" in case "$ibrs_enabled" in
"") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;; "") [ "$ibrs_supported" = 1 ] && pstatus yellow UNKNOWN || pstatus red NO;;
0) pstatus red NO;; 0) pstatus red NO;;
@ -158,13 +194,17 @@ case "$ibrs_enabled" in
esac esac
if [ "$mounted_debugfs" = 1 ]; then if [ "$mounted_debugfs" = 1 ]; then
# umount debugfs if we did mount it ourselves
umount /sys/kernel/debug umount /sys/kernel/debug
fi fi
/bin/echo "* Mitigation 2" /bin/echo "* Mitigation 2"
/bin/echo -n "* Kernel compiled with retpolines: " /bin/echo -n "* Kernel compiled with retpolines: "
# We check the RETPOLINE kernel options
# XXX this doesn't mean the kernel has been compiled with a retpoline-aware gcc # XXX this doesn't mean the kernel has been compiled with a retpoline-aware gcc
# still looking for a way do detect that ...
if [ -e /proc/config.gz ]; then if [ -e /proc/config.gz ]; then
# either the running kernel exports his own config
if zgrep -q '^CONFIG_RETPOLINE=y' /proc/config.gz; then if zgrep -q '^CONFIG_RETPOLINE=y' /proc/config.gz; then
pstatus green YES pstatus green YES
retpoline=1 retpoline=1
@ -172,6 +212,7 @@ if [ -e /proc/config.gz ]; then
pstatus red NO pstatus red NO
fi fi
elif [ -e /boot/config-$(uname -r) ]; then elif [ -e /boot/config-$(uname -r) ]; then
# or we can find a config file in /root with the kernel release name
if grep -q '^CONFIG_RETPOLINE=y' /boot/config-$(uname -r); then if grep -q '^CONFIG_RETPOLINE=y' /boot/config-$(uname -r); then
pstatus green YES pstatus green YES
retpoline=1 retpoline=1
@ -193,40 +234,58 @@ else
pstatus red VULNERABLE "IBRS hardware + kernel support OR kernel with retpolines are needed to mitigate the vulnerability" pstatus red VULNERABLE "IBRS hardware + kernel support OR kernel with retpolines are needed to mitigate the vulnerability"
fi fi
##########
# MELTDOWN # MELTDOWN
/bin/echo /bin/echo
/bin/echo -e "\033[1;34mCVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3'\033[0m" /bin/echo -e "\033[1;34mCVE-2017-5754 [rogue data cache load] aka 'Meltdown' aka 'Variant 3'\033[0m"
/bin/echo -n "* Kernel supports Page Table Isolation (PTI): " /bin/echo -n "* Kernel supports Page Table Isolation (PTI): "
kpti_support=0
kpti_can_tell=0
if [ -e /proc/config.gz ]; then if [ -e /proc/config.gz ]; then
# either the running kernel exports his own config
kpti_can_tell=1
if zgrep -q '^CONFIG_PAGE_TABLE_ISOLATION=y' /proc/config.gz; then if zgrep -q '^CONFIG_PAGE_TABLE_ISOLATION=y' /proc/config.gz; then
pstatus green YES
kpti_support=1 kpti_support=1
else
pstatus red NO
fi fi
elif [ -e /boot/config-$(uname -r) ]; then elif [ -e /boot/config-$(uname -r) ]; then
# or we can find a config file in /root with the kernel release name
kpti_can_tell=1
if grep -q '^CONFIG_PAGE_TABLE_ISOLATION=y' /boot/config-$(uname -r); then if grep -q '^CONFIG_PAGE_TABLE_ISOLATION=y' /boot/config-$(uname -r); then
pstatus green YES
kpti_support=1 kpti_support=1
else
pstatus red NO
fi fi
elif [ -e /boot/System.map-$(uname -r) ]; then fi
if [ -e /boot/System.map-$(uname -r) ]; then
# it's not an elif: some backports don't have the PTI config but still include the patch
# so we try to find an exported symbol that is part of the PTI patch in System.map
kpti_can_tell=1
if grep -qw kpti_force_enabled /boot/System.map-$(uname -r); then if grep -qw kpti_force_enabled /boot/System.map-$(uname -r); then
pstatus green YES
kpti_support=1 kpti_support=1
else
pstatus red NO
fi fi
fi
if [ -n "$vmlinux" ]; then
# same as above but in case we don't have System.map and only vmlinux, look for the
# nopti option that is part of the patch (kernel command line option)
kpti_can_tell=1
if strings "$vmlinux" | grep -qw nopti; then
kpti_support=1
fi
fi
if [ "$kpti_support" = 1 ]; then
pstatus green YES
elif [ "$kpti_can_tell" = 1 ]; then
pstatus red NO
else else
pstatus yellow UNKNOWN "couldn't read your kernel configuration" pstatus yellow UNKNOWN "couldn't read your kernel configuration"
fi fi
/bin/echo -n "* PTI enabled and active: " /bin/echo -n "* PTI enabled and active: "
if grep ^flags /proc/cpuinfo | grep -qw pti; then if grep ^flags /proc/cpuinfo | grep -qw pti; then
# vanilla PTI patch sets the 'pti' flag in cpuinfo
pstatus green YES pstatus green YES
kpti_enabled=1 kpti_enabled=1
elif dmesg | grep -q 'Kernel/User page tables isolation: enabled'; then elif dmesg | grep -Eq 'Kernel/User page tables isolation: enabled|Kernel page table isolation enabled'; then
# if we can't find the flag, grep in dmesg
pstatus green YES pstatus green YES
kpti_enabled=1 kpti_enabled=1
else else
@ -242,10 +301,6 @@ else
pstatus red "VULNERABLE" "PTI is needed to mitigate the vulnerability" pstatus red "VULNERABLE" "PTI is needed to mitigate the vulnerability"
fi fi
/bin/echo /bin/echo
if [ "$USER" != root ]; then
/bin/echo "Note that you should launch this script with root privileges to get accurate information"
/bin/echo "You can try the following command: sudo $0"
fi
[ -n "$vmlinux" -a -f "$vmlinux" ] && rm -f "$vmlinux"