From ff5c92fa6fe3e5529600f6e712ca2c72c546c65b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Lesimple?= Date: Sun, 21 Jan 2018 18:02:11 +0100 Subject: [PATCH] feat(sysfs): print details even with sysfs Before, when the /sys kernel vulnerability interface was available, we would bypass all our tests and just print the output of the vulnerability interface. Now, we still rely on it when available, but we run our checks anyway, except for variant 1 where the current method of mitigation detection doesn't add much value to the bare /sys check --- spectre-meltdown-checker.sh | 71 +++++++++++++++++++++++++++---------- 1 file changed, 53 insertions(+), 18 deletions(-) diff --git a/spectre-meltdown-checker.sh b/spectre-meltdown-checker.sh index 74514e2..904cfbb 100755 --- a/spectre-meltdown-checker.sh +++ b/spectre-meltdown-checker.sh @@ -34,6 +34,7 @@ show_usage() --no-color Don't use color codes --verbose, -v Increase verbosity level --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) --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... @@ -91,6 +92,7 @@ opt_variant2=0 opt_variant3=0 opt_allvariants=1 opt_no_sysfs=0 +opt_sysfs_only=0 opt_coreos=0 global_critical=0 @@ -343,6 +345,9 @@ while [ -n "$1" ]; do elif [ "$1" = "--no-sysfs" ]; then opt_no_sysfs=1 shift + elif [ "$1" = "--sysfs-only" ]; then + opt_sysfs_only=1 + shift elif [ "$1" = "--coreos" ]; then opt_coreos=1 shift @@ -404,6 +409,11 @@ done show_header +if [ "$opt_no_sysfs" = 1 -a "$opt_sysfs_only" = 1 ]; then + _warn "Incompatible options specified (--no-sysfs and --sysfs-only), aborting" + exit 255 +fi + # print status function pstatus() { @@ -771,7 +781,7 @@ _info sys_interface_check() { [ "$opt_live" = 1 -a "$opt_no_sysfs" = 0 -a -r "$1" ] || return 1 - _info_nol "* Checking whether we're safe according to the /sys interface: " + _info_nol "* Mitigated according to the /sys interface: " if grep -qi '^not affected' "$1"; then # Not affected status=OK @@ -805,7 +815,7 @@ check_variant1() if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v1"; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 - else + elif [ "$opt_sysfs_only" != 1 ]; then # no /sys interface (or offline mode), fallback to our own ways _info_nol "* Checking count of LFENCE opcodes in kernel: " if [ -n "$vmlinux_err" ]; then @@ -835,6 +845,10 @@ check_variant1() fi fi fi + else + # we have no sysfs but were asked to use it only! + msg="/sys vulnerability interface use forced, but it's not available!" + status=UNK fi # if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it @@ -860,7 +874,8 @@ check_variant2() if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/spectre_v2"; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 - else + fi + if [ "$opt_sysfs_only" != 1 ]; then _info "* Mitigation 1" _info " * Hardware support (CPU microcode)" _info " * Indirect Branch Restricted Speculation (IBRS)" @@ -1109,13 +1124,22 @@ check_variant2() # See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79 # 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 "$opt_map" ]; then + if [ -e "/sys/devices/system/cpu/vulnerabilities/spectre_v2" ]; then + if grep -qw Minimal /sys/devices/system/cpu/vulnerabilities/spectre_v2; then + pstatus red NO "kernel reports minimal retpoline compilation" + elif grep -qw Full /sys/devices/system/cpu/vulnerabilities/spectre_v2; then + retpoline_compiler=1 + pstatus green YES "kernel reports full retpoline compilation" + else + pstatus yellow UNKNOWN + fi + elif [ -n "$opt_map" ]; then # look for the symbol if grep -qw noretpoline_setup "$opt_map"; then retpoline_compiler=1 pstatus green YES "noretpoline_setup symbol found in System.map" else - pstatus red NO + pstatus yellow UNKNOWN fi elif [ -n "$vmlinux" ]; then # look for the symbol @@ -1125,7 +1149,7 @@ check_variant2() retpoline_compiler=1 pstatus green YES "noretpoline_setup found in vmlinux symbols" else - pstatus red NO + pstatus yellow UNKNOWN fi elif grep -q noretpoline_setup "$vmlinux"; then # if we don't have nm, nevermind, the symbol name is long enough to not have @@ -1133,40 +1157,46 @@ check_variant2() retpoline_compiler=1 pstatus green YES "noretpoline_setup found in vmlinux" else - pstatus red NO + pstatus yellow UNKNOWN fi else pstatus yellow UNKNOWN "couldn't find your kernel image or System.map" fi + elif [ "$sys_interface_available" = 0 ]; then + # we have no sysfs but were asked to use it only! + msg="/sys vulnerability interface use forced, but it's not available!" + status=UNK fi + cve='CVE-2017-5715' # if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it if [ "$sys_interface_available" = 0 ] && ! is_cpu_vulnerable 2; then # override status & msg in case CPU is not vulnerable after all - pvulnstatus CVE-2017-5715 OK "your CPU vendor reported your CPU model as not vulnerable" + pvulnstatus $cve OK "your CPU vendor reported your CPU model as not vulnerable" elif [ -z "$msg" ]; then # if msg is empty, sysfs check didn't fill it, rely on our own test if [ "$retpoline" = 1 -a "$retpoline_compiler" = 1 ]; then - pvulnstatus CVE-2017-5715 OK "retpoline mitigate the vulnerability" + pvulnstatus $cve OK "retpoline mitigates the vulnerability" elif [ "$opt_live" = 1 ]; then if [ "$ibrs_enabled" = 1 -o "$ibrs_enabled" = 2 ] && [ "$ibpb_enabled" = 1 ]; then - pvulnstatus CVE-2017-5715 OK "IBRS/IBPB are mitigating the vulnerability" + pvulnstatus $cve OK "IBRS/IBPB are mitigating the vulnerability" elif [ "$ibpb_enabled" = 2 ]; then - pvulnstatus CVE-2017-5715 OK "Full IBPB is mitigating the vulnerability" + pvulnstatus $cve OK "Full IBPB is mitigating the vulnerability" else - pvulnstatus CVE-2017-5715 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 else if [ "$ibrs_supported" = 1 ]; then - pvulnstatus CVE-2017-5715 OK "offline mode: IBRS/IBPB will mitigate the vulnerability if enabled at runtime" + pvulnstatus $cve OK "offline mode: IBRS/IBPB will mitigate the vulnerability if enabled at runtime" elif [ "$ibrs_can_tell" = 1 ]; then - pvulnstatus CVE-2017-5715 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" else - pvulnstatus CVE-2017-5715 UNK "offline mode: not enough information" + pvulnstatus $cve UNK "offline mode: not enough information" fi fi else - pvulnstatus CVE-2017-5715 "$status" "$msg" + [ "$msg" = "Vulnerable" ] && msg="IBRS hardware + kernel support OR kernel with retpoline are needed to mitigate the vulnerability" + pvulnstatus $cve "$status" "$msg" fi } @@ -1182,7 +1212,7 @@ check_variant3() if sys_interface_check "/sys/devices/system/cpu/vulnerabilities/meltdown"; then # this kernel has the /sys interface, trust it over everything sys_interface_available=1 - else + elif [ "$opt_sysfs_only" != 1 ]; then _info_nol "* Kernel supports Page Table Isolation (PTI): " kpti_support=0 kpti_can_tell=0 @@ -1292,7 +1322,7 @@ check_variant3() if [ "$opt_live" = 1 ]; then # checking whether we're running under Xen PV 64 bits. If yes, we're not affected by variant3 - _info_nol "* Checking if we're running under Xen PV (64 bits): " + _info_nol "* Running under Xen PV (64 bits): " if [ "$(uname -m)" = "x86_64" ]; then # XXX do we have a better way that relying on dmesg? dmesg_grep 'Booting paravirtualized kernel on Xen$'; ret=$? @@ -1308,6 +1338,10 @@ check_variant3() pstatus blue NO fi fi + elif [ "$sys_interface_available" = 0 ]; then + # we have no sysfs but were asked to use it only! + msg="/sys vulnerability interface use forced, but it's not available!" + status=UNK fi # if we have the /sys interface, don't even check is_cpu_vulnerable ourselves, the kernel already does it @@ -1335,6 +1369,7 @@ check_variant3() fi fi else + [ "$msg" = "Vulnerable" ] && msg="PTI is needed to mitigate the vulnerability" pvulnstatus $cve "$status" "$msg" fi }