diff --git a/spectre-meltdown-checker.sh b/spectre-meltdown-checker.sh index 820c10c..a6cb99f 100755 --- a/spectre-meltdown-checker.sh +++ b/spectre-meltdown-checker.sh @@ -10,6 +10,170 @@ # VERSION=0.19 +# Script configuration +show_usage() +{ + cat <] [--config ] [--map ] + + Modes: + Two modes are available. + + First mode is the "live" mode (default), it does its best to find information about the currently running kernel. + To run under this mode, just start the script without any option (you can also use --live explicitely) + + Second mode is the "offline" mode, where you can inspect a non-running kernel. + You'll need to specify the location of the vmlinux file, and if possible, the corresponding config and System.map files: + + --kernel vmlinux_file Specify a (possibly compressed) vmlinux file + --config kernel_config Specify a kernel config file + --map kernel_map_file Specify a kernel System.map file + + Options: + --no-color Don't use color codes + +EOF +} + +# parse options +opt_kernel='' +opt_config='' +opt_map='' +opt_live_explicit=0 +opt_live=1 +opt_no_color=0 + +__echo() +{ + opt="$1" + shift + msg="$@" + if [ "$opt_no_color" = 1 ] ; then + # strip ANSI color codes + msg=$(echo "$msg" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g") + fi + # explicitely call /bin/echo to avoid shell builtins that might not take options + /bin/echo $opt -e "$msg" +} + +_echo() +{ + __echo '' "$@" +} + +_echo_nol() +{ + __echo -n "$@" +} + +is_cpu_vulnerable() +{ + # param: 1, 2 or 3 (variant) + # returns 0 if vulnerable, 1 if vulnerable, 2 if not vulnerable, 255 on error + variant1=1 + variant2=1 + variant3=1 + if grep -q AMD /proc/cpuinfo; then + variant1=1 + variant2=0 + variant3=0 + elif grep -qi 'CPU implementer : 0x41' /proc/cpuinfo; then + # ARM + # reference: https://developer.arm.com/support/security-update + cpupart=$(awk '/CPU part :/ {print $4;exit}' /proc/cpuinfo) + cpuarch=$(awk '/CPU architecture:/ {print $3;exit}' /proc/cpuinfo) + if [ -n "$cpupart" -a -n "$cpuarch" ]; then + # 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 + # model R7 R8 A9 A15 A17 A57 A72 A73 A75 + # part ? ? 0xc09 0xc0f 0xc0e 0xd07 0xd08 0xd09 0xd0a + # arch 7? 7? 7 7 7 8 8 8 8 + if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -Eq '^0x(c09|c0f|c0e)$'; then + # armv7 vulnerable chips + variant1=1 + variant2=1 + elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -Eq '^0x(d07|d08|d09|d0a)$'; then + # armv8 vulnerable chips + variant1=1 + variant2=1 + else + variant1=0 + variant2=0 + fi + # for variant3, only A75 is vulnerable + if [ "$cpuarch" = 8 -a "$cpupart" = 0xd0a ]; then + variant3=1 + else + variant3=0 + fi + fi + fi + [ "$1" = 1 ] && return $variant1 + [ "$1" = 2 ] && return $variant2 + [ "$1" = 3 ] && return $variant3 + return 255 +} + +_echo "\033[1;34mSpectre and Meltdown mitigation detection tool v$VERSION\033[0m" +_echo + +parse_opt_file() +{ + # parse_opt_file option_name option_value + option_name="$1" + option_value="$2" + if [ -z "$option_value" ]; then + show_usage + echo "$0: error: --$option_name expects one parameter (a file)" >&2 + exit 1 + elif [ ! -e "$option_value" ]; then + echo "$0: error: couldn't find file $option_value" >&2 + exit 1 + elif [ ! -f "$option_value" ]; then + echo "$0: error: $option_value is not a file" >&2 + exit 1 + elif [ ! -e "$option_value" ]; then + echo "$0: error: couldn't read $option_value (are you root?)" >&2 + exit 1 + fi + echo "$option_value" + exit 0 +} + +while [ -n "$1" ]; do + if [ "$1" = "--kernel" ]; then + opt_kernel=$(parse_opt_file kernel "$2") + [ $? -ne 0 ] && exit $? + shift 2 + opt_live=0 + elif [ "$1" = "--config" ]; then + opt_config=$(parse_opt_file config "$2") + [ $? -ne 0 ] && exit $? + shift 2 + opt_live=0 + elif [ "$1" = "--map" ]; then + opt_map=$(parse_opt_file map "$2") + [ $? -ne 0 ] && exit $? + shift 2 + opt_live=0 + elif [ "$1" = "--live" ]; then + opt_live_explicit=1 + shift + elif [ "$1" = "--no-color" ]; then + opt_no_color=1 + shift + elif [ "$1" = "-h" -o "$1" = "--help" ]; then + show_usage + exit 0 + else + show_usage + echo "$0: error: unknown option '$1'" + exit 1 + fi +done + # print status function pstatus() { @@ -97,169 +261,6 @@ extract_vmlinux() # end of extract-vmlinux functions -show_usage() -{ - cat <] [--config ] [--map ] - - Modes: - Two modes are available. - - First mode is the "live" mode (default), it does its best to find information about the currently running kernel. - To run under this mode, just start the script without any option (you can also use --live explicitely) - - Second mode is the "offline" mode, where you can inspect a non-running kernel. - You'll need to specify the location of the vmlinux file, and if possible, the corresponding config and System.map files: - - --kernel vmlinux_file Specify a (possibly compressed) vmlinux file - --config kernel_config Specify a kernel config file - --map kernel_map_file Specify a kernel System.map file - - Options: - --no-color Don't use color codes - -EOF -} - -__echo() -{ - opt="$1" - shift - msg="$@" - if [ "$opt_no_color" = 1 ] ; then - # strip ANSI color codes - msg=$(echo "$msg" | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g") - fi - # explicitely call /bin/echo to avoid shell builtins that might not take options - /bin/echo $opt -e "$msg" -} - -_echo() -{ - __echo '' "$@" -} - -_echo_nol() -{ - __echo -n "$@" -} - -is_cpu_vulnerable() -{ - # param: 1, 2 or 3 (variant) - # returns 0 if vulnerable, 1 if vulnerable, 2 if not vulnerable, 255 on error - variant1=1 - variant2=1 - variant3=1 - if grep -q AMD /proc/cpuinfo; then - variant1=1 - variant2=0 - variant3=0 - elif grep -qi 'CPU implementer : 0x41' /proc/cpuinfo; then - # ARM - # reference: https://developer.arm.com/support/security-update - cpupart=$(awk '/CPU part :/ {print $4;exit}' /proc/cpuinfo) - cpuarch=$(awk '/CPU architecture:/ {print $3;exit}' /proc/cpuinfo) - if [ -n "$cpupart" -a -n "$cpuarch" ]; then - # 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 - # model R7 R8 A9 A15 A17 A57 A72 A73 A75 - # part ? ? 0xc09 0xc0f 0xc0e 0xd07 0xd08 0xd09 0xd0a - # arch 7? 7? 7 7 7 8 8 8 8 - if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -Eq '^0x(c09|c0f|c0e)$'; then - # armv7 vulnerable chips - variant1=1 - variant2=1 - elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -Eq '^0x(d07|d08|d09|d0a)$'; then - # armv8 vulnerable chips - variant1=1 - variant2=1 - else - variant1=0 - variant2=0 - fi - # for variant3, only A75 is vulnerable - if [ "$cpuarch" = 8 -a "$cpupart" = 0xd0a ]; then - variant3=1 - else - variant3=0 - fi - fi - fi - [ "$1" = 1 ] && return $variant1 - [ "$1" = 2 ] && return $variant2 - [ "$1" = 3 ] && return $variant3 - return 255 -} - -_echo "\033[1;34mSpectre and Meltdown mitigation detection tool v$VERSION\033[0m" -_echo - -# parse options -opt_kernel='' -opt_config='' -opt_map='' -opt_live_explicit=0 -opt_live=1 -opt_no_color=0 - -parse_opt_file() -{ - # parse_opt_file option_name option_value - option_name="$1" - option_value="$2" - if [ -z "$option_value" ]; then - show_usage - echo "$0: error: --$option_name expects one parameter (a file)" >&2 - exit 1 - elif [ ! -e "$option_value" ]; then - echo "$0: error: couldn't find file $option_value" >&2 - exit 1 - elif [ ! -f "$option_value" ]; then - echo "$0: error: $option_value is not a file" >&2 - exit 1 - elif [ ! -e "$option_value" ]; then - echo "$0: error: couldn't read $option_value (are you root?)" >&2 - exit 1 - fi - echo "$option_value" - exit 0 -} - -while [ -n "$1" ]; do - if [ "$1" = "--kernel" ]; then - opt_kernel=$(parse_opt_file kernel "$2") - [ $? -ne 0 ] && exit $? - shift 2 - opt_live=0 - elif [ "$1" = "--config" ]; then - opt_config=$(parse_opt_file config "$2") - [ $? -ne 0 ] && exit $? - shift 2 - opt_live=0 - elif [ "$1" = "--map" ]; then - opt_map=$(parse_opt_file map "$2") - [ $? -ne 0 ] && exit $? - shift 2 - opt_live=0 - elif [ "$1" = "--live" ]; then - opt_live_explicit=1 - shift - elif [ "$1" = "--no-color" ]; then - opt_no_color=1 - shift - elif [ "$1" = "-h" -o "$1" = "--help" ]; then - show_usage - exit 0 - else - show_usage - echo "$0: error: unknown option '$1'" - exit 1 - fi -done - # check for mode selection inconsistency if [ "$opt_live_explicit" = 1 ]; then if [ -n "$opt_kernel" -o -n "$opt_config" -o -n "$opt_map" ]; then