mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-06-06 06:33:04 +02:00
7329c1fd2f
CVE_REGISTRY gains an optional fifth field that tags checks as x86-only or arm-only, untagged entries apply everywhere. The main CVE dispatcher and the affectedness summary both skip gated entries in default "all CVEs" runs, removing the noise of arm64 errata on x86 hosts and of x86 CVEs on ARM hosts across text, json, nrpe and prometheus outputs. Explicit --cve/--variant/--errata selection bypasses the gate so manual queries still run anywhere. The gate honours no-hw mode by ignoring the host CPU and keying off the inspected kernel's architecture only, which handles cross-arch offline analysis driven by --kernel/--config/--map.
252 lines
13 KiB
Bash
252 lines
13 KiB
Bash
# vim: set ts=4 sw=4 sts=4 et:
|
|
# Print command-line usage information to stdout
|
|
show_usage() {
|
|
# shellcheck disable=SC2086
|
|
cat <<EOF
|
|
Modes:
|
|
* Live mode: $(basename $0) [options] [--kernel <kimage>] [--config <kconfig>] [--map <mapfile>]
|
|
Inspect the currently running kernel within the context of the CPU it's running on.
|
|
You can optionally specify --kernel, --config, or --map to help the script locate files it couldn't auto-detect
|
|
|
|
* No-runtime mode: $(basename $0) [options] --no-runtime <--kernel <kimage>> [--config <kconfig>] [--map <mapfile>]
|
|
Inspect the CPU hardware, but skips all running-kernel artifacts (/sys, /proc, dmesg).
|
|
Use this when you have a kernel image different from the kernel you're running but want to check it against this CPU.
|
|
|
|
* No-hardware mode: $(basename $0) [options] --no-hw <--kernel <kimage>> [--config <kconfig>] [--map <mapfile>]
|
|
Ignore both CPU hardware and running-kernel artifacts. Use this for pure static analysis of a kernel image,
|
|
for example when inspecting a kernel targeted for another system or CPU.
|
|
|
|
* Hardware-only mode: $(basename $0) [options] --hw-only
|
|
Only inspect the CPU hardware, and report information and affectedness per vulnerability.
|
|
|
|
Vulnerability selection:
|
|
--variant VARIANT specify which variant you'd like to check, by default all variants are checked.
|
|
can be used multiple times (e.g. --variant 3a --variant l1tf). For a list use 'help'.
|
|
--cve CVE specify which CVE you'd like to check, by default all supported CVEs are checked
|
|
can be used multiple times (e.g. --cve CVE-2017-5753 --cve CVE-2020-0543)
|
|
--errata NUMBER specify a vendor-numbered erratum (e.g. ARM64 erratum 1530923) that has no CVE
|
|
assigned. Maps the erratum to the corresponding check. For a list use 'help'.
|
|
Can be used multiple times (e.g. --errata 1530923 --errata 3194386).
|
|
|
|
Check scope:
|
|
--no-sysfs don't use the /sys interface even if present [Linux]
|
|
--sysfs-only only use the /sys interface, don't run our own checks [Linux]
|
|
|
|
Strictness:
|
|
--paranoid require all mitigations to be enabled to the fullest extent, including those that
|
|
are not strictly necessary but provide defense in depth (e.g. SMT disabled, IBPB
|
|
always-on); without this flag, the script follows the security community consensus
|
|
--extra run additional checks for issues that don't have a CVE but are still security-relevant,
|
|
such as compile-time mitigations not enabled by default (e.g. Straight-Line Speculation)
|
|
|
|
Hardware and platform:
|
|
--cpu [#,all] interact with CPUID and MSR of CPU core number #, or all (default: CPU core 0)
|
|
--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
|
|
--arch-prefix PREFIX specify a prefix for cross-inspecting a kernel of a different arch, for example "aarch64-linux-gnu-",
|
|
so that invoked tools will be prefixed with this (i.e. aarch64-linux-gnu-objdump)
|
|
--coreos special mode for CoreOS (use an ephemeral toolbox to inspect kernel) [Linux]
|
|
|
|
Output:
|
|
--batch FORMAT produce machine readable output; FORMAT is one of:
|
|
text (default), short, json, json-terse, nrpe, prometheus
|
|
--no-color don't use color codes
|
|
--verbose, -v increase verbosity level, possibly several times
|
|
--explain produce an additional human-readable explanation of actions to take to mitigate a vulnerability
|
|
|
|
Firmware database:
|
|
--update-fwdb update our local copy of the CPU microcodes versions database (using the awesome
|
|
MCExtractor project and the Intel firmwares GitHub repository)
|
|
--update-builtin-fwdb same as --update-fwdb but update builtin DB inside the script itself
|
|
|
|
Debug:
|
|
--dump-mock-data used to mimick a CPU on an other system, mainly used to help debugging this script
|
|
|
|
Return codes:
|
|
0 (not vulnerable), 2 (vulnerable), 3 (unknown), 255 (error)
|
|
|
|
IMPORTANT:
|
|
A false sense of security is worse than no security at all.
|
|
Please use the --disclaimer option to understand exactly what this script does.
|
|
|
|
EOF
|
|
}
|
|
|
|
# Print the legal disclaimer about tool accuracy and limitations
|
|
show_disclaimer() {
|
|
cat <<EOF
|
|
Disclaimer:
|
|
|
|
This tool does its best to determine whether your system is immune (or has proper mitigations in place) for the
|
|
collectively named "transient execution" (aka "speculative execution") vulnerabilities that started to appear
|
|
since early 2018 with the infamous Spectre & Meltdown.
|
|
|
|
This tool does NOT attempt to run any kind of exploit, and can't 100% guarantee that your system is secure,
|
|
but rather helps you verifying whether your system has the known correct mitigations in place.
|
|
However, some mitigations could also exist in your kernel that this script doesn't know (yet) how to detect, or it might
|
|
falsely detect mitigations that in the end don't work as expected (for example, on backported or modified kernels).
|
|
|
|
Your system affectability to a given vulnerability depends on your CPU model and CPU microcode version, whereas the
|
|
mitigations in place depend on your CPU (model and microcode), your kernel version, and both the runtime configuration
|
|
of your CPU (through bits set through the MSRs) and your kernel. The script attempts to explain everything for each
|
|
vulnerability, so you know where your system stands. For a given vulnerability, detailed information is sometimes
|
|
available using the \`--explain\` switch.
|
|
|
|
Please also note that for the Spectre-like vulnerabilities, all software can possibly be exploited, in which case
|
|
this tool only verifies that the kernel (which is the core of the system) you're using has the proper protections
|
|
in place. Verifying all the other software is out of the scope of this tool, as it can't be done in a simple way.
|
|
As a general measure, ensure you always have the most up to date stable versions of all the software you use,
|
|
especially for those who are exposed to the world, such as network daemons and browsers.
|
|
|
|
For more information and answers to related questions, please refer to the FAQ.md file.
|
|
|
|
This tool has been released in the hope that it'll be useful, but don't use it to jump to conclusions about your security.
|
|
|
|
EOF
|
|
}
|
|
|
|
g_os=$(uname -s)
|
|
|
|
# parse options
|
|
opt_kernel=''
|
|
opt_config=''
|
|
opt_map=''
|
|
opt_runtime=1
|
|
opt_no_color=0
|
|
opt_batch=0
|
|
opt_batch_format='text'
|
|
opt_verbose=1
|
|
opt_cve_list=''
|
|
opt_cve_all=1
|
|
opt_no_sysfs=0
|
|
opt_sysfs_only=0
|
|
opt_coreos=0
|
|
opt_arch_prefix=''
|
|
opt_hw_only=0
|
|
opt_no_hw=0
|
|
opt_vmm=-1
|
|
opt_allow_msr_write=0
|
|
opt_cpu=0
|
|
opt_explain=0
|
|
# Canonical run mode, set at the end of option parsing.
|
|
# Values: live, no-runtime, no-hw, hw-only
|
|
g_mode='live'
|
|
|
|
# Return 0 (true) if runtime state is accessible (procfs, sysfs, dmesg, debugfs).
|
|
# True in live and hw-only modes; false in no-runtime and no-hw modes.
|
|
has_runtime() { [ "$g_mode" = live ] || [ "$g_mode" = hw-only ]; }
|
|
opt_paranoid=0
|
|
opt_extra=0
|
|
opt_mock=0
|
|
|
|
g_critical=0
|
|
g_unknown=0
|
|
g_nrpe_total=0
|
|
g_nrpe_vuln_count=0
|
|
g_nrpe_unk_count=0
|
|
g_nrpe_vuln_ids=''
|
|
g_nrpe_vuln_details=''
|
|
g_nrpe_unk_details=''
|
|
g_smc_vuln_output=''
|
|
g_smc_ok_count=0
|
|
g_smc_vuln_count=0
|
|
g_smc_unk_count=0
|
|
g_smc_system_info_line=''
|
|
g_smc_cpu_info_line=''
|
|
|
|
# CVE Registry: single source of truth for all CVE metadata.
|
|
# Fields: cve_id|json_key_name|affected_var_suffix|complete_name_and_aliases|arch
|
|
#
|
|
# The optional `arch` field gates whether the check is run at all, based on the
|
|
# host CPU architecture and the inspected kernel architecture. Values:
|
|
# x86 - only relevant when host CPU or inspected kernel is x86/amd64
|
|
# arm - only relevant when host CPU or inspected kernel is ARM/ARM64
|
|
# (empty) - always relevant (shared logic across architectures, e.g. Spectre V1-V4)
|
|
# The gate only applies to default "all CVEs" runs; explicit --cve/--variant/--errata
|
|
# selection bypasses it (if the user asks for it, they get it regardless of arch).
|
|
#
|
|
# Three ranges of placeholder IDs are reserved when no real CVE applies:
|
|
# CVE-0000-NNNN: permanent placeholder for supplementary checks (--extra only)
|
|
# that will never receive a real CVE (e.g. SLS, compile-time hardening).
|
|
# CVE-0001-NNNN: permanent placeholder for vendor-numbered errata that will never
|
|
# receive a CVE (e.g. ARM64 silicon errata tracked only by erratum ID).
|
|
# Selectable via --errata <number>.
|
|
# CVE-9999-NNNN: temporary placeholder for real vulnerabilities awaiting CVE
|
|
# assignment. Rename across the codebase once the real CVE is issued.
|
|
readonly CVE_REGISTRY='
|
|
CVE-2017-5753|SPECTRE VARIANT 1|variant1|Spectre Variant 1, bounds check bypass|
|
|
CVE-2017-5715|SPECTRE VARIANT 2|variant2|Spectre Variant 2, branch target injection|
|
|
CVE-2017-5754|MELTDOWN|variant3|Variant 3, Meltdown, rogue data cache load|
|
|
CVE-2018-3640|VARIANT 3A|variant3a|Variant 3a, rogue system register read|
|
|
CVE-2018-3639|VARIANT 4|variant4|Variant 4, speculative store bypass|
|
|
CVE-2018-3615|L1TF SGX|variantl1tf_sgx|Foreshadow (SGX), L1 terminal fault|x86
|
|
CVE-2018-3620|L1TF OS|variantl1tf|Foreshadow-NG (OS), L1 terminal fault|x86
|
|
CVE-2018-3646|L1TF VMM|variantl1tf|Foreshadow-NG (VMM), L1 terminal fault|x86
|
|
CVE-2018-12126|MSBDS|msbds|Fallout, microarchitectural store buffer data sampling (MSBDS)|x86
|
|
CVE-2018-12130|MFBDS|mfbds|ZombieLoad, microarchitectural fill buffer data sampling (MFBDS)|x86
|
|
CVE-2018-12127|MLPDS|mlpds|RIDL, microarchitectural load port data sampling (MLPDS)|x86
|
|
CVE-2019-11091|MDSUM|mdsum|RIDL, microarchitectural data sampling uncacheable memory (MDSUM)|x86
|
|
CVE-2019-11135|TAA|taa|ZombieLoad V2, TSX Asynchronous Abort (TAA)|x86
|
|
CVE-2018-12207|ITLBMH|itlbmh|No eXcuses, iTLB Multihit, machine check exception on page size changes (MCEPSC)|x86
|
|
CVE-2020-0543|SRBDS|srbds|Special Register Buffer Data Sampling (SRBDS)|x86
|
|
CVE-2022-21123|SBDR|mmio|Shared Buffers Data Read (SBDR), MMIO Stale Data|x86
|
|
CVE-2022-21125|SBDS|mmio|Shared Buffers Data Sampling (SBDS), MMIO Stale Data|x86
|
|
CVE-2022-21166|DRPW|mmio|Device Register Partial Write (DRPW), MMIO Stale Data|x86
|
|
CVE-2023-20588|DIV0|div0|Division by Zero, AMD Zen1 speculative data leak|x86
|
|
CVE-2023-20593|ZENBLEED|zenbleed|Zenbleed, cross-process information leak|x86
|
|
CVE-2022-40982|DOWNFALL|downfall|Downfall, gather data sampling (GDS)|x86
|
|
CVE-2022-29900|RETBLEED AMD|retbleed|Retbleed, arbitrary speculative code execution with return instructions (AMD)|x86
|
|
CVE-2022-29901|RETBLEED INTEL|retbleed|Retbleed, arbitrary speculative code execution with return instructions (Intel)|x86
|
|
CVE-2023-20569|INCEPTION|inception|Inception, return address security (RAS)|x86
|
|
CVE-2023-23583|REPTAR|reptar|Reptar, redundant prefix issue|x86
|
|
CVE-2024-36350|TSA_SQ|tsa|Transient Scheduler Attack - Store Queue (TSA-SQ)|x86
|
|
CVE-2024-36357|TSA_L1|tsa|Transient Scheduler Attack - L1 (TSA-L1)|x86
|
|
CVE-2024-28956|ITS|its|Indirect Target Selection (ITS)|x86
|
|
CVE-2025-40300|VMSCAPE|vmscape|VMScape, VM-exit stale branch prediction|x86
|
|
CVE-2023-28746|RFDS|rfds|Register File Data Sampling (RFDS)|x86
|
|
CVE-2024-45332|BPI|bpi|Branch Privilege Injection (BPI)|x86
|
|
CVE-0000-0001|SLS|sls|Straight-Line Speculation (SLS)|
|
|
CVE-2025-54505|FPDSS|fpdss|FPDSS, AMD Zen1 Floating-Point Divider Stale Data Leak|x86
|
|
CVE-0001-0001|ARM SPEC AT|arm_spec_at|ARM64 errata 1165522/1319367/1319537/1530923, Speculative AT TLB corruption|arm
|
|
CVE-0001-0002|ARM SPEC UNPRIV LOAD|arm_spec_unpriv_load|ARM64 errata 2966298/3117295, Speculative unprivileged load|arm
|
|
CVE-0001-0003|ARM SSBS NOSYNC|arm_ssbs_nosync|ARM64 erratum 3194386, MSR SSBS not self-synchronizing|arm
|
|
'
|
|
|
|
# Derive the supported CVE list from the registry
|
|
g_supported_cve_list=$(echo "$CVE_REGISTRY" | grep '^CVE-' | cut -d'|' -f1)
|
|
|
|
# Look up a field from the CVE registry
|
|
# Args: $1=cve_id $2=field_number (see CVE_REGISTRY format above)
|
|
# Callers: cve2name, _is_cpu_affected_cached, pvulnstatus
|
|
_cve_registry_field() {
|
|
local line
|
|
line=$(echo "$CVE_REGISTRY" | grep -E "^$1\|")
|
|
if [ -z "$line" ]; then
|
|
echo "$0: error: invalid CVE '$1' passed to _cve_registry_field()" >&2
|
|
exit 255
|
|
fi
|
|
echo "$line" | cut -d'|' -f"$2"
|
|
}
|
|
|
|
# find a sane command to print colored messages, we prefer `printf` over `echo`
|
|
# because `printf` behavior is more standard across Linux/BSD
|
|
# we'll try to avoid using shell builtins that might not take options
|
|
g_echo_cmd_type='echo'
|
|
# ignore SC2230 here because `which` ignores builtins while `command -v` doesn't, and
|
|
# we don't want builtins here. Even if `which` is not installed, we'll fallback to the
|
|
# `echo` builtin anyway, so this is safe.
|
|
# shellcheck disable=SC2230
|
|
if command -v printf >/dev/null 2>&1; then
|
|
g_echo_cmd=$(command -v printf)
|
|
g_echo_cmd_type='printf'
|
|
elif which echo >/dev/null 2>&1; then
|
|
g_echo_cmd=$(which echo)
|
|
else
|
|
# maybe the `which` command is broken?
|
|
[ -x /bin/echo ] && g_echo_cmd=/bin/echo
|
|
# for Android
|
|
[ -x /system/bin/echo ] && g_echo_cmd=/system/bin/echo
|
|
fi
|
|
# still empty? fallback to builtin
|
|
[ -z "$g_echo_cmd" ] && g_echo_cmd='echo'
|