From ecdc4485310d88da31fca10ff52890cb3fb8bb81 Mon Sep 17 00:00:00 2001 From: Alex Date: Sat, 17 Mar 2018 09:17:15 -0700 Subject: [PATCH] Check MSR in each CPU/Thread (#136) --- spectre-meltdown-checker.sh | 120 ++++++++++++++++++++++++++++++++---- 1 file changed, 109 insertions(+), 11 deletions(-) diff --git a/spectre-meltdown-checker.sh b/spectre-meltdown-checker.sh index a3c35eb..780d91f 100755 --- a/spectre-meltdown-checker.sh +++ b/spectre-meltdown-checker.sh @@ -1059,6 +1059,38 @@ sys_interface_check() return 0 } +number_of_cpus() +{ + n=$(grep -c ^processor /proc/cpuinfo) + return "$n" +} + +# $1 - msr number +# $2 - cpu index +check_msr_enable() +{ + dd if=/dev/cpu/"$2"/msr of=/dev/null bs=8 count=1 skip="$1" iflag=skip_bytes 2>/dev/null; ret=$? + return $ret +} + +# $1 - msr number +# $2 - cpu index +# $3 - value +write_to_msr() +{ + $echo_cmd -ne "$3" | dd of=/dev/cpu/"$2"/msr bs=8 count=1 seek="$1" oflag=seek_bytes 2>/dev/null; ret=$? + return $ret +} + +# $1 - msr number +# $2 - cpu index +read_msr() +{ + msr=$(dd if=/dev/cpu/"$2"/msr bs=8 count=1 skip="$1" iflag=skip_bytes 2>/dev/null | od -t u1 -A n | awk '{print $8}'); + return "$msr" +} + + check_cpu() { _info "\033[1;34mHardware check\033[0m" @@ -1066,6 +1098,9 @@ check_cpu() _info "* Hardware support (CPU microcode) for mitigation techniques" _info " * Indirect Branch Restricted Speculation (IBRS)" _info_nol " * SPEC_CTRL MSR is available: " + number_of_cpus + ncpus=$? + idx_max_cpu=$((ncpus-1)) if [ ! -e /dev/cpu/0/msr ]; then # try to load the module ourselves (and remember it so we can rmmod it afterwards) load_msr @@ -1078,10 +1113,30 @@ check_cpu() # 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. bs has to be 8 for msr # skip=9 because 8*9=72=0x48 - dd if=/dev/cpu/0/msr of=/dev/null bs=8 count=1 skip=9 2>/dev/null; ret=$? - if [ $ret -eq 0 ]; then - spec_ctrl_msr=1 - pstatus green YES + val=0 + cpu_mismatch=0 + for i in $(seq 0 "$idx_max_cpu") + do + check_msr_enable 72 "$i" + ret=$? + if [ "$i" -eq 0 ]; then + val=$ret + else + if [ "$ret" -eq $val ]; then + continue + else + cpu_mismatch=1 + fi + fi + done + if [ $val -eq 0 ]; then + if [ $cpu_mismatch -eq 0 ]; then + spec_ctrl_msr=1 + pstatus green YES + else + spec_ctrl_msr=1 + pstatus green YES "But not in all CPUs" + fi else spec_ctrl_msr=0 pstatus red NO @@ -1126,15 +1181,34 @@ check_cpu() # the new MSR 'PRED_CTRL' is at offset 0x49, write-only # here we use dd, it's the same as using 'wrmsr 0x49 0' but without needing the wrmsr tool # if we get a write error, the MSR is not there - $echo_cmd -ne "\0\0\0\0\0\0\0\0" | dd of=/dev/cpu/0/msr bs=8 count=1 seek=73 oflag=seek_bytes 2>/dev/null; ret=$? - if [ $ret -eq 0 ]; then - pstatus green YES + val=0 + cpu_mismatch=0 + for i in $(seq 0 "$idx_max_cpu") + do + write_to_msr 73 "$i" "\0\0\0\0\0\0\0\0" + ret=$? + if [ "$i" -eq 0 ]; then + val=$ret + else + if [ "$ret" -eq $val ]; then + continue + else + cpu_mismatch=1 + fi + fi + done + + if [ $val -eq 0 ]; then + if [ $cpu_mismatch -eq 0 ]; then + pstatus green YES + else + pstatus green YES "But not in all CPUs" + fi else pstatus red NO fi fi - _info_nol " * CPU indicates IBPB capability: " # CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB. read_cpuid 2147483656 5 16; ret=$? @@ -1201,16 +1275,40 @@ check_cpu() # the new MSR 'ARCH_CAPABILITIES' is at offset 0x10a # here we use dd, it's the same as using 'rdmsr 0x10a' but without needing the rdmsr tool # if we get a read error, the MSR is not there. bs has to be 8 for msr - capabilities=$(dd if=/dev/cpu/0/msr bs=8 count=1 skip=266 iflag=skip_bytes 2>/dev/null | od -t u1 -A n | awk '{print $8}'); ret=$? + val=0 + val_cap_msr=0 + cpu_mismatch=0 + for i in $(seq 0 "$idx_max_cpu") + do + check_msr_enable 266 "$i" + ret=$? + read_msr 266 "$i" + capabilities=$? + if [ "$i" -eq 0 ]; then + val=$ret + val_cap_msr=$capabilities + else + if [ "$ret" -eq "$val" -a "$capabilities" -eq "$val_cap_msr" ]; then + continue + else + cpu_mismatch=1 + fi + fi + done + capabilities=$val_cap_msr capabilities_rdcl_no=0 capabilities_ibrs_all=0 - if [ $ret -eq 0 ]; then + if [ $val -eq 0 ]; then _debug "capabilities MSR lower byte is $capabilities (decimal)" [ $(( capabilities & 1 )) -eq 1 ] && capabilities_rdcl_no=1 [ $(( capabilities & 2 )) -eq 2 ] && capabilities_ibrs_all=1 _debug "capabilities says rdcl_no=$capabilities_rdcl_no ibrs_all=$capabilities_ibrs_all" if [ "$capabilities_ibrs_all" = 1 ]; then - pstatus green YES + if [ $cpu_mismatch -eq 0 ]; then + pstatus green YES + else: + pstatus green YES "But not in all CPUs" + fi else pstatus red NO fi