Compare commits

...

6 Commits

Author SHA1 Message Date
Stéphane Lesimple
954eb13468 enh: when reading CPUID is unavailable (VM?), fallback to cpuinfo where applicable
cap_* variable <= cpuinfo flag

cap_ibrs              <= ibrs
cap_ibpb              <= ibpb
cap_stibp             <= stibp
cap_ssbd              <= ssbd / virt_ssbd
cap_l1df              <= flush_l1d
cap_md_clear          <= md_clear
cap_arch_capabilities <= arch_capabilities

Should fix #288
2026-04-06 18:58:36 +02:00
Stéphane Lesimple
be91749d3a enh: read/write_msr: clearer error messages 2026-04-06 18:43:36 +02:00
Stéphane Lesimple
d040c0ffc3 fix: CVE-2017-5715 (Spectre V2): Red Hat specific fix for RSB Filling (fixes #235) 2026-04-06 17:40:59 +02:00
Stéphane Lesimple
c143bdb073 fix: read/write msr and lockdown: fix a variable error, properly report lockdown to users 2026-04-06 17:40:25 +02:00
Stéphane Lesimple
fc34cb729b fix: better compatibility under busybox, silence buggy unzlma versions (fix #432) 2026-04-06 17:12:21 +02:00
Stéphane Lesimple
fe5bf7c003 fix: wrmsr: specify core number (closes #294) 2026-04-06 17:01:17 +02:00
6 changed files with 170 additions and 35 deletions

View File

@@ -129,11 +129,54 @@ Never look at the microcode version to determine whether it has the proper mitig
**Exception**: When a vulnerability is fixed purely by a microcode update and the fix exposes **no** detectable CPUID bit, MSR bit, or ARCH\_CAP flag, then we must hardcode the known-fixing microcode versions for each affected CPU stepping. In this case, build a `<vuln>_ucode_list` table of `FF-MM-SS/platformid_mask,fixed_ucode_version` tuples (sourced from the Intel affected processor list and the Intel-Linux-Processor-Microcode-Data-Files release notes), match against `cpu_cpuid` + `cpu_platformid` in `is_cpu_affected()`, and store the required version in a `g_<vuln>_fixed_ucode_version` global. The CVE check then compares `cpu_ucode` against this threshold. Because Intel never lists EOL CPUs, the microcode list may be incomplete: keep a model blacklist as a fallback so that affected CPUs without a known fix are still flagged as affected (the CVE check should handle the empty `g_<vuln>_fixed_ucode_version` case by reporting VULN with "no microcode update available"). See Reptar (`g_reptar_fixed_ucode_version`) and BPI (`g_bpi_fixed_ucode_version`) for reference implementations.
### 4. Assume affected unless proven otherwise (whitelist approach)
### 4. `/proc/cpuinfo` fallback for CPUID reads
The primary way to read CPU capability bits is via `read_cpuid` (which uses `/dev/cpu/N/cpuid`). However, this device may be unavailable — most commonly inside virtual machines where the `cpuid` kernel module cannot be loaded. When `read_cpuid` returns `READ_CPUID_RET_ERR` (could not read at all), we can fall back to checking `/proc/cpuinfo` flags as a secondary source, **in live mode only**.
This works because the kernel always has direct access to CPUID (it doesn't need `/dev/cpu`), and exposes the results as flags in `/proc/cpuinfo`. When a hypervisor virtualizes a CPUID bit for the guest, the guest kernel sees it and reports it in `/proc/cpuinfo`. This is the same information `read_cpuid` would return if the device were available.
**Rules:**
- This is strictly a fallback: `read_cpuid` via `/dev/cpu/N/cpuid` remains the primary method.
- Only use it when `read_cpuid` returned `READ_CPUID_RET_ERR` (device unavailable), **never** when it returned `READ_CPUID_RET_KO` (device available but bit is 0 — meaning the CPU/hypervisor explicitly reports the feature as absent).
- Only in live mode (`$opt_live = 1`), since `/proc/cpuinfo` is not available in offline mode.
- Only for CPUID bits that the kernel exposes as `/proc/cpuinfo` flags. Not all bits have a corresponding flag — only those listed in the kernel's `capflags.c`. If a bit has no `/proc/cpuinfo` flag, no fallback is possible.
- The fallback depends on the running kernel being recent enough to know about the CPUID bit in question. An older kernel won't expose a flag it doesn't know about, so the fallback will silently not trigger — which is fine (we just stay at UNKNOWN, same as the ERR case without fallback).
**Known mappings** (CPUID bit → `/proc/cpuinfo` flag → script `cap_*` variable):
| CPUID source | `/proc/cpuinfo` flag | `cap_*` variable |
|---|---|---|
| Intel 0x7.0.EDX[26] / AMD 0x80000008.EBX[14] | `ibrs` | `cap_ibrs` |
| AMD 0x80000008.EBX[12] | `ibpb` | `cap_ibpb` |
| Intel 0x7.0.EDX[27] / AMD 0x80000008.EBX[15] | `stibp` | `cap_stibp` |
| Intel 0x7.0.EDX[31] / AMD 0x80000008.EBX[24,25] | `ssbd` / `virt_ssbd` | `cap_ssbd` |
| Intel 0x7.0.EDX[28] | `flush_l1d` | `cap_l1df` |
| Intel 0x7.0.EDX[10] | `md_clear` | `cap_md_clear` |
| Intel 0x7.0.EDX[29] | `arch_capabilities` | `cap_arch_capabilities` |
**Implementation pattern** in `check_cpu()`:
```sh
read_cpuid 0x7 0x0 $EDX 31 1 1
ret=$?
if [ $ret = $READ_CPUID_RET_OK ]; then
cap_ssbd='Intel SSBD'
elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw ssbd; then
cap_ssbd='Intel SSBD (cpuinfo)'
ret=$READ_CPUID_RET_OK
fi
fi
```
When the fallback sets a `cap_*` variable, append ` (cpuinfo)` to the value string so the output makes it clear the information was derived from `/proc/cpuinfo` rather than read directly from hardware. Update `ret` to `READ_CPUID_RET_OK` so downstream status display logic (`pstatus`) reports YES rather than UNKNOWN.
### 5. Assume affected unless proven otherwise (whitelist approach)
When a CPU is not explicitly known to be unaffected by a vulnerability, assume that it is affected. This conservative default has been the right call since the early Spectre/Meltdown days and remains sound.
### 5. Offline mode
### 6. Offline mode
The script can analyze a non-running kernel via `--kernel`, `--config`, `--map` flags, allowing verification before deployment.
@@ -167,6 +210,7 @@ Common traps to avoid:
| `xargs` | `-r` (no-op if empty, GNU only) | Guard with a prior `[ -n "..." ]` check, or accept the harmless empty invocation |
| `readlink` | `-f` (canonicalize, GNU only) | Use only in Linux-specific code paths, or reimplement with `cd`/`pwd` |
| `dd` | `iflag=`, `oflag=` (GNU only) | Use only in Linux-specific code paths (e.g. `/dev/cpu/*/msr`) |
| `base64` | `-w N` (set line-wrap width, GNU only; BusyBox doesn't support it) | Pipe through `tr -d '\n'` to remove newlines instead of `-w0` |
When a tool genuinely has no portable equivalent, restrict the non-portable call to a platform-specific code path (i.e. inside a BSD-only or Linux-only branch) and document why.

View File

@@ -88,7 +88,9 @@ try_decompress() {
fi
pos=${pos%%:*}
# shellcheck disable=SC2086
tail -c+$pos "$6" 2>/dev/null | $3 $4 >"$g_kerneltmp" 2>/dev/null
# wrap in subshell so that if $3 segfaults (e.g. old BusyBox unlzma on random data),
# the "Segmentation fault" message printed by the shell goes to /dev/null
(tail -c+$pos "$6" 2>/dev/null | $3 $4 >"$g_kerneltmp" 2>/dev/null) 2>/dev/null
ret=$?
if [ ! -s "$g_kerneltmp" ]; then
# don't rely on $ret, sometimes it's != 0 but worked

View File

@@ -5,20 +5,27 @@ readonly WRITE_MSR_RET_ERR=2
readonly WRITE_MSR_RET_LOCKDOWN=3
# Write a value to an MSR register across one or all cores
# Args: $1=msr_address $2=value(optional) $3=cpu_index(optional, default 0)
# Sets: ret_write_msr_msg
# Sets: ret_write_msr_msg, ret_write_msr_ADDR_msg (where ADDR is the hex address, e.g. ret_write_msr_0x123_msg)
# Returns: WRITE_MSR_RET_OK | WRITE_MSR_RET_KO | WRITE_MSR_RET_ERR | WRITE_MSR_RET_LOCKDOWN
write_msr() {
local ret core first_core_ret
local ret core first_core_ret msr_dec msr
msr_dec=$(($1))
msr=$(printf "0x%x" "$msr_dec")
if [ "$opt_cpu" != all ]; then
# we only have one core to write to, do it and return the result
write_msr_one_core "$opt_cpu" "$@"
return $?
ret=$?
# shellcheck disable=SC2163
eval "ret_write_msr_${msr}_msg=\$ret_write_msr_msg"
return $ret
fi
# otherwise we must write on all cores
for core in $(seq 0 "$g_max_core_id"); do
write_msr_one_core "$core" "$@"
ret=$?
# shellcheck disable=SC2163
eval "ret_write_msr_${msr}_msg=\$ret_write_msr_msg"
if [ "$core" = 0 ]; then
# save the result of the first core, for comparison with the others
first_core_ret=$ret
@@ -26,6 +33,8 @@ write_msr() {
# compare first core with the other ones
if [ "$first_core_ret" != "$ret" ]; then
ret_write_msr_msg="result is not homogeneous between all cores, at least core 0 and $core differ!"
# shellcheck disable=SC2163
eval "ret_write_msr_${msr}_msg=\$ret_write_msr_msg"
return $WRITE_MSR_RET_ERR
fi
fi
@@ -52,10 +61,17 @@ write_msr_one_core() {
mockvarname="SMC_MOCK_WRMSR_${msr}_RET"
# shellcheck disable=SC2086,SC1083
if [ -n "$(eval echo \${$mockvarname:-})" ]; then
pr_debug "write_msr: MOCKING enabled for msr $msr func returns $(eval echo \$$mockvarname)"
local mockret
mockret="$(eval echo \$$mockvarname)"
pr_debug "write_msr: MOCKING enabled for msr $msr func returns $mockret"
g_mocked=1
[ "$(eval echo \$$mockvarname)" = $WRITE_MSR_RET_LOCKDOWN ] && g_msr_locked_down=1
return "$(eval echo \$$mockvarname)"
if [ "$mockret" = "$WRITE_MSR_RET_LOCKDOWN" ]; then
g_msr_locked_down=1
ret_write_msr_msg="kernel lockdown is enabled, MSR writes are restricted"
elif [ "$mockret" = "$WRITE_MSR_RET_ERR" ]; then
ret_write_msr_msg="could not write MSR"
fi
return "$mockret"
fi
# proactive lockdown detection via sysfs (vanilla 5.4+, CentOS 8+, Rocky 9+):
@@ -76,7 +92,7 @@ write_msr_one_core() {
load_msr
fi
if [ ! -e $CPU_DEV_BASE/0/msr ] && [ ! -e ${BSD_CPUCTL_DEV_BASE}0 ]; then
ret_read_msr_msg="is msr kernel module available?"
ret_write_msr_msg="msr kernel module is not available"
return $WRITE_MSR_RET_ERR
fi
@@ -86,14 +102,13 @@ write_msr_one_core() {
ret=$?
else
# for Linux
# convert to decimal
if [ ! -w $CPU_DEV_BASE/"$core"/msr ]; then
ret_write_msr_msg="No write permission on $CPU_DEV_BASE/$core/msr"
return $WRITE_MSR_RET_ERR
# if wrmsr is available, use it
elif command -v wrmsr >/dev/null 2>&1 && [ "${SMC_NO_WRMSR:-}" != 1 ]; then
pr_debug "write_msr: using wrmsr"
wrmsr $msr_dec $value_dec 2>/dev/null
wrmsr -p "$core" $msr_dec $value_dec 2>/dev/null
ret=$?
# ret=4: msr doesn't exist, ret=127: msr.allow_writes=off
[ "$ret" = 127 ] && write_denied=1
@@ -172,22 +187,31 @@ readonly MSR_IA32_MCU_OPT_CTRL=0x123
readonly READ_MSR_RET_OK=0
readonly READ_MSR_RET_KO=1
readonly READ_MSR_RET_ERR=2
readonly READ_MSR_RET_LOCKDOWN=3
# Read an MSR register value across one or all cores
# Args: $1=msr_address $2=cpu_index(optional, default 0)
# Sets: ret_read_msr_value, ret_read_msr_value_hi, ret_read_msr_value_lo, ret_read_msr_msg
# Returns: READ_MSR_RET_OK | READ_MSR_RET_KO | READ_MSR_RET_ERR
# Sets: ret_read_msr_value, ret_read_msr_value_hi, ret_read_msr_value_lo, ret_read_msr_msg,
# ret_read_msr_ADDR_msg (where ADDR is the hex address, e.g. ret_read_msr_0x10a_msg)
# Returns: READ_MSR_RET_OK | READ_MSR_RET_KO | READ_MSR_RET_ERR | READ_MSR_RET_LOCKDOWN
read_msr() {
local ret core first_core_ret first_core_value
local ret core first_core_ret first_core_value msr_dec msr
msr_dec=$(($1))
msr=$(printf "0x%x" "$msr_dec")
if [ "$opt_cpu" != all ]; then
# we only have one core to read, do it and return the result
read_msr_one_core "$opt_cpu" "$@"
return $?
ret=$?
# shellcheck disable=SC2163
eval "ret_read_msr_${msr}_msg=\$ret_read_msr_msg"
return $ret
fi
# otherwise we must read all cores
for core in $(seq 0 "$g_max_core_id"); do
read_msr_one_core "$core" "$@"
ret=$?
# shellcheck disable=SC2163
eval "ret_read_msr_${msr}_msg=\$ret_read_msr_msg"
if [ "$core" = 0 ]; then
# save the result of the first core, for comparison with the others
first_core_ret=$ret
@@ -196,6 +220,8 @@ read_msr() {
# compare first core with the other ones
if [ "$first_core_ret" != "$ret" ] || [ "$first_core_value" != "$ret_read_msr_value" ]; then
ret_read_msr_msg="result is not homogeneous between all cores, at least core 0 and $core differ!"
# shellcheck disable=SC2163
eval "ret_read_msr_${msr}_msg=\$ret_read_msr_msg"
return $READ_MSR_RET_ERR
fi
fi
@@ -207,7 +233,7 @@ read_msr() {
# Read an MSR register value from a single CPU core
# Args: $1=core $2=msr_address
# Sets: ret_read_msr_value, ret_read_msr_value_hi, ret_read_msr_value_lo, ret_read_msr_msg
# Returns: READ_MSR_RET_OK | READ_MSR_RET_KO | READ_MSR_RET_ERR
# Returns: READ_MSR_RET_OK | READ_MSR_RET_KO | READ_MSR_RET_ERR | READ_MSR_RET_LOCKDOWN
read_msr_one_core() {
local ret core msr msr_dec mockvarname msr_h msr_l mockval
core="$1"
@@ -239,21 +265,28 @@ read_msr_one_core() {
mockvarname="SMC_MOCK_RDMSR_${msr}_RET"
# shellcheck disable=SC2086,SC1083
if [ -n "$(eval echo \${$mockvarname:-})" ] && [ "$(eval echo \$$mockvarname)" -ne 0 ]; then
pr_debug "read_msr: MOCKING enabled for msr $msr func returns $(eval echo \$$mockvarname)"
local mockret
mockret="$(eval echo \$$mockvarname)"
pr_debug "read_msr: MOCKING enabled for msr $msr func returns $mockret"
g_mocked=1
return "$(eval echo \$$mockvarname)"
if [ "$mockret" = "$READ_MSR_RET_LOCKDOWN" ]; then
ret_read_msr_msg="kernel lockdown is enabled, MSR reads are restricted"
elif [ "$mockret" = "$READ_MSR_RET_ERR" ]; then
ret_read_msr_msg="could not read MSR"
fi
return "$mockret"
fi
# proactive lockdown detection via sysfs (vanilla 5.4+, CentOS 8+, Rocky 9+):
# if the kernel lockdown is set to integrity or confidentiality, MSR writes will be denied,
# so we can skip the write attempt entirely and avoid relying on dmesg parsing
# if the kernel lockdown is set to integrity or confidentiality, MSR reads will be denied,
# so we can skip the read attempt entirely and avoid relying on dmesg parsing
if [ -e "$SYSKERNEL_BASE/security/lockdown" ]; then
if grep -qE '\[integrity\]|\[confidentiality\]' "$SYSKERNEL_BASE/security/lockdown" 2>/dev/null; then
pr_debug "write_msr: kernel lockdown detected via $SYSKERNEL_BASE/security/lockdown"
g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_WRMSR_${msr}_RET=$WRITE_MSR_RET_LOCKDOWN")
pr_debug "read_msr: kernel lockdown detected via $SYSKERNEL_BASE/security/lockdown"
g_mockme=$(printf "%b\n%b" "$g_mockme" "SMC_MOCK_RDMSR_${msr}_RET=$READ_MSR_RET_LOCKDOWN")
g_msr_locked_down=1
ret_write_msr_msg="your kernel is locked down, please reboot with lockdown=none in the kernel cmdline and retry"
return $WRITE_MSR_RET_LOCKDOWN
ret_read_msr_msg="kernel lockdown is enabled, MSR reads are restricted"
return $READ_MSR_RET_LOCKDOWN
fi
fi
@@ -262,7 +295,7 @@ read_msr_one_core() {
load_msr
fi
if [ ! -e $CPU_DEV_BASE/0/msr ] && [ ! -e ${BSD_CPUCTL_DEV_BASE}0 ]; then
ret_read_msr_msg="is msr kernel module available?"
ret_read_msr_msg="msr kernel module is not available"
return $READ_MSR_RET_ERR
fi

View File

@@ -446,6 +446,15 @@ check_cpu() {
ret=invalid
pstatus yellow NO "unknown CPU"
fi
if [ -z "$cap_ibrs" ] && [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw ibrs; then
cap_ibrs='IBRS (cpuinfo)'
cap_spec_ctrl=1
pstatus green YES "ibrs flag in $g_procfs/cpuinfo"
ret=$READ_CPUID_RET_OK
fi
fi
if [ $ret = $READ_CPUID_RET_KO ]; then
pstatus yellow NO
elif [ $ret = $READ_CPUID_RET_ERR ]; then
@@ -514,6 +523,10 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then
cap_ibpb='IBPB_SUPPORT'
pstatus green YES "IBPB_SUPPORT feature bit"
elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw ibpb; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
cap_ibpb='IBPB (cpuinfo)'
pstatus green YES "ibpb flag in $g_procfs/cpuinfo"
elif [ $ret = $READ_CPUID_RET_KO ]; then
pstatus yellow NO
else
@@ -549,7 +562,7 @@ check_cpu() {
elif [ "$spec_ctrl_msr" = 0 ]; then
pstatus yellow NO
else
pstatus yellow UNKNOWN "is msr kernel module available?"
pstatus yellow UNKNOWN "$ret_read_msr_msg"
fi
pr_info_nol " * CPU indicates STIBP capability: "
@@ -581,6 +594,14 @@ check_cpu() {
ret=invalid
pstatus yellow UNKNOWN "unknown CPU"
fi
if [ -z "$cap_stibp" ] && [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw stibp; then
cap_stibp='STIBP (cpuinfo)'
pstatus green YES "stibp flag in $g_procfs/cpuinfo"
ret=$READ_CPUID_RET_OK
fi
fi
if [ $ret = $READ_CPUID_RET_KO ]; then
pstatus yellow NO
elif [ $ret = $READ_CPUID_RET_ERR ]; then
@@ -645,6 +666,15 @@ check_cpu() {
fi
fi
if [ -z "$cap_ssbd" ] && [ "$ret24" = $READ_CPUID_RET_ERR ] && [ "$ret25" = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ]; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
if grep ^flags "$g_procfs/cpuinfo" | grep -qw ssbd; then
cap_ssbd='SSBD (cpuinfo)'
elif grep ^flags "$g_procfs/cpuinfo" | grep -qw virt_ssbd; then
cap_ssbd='SSBD in VIRT_SPEC_CTRL (cpuinfo)'
fi
fi
if [ -n "${cap_ssbd:=}" ]; then
pstatus green YES "$cap_ssbd"
elif [ "$ret24" = $READ_CPUID_RET_ERR ] && [ "$ret25" = $READ_CPUID_RET_ERR ]; then
@@ -700,6 +730,10 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then
pstatus green YES "L1D flush feature bit"
cap_l1df=1
elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw flush_l1d; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
pstatus green YES "flush_l1d flag in $g_procfs/cpuinfo"
cap_l1df=1
elif [ $ret = $READ_CPUID_RET_KO ]; then
pstatus yellow NO
cap_l1df=0
@@ -716,6 +750,10 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then
cap_md_clear=1
pstatus green YES "MD_CLEAR feature bit"
elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
cap_md_clear=1
pstatus green YES "md_clear flag in $g_procfs/cpuinfo"
elif [ $ret = $READ_CPUID_RET_KO ]; then
cap_md_clear=0
pstatus yellow NO
@@ -782,6 +820,10 @@ check_cpu() {
if [ $ret = $READ_CPUID_RET_OK ]; then
pstatus green YES
cap_arch_capabilities=1
elif [ $ret = $READ_CPUID_RET_ERR ] && [ "$opt_live" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw arch_capabilities; then
# CPUID device unavailable (e.g. in a VM): fall back to /proc/cpuinfo
pstatus green YES "arch_capabilities flag in $g_procfs/cpuinfo"
cap_arch_capabilities=1
elif [ $ret = $READ_CPUID_RET_KO ]; then
pstatus yellow NO
cap_arch_capabilities=0
@@ -974,7 +1016,8 @@ check_cpu() {
elif [ "$cap_tsx_ctrl_rtm_disable" = 0 ]; then
pstatus blue NO
else
pstatus yellow UNKNOWN "couldn't read MSR"
# shellcheck disable=SC2154
pstatus yellow UNKNOWN "$ret_read_msr_0x122_msg"
fi
pr_info_nol " * TSX_CTRL MSR indicates TSX CPUID bit is cleared: "
@@ -983,7 +1026,8 @@ check_cpu() {
elif [ "$cap_tsx_ctrl_cpuid_clear" = 0 ]; then
pstatus blue NO
else
pstatus yellow UNKNOWN "couldn't read MSR"
# shellcheck disable=SC2154
pstatus yellow UNKNOWN "$ret_read_msr_0x122_msg"
fi
fi
@@ -1008,7 +1052,8 @@ check_cpu() {
pr_info_nol " * GDS microcode mitigation is disabled (GDS_MITG_DIS): "
if [ "$cap_gds_mitg_dis" = -1 ]; then
pstatus yellow UNKNOWN "couldn't read MSR"
# shellcheck disable=SC2154
pstatus yellow UNKNOWN "$ret_read_msr_0x123_msg"
elif [ "$cap_gds_mitg_dis" = 1 ]; then
pstatus yellow YES
else
@@ -1017,7 +1062,8 @@ check_cpu() {
pr_info_nol " * GDS microcode mitigation is locked in enabled state (GDS_MITG_LOCK): "
if [ "$cap_gds_mitg_lock" = -1 ]; then
pstatus yellow UNKNOWN "couldn't read MSR"
# shellcheck disable=SC2154
pstatus yellow UNKNOWN "$ret_read_msr_0x123_msg"
elif [ "$cap_gds_mitg_lock" = 1 ]; then
pstatus blue YES
else
@@ -1205,7 +1251,8 @@ check_cpu() {
elif [ "$cap_tsx_force_abort_rtm_disable" = 0 ]; then
pstatus blue NO
else
pstatus yellow UNKNOWN "couldn't read MSR"
# shellcheck disable=SC2154
pstatus yellow UNKNOWN "$ret_read_msr_0x10f_msg"
fi
pr_info_nol " * TSX_FORCE_ABORT MSR indicates TSX CPUID bit is cleared: "
@@ -1214,7 +1261,8 @@ check_cpu() {
elif [ "$cap_tsx_force_abort_cpuid_clear" = 0 ]; then
pstatus blue NO
else
pstatus yellow UNKNOWN "couldn't read MSR"
# shellcheck disable=SC2154
pstatus yellow UNKNOWN "$ret_read_msr_0x10f_msg"
fi
fi

View File

@@ -35,7 +35,7 @@ if [ -n "$g_mockme" ] && [ "$opt_mock" = 1 ]; then
# not a useless use of cat: gzipping cpuinfo directly doesn't work well
# shellcheck disable=SC2002
if command -v "base64" >/dev/null 2>&1; then
g_mock_cpuinfo="$(cat /proc/cpuinfo | gzip -c | base64 -w0)"
g_mock_cpuinfo="$(cat /proc/cpuinfo | gzip -c | base64 | tr -d '\n')"
elif command -v "uuencode" >/dev/null 2>&1; then
g_mock_cpuinfo="$(cat /proc/cpuinfo | gzip -c | uuencode -m - | grep -Fv 'begin-base64' | grep -Fxv -- '====' | tr -d "\n")"
fi

View File

@@ -633,7 +633,15 @@ check_CVE_2017_5715_linux() {
fi
fi
if [ "$rsb_filling" = 0 ]; then
if [ -n "$g_kernel_err" ]; then
# Red Hat kernels (RHEL 6/7/8) stuff RSB on context switch as part of
# their retpoline implementation when retp_enabled=1, but don't use the
# upstream X86_FEATURE_RSB_CTXSW flag or "Filling RSB on context switch"
# string. Detect this via the RHEL-specific debugfs knob.
# See https://bugzilla.redhat.com/show_bug.cgi?id=1616245#c8
if [ "$retp_enabled" = 1 ]; then
rsb_filling=1
pstatus green YES "Red Hat kernel with retpoline enabled includes RSB filling"
elif [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
else
if grep -qw -e 'Filling RSB on context switch' "$g_kernel"; then