From 2d993812ab168d9e881da8e706c4c4583137c9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lesimple?= Date: Sat, 17 Mar 2018 13:17:10 +0100 Subject: [PATCH] feat: add --prefix-arch for cross-arch kernel inspection --- spectre-meltdown-checker.sh | 40 +++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/spectre-meltdown-checker.sh b/spectre-meltdown-checker.sh index 6964b7c..f77be60 100755 --- a/spectre-meltdown-checker.sh +++ b/spectre-meltdown-checker.sh @@ -50,6 +50,8 @@ show_usage() --no-sysfs Don't use the /sys interface even if present --sysfs-only Only use the /sys interface, don't run our own checks --coreos Special mode for CoreOS (use an ephemeral toolbox to inspect kernel) + --arch-prefix PREFIX Specify a prefix for cross-inspecting a kernel of a different arch, for example "aarch64-linux-gnu-", + so that invoked tools such as objdump will be prefixed with this (i.e. aarch64-linux-gnu-objdump) --batch text Produce machine readable output, this is the default if --batch is specified alone --batch json Produce JSON output formatted for Puppet, Ansible, Chef... --batch nrpe Produce machine readable output formatted for NRPE @@ -114,6 +116,7 @@ opt_allvariants=1 opt_no_sysfs=0 opt_sysfs_only=0 opt_coreos=0 +opt_arch_prefix='' global_critical=0 global_unknown=0 @@ -392,6 +395,9 @@ while [ -n "$1" ]; do [ $ret -ne 0 ] && exit 255 shift 2 opt_live=0 + elif [ "$1" = "--arch-prefix" ]; then + opt_arch_prefix="$2" + shift 2 elif [ "$1" = "--live" ]; then opt_live_explicit=1 shift @@ -556,7 +562,7 @@ vmlinux='' vmlinux_err='' check_vmlinux() { - readelf -h "$1" >/dev/null 2>&1 && return 0 + "${opt_arch_prefix}readelf" -h "$1" >/dev/null 2>&1 && return 0 return 1 } @@ -995,9 +1001,9 @@ if [ "$bad_accuracy" = 1 ]; then fi if [ -e "$opt_kernel" ]; then - if ! which readelf >/dev/null 2>&1; then + if ! which "${opt_arch_prefix}readelf" >/dev/null 2>&1; then _debug "readelf not found" - vmlinux_err="missing 'readelf' tool, please install it, usually it's in the 'binutils' package" + vmlinux_err="missing '${opt_arch_prefix}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 @@ -1010,10 +1016,10 @@ fi if [ -z "$vmlinux" ] || [ ! -r "$vmlinux" ]; then [ -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) + vmlinux_version=$("${opt_arch_prefix}strings" "$vmlinux" 2>/dev/null | grep '^Linux version ' | head -1) if [ -z "$vmlinux_version" ]; then # try harder with some kernels (such as Red Hat) that don't have ^Linux version before their version string - vmlinux_version=$(strings "$vmlinux" 2>/dev/null | grep -E '^[[:alnum:]][^[:space:]]+ \([^[:space:]]+\) #[0-9]+ .+ (19|20)[0-9][0-9]$' | head -1) + vmlinux_version=$("${opt_arch_prefix}strings" "$vmlinux" 2>/dev/null | grep -E '^[[:alnum:]][^[:space:]]+ \([^[:space:]]+\) #[0-9]+ .+ (19|20)[0-9][0-9]$' | head -1) fi if [ -n "$vmlinux_version" ]; then # in live mode, check if the img we found is the correct one @@ -1292,7 +1298,7 @@ check_cpu() val=$ret val_cap_msr=$capabilities else - if [ "$ret" -eq "$val" -a "$capabilities" -eq "$val_cap_msr" ]; then + if [ "$ret" -eq "$val" ] && [ "$capabilities" -eq "$val_cap_msr" ]; then continue else cpu_mismatch=1 @@ -1361,7 +1367,7 @@ 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 + if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then redhat_canonical_spectre=-1 elif [ -n "$vmlinux_err" ]; then redhat_canonical_spectre=-2 @@ -1370,7 +1376,7 @@ check_redhat_canonical_spectre() # 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 + if "${opt_arch_prefix}strings" "$vmlinux" | grep -qw noibrs && "${opt_arch_prefix}strings" "$vmlinux" | grep -qw noibpb; then _debug "found redhat/canonical version of the variant2 patch (implies variant1)" redhat_canonical_spectre=1 else @@ -1433,7 +1439,7 @@ check_variant1() _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" + pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package" elif [ "$redhat_canonical_spectre" = -2 ]; then pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)" elif [ "$redhat_canonical_spectre" = 1 ]; then @@ -1449,8 +1455,8 @@ check_variant1() if [ -n "$vmlinux_err" ]; then pstatus yellow UNKNOWN "couldn't check ($vmlinux_err)" else - if ! which objdump >/dev/null 2>&1; then - pstatus yellow UNKNOWN "missing 'objdump' tool, please install it, usually it's in the binutils package" + if ! which "${opt_arch_prefix}objdump" >/dev/null 2>&1; then + pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package" else # here we disassemble the kernel and count the number of occurrences of the LFENCE opcode # in non-patched kernels, this has been empirically determined as being around 40-50 @@ -1459,7 +1465,7 @@ check_variant1() # so let's push the threshold to 70. # v0.33+: now only count lfence opcodes after a jump, way less error-prone # non patched kernel have between 0 and 20 matches, patched ones have at least 40-45 - nb_lfence=$(objdump -d "$vmlinux" | grep -w -B1 lfence | grep -Ewc 'jmp|jne|je') + nb_lfence=$("${opt_arch_prefix}objdump" -d "$vmlinux" | grep -w -B1 lfence | grep -Ewc 'jmp|jne|je') if [ "$nb_lfence" -lt 30 ]; then pstatus red NO "only $nb_lfence jump-then-lfence instructions found, should be >= 30 (heuristic)" else @@ -1716,9 +1722,9 @@ check_variant2() fi elif [ -n "$vmlinux" ]; then # look for the symbol - if which nm >/dev/null 2>&1; then + if which "${opt_arch_prefix}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 + if "${opt_arch_prefix}nm" "$vmlinux" 2>/dev/null | grep -qw 'noretpoline_setup'; then retpoline_compiler=1 pstatus green YES "noretpoline_setup found in vmlinux symbols" else @@ -1827,10 +1833,10 @@ check_variant3() # 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 ! which strings >/dev/null 2>&1; then - pstatus yellow UNKNOWN "missing 'strings' tool, please install it, usually it's in the binutils package" + if ! which "${opt_arch_prefix}strings" >/dev/null 2>&1; then + pstatus yellow UNKNOWN "missing '${opt_arch_prefix}strings' tool, please install it, usually it's in the binutils package" else - if strings "$vmlinux" | grep -qw nopti; then + if "${opt_arch_prefix}strings" "$vmlinux" | grep -qw nopti; then _debug "kpti_support: found nopti string in $vmlinux" kpti_support=1 fi