mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-06-04 13:43:05 +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.
952 lines
47 KiB
Bash
952 lines
47 KiB
Bash
# vim: set ts=4 sw=4 sts=4 et:
|
|
|
|
# Helpers for is_cpu_affected: encode the 4 patterns for setting affected_* variables.
|
|
# Each function takes the variable suffix as $1 (e.g. "variantl1tf", not "affected_variantl1tf").
|
|
# Variables hold 1 (not affected / immune) or 0 (affected / vuln); empty = not yet decided.
|
|
|
|
# Set affected_$1 to 1 (not affected) unconditionally.
|
|
# Use for: hardware capability bits (cap_rdcl_no, cap_ssb_no, cap_gds_no, cap_tsa_*_no),
|
|
# is_cpu_specex_free results, and vendor-wide immune facts (AMD/L1TF, Cavium, etc.).
|
|
# This always wins and cannot be overridden by _infer_vuln (which only fires on empty).
|
|
# Must not be followed by _set_vuln for the same variable in the same code path.
|
|
_set_immune() { eval "affected_$1=1"; }
|
|
|
|
# Set affected_$1 to 0 (affected) unconditionally.
|
|
# Use for: confirmed-vuln model/erratum lists, ARM unknown-CPU fallback.
|
|
# Note: intentionally overrides a prior _infer_immune (1) — this is required for ARM
|
|
# big.LITTLE cumulative logic where a second vuln core must override a prior safe core.
|
|
# Must not be called after _set_immune for the same variable in the same code path.
|
|
_set_vuln() { eval "affected_$1=0"; }
|
|
|
|
# Set affected_$1 to 1 (not affected) only if not yet decided (currently empty).
|
|
# Use for: model/family whitelists, per-part ARM immune inferences,
|
|
# AMD/ARM partial immunity (immune on this variant axis but not others).
|
|
_infer_immune() { eval "[ -z \"\$affected_$1\" ] && affected_$1=1 || :"; }
|
|
|
|
# Set affected_$1 to 0 (affected) only if not yet decided (currently empty).
|
|
# Use for: family-level catch-all fallbacks (Intel L1TF non-whitelist, itlbmh non-whitelist).
|
|
_infer_vuln() { eval "[ -z \"\$affected_$1\" ] && affected_$1=0 || :"; }
|
|
|
|
# Return 0 (true) if a CVE's arch tag matches the current context (host CPU
|
|
# and/or target kernel), so the check is worth running. Untagged CVEs are
|
|
# always relevant.
|
|
# - In no-hw mode the host CPU is ignored: gate only on target kernel arch.
|
|
# - Otherwise a match on either the host CPU or the target kernel is enough
|
|
# (they normally agree in live mode; if they disagree, check_kernel_cpu_arch_mismatch
|
|
# has already forced no-hw, handled by the branch above).
|
|
# Args: $1=cve_id
|
|
# Callers: src/main.sh (CVE dispatch loop), check_cpu_vulnerabilities
|
|
_is_cve_relevant_arch() {
|
|
local arch
|
|
arch=$(_cve_registry_field "$1" 5)
|
|
# Untagged CVE: always relevant
|
|
[ -z "$arch" ] && return 0
|
|
case "$arch" in
|
|
x86)
|
|
[ "$g_mode" != no-hw ] && is_x86_cpu && return 0
|
|
is_x86_kernel && return 0
|
|
return 1
|
|
;;
|
|
arm)
|
|
[ "$g_mode" != no-hw ] && is_arm_cpu && return 0
|
|
is_arm_kernel && return 0
|
|
return 1
|
|
;;
|
|
esac
|
|
# Unknown tag value: don't gate (fail open)
|
|
return 0
|
|
}
|
|
|
|
# Return the cached affected_* status for a given CVE
|
|
# Args: $1=cve_id
|
|
# Returns: 0 if affected, 1 if not affected
|
|
# Callers: is_cpu_affected
|
|
_is_cpu_affected_cached() {
|
|
local suffix
|
|
suffix=$(_cve_registry_field "$1" 3)
|
|
# shellcheck disable=SC2086
|
|
eval "return \$affected_${suffix}"
|
|
}
|
|
|
|
# Determine whether the current CPU is affected by a given CVE using whitelist logic
|
|
# Args: $1=cve_id (one of the $g_supported_cve_list items)
|
|
# Returns: 0 if affected, 1 if not affected
|
|
is_cpu_affected() {
|
|
local result cpuid_hex reptar_ucode_list bpi_ucode_list tuple fixed_ucode_ver affected_fmspi affected_fms ucode_platformid_mask affected_cpuid i cpupart cpuarch
|
|
|
|
# if CPU is Intel and is in our dump of the Intel official affected CPUs page, use it:
|
|
if is_intel; then
|
|
cpuid_hex=$(printf "0x%08X" $((cpu_cpuid)))
|
|
if [ "${g_intel_line:-}" = "no" ]; then
|
|
pr_debug "is_cpu_affected: $cpuid_hex not in Intel database (cached)"
|
|
elif [ -z "$g_intel_line" ]; then
|
|
# Try hybrid-specific entry first (H=0 or H=1), fall back to unqualified entry
|
|
g_intel_line=$(read_inteldb | grep -F "$cpuid_hex,H=$cpu_hybrid," | head -n1)
|
|
if [ -z "$g_intel_line" ]; then
|
|
# No hybrid-specific entry, try unqualified (no H= field)
|
|
g_intel_line=$(read_inteldb | grep -F "$cpuid_hex," | grep -v ',H=' | head -n1)
|
|
fi
|
|
if [ -z "$g_intel_line" ]; then
|
|
g_intel_line=no
|
|
pr_debug "is_cpu_affected: $cpuid_hex not in Intel database"
|
|
fi
|
|
fi
|
|
if [ "$g_intel_line" != "no" ]; then
|
|
result=$(echo "$g_intel_line" | grep -Eo ,"$(echo "$1" | cut -c5-)"'=[^,]+' | cut -d= -f2)
|
|
pr_debug "is_cpu_affected: inteldb for $1 says '$result'"
|
|
|
|
# handle special case for Foreshadow SGX (CVE-2018-3615):
|
|
# even if we are affected to L1TF (CVE-2018-3620/CVE-2018-3646), if there's no SGX on our CPU,
|
|
# then we're not affected to the original Foreshadow.
|
|
if [ "$1" = "CVE-2018-3615" ] && [ "$cap_sgx" = 0 ]; then
|
|
# not affected
|
|
return 1
|
|
fi
|
|
# /special case
|
|
|
|
if [ "$result" = "N" ]; then
|
|
# not affected
|
|
return 1
|
|
elif [ -n "$result" ]; then
|
|
# non-empty string != N means affected
|
|
return 0
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# Otherwise, do it ourselves
|
|
|
|
if [ "$g_is_cpu_affected_cached" = 1 ]; then
|
|
_is_cpu_affected_cached "$1"
|
|
return $?
|
|
fi
|
|
|
|
affected_variant1=''
|
|
affected_variant2=''
|
|
affected_variant3=''
|
|
affected_variant3a=''
|
|
affected_variant4=''
|
|
affected_variantl1tf=''
|
|
affected_msbds=''
|
|
affected_mfbds=''
|
|
affected_mlpds=''
|
|
affected_mdsum=''
|
|
affected_taa=''
|
|
affected_itlbmh=''
|
|
affected_srbds=''
|
|
affected_mmio=''
|
|
affected_sls=''
|
|
# ARM64 speculation-related errata (ARM Ltd, implementer 0x41); non-ARM systems are immune below.
|
|
affected_arm_spec_at=''
|
|
affected_arm_spec_unpriv_load=''
|
|
affected_arm_ssbs_nosync=''
|
|
# DIV0, FPDSS, Zenbleed and Inception are all AMD specific, look for "is_amd" below:
|
|
_set_immune div0
|
|
_set_immune fpdss
|
|
_set_immune zenbleed
|
|
_set_immune inception
|
|
# TSA is AMD specific (Zen 3/4), look for "is_amd" below:
|
|
_set_immune tsa
|
|
# Retbleed: AMD (CVE-2022-29900) and Intel (CVE-2022-29901) specific:
|
|
_set_immune retbleed
|
|
# Downfall, Reptar, RFDS, ITS & BPI are Intel specific, look for "is_intel" below:
|
|
_set_immune downfall
|
|
_set_immune reptar
|
|
_set_immune rfds
|
|
_set_immune its
|
|
_set_immune bpi
|
|
# VMScape affects Intel, AMD and Hygon — set immune, overridden below:
|
|
_set_immune vmscape
|
|
|
|
if is_cpu_mds_free; then
|
|
_infer_immune msbds
|
|
_infer_immune mfbds
|
|
_infer_immune mlpds
|
|
_infer_immune mdsum
|
|
pr_debug "is_cpu_affected: cpu not affected by Microarchitectural Data Sampling"
|
|
elif is_cpu_msbds_only; then
|
|
_infer_immune mfbds
|
|
_infer_immune mlpds
|
|
_infer_immune mdsum
|
|
pr_debug "is_cpu_affected: cpu only affected by MSBDS, not MFBDS/MLPDS/MDSUM"
|
|
fi
|
|
|
|
if is_cpu_taa_free; then
|
|
_infer_immune taa
|
|
pr_debug "is_cpu_affected: cpu not affected by TSX Asynhronous Abort"
|
|
fi
|
|
|
|
if is_cpu_srbds_free; then
|
|
_infer_immune srbds
|
|
pr_debug "is_cpu_affected: cpu not affected by Special Register Buffer Data Sampling"
|
|
fi
|
|
|
|
if is_cpu_mmio_free; then
|
|
_infer_immune mmio
|
|
pr_debug "is_cpu_affected: cpu not affected by MMIO Stale Data"
|
|
fi
|
|
|
|
# NO_SPECTRE_V2: Centaur family 7 and Zhaoxin family 7 are immune to Spectre V2
|
|
# kernel commit 1e41a766c98b (v5.6-rc1): added NO_SPECTRE_V2 exemption
|
|
# Zhaoxin vendor_id is " Shanghai " in cpuinfo (parsed as "Shanghai" by awk)
|
|
if { [ "$cpu_vendor" = "CentaurHauls" ] || [ "$cpu_vendor" = "Shanghai" ]; } && [ "$cpu_family" = 7 ]; then
|
|
_infer_immune variant2
|
|
pr_debug "is_cpu_affected: Centaur/Zhaoxin family 7 immune to Spectre V2 (NO_SPECTRE_V2)"
|
|
fi
|
|
|
|
if is_cpu_specex_free; then
|
|
_set_immune variant1
|
|
_set_immune variant2
|
|
_set_immune variant3
|
|
_set_immune variant3a
|
|
_set_immune variant4
|
|
_set_immune variantl1tf
|
|
_set_immune msbds
|
|
_set_immune mfbds
|
|
_set_immune mlpds
|
|
_set_immune mdsum
|
|
_set_immune taa
|
|
_set_immune srbds
|
|
_set_immune mmio
|
|
elif is_intel; then
|
|
# Intel
|
|
# https://github.com/crozone/SpectrePoC/issues/1 ^F E5200 => spectre 2 not affected
|
|
# https://github.com/paboldin/meltdown-exploit/issues/19 ^F E5200 => meltdown affected
|
|
# model name : Pentium(R) Dual-Core CPU E5200 @ 2.50GHz
|
|
if echo "$cpu_friendly_name" | grep -qE 'Pentium\(R\) Dual-Core[[:space:]]+CPU[[:space:]]+E[0-9]{4}K?'; then
|
|
_set_vuln variant1
|
|
_infer_immune variant2
|
|
_set_vuln variant3
|
|
fi
|
|
if [ "$cap_rdcl_no" = 1 ]; then
|
|
# capability bit for future Intel processor that will explicitly state
|
|
# that they're not affected to Meltdown
|
|
# this var is set in check_cpu()
|
|
_set_immune variant3
|
|
_set_immune variantl1tf
|
|
pr_debug "is_cpu_affected: RDCL_NO is set so not vuln to meltdown nor l1tf"
|
|
fi
|
|
if [ "$cap_ssb_no" = 1 ]; then
|
|
# capability bit for future Intel processor that will explicitly state
|
|
# that they're not affected to Variant 4
|
|
# this var is set in check_cpu()
|
|
_set_immune variant4
|
|
pr_debug "is_cpu_affected: SSB_NO is set so not vuln to affected_variant4"
|
|
fi
|
|
if is_cpu_ssb_free; then
|
|
_infer_immune variant4
|
|
pr_debug "is_cpu_affected: cpu not affected by speculative store bypass so not vuln to affected_variant4"
|
|
fi
|
|
# variant 3a
|
|
if [ "$cpu_family" = 6 ]; then
|
|
if [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] || [ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
|
|
pr_debug "is_cpu_affected: xeon phi immune to variant 3a"
|
|
_infer_immune variant3a
|
|
elif [ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ]; then
|
|
# https://www.intel.com/content/www/us/en/security-center/advisory/intel-sa-00115.html
|
|
# https://github.com/speed47/spectre-meltdown-checker/issues/310
|
|
# => silvermont CPUs (aka cherry lake for tablets and brawsell for mobile/desktop) don't seem to be affected
|
|
# => goldmont ARE affected
|
|
pr_debug "is_cpu_affected: silvermont immune to variant 3a"
|
|
_infer_immune variant3a
|
|
fi
|
|
fi
|
|
# L1TF (cap_rdcl_no already checked above)
|
|
if [ "$cpu_family" = 6 ]; then
|
|
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_TABLET" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID2" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT_NP" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ]; then
|
|
|
|
pr_debug "is_cpu_affected: intel family 6 but model known to be immune to l1tf"
|
|
_infer_immune variantl1tf
|
|
else
|
|
pr_debug "is_cpu_affected: intel family 6 is vuln to l1tf"
|
|
_infer_vuln variantl1tf
|
|
fi
|
|
elif [ "$cpu_family" -lt 6 ]; then
|
|
pr_debug "is_cpu_affected: intel family < 6 is immune to l1tf"
|
|
_infer_immune variantl1tf
|
|
fi
|
|
# Downfall
|
|
if [ "$cap_gds_no" = 1 ]; then
|
|
# capability bit for future Intel processors that will explicitly state
|
|
# that they're unaffected by GDS. Also set by hypervisors on virtual CPUs
|
|
# so that the guest kernel doesn't try to mitigate GDS when it's already mitigated on the host
|
|
pr_debug "is_cpu_affected: downfall: not affected (GDS_NO)"
|
|
_set_immune downfall
|
|
elif [ "$cpu_family" = 6 ]; then
|
|
# model blacklist from the kernel (arch/x86/kernel/cpu/common.c cpu_vuln_blacklist):
|
|
# 8974eb588283 (initial list) + c9f4c45c8ec3 (added Skylake/Skylake_L client)
|
|
set -u
|
|
if [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ]; then
|
|
pr_debug "is_cpu_affected: downfall: affected"
|
|
_set_vuln downfall
|
|
elif [ "$cap_avx2" = 0 ] && [ "$cap_avx512" = 0 ]; then
|
|
pr_debug "is_cpu_affected: downfall: no avx; immune"
|
|
_infer_immune downfall
|
|
else
|
|
# Intel family 6 CPU with AVX2 or AVX512, not in the known-affected list
|
|
# and GDS_NO not set: assume affected (whitelist principle)
|
|
pr_debug "is_cpu_affected: downfall: unknown AVX-capable CPU, defaulting to affected"
|
|
_infer_vuln downfall
|
|
fi
|
|
set +u
|
|
fi
|
|
# RFDS (Register File Data Sampling, CVE-2023-28746)
|
|
# kernel cpu_vuln_blacklist (8076fcde016c, initial model list)
|
|
# immunity: ARCH_CAP_RFDS_NO (bit 27 of IA32_ARCH_CAPABILITIES)
|
|
# vendor scope: Intel only (family 6), Atom/hybrid cores
|
|
if [ "$cap_rfds_no" = 1 ]; then
|
|
pr_debug "is_cpu_affected: rfds: not affected (RFDS_NO)"
|
|
_set_immune rfds
|
|
elif [ "$cpu_family" = 6 ]; then
|
|
set -u
|
|
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_TREMONT_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GRACEMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_P" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_S" ]; then
|
|
pr_debug "is_cpu_affected: rfds: affected"
|
|
_set_vuln rfds
|
|
fi
|
|
set +u
|
|
fi
|
|
# ITS (Indirect Target Selection, CVE-2024-28956)
|
|
# kernel vulnerable_to_its() + cpu_vuln_blacklist (159013a7ca18)
|
|
# immunity: ARCH_CAP_ITS_NO (bit 62 of IA32_ARCH_CAPABILITIES)
|
|
# immunity: X86_FEATURE_BHI_CTRL (none of the affected CPUs have this)
|
|
# vendor scope: Intel only (family 6), with stepping constraints on some models
|
|
if [ "$cap_its_no" = 1 ]; then
|
|
pr_debug "is_cpu_affected: its: not affected (ITS_NO)"
|
|
_set_immune its
|
|
elif [ "$cpu_family" = 6 ]; then
|
|
set -u
|
|
if { [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] && [ "$cpu_stepping" -gt 5 ]; } ||
|
|
{ [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] && [ "$cpu_stepping" -gt 11 ]; } ||
|
|
{ [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] && [ "$cpu_stepping" -gt 12 ]; } ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ]; then
|
|
pr_debug "is_cpu_affected: its: affected"
|
|
_set_vuln its
|
|
fi
|
|
set +u
|
|
fi
|
|
# Reptar
|
|
# the only way to know whether a CPU is vuln, is to check whether there is a known ucode update for it,
|
|
# as the mitigation is only ucode-based and there's no flag exposed by the kernel or by an updated ucode.
|
|
# we have to hardcode the truthtable of affected CPUs vs updated ucodes...
|
|
# https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/redundant-prefix-issue.html
|
|
# list initially taken from:
|
|
# https://github.com/intel/Intel-Linux-Processor-Microcode-Data-Files/commit/ece0d294a29a1375397941a4e6f2f7217910bc89#diff-e6fad0f2abbac6c9603b2e8f88fe1d151a83de708aeca1c1d93d881c958ecba4R26
|
|
# updated 2026-04 with Intel affected processor list + releasenote.md:
|
|
# added 06-9a-04/40 (AZB), 06-bd-01/80 (Lunar Lake, post-dates Reptar: first ucode already includes fix)
|
|
g_reptar_fixed_ucode_version=''
|
|
reptar_ucode_list='
|
|
06-97-02/07,00000032
|
|
06-97-05/07,00000032
|
|
06-9a-03/80,00000430
|
|
06-9a-04/80,00000430
|
|
06-9a-04/40,00000005
|
|
06-6c-01/10,01000268
|
|
06-6a-06/87,0d0003b9
|
|
06-7e-05/80,000000c2
|
|
06-ba-02/e0,0000411c
|
|
06-b7-01/32,0000011d
|
|
06-a7-01/02,0000005d
|
|
06-bf-05/07,00000032
|
|
06-bf-02/07,00000032
|
|
06-ba-03/e0,0000411c
|
|
06-8f-08/87,2b0004d0
|
|
06-8f-07/87,2b0004d0
|
|
06-8f-06/87,2b0004d0
|
|
06-8f-05/87,2b0004d0
|
|
06-8f-04/87,2b0004d0
|
|
06-8f-08/10,2c000290
|
|
06-8c-01/80,000000b4
|
|
06-8c-00/ff,000000b4
|
|
06-8d-01/c2,0000004e
|
|
06-8d-00/c2,0000004e
|
|
06-8c-02/c2,00000034
|
|
06-bd-01/80,0000011f
|
|
'
|
|
for tuple in $reptar_ucode_list; do
|
|
fixed_ucode_ver=$((0x$(echo "$tuple" | cut -d, -f2)))
|
|
affected_fmspi=$(echo "$tuple" | cut -d, -f1)
|
|
affected_fms=$(echo "$affected_fmspi" | cut -d/ -f1)
|
|
ucode_platformid_mask=0x$(echo "$affected_fmspi" | cut -d/ -f2)
|
|
affected_cpuid=$(
|
|
fms2cpuid \
|
|
0x"$(echo "$affected_fms" | cut -d- -f1)" \
|
|
0x"$(echo "$affected_fms" | cut -d- -f2)" \
|
|
0x"$(echo "$affected_fms" | cut -d- -f3)"
|
|
)
|
|
if [ "$cpu_cpuid" = "$affected_cpuid" ] && [ $((cpu_platformid & ucode_platformid_mask)) -gt 0 ]; then
|
|
_set_vuln reptar
|
|
g_reptar_fixed_ucode_version=$fixed_ucode_ver
|
|
break
|
|
fi
|
|
done
|
|
# if we didn't match the ucode list above, also check the model blacklist:
|
|
# Intel never tells about their EOL CPUs, so more CPUs might be affected
|
|
# than the ones that received a microcode update (e.g. steppings with
|
|
# different platform IDs that were dropped before the Reptar fix).
|
|
if [ -z "$g_reptar_fixed_ucode_version" ] && [ "$cpu_family" = 6 ]; then
|
|
set -u
|
|
if [ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SAPPHIRERAPIDS_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_P" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_S" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_LUNARLAKE_M" ]; then
|
|
pr_debug "is_cpu_affected: reptar: affected (model match, no known fixing ucode)"
|
|
_set_vuln reptar
|
|
fi
|
|
set +u
|
|
fi
|
|
|
|
# Retbleed (Intel, CVE-2022-29901): Skylake through Rocket Lake, or any CPU with RSBA
|
|
# kernel cpu_vuln_blacklist for RETBLEED (6b80b59b3555, 6ad0ad2bf8a6, f54d45372c6a)
|
|
# plus ARCH_CAP_RSBA catch-all (bit 2 of IA32_ARCH_CAPABILITIES)
|
|
if [ "$cap_rsba" = 1 ]; then
|
|
_set_vuln retbleed
|
|
elif [ "$cpu_family" = 6 ]; then
|
|
if [ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_CANNONLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_LAKEFIELD" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ]; then
|
|
_set_vuln retbleed
|
|
fi
|
|
fi
|
|
|
|
# VMScape (CVE-2025-40300): Intel model blacklist
|
|
# kernel cpu_vuln_blacklist VMSCAPE (a508cec6e521 + 8a68d64bb103)
|
|
# immunity: no ARCH_CAP bits (purely blacklist-based)
|
|
# note: kernel only sets bug on bare metal (!X86_FEATURE_HYPERVISOR)
|
|
# vendor scope: Intel + AMD + Hygon (AMD/Hygon handled below)
|
|
if [ "$cpu_family" = 6 ]; then
|
|
set -u
|
|
if [ "$cpu_model" = "$INTEL_FAM6_SANDYBRIDGE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SANDYBRIDGE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_IVYBRIDGE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_IVYBRIDGE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_HASWELL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_HASWELL_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_HASWELL_G" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_HASWELL_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL_G" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_BROADWELL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_CANNONLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_P" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_S" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_METEORLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ARROWLAKE_H" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ARROWLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ARROWLAKE_U" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_LUNARLAKE_M" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SAPPHIRERAPIDS_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_GRANITERAPIDS_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_EMERALDRAPIDS_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GRACEMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_CRESTMONT_X" ]; then
|
|
pr_debug "is_cpu_affected: vmscape: affected"
|
|
_set_vuln vmscape
|
|
fi
|
|
set +u
|
|
fi
|
|
|
|
# BPI (Branch Privilege Injection, CVE-2024-45332)
|
|
# microcode-only fix, no kernel X86_BUG flag, no CPUID/MSR indicator for the fix.
|
|
# We have to hardcode the truthtable of affected CPUs vs fixing ucodes,
|
|
# same approach as Reptar (see above).
|
|
# https://www.intel.com/content/www/us/en/developer/articles/technical/software-security-guidance/advisory-guidance/indirect-branch-predictor-delayed-updates.html
|
|
# list taken from Intel affected processor list + Intel-Linux-Processor-Microcode-Data-Files releasenote.md
|
|
# format: FF-MM-SS/platformid_mask,fixed_ucode_version
|
|
g_bpi_fixed_ucode_version=''
|
|
bpi_ucode_list='
|
|
06-9e-0d/22,00000104
|
|
06-8e-0a/c0,000000f6
|
|
06-8e-0b/d0,000000f6
|
|
06-8e-0c/94,00000100
|
|
06-a5-02/20,00000100
|
|
06-a5-03/22,00000100
|
|
06-a5-05/22,00000100
|
|
06-a6-00/80,00000102
|
|
06-a6-01/80,00000100
|
|
06-a7-01/02,00000065
|
|
06-7e-05/80,000000cc
|
|
06-6a-06/87,0d000421
|
|
06-6c-01/10,010002f1
|
|
06-8c-01/80,000000be
|
|
06-8c-02/c2,0000003e
|
|
06-8d-01/c2,00000058
|
|
06-97-02/07,0000003e
|
|
06-97-05/07,0000003e
|
|
06-9a-03/80,0000043b
|
|
06-9a-04/80,0000043b
|
|
06-9a-04/40,0000000c
|
|
06-be-00/19,00000021
|
|
06-b7-01/32,00000133
|
|
06-ba-02/e0,00006134
|
|
06-ba-03/e0,00006134
|
|
06-bf-02/07,0000003e
|
|
06-bf-05/07,0000003e
|
|
06-aa-04/e6,00000028
|
|
06-b5-00/80,0000000d
|
|
06-c5-02/82,0000011b
|
|
06-c6-02/82,0000011b
|
|
06-bd-01/80,00000125
|
|
06-55-0b/bf,07002b01
|
|
06-8f-07/87,2b000661
|
|
06-8f-08/87,2b000661
|
|
06-8f-08/10,2c000421
|
|
06-cf-02/87,210002d3
|
|
06-7a-08/01,00000026
|
|
'
|
|
for tuple in $bpi_ucode_list; do
|
|
fixed_ucode_ver=$((0x$(echo "$tuple" | cut -d, -f2)))
|
|
affected_fmspi=$(echo "$tuple" | cut -d, -f1)
|
|
affected_fms=$(echo "$affected_fmspi" | cut -d/ -f1)
|
|
ucode_platformid_mask=0x$(echo "$affected_fmspi" | cut -d/ -f2)
|
|
affected_cpuid=$(
|
|
fms2cpuid \
|
|
0x"$(echo "$affected_fms" | cut -d- -f1)" \
|
|
0x"$(echo "$affected_fms" | cut -d- -f2)" \
|
|
0x"$(echo "$affected_fms" | cut -d- -f3)"
|
|
)
|
|
if [ "$cpu_cpuid" = "$affected_cpuid" ] && [ $((cpu_platformid & ucode_platformid_mask)) -gt 0 ]; then
|
|
_set_vuln bpi
|
|
g_bpi_fixed_ucode_version=$fixed_ucode_ver
|
|
break
|
|
fi
|
|
done
|
|
# if we didn't match the ucode list above, also check the model blacklist:
|
|
# Intel never tells about their EOL CPUs, so more CPUs might be affected
|
|
# than the ones that received a microcode update. In that case, we flag
|
|
# the CPU as affected but g_bpi_fixed_ucode_version stays empty (the CVE
|
|
# check will handle this by reporting VULN with no known fix).
|
|
if [ -z "$g_bpi_fixed_ucode_version" ] && [ "$cpu_family" = 6 ]; then
|
|
set -u
|
|
if [ "$cpu_model" = "$INTEL_FAM6_KABYLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_KABYLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_COMETLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ROCKETLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ICELAKE_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_TIGERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ALDERLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GRACEMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_P" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_RAPTORLAKE_S" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_METEORLAKE_L" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ARROWLAKE_H" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ARROWLAKE" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ARROWLAKE_U" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_LUNARLAKE_M" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SKYLAKE_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_SAPPHIRERAPIDS_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_EMERALDRAPIDS_X" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_CRESTMONT" ]; then
|
|
pr_debug "is_cpu_affected: bpi: affected (model match, no known fixing ucode)"
|
|
_set_vuln bpi
|
|
fi
|
|
set +u
|
|
fi
|
|
|
|
elif is_amd || is_hygon; then
|
|
# AMD revised their statement about affected_variant2 => affected
|
|
# https://www.amd.com/en/corporate/speculative-execution
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_infer_immune variant3
|
|
# https://www.amd.com/en/corporate/security-updates
|
|
# "We have not identified any AMD x86 products susceptible to the Variant 3a vulnerability in our analysis to-date."
|
|
_infer_immune variant3a
|
|
if is_cpu_ssb_free; then
|
|
_infer_immune variant4
|
|
pr_debug "is_cpu_affected: cpu not affected by speculative store bypass so not vuln to affected_variant4"
|
|
fi
|
|
_set_immune variantl1tf
|
|
|
|
# DIV0 (Zen1/Zen+)
|
|
# 77245f1c3c64 (v6.5, initial model list): family 0x17 models 0x00-0x2f, 0x50-0x5f
|
|
# bfff3c6692ce (v6.8): moved to init_amd_zen1(), unconditional for all ZEN1-flagged CPUs
|
|
# The kernel's X86_FEATURE_ZEN1 covers family 0x17 models 0x00-0x2f and 0x50-0x5f,
|
|
# which spans both Zen1 (Summit Ridge, Naples, Raven Ridge, Snowy Owl) and Zen+
|
|
# (Pinnacle Ridge, Picasso, Dali, Colfax) products -- all using the same divider silicon.
|
|
amd_legacy_erratum "$(amd_model_range 0x17 0x00 0x0 0x2f 0xf)" && _set_vuln div0
|
|
amd_legacy_erratum "$(amd_model_range 0x17 0x50 0x0 0x5f 0xf)" && _set_vuln div0
|
|
|
|
# FPDSS: same Zen1/Zen+ cohort as DIV0 (both applied unconditionally in init_amd_zen1()).
|
|
# e55d98e77561 (v7.1): unconditional in init_amd_zen1(); CVE-2025-54505 / AMD-SB-7053.
|
|
# AMD-SB-7053 only enumerates a subset (EPYC 7001, EPYC Embedded 3000, Athlon/Ryzen 3000
|
|
# with Radeon, Ryzen PRO 3000 with Radeon Vega), but the kernel mitigates the full
|
|
# ZEN1 cohort, so we flag all of it to match the kernel's behavior.
|
|
# shellcheck disable=SC2154
|
|
[ "$affected_div0" = 0 ] && _set_vuln fpdss
|
|
|
|
# Zenbleed
|
|
amd_legacy_erratum "$(amd_model_range 0x17 0x30 0x0 0x4f 0xf)" && _set_vuln zenbleed
|
|
amd_legacy_erratum "$(amd_model_range 0x17 0x60 0x0 0x7f 0xf)" && _set_vuln zenbleed
|
|
amd_legacy_erratum "$(amd_model_range 0x17 0xa0 0x0 0xaf 0xf)" && _set_vuln zenbleed
|
|
|
|
# Inception (according to kernel, zen 1 to 4)
|
|
if [ "$cpu_family" = $((0x17)) ] || [ "$cpu_family" = $((0x19)) ]; then
|
|
_set_vuln inception
|
|
fi
|
|
|
|
# TSA (Zen 3/4 are affected, unless CPUID says otherwise)
|
|
if [ "$cap_tsa_sq_no" = 1 ] && [ "$cap_tsa_l1_no" = 1 ]; then
|
|
# capability bits for AMD processors that explicitly state
|
|
# they're not affected to TSA-SQ and TSA-L1
|
|
# these vars are set in check_cpu()
|
|
pr_debug "is_cpu_affected: TSA_SQ_NO and TSA_L1_NO are set so not vuln to TSA"
|
|
_set_immune tsa
|
|
elif [ "$cpu_family" = $((0x19)) ]; then
|
|
_set_vuln tsa
|
|
fi
|
|
|
|
# Retbleed (AMD, CVE-2022-29900): families 0x15-0x17 (kernel X86_BUG_RETBLEED)
|
|
if [ "$cpu_family" = $((0x15)) ] || [ "$cpu_family" = $((0x16)) ] || [ "$cpu_family" = $((0x17)) ]; then
|
|
_set_vuln retbleed
|
|
fi
|
|
|
|
# VMScape (CVE-2025-40300): AMD families 0x17/0x19/0x1a, Hygon family 0x18
|
|
# kernel cpu_vuln_blacklist VMSCAPE (a508cec6e521)
|
|
if is_amd; then
|
|
if [ "$cpu_family" = $((0x17)) ] || [ "$cpu_family" = $((0x19)) ] || [ "$cpu_family" = $((0x1a)) ]; then
|
|
pr_debug "is_cpu_affected: vmscape: AMD family $cpu_family affected"
|
|
_set_vuln vmscape
|
|
fi
|
|
elif is_hygon; then
|
|
if [ "$cpu_family" = $((0x18)) ]; then
|
|
pr_debug "is_cpu_affected: vmscape: Hygon family $cpu_family affected"
|
|
_set_vuln vmscape
|
|
fi
|
|
fi
|
|
|
|
elif [ "$cpu_vendor" = CAVIUM ]; then
|
|
_set_immune variant3
|
|
_set_immune variant3a
|
|
_set_immune variantl1tf
|
|
elif [ "$cpu_vendor" = PHYTIUM ]; then
|
|
_set_immune variant3
|
|
_set_immune variant3a
|
|
_set_immune variantl1tf
|
|
elif [ "$cpu_vendor" = ARM ]; then
|
|
# ARM
|
|
# reference: https://developer.arm.com/support/security-update
|
|
# some devices (phones or other) have several ARMs and as such different part numbers,
|
|
# an example is "bigLITTLE". we shouldn't rely on the first CPU only, so we check the whole list
|
|
i=0
|
|
for cpupart in $cpu_part_list; do
|
|
i=$((i + 1))
|
|
# do NOT quote $cpu_arch_list below
|
|
# shellcheck disable=SC2086
|
|
cpuarch=$(echo $cpu_arch_list | awk '{ print $'$i' }')
|
|
pr_debug "checking cpu$i: <$cpupart> <$cpuarch>"
|
|
# some kernels report AArch64 instead of 8
|
|
[ "$cpuarch" = "AArch64" ] && cpuarch=8
|
|
# some kernels report architecture with suffix (e.g. "5TEJ" for ARMv5TEJ), extract numeric prefix
|
|
cpuarch=$(echo "$cpuarch" | grep -oE '^[0-9]+')
|
|
if [ -n "$cpupart" ] && [ -n "$cpuarch" ]; then
|
|
# Cortex-R7 and Cortex-R8 are real-time and only used in medical devices or such
|
|
# I can't find their CPU part number, but it's probably not that useful anyway
|
|
# model R7 R8 A8 A9 A12 A15 A17 A57 A72 A73 A75 A76 A77 Neoverse-N1 Neoverse-V1 Neoverse-N1 Neoverse-V2
|
|
# part ? ? c08 c09 c0d c0f c0e d07 d08 d09 d0a d0b d0d d0c d40 d49 d4f
|
|
# arch 7? 7? 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8
|
|
#
|
|
# Whitelist identified non-affected processors, use vulnerability information from
|
|
# https://developer.arm.com/support/arm-security-updates/speculative-processor-vulnerability
|
|
# Partnumbers can be found here:
|
|
# https://github.com/gcc-mirror/gcc/blob/master/gcc/config/arm/arm-cpus.in
|
|
#
|
|
# Maintain cumulative check of vulnerabilities -
|
|
# if at least one of the cpu is affected, then the system is affected
|
|
if [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc08 -e 0xc09 -e 0xc0d -e 0xc0e; then
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_infer_immune variant3
|
|
_infer_immune variant3a
|
|
_infer_immune variant4
|
|
pr_debug "checking cpu$i: armv7 A8/A9/A12/A17 non affected to variants 3, 3a & 4"
|
|
elif [ "$cpuarch" = 7 ] && echo "$cpupart" | grep -q -w -e 0xc0f; then
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_infer_immune variant3
|
|
_set_vuln variant3a
|
|
_infer_immune variant4
|
|
pr_debug "checking cpu$i: armv7 A15 non affected to variants 3 & 4"
|
|
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd07 -e 0xd08; then
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_infer_immune variant3
|
|
_set_vuln variant3a
|
|
_set_vuln variant4
|
|
pr_debug "checking cpu$i: armv8 A57/A72 non affected to variants 3"
|
|
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd09; then
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_infer_immune variant3
|
|
_infer_immune variant3a
|
|
_set_vuln variant4
|
|
pr_debug "checking cpu$i: armv8 A73 non affected to variants 3 & 3a"
|
|
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0a; then
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_set_vuln variant3
|
|
_infer_immune variant3a
|
|
_set_vuln variant4
|
|
pr_debug "checking cpu$i: armv8 A75 non affected to variant 3a"
|
|
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd0b -e 0xd0c -e 0xd0d; then
|
|
_set_vuln variant1
|
|
_infer_immune variant2
|
|
_infer_immune variant3
|
|
_infer_immune variant3a
|
|
_set_vuln variant4
|
|
pr_debug "checking cpu$i: armv8 A76/A77/NeoverseN1 non affected to variant 2, 3 & 3a"
|
|
elif [ "$cpuarch" = 8 ] && echo "$cpupart" | grep -q -w -e 0xd40 -e 0xd49 -e 0xd4f; then
|
|
_set_vuln variant1
|
|
_infer_immune variant2
|
|
_infer_immune variant3
|
|
_infer_immune variant3a
|
|
_infer_immune variant4
|
|
pr_debug "checking cpu$i: armv8 NeoverseN2/V1/V2 non affected to variant 2, 3, 3a & 4"
|
|
elif [ "$cpuarch" -le 7 ] || { [ "$cpuarch" = 8 ] && [ $((cpupart)) -lt $((0xd07)) ]; }; then
|
|
_infer_immune variant1
|
|
_infer_immune variant2
|
|
_infer_immune variant3
|
|
_infer_immune variant3a
|
|
_infer_immune variant4
|
|
pr_debug "checking cpu$i: arm arch$cpuarch, all immune (v7 or v8 and model < 0xd07)"
|
|
else
|
|
_set_vuln variant1
|
|
_set_vuln variant2
|
|
_set_vuln variant3
|
|
_set_vuln variant3a
|
|
_set_vuln variant4
|
|
pr_debug "checking cpu$i: arm unknown arch$cpuarch part$cpupart, considering vuln"
|
|
fi
|
|
fi
|
|
pr_debug "is_cpu_affected: for cpu$i and so far, we have <$affected_variant1> <$affected_variant2> <$affected_variant3> <$affected_variant3a> <$affected_variant4>"
|
|
done
|
|
_set_immune variantl1tf
|
|
fi
|
|
|
|
# we handle iTLB Multihit here (not linked to is_specex_free)
|
|
if is_intel; then
|
|
# commit f9aa6b73a407b714c9aac44734eb4045c893c6f7
|
|
if [ "$cpu_family" = 6 ]; then
|
|
if [ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_TABLET" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SALTWELL_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_BONNELL_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_AIRMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNL" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_XEON_PHI_KNM" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_SILVERMONT_MID2" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_D" ] ||
|
|
[ "$cpu_model" = "$INTEL_FAM6_ATOM_GOLDMONT_PLUS" ]; then
|
|
pr_debug "is_cpu_affected: intel family 6 but model known to be immune to itlbmh"
|
|
_infer_immune itlbmh
|
|
else
|
|
pr_debug "is_cpu_affected: intel family 6 is vuln to itlbmh"
|
|
_infer_vuln itlbmh
|
|
fi
|
|
elif [ "$cpu_family" -lt 6 ]; then
|
|
pr_debug "is_cpu_affected: intel family < 6 is immune to itlbmh"
|
|
_infer_immune itlbmh
|
|
fi
|
|
else
|
|
pr_debug "is_cpu_affected: non-intel not affected to itlbmh"
|
|
_infer_immune itlbmh
|
|
fi
|
|
|
|
# SLS (Straight-Line Speculation):
|
|
# - x86_64: all CPUs are affected (compile-time mitigation CONFIG_MITIGATION_SLS)
|
|
# - arm64 (CVE-2020-13844): Cortex-A32/A34/A35/A53/A57/A72/A73 confirmed affected,
|
|
# and broadly all speculative Armv8-A cores. No kernel mitigation merged.
|
|
# Part numbers: A32=0xd01 A34=0xd02 A53=0xd03 A35=0xd04 A57=0xd07 A72=0xd08 A73=0xd09
|
|
# Plus later speculative cores: A75=0xd0a A76=0xd0b A77=0xd0d N1=0xd0c V1=0xd40 N2=0xd49 V2=0xd4f
|
|
if is_intel || is_amd; then
|
|
_infer_vuln sls
|
|
elif [ "$cpu_vendor" = ARM ]; then
|
|
for cpupart in $cpu_part_list; do
|
|
if echo "$cpupart" | grep -q -w -e 0xd01 -e 0xd02 -e 0xd03 -e 0xd04 \
|
|
-e 0xd07 -e 0xd08 -e 0xd09 -e 0xd0a -e 0xd0b -e 0xd0c -e 0xd0d \
|
|
-e 0xd40 -e 0xd49 -e 0xd4f; then
|
|
_set_vuln sls
|
|
fi
|
|
done
|
|
# non-speculative ARM cores (arch <= 7, or early v8 models) are not affected
|
|
_infer_immune sls
|
|
else
|
|
_infer_immune sls
|
|
fi
|
|
|
|
# ARM64 silicon errata (speculation/security-relevant, no CVE assignments).
|
|
# References: arch/arm64/Kconfig (ARM64_ERRATUM_*), arch/arm64/kernel/cpu_errata.c MIDR lists.
|
|
# Iterates per-core (impl, part, variant, revision) tuples. Implementers currently handled:
|
|
# 0x41 ARM Ltd; 0x51 Qualcomm (Kryo4xx Silver for erratum 1530923).
|
|
# Revision ranges mirror the kernel's MIDR_RANGE/MIDR_REV_RANGE/MIDR_REV macros. A variant
|
|
# 'v' and revision 'p' are packed as (v<<4)|p for range compares — equivalent to the kernel's
|
|
# layout (MIDR_VARIANT_SHIFT=20, MIDR_REVISION_MASK=0xf) under the same order semantics.
|
|
# Unknown variant/revision ⇒ treat as in range (whitelist principle, DEVELOPMENT.md rule 5).
|
|
if [ -n "$cpu_part_list" ]; then
|
|
i=0
|
|
for cpupart in $cpu_part_list; do
|
|
i=$((i + 1))
|
|
# shellcheck disable=SC2086
|
|
cpuimpl=$(echo $cpu_impl_list | awk '{print $'$i'}')
|
|
# shellcheck disable=SC2086
|
|
cpuvar=$(echo $cpu_variant_list | awk '{print $'$i'}')
|
|
# shellcheck disable=SC2086
|
|
cpurev=$(echo $cpu_revision_list | awk '{print $'$i'}')
|
|
packed=''
|
|
[ -n "$cpuvar" ] && [ -n "$cpurev" ] && packed=$(((cpuvar << 4) | cpurev))
|
|
|
|
# Speculative AT TLB corruption (errata 1165522, 1319367, 1319537, 1530923)
|
|
if [ "$cpuimpl" = 0x41 ]; then
|
|
if echo "$cpupart" | grep -q -w -e 0xd07 -e 0xd08; then
|
|
# Cortex-A57 (0xd07) / A72 (0xd08): all revisions
|
|
_set_vuln arm_spec_at
|
|
elif echo "$cpupart" | grep -q -w -e 0xd05 -e 0xd0b; then
|
|
# Cortex-A55 (0xd05) / A76 (0xd0b): r0p0..r2p0 (packed 0..32)
|
|
if [ -z "$packed" ] || [ "$packed" -le 32 ]; then
|
|
_set_vuln arm_spec_at
|
|
fi
|
|
fi
|
|
elif [ "$cpuimpl" = 0x51 ] && [ "$cpupart" = 0x805 ]; then
|
|
# Qualcomm Kryo4xx Silver: kernel matches MIDR_REV(var 0xd, rev 0xe) only — packed 0xde = 222
|
|
if [ -z "$packed" ] || [ "$packed" = 222 ]; then
|
|
_set_vuln arm_spec_at
|
|
fi
|
|
fi
|
|
|
|
# Speculative unprivileged load (errata 2966298 A520, 3117295 A510) — ARM Ltd only
|
|
if [ "$cpuimpl" = 0x41 ]; then
|
|
if [ "$cpupart" = 0xd46 ]; then
|
|
# Cortex-A510: all revisions
|
|
_set_vuln arm_spec_unpriv_load
|
|
elif [ "$cpupart" = 0xd80 ]; then
|
|
# Cortex-A520: r0p0..r0p1 (packed 0..1)
|
|
if [ -z "$packed" ] || [ "$packed" -le 1 ]; then
|
|
_set_vuln arm_spec_unpriv_load
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
# MSR SSBS not self-synchronizing (erratum 3194386 + siblings) — ARM Ltd only, all revisions.
|
|
# A76/A77/A78/A78C/A710/A715/A720/A720AE/A725, X1/X1C/X2/X3/X4/X925, N1/N2/N3, V1/V2/V3/V3AE
|
|
if [ "$cpuimpl" = 0x41 ]; then
|
|
if echo "$cpupart" | grep -q -w \
|
|
-e 0xd0b -e 0xd0d -e 0xd41 -e 0xd4b \
|
|
-e 0xd47 -e 0xd4d -e 0xd81 -e 0xd89 -e 0xd87 \
|
|
-e 0xd44 -e 0xd4c -e 0xd48 -e 0xd4e -e 0xd82 -e 0xd85 \
|
|
-e 0xd0c -e 0xd49 -e 0xd8e \
|
|
-e 0xd40 -e 0xd4f -e 0xd84 -e 0xd83; then
|
|
_set_vuln arm_ssbs_nosync
|
|
fi
|
|
fi
|
|
done
|
|
fi
|
|
# Default everything else to immune (covers non-ARM, and ARM cores not in the affected lists)
|
|
_infer_immune arm_spec_at
|
|
_infer_immune arm_spec_unpriv_load
|
|
_infer_immune arm_ssbs_nosync
|
|
|
|
# shellcheck disable=SC2154
|
|
{
|
|
pr_debug "is_cpu_affected: final results: variant1=$affected_variant1 variant2=$affected_variant2 variant3=$affected_variant3 variant3a=$affected_variant3a"
|
|
pr_debug "is_cpu_affected: final results: variant4=$affected_variant4 variantl1tf=$affected_variantl1tf msbds=$affected_msbds mfbds=$affected_mfbds"
|
|
pr_debug "is_cpu_affected: final results: mlpds=$affected_mlpds mdsum=$affected_mdsum taa=$affected_taa itlbmh=$affected_itlbmh srbds=$affected_srbds"
|
|
pr_debug "is_cpu_affected: final results: div0=$affected_div0 fpdss=$affected_fpdss zenbleed=$affected_zenbleed inception=$affected_inception retbleed=$affected_retbleed tsa=$affected_tsa downfall=$affected_downfall reptar=$affected_reptar rfds=$affected_rfds its=$affected_its"
|
|
pr_debug "is_cpu_affected: final results: vmscape=$affected_vmscape bpi=$affected_bpi sls=$affected_sls mmio=$affected_mmio"
|
|
pr_debug "is_cpu_affected: final results: arm_spec_at=$affected_arm_spec_at arm_spec_unpriv_load=$affected_arm_spec_unpriv_load arm_ssbs_nosync=$affected_arm_ssbs_nosync"
|
|
}
|
|
affected_variantl1tf_sgx="$affected_variantl1tf"
|
|
# even if we are affected to L1TF, if there's no SGX, we're not affected to the original foreshadow
|
|
[ "$cap_sgx" = 0 ] && _set_immune variantl1tf_sgx
|
|
pr_debug "is_cpu_affected: variantl1tf_sgx=<$affected_variantl1tf_sgx>"
|
|
g_is_cpu_affected_cached=1
|
|
_is_cpu_affected_cached "$1"
|
|
return $?
|
|
}
|