mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2025-04-19 12:45:17 +02:00
feat: add --allow-msr-write, no longer write by default (#385), detect when writing is denied
This commit is contained in:
parent
ee266d43b7
commit
2a5b965b98
@ -91,6 +91,7 @@ show_usage()
|
|||||||
--hw-only only check for CPU information, don't check for any variant
|
--hw-only only check for CPU information, don't check for any variant
|
||||||
--no-hw skip CPU information and checks, if you're inspecting a kernel not to be run on this host
|
--no-hw skip CPU information and checks, if you're inspecting a kernel not to be run on this host
|
||||||
--vmm [auto,yes,no] override the detection of the presence of a hypervisor, default: auto
|
--vmm [auto,yes,no] override the detection of the presence of a hypervisor, default: auto
|
||||||
|
--allow-msr-write allow probing for write-only MSRs, this might produce kernel logs or be blocked by your system
|
||||||
--cpu [#,all] interact with CPUID and MSR of CPU core number #, or all (default: CPU core 0)
|
--cpu [#,all] interact with CPUID and MSR of CPU core number #, or all (default: CPU core 0)
|
||||||
--update-fwdb update our local copy of the CPU microcodes versions database (using the awesome
|
--update-fwdb update our local copy of the CPU microcodes versions database (using the awesome
|
||||||
MCExtractor project and the Intel firmwares GitHub repository)
|
MCExtractor project and the Intel firmwares GitHub repository)
|
||||||
@ -157,6 +158,7 @@ opt_arch_prefix=''
|
|||||||
opt_hw_only=0
|
opt_hw_only=0
|
||||||
opt_no_hw=0
|
opt_no_hw=0
|
||||||
opt_vmm=-1
|
opt_vmm=-1
|
||||||
|
opt_allow_msr_write=0
|
||||||
opt_cpu=0
|
opt_cpu=0
|
||||||
opt_explain=0
|
opt_explain=0
|
||||||
opt_paranoid=0
|
opt_paranoid=0
|
||||||
@ -1047,6 +1049,9 @@ while [ -n "${1:-}" ]; do
|
|||||||
elif [ "$1" = "--no-hw" ]; then
|
elif [ "$1" = "--no-hw" ]; then
|
||||||
opt_no_hw=1
|
opt_no_hw=1
|
||||||
shift
|
shift
|
||||||
|
elif [ "$1" = "--allow-msr-write" ]; then
|
||||||
|
opt_allow_msr_write=1
|
||||||
|
shift
|
||||||
elif [ "$1" = "--cpu" ]; then
|
elif [ "$1" = "--cpu" ]; then
|
||||||
opt_cpu=$2
|
opt_cpu=$2
|
||||||
if [ "$opt_cpu" != all ]; then
|
if [ "$opt_cpu" != all ]; then
|
||||||
@ -2497,6 +2502,7 @@ write_msr_one_core()
|
|||||||
return $WRITE_MSR_RET_ERR
|
return $WRITE_MSR_RET_ERR
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
_write_denied=0
|
||||||
if [ "$os" != Linux ]; then
|
if [ "$os" != Linux ]; then
|
||||||
cpucontrol -m "$_msr=0" "/dev/cpuctl$_core" >/dev/null 2>&1; ret=$?
|
cpucontrol -m "$_msr=0" "/dev/cpuctl$_core" >/dev/null 2>&1; ret=$?
|
||||||
else
|
else
|
||||||
@ -2509,15 +2515,23 @@ write_msr_one_core()
|
|||||||
elif command -v wrmsr >/dev/null 2>&1 && [ "${SMC_NO_WRMSR:-}" != 1 ]; then
|
elif command -v wrmsr >/dev/null 2>&1 && [ "${SMC_NO_WRMSR:-}" != 1 ]; then
|
||||||
_debug "write_msr: using wrmsr"
|
_debug "write_msr: using wrmsr"
|
||||||
wrmsr $_msr_dec 0 2>/dev/null; ret=$?
|
wrmsr $_msr_dec 0 2>/dev/null; ret=$?
|
||||||
|
# ret=4: msr doesn't exist, ret=127: msr.allow_writes=off
|
||||||
|
[ "$ret" = 127 ] && _write_denied=1
|
||||||
|
# or fallback to dd if it supports seek_bytes, we prefer it over perl because we can tell the difference between EPERM and EIO
|
||||||
|
elif dd if=/dev/null of=/dev/null bs=8 count=1 seek="$_msr_dec" oflag=seek_bytes 2>/dev/null && [ "${SMC_NO_DD:-}" != 1 ]; then
|
||||||
|
_debug "write_msr: using dd"
|
||||||
|
dd if=/dev/zero of=/dev/cpu/"$_core"/msr bs=8 count=1 seek="$_msr_dec" oflag=seek_bytes 2>/dev/null; ret=$?
|
||||||
|
# if it failed, inspect stderrto look for EPERM
|
||||||
|
if [ "$ret" != 0 ]; then
|
||||||
|
if dd if=/dev/zero of=/dev/cpu/"$_core"/msr bs=8 count=1 seek="$_msr_dec" oflag=seek_bytes 2>&1 | grep -qF 'Operation not permitted'; then
|
||||||
|
_write_denied=1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
# or if we have perl, use it, any 5.x version will work
|
# or if we have perl, use it, any 5.x version will work
|
||||||
elif command -v perl >/dev/null 2>&1 && [ "${SMC_NO_PERL:-}" != 1 ]; then
|
elif command -v perl >/dev/null 2>&1 && [ "${SMC_NO_PERL:-}" != 1 ]; then
|
||||||
_debug "write_msr: using perl"
|
_debug "write_msr: using perl"
|
||||||
ret=1
|
ret=1
|
||||||
perl -e "open(M,'>','/dev/cpu/$_core/msr') and seek(M,$_msr_dec,0) and exit(syswrite(M,pack('H16',0)))"; [ $? -eq 8 ] && ret=0
|
perl -e "open(M,'>','/dev/cpu/$_core/msr') and seek(M,$_msr_dec,0) and exit(syswrite(M,pack('H16',0)))"; [ $? -eq 8 ] && ret=0
|
||||||
# fallback to dd if it supports seek_bytes
|
|
||||||
elif dd if=/dev/null of=/dev/null bs=8 count=1 seek="$_msr_dec" oflag=seek_bytes 2>/dev/null; then
|
|
||||||
_debug "write_msr: using dd"
|
|
||||||
dd if=/dev/zero of=/dev/cpu/"$_core"/msr bs=8 count=1 seek="$_msr_dec" oflag=seek_bytes 2>/dev/null; ret=$?
|
|
||||||
else
|
else
|
||||||
_debug "write_msr: got no wrmsr, perl or recent enough dd!"
|
_debug "write_msr: got no wrmsr, perl or recent enough dd!"
|
||||||
mockme=$(printf "%b\n%b" "$mockme" "SMC_MOCK_WRMSR_${_msr}_RET=$WRITE_MSR_RET_ERR")
|
mockme=$(printf "%b\n%b" "$mockme" "SMC_MOCK_WRMSR_${_msr}_RET=$WRITE_MSR_RET_ERR")
|
||||||
@ -2531,7 +2545,15 @@ write_msr_one_core()
|
|||||||
# when this happens, any write will fail and dmesg will have a msg printed "msr: Direct access to MSR"
|
# when this happens, any write will fail and dmesg will have a msg printed "msr: Direct access to MSR"
|
||||||
# * A version of this patch also made it to vanilla in 5.4+, in that case the message is: 'raw MSR access is restricted'
|
# * A version of this patch also made it to vanilla in 5.4+, in that case the message is: 'raw MSR access is restricted'
|
||||||
# * we don't use dmesg_grep() because we don't care if dmesg is truncated here, as the message has just been printed
|
# * we don't use dmesg_grep() because we don't care if dmesg is truncated here, as the message has just been printed
|
||||||
if dmesg | grep -qF "msr: Direct access to MSR"; then
|
# yet more recent versions of the msr module can be set to msr.allow_writes=off, in which case no dmesg message is printed,
|
||||||
|
# but the write fails
|
||||||
|
if [ "$_write_denied" = 1 ]; then
|
||||||
|
_debug "write_msr: writing to msr has been denied"
|
||||||
|
mockme=$(printf "%b\n%b" "$mockme" "SMC_MOCK_WRMSR_${_msr}_RET=$WRITE_MSR_RET_LOCKDOWN")
|
||||||
|
msr_locked_down=1
|
||||||
|
write_msr_msg="your kernel is configured to deny writes to MSRs from user space"
|
||||||
|
return $WRITE_MSR_RET_LOCKDOWN
|
||||||
|
elif dmesg | grep -qF "msr: Direct access to MSR"; then
|
||||||
_debug "write_msr: locked down kernel detected (Red Hat / Fedora)"
|
_debug "write_msr: locked down kernel detected (Red Hat / Fedora)"
|
||||||
mockme=$(printf "%b\n%b" "$mockme" "SMC_MOCK_WRMSR_${_msr}_RET=$WRITE_MSR_RET_LOCKDOWN")
|
mockme=$(printf "%b\n%b" "$mockme" "SMC_MOCK_WRMSR_${_msr}_RET=$WRITE_MSR_RET_LOCKDOWN")
|
||||||
msr_locked_down=1
|
msr_locked_down=1
|
||||||
@ -2544,6 +2566,7 @@ write_msr_one_core()
|
|||||||
write_msr_msg="your kernel is locked down, please reboot with lockdown=none in the kernel cmdline and retry"
|
write_msr_msg="your kernel is locked down, please reboot with lockdown=none in the kernel cmdline and retry"
|
||||||
return $WRITE_MSR_RET_LOCKDOWN
|
return $WRITE_MSR_RET_LOCKDOWN
|
||||||
fi
|
fi
|
||||||
|
unset _write_denied
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -2754,6 +2777,8 @@ check_cpu()
|
|||||||
|
|
||||||
# IBPB
|
# IBPB
|
||||||
_info " * Indirect Branch Prediction Barrier (IBPB)"
|
_info " * Indirect Branch Prediction Barrier (IBPB)"
|
||||||
|
|
||||||
|
if [ "$opt_allow_msr_write" = 1 ]; then
|
||||||
_info_nol " * PRED_CMD MSR is available: "
|
_info_nol " * PRED_CMD MSR is available: "
|
||||||
# the new MSR 'PRED_CTRL' is at offset 0x49, write-only
|
# the new MSR 'PRED_CTRL' is at offset 0x49, write-only
|
||||||
write_msr 0x49; ret=$?
|
write_msr 0x49; ret=$?
|
||||||
@ -2764,6 +2789,7 @@ check_cpu()
|
|||||||
else
|
else
|
||||||
pstatus yellow UNKNOWN "$write_msr_msg"
|
pstatus yellow UNKNOWN "$write_msr_msg"
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
_info_nol " * CPU indicates IBPB capability: "
|
_info_nol " * CPU indicates IBPB capability: "
|
||||||
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
|
# CPUID EAX=0x80000008, ECX=0x00 return EBX[12] indicates support for just IBPB.
|
||||||
@ -2912,6 +2938,8 @@ check_cpu()
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
_info " * L1 data cache invalidation"
|
_info " * L1 data cache invalidation"
|
||||||
|
|
||||||
|
if [ "$opt_allow_msr_write" = 1 ]; then
|
||||||
_info_nol " * FLUSH_CMD MSR is available: "
|
_info_nol " * FLUSH_CMD MSR is available: "
|
||||||
# the new MSR 'FLUSH_CMD' is at offset 0x10b, write-only
|
# the new MSR 'FLUSH_CMD' is at offset 0x10b, write-only
|
||||||
write_msr 0x10b; ret=$?
|
write_msr 0x10b; ret=$?
|
||||||
@ -2925,6 +2953,7 @@ check_cpu()
|
|||||||
pstatus yellow UNKNOWN "$write_msr_msg"
|
pstatus yellow UNKNOWN "$write_msr_msg"
|
||||||
cpu_flush_cmd=-1
|
cpu_flush_cmd=-1
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# CPUID of L1D
|
# CPUID of L1D
|
||||||
_info_nol " * CPU indicates L1D flush capability: "
|
_info_nol " * CPU indicates L1D flush capability: "
|
||||||
@ -2940,6 +2969,12 @@ check_cpu()
|
|||||||
cpuid_l1df=-1
|
cpuid_l1df=-1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# if we weren't allowed to probe the write-only MSR but the CPUID
|
||||||
|
# bit says that it shoul be there, make the assumption that it is
|
||||||
|
if [ "$opt_allow_msr_write" != 1 ]; then
|
||||||
|
cpu_flush_cmd=$cpuid_l1df
|
||||||
|
fi
|
||||||
|
|
||||||
if is_intel; then
|
if is_intel; then
|
||||||
_info " * Microarchitectural Data Sampling"
|
_info " * Microarchitectural Data Sampling"
|
||||||
_info_nol " * VERW instruction is available: "
|
_info_nol " * VERW instruction is available: "
|
||||||
|
Loading…
x
Reference in New Issue
Block a user