8 Commits
v0.14 ... v0.16

View File

@ -1,7 +1,7 @@
#! /bin/sh #! /bin/sh
# Spectre & Meltdown checker # Spectre & Meltdown checker
# Stephane Lesimple # Stephane Lesimple
VERSION=0.14 VERSION=0.16
# print status function # print status function
pstatus() pstatus()
@ -33,9 +33,11 @@ pstatus()
# Licensed under the GNU General Public License, version 2 (GPLv2). # Licensed under the GNU General Public License, version 2 (GPLv2).
# ---------------------------------------------------------------------- # ----------------------------------------------------------------------
vmlinux=''
vmlinux_err=''
check_vmlinux() check_vmlinux()
{ {
file "$1" 2>/dev/null | grep -q ELF || return 1 readelf -h $1 > /dev/null 2>&1 || return 1
return 0 return 0
} }
@ -45,11 +47,15 @@ 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=" < "$4" | grep -abo "^$2"` for pos in `tr "$1\n$2" "\n$2=" < "$5" | grep -abo "^$2"`
do do
if ! which $3 >/dev/null 2>&1; then
vmlinux_err="missing '$3' tool, please install it, usually it's in the '$4' package"
return 0
fi
pos=${pos%%:*} pos=${pos%%:*}
tail -c+$pos "$4" | $3 > $vmlinuxtmp 2> /dev/null tail -c+$pos "$5" | $3 > $vmlinuxtmp 2> /dev/null
check_vmlinux "$vmlinuxtmp" && echo "$vmlinuxtmp" && return 0 check_vmlinux "$vmlinuxtmp" && vmlinux=$vmlinuxtmp && return 0
done done
return 1 return 1
} }
@ -68,11 +74,11 @@ extract_vmlinux()
fi fi
# That didn't work, so retry after decompression. # That didn't work, so retry after decompression.
try_decompress '\037\213\010' xy gunzip "$1" && return 0 try_decompress '\037\213\010' xy gunzip gunzip "$1" && return 0
try_decompress '\3757zXZ\000' abcde unxz "$1" && return 0 try_decompress '\3757zXZ\000' abcde unxz xz-utils "$1" && return 0
try_decompress 'BZh' xy bunzip2 "$1" && return 0 try_decompress 'BZh' xy bunzip2 bzip2 "$1" && return 0
try_decompress '\135\0\0\0' xxx unlzma "$1" && return 0 try_decompress '\135\0\0\0' xxx unlzma xz-utils "$1" && return 0
try_decompress '\211\114\132' xy 'lzop -d' "$1" && return 0 try_decompress '\211\114\132' xy 'lzop -d' lzop "$1" && return 0
return 1 return 1
} }
@ -109,8 +115,13 @@ img=''
if [ -z "$img" ]; then if [ -z "$img" ]; then
pstatus yellow UNKNOWN "couldn't find your kernel image in /boot, if you used netboot, this is normal" pstatus yellow UNKNOWN "couldn't find your kernel image in /boot, if you used netboot, this is normal"
else else
vmlinux=$(extract_vmlinux $img) if ! which readelf >/dev/null 2>&1; then
if [ -z "$vmlinux" -o ! -r "$vmlinux" ]; then pstatus yellow UNKNOWN "missing 'readelf' tool, please install it, usually it's in the 'binutils' package"
else
extract_vmlinux $img
if [ "$vmlinux_err" != "" ]; then
pstatus yellow UNKNOWN "couldn't extract your kernel from $img: $vmlinux_err"
elif [ -z "$vmlinux" -o ! -r "$vmlinux" ]; then
pstatus yellow UNKNOWN "couldn't extract your kernel from $img" 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"
@ -130,6 +141,7 @@ else
status=2 status=2
fi fi
fi fi
fi
fi fi
/bin/echo -ne "> \033[46m\033[30mSTATUS:\033[0m " /bin/echo -ne "> \033[46m\033[30mSTATUS:\033[0m "
@ -231,53 +243,30 @@ fi
# Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm # Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm
# For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles) # For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles)
# See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79 # See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79
# We'll look for the presence of 'retpoline_call_target' in symbols # In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_RETPOLINE is set
# *AND* if the compiler is retpoline-compliant, so look for that symbol
if [ -n "$vmlinux" ]; then if [ -n "$vmlinux" ]; then
# look for the symbol # look for the symbol
if which nm >/dev/null 2>&1; then if [ -e /boot/System.map-$(uname -r) ]; then
# the proper way: use nm and look for the symbol if grep -qw noretpoline_setup /boot/System.map-$(uname -r); then
if nm "$vmlinux" 2>/dev/null | grep -qw retpoline_call_target; then
retpoline_compiler=1 retpoline_compiler=1
pstatus green YES "retpoline_call_target found" pstatus green YES "noretpoline_setup symbol found in System.map"
fi fi
else elif which nm >/dev/null 2>&1; then
# the proper way: use nm and look for the symbol
if nm "$vmlinux" 2>/dev/null | grep -qw 'noretpoline_setup'; then
retpoline_compiler=1
pstatus green YES "noretpoline_setup symbol found in vmlinux"
fi
elif grep -q noretpoline_setup "$vmlinux"; then
# if we don't have nm, nevermind, the symbol name is long enough to not have # if we don't have nm, nevermind, the symbol name is long enough to not have
# any false positive using good old grep directly on the binary # any false positive using good old grep directly on the binary
if grep -q retpoline_call_target "$vmlinux"; then
retpoline_compiler=1 retpoline_compiler=1
pstatus green YES "retpoline_call_target found" pstatus green YES "noretpoline_setup symbol found in vmlinux"
fi
fi fi
if [ "$retpoline_compiler" != 1 ]; then if [ "$retpoline_compiler" != 1 ]; then
# still not ? maybe we just don't have symbols in the kernel image (stripped)
# let's objdump it and look for the asm sequence (here for 64 bits)
#
# ffffffff81000350 <__x86.indirect_thunk>:
# ffffffff81000350: e8 05 00 00 00 callq ffffffff8100035a <retpoline_call_target>
# ffffffff81000355: 0f ae e8 lfence
# ffffffff81000358: eb fb jmp ffffffff81000355 <__x86.indirect_thunk+0x5>
# ffffffff8100035a <retpoline_call_target>:
# ffffffff8100035a: 48 8d 64 24 08 lea 0x8(%rsp),%rsp
# ffffffff8100035f: c3 retq
#
if ! which perl >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'perl', please install it"
else
# directly look for the opcode sequence in the binary
# 64 bits version
if perl -ne '/\xe8\x05\x00\x00\x00\x0f\xae\xe8\xeb\xfb\x48\x8d\x64\x24\x08\xc3/ and $found=1; END { exit($found ? 0 : 1) }' "$vmlinux"; then
retpoline_compiler=1
pstatus green YES "retpoline 64 bits asm sequence found"
#elif perl -ne ... 32 bits version of retpoline asm seq
# TODO
# retpoline_compiler=1
# pstatus green YES "retpoline 33 bits asm sequence found"
else
pstatus red NO pstatus red NO
fi fi
fi
fi
else else
pstatus yellow UNKNOWN "couldn't find your kernel image" pstatus yellow UNKNOWN "couldn't find your kernel image"
fi fi
@ -314,7 +303,7 @@ elif [ -e /boot/config-$(uname -r) ]; then
kpti_support=1 kpti_support=1
fi fi
fi fi
if [ -e /boot/System.map-$(uname -r) ]; then if [ "$kpti_support" = 0 -a -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 # 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 # so we try to find an exported symbol that is part of the PTI patch in System.map
kpti_can_tell=1 kpti_can_tell=1
@ -322,13 +311,17 @@ if [ -e /boot/System.map-$(uname -r) ]; then
kpti_support=1 kpti_support=1
fi fi
fi fi
if [ -n "$vmlinux" ]; then if [ "$kpti_support" = 0 -a -n "$vmlinux" ]; then
# same as above but in case we don't have System.map and only vmlinux, look for the # 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) # nopti option that is part of the patch (kernel command line option)
kpti_can_tell=1 kpti_can_tell=1
if ! which strings >/dev/null 2>&1; then
pstatus yellow UNKNOWN "missing 'strings' tool, please install it, usually it's in the binutils package"
else
if strings "$vmlinux" | grep -qw nopti; then if strings "$vmlinux" | grep -qw nopti; then
kpti_support=1 kpti_support=1
fi fi
fi
fi fi
if [ "$kpti_support" = 1 ]; then if [ "$kpti_support" = 1 ]; then