enh: factorize is_arch_kernel

This commit is contained in:
Stéphane Lesimple
2026-04-10 18:37:14 +02:00
parent de853fc801
commit e110706df8
5 changed files with 27 additions and 21 deletions

View File

@@ -105,6 +105,7 @@ The entire tool is a single bash script with no external script dependencies. Ke
- **Output/logging functions** (~line 253): `pr_warn`, `pr_info`, `pr_verbose`, `pr_debug`, `explain`, `pstatus`, `pvulnstatus` - verbosity-aware output with color support - **Output/logging functions** (~line 253): `pr_warn`, `pr_info`, `pr_verbose`, `pr_debug`, `explain`, `pstatus`, `pvulnstatus` - verbosity-aware output with color support
- **CPU detection** (~line 2171): `parse_cpu_details`, `is_intel`/`is_amd`/`is_hygon`, `read_cpuid`, `read_msr`, `is_cpu_smt_enabled` - hardware identification via CPUID/MSR registers - **CPU detection** (~line 2171): `parse_cpu_details`, `is_intel`/`is_amd`/`is_hygon`, `read_cpuid`, `read_msr`, `is_cpu_smt_enabled` - hardware identification via CPUID/MSR registers
- **Kernel architecture detection** (`src/libs/365_kernel_arch.sh`): `is_arm64_kernel`/`is_x86_kernel` - detects the target kernel's architecture (not the host CPU) using kernel artifacts (System.map symbols, kconfig, kernel image), with `cpu_vendor` as a fast path for live mode. Results are cached in `g_kernel_arch`. Use these helpers to guard arch-specific kernel/kconfig/System.map checks and to select the appropriate verdict messages
- **Microcode database** (embedded): Intel/AMD microcode version lookup via `read_mcedb`/`read_inteldb`; updated automatically via `.github/workflows/autoupdate.yml` - **Microcode database** (embedded): Intel/AMD microcode version lookup via `read_mcedb`/`read_inteldb`; updated automatically via `.github/workflows/autoupdate.yml`
- **Kernel analysis** (~line 1568): `extract_kernel`, `try_decompress` - extracts and inspects kernel images (handles gzip, bzip2, xz, lz4, zstd compression) - **Kernel analysis** (~line 1568): `extract_kernel`, `try_decompress` - extracts and inspects kernel images (handles gzip, bzip2, xz, lz4, zstd compression)
- **Vulnerability checks**: 19 `check_CVE_<year>_<number>()` functions, each with `_linux()` and `_bsd()` variants. Uses whitelist logic (assumes affected unless proven otherwise) - **Vulnerability checks**: 19 `check_CVE_<year>_<number>()` functions, each with `_linux()` and `_bsd()` variants. Uses whitelist logic (assumes affected unless proven otherwise)
@@ -390,6 +391,19 @@ This is where the real detection lives. Check for mitigations at each layer:
Each source may independently be unavailable (no-runtime mode without the file, or stripped kernel), so check all that are present. A match in any one confirms kernel support. Each source may independently be unavailable (no-runtime mode without the file, or stripped kernel), so check all that are present. A match in any one confirms kernel support.
**Architecture awareness:** Kernel symbols, kconfig options, and kernel-image strings are architecture-specific. An x86 host may be inspecting an ARM64 kernel (or vice versa) in offline mode, so always guard arch-specific checks with `is_arm64_kernel` or `is_x86_kernel` from `src/libs/365_kernel_arch.sh`. This prevents searching for irrelevant strings (e.g. x86 `spec_store_bypass` in an ARM64 kernel image) and ensures verdict messages and `explain` text match the target architecture (e.g. "update CPU microcode" for x86 vs "update firmware for SMCCC ARCH_WORKAROUND_2" for ARM). Example:
```sh
# x86-specific kernel image search: skip on ARM64 kernels
if [ -n "$g_kernel" ] && ! is_arm64_kernel; then
mitigation=$("${opt_arch_prefix}strings" "$g_kernel" | grep x86_specific_string)
fi
# ARM64-specific System.map search: skip on x86 kernels
if [ -n "$opt_map" ] && is_arm64_kernel; then
mitigation=$(grep -w arm64_mitigation_function "$opt_map")
fi
```
The same applies to Phase 4 verdict messages: when the explanation or remediation advice differs between architectures (e.g. "CPU microcode update" vs "firmware/kernel update"), branch on `is_arm64_kernel`/`is_x86_kernel` rather than on `cpu_vendor`, because `cpu_vendor` reflects the host, not the target kernel.
- **Runtime state** (live mode only): Read MSRs, check cpuinfo flags, parse dmesg, inspect debugfs. All runtime-only checks — including `/proc/cpuinfo` flags — must be guarded by `if [ "$opt_runtime" = 1 ]`, both when collecting the evidence in Phase 2 and when using it in Phase 4. In Phase 4, use explicit live/no-runtime branches so that live-only variables (e.g. cpuinfo flags, MSR values) are never referenced in the no-runtime path. - **Runtime state** (live mode only): Read MSRs, check cpuinfo flags, parse dmesg, inspect debugfs. All runtime-only checks — including `/proc/cpuinfo` flags — must be guarded by `if [ "$opt_runtime" = 1 ]`, both when collecting the evidence in Phase 2 and when using it in Phase 4. In Phase 4, use explicit live/no-runtime branches so that live-only variables (e.g. cpuinfo flags, MSR values) are never referenced in the no-runtime path.
```sh ```sh
if [ "$opt_runtime" = 1 ]; then if [ "$opt_runtime" = 1 ]; then
@@ -789,6 +803,7 @@ CVEs that need VMM context should call `check_has_vmm` early in their `_linux()`
- **Handle `--paranoid` and `--vmm`** when the CVE has stricter mitigation tiers or VMM-specific aspects (see "Cross-Cutting Features" above). - **Handle `--paranoid` and `--vmm`** when the CVE has stricter mitigation tiers or VMM-specific aspects (see "Cross-Cutting Features" above).
- **Keep JSON output in sync** - when adding new `cap_*` variables, add them to `_build_json_cpu()` in `src/libs/250_output_emitters.sh` (see Step 2 JSON note above). Per-CVE fields are handled automatically. - **Keep JSON output in sync** - when adding new `cap_*` variables, add them to `_build_json_cpu()` in `src/libs/250_output_emitters.sh` (see Step 2 JSON note above). Per-CVE fields are handled automatically.
- **All indentation must use 4 spaces** (CI enforces this via `fmt-check`; the vim modeline `et` enables expandtab). - **All indentation must use 4 spaces** (CI enforces this via `fmt-check`; the vim modeline `et` enables expandtab).
- **Guard arch-specific checks with `is_arm64_kernel`/`is_x86_kernel`** - kernel image strings, kconfig symbols, and System.map functions are architecture-specific. Use the helpers from `src/libs/365_kernel_arch.sh` to avoid searching for irrelevant symbols and to select correct verdict messages. Never use `cpu_vendor` to branch on architecture in Phase 2/4 — it reflects the host, not the target kernel being inspected.
- **Stay POSIX-compatible** - no bashisms, no GNU-only flags in portable code paths. - **Stay POSIX-compatible** - no bashisms, no GNU-only flags in portable code paths.
## Function documentation headers ## Function documentation headers

View File

@@ -2,6 +2,11 @@
check_kernel_info check_kernel_info
# Detect arch mismatch between host CPU and target kernel (e.g. x86 host
# inspecting an ARM kernel): force no-hw mode so CPUID/MSR/sysfs reads
# from the host don't pollute the results.
check_kernel_cpu_arch_mismatch
# Build JSON meta and system sections early (after kernel info is resolved) # Build JSON meta and system sections early (after kernel info is resolved)
if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "json" ]; then if [ "$opt_batch" = 1 ] && [ "$opt_batch_format" = "json" ]; then
_build_json_meta _build_json_meta

View File

@@ -903,7 +903,7 @@ check_CVE_2017_5715_linux() {
# ARM branch predictor hardening (unchanged) # ARM branch predictor hardening (unchanged)
if [ -n "$bp_harden" ]; then if [ -n "$bp_harden" ]; then
pvulnstatus "$cve" OK "Branch predictor hardening mitigates the vulnerability" pvulnstatus "$cve" OK "Branch predictor hardening mitigates the vulnerability"
elif [ -z "$bp_harden" ] && [ "$cpu_vendor" = ARM ]; then elif [ -z "$bp_harden" ] && is_arm64_kernel; then
pvulnstatus "$cve" VULN "Branch predictor hardening is needed to mitigate the vulnerability" pvulnstatus "$cve" VULN "Branch predictor hardening is needed to mitigate the vulnerability"
explain "Your kernel has not been compiled with the CONFIG_UNMAP_KERNEL_AT_EL0 option, recompile it with this option enabled." explain "Your kernel has not been compiled with the CONFIG_UNMAP_KERNEL_AT_EL0 option, recompile it with this option enabled."

View File

@@ -25,12 +25,12 @@ check_CVE_2018_3639_linux() {
fi fi
fi fi
# arm64 kernels can have cpu_show_spec_store_bypass with ARM64_SSBD, so exclude them # arm64 kernels can have cpu_show_spec_store_bypass with ARM64_SSBD, so exclude them
if [ -z "$kernel_ssb" ] && [ -n "$g_kernel" ] && ! grep -q 'arm64_sys_' "$g_kernel"; then if [ -z "$kernel_ssb" ] && [ -n "$g_kernel" ] && ! is_arm64_kernel; then
kernel_ssb=$("${opt_arch_prefix}strings" "$g_kernel" | grep spec_store_bypass | head -n1) kernel_ssb=$("${opt_arch_prefix}strings" "$g_kernel" | grep spec_store_bypass | head -n1)
[ -n "$kernel_ssb" ] && kernel_ssb="found $kernel_ssb in kernel" [ -n "$kernel_ssb" ] && kernel_ssb="found $kernel_ssb in kernel"
fi fi
# arm64 kernels can have cpu_show_spec_store_bypass with ARM64_SSBD, so exclude them # arm64 kernels can have cpu_show_spec_store_bypass with ARM64_SSBD, so exclude them
if [ -z "$kernel_ssb" ] && [ -n "$opt_map" ] && ! grep -q 'arm64_sys_' "$opt_map"; then if [ -z "$kernel_ssb" ] && [ -n "$opt_map" ] && ! is_arm64_kernel; then
kernel_ssb=$(grep spec_store_bypass "$opt_map" | awk '{print $3}' | head -n1) kernel_ssb=$(grep spec_store_bypass "$opt_map" | awk '{print $3}' | head -n1)
[ -n "$kernel_ssb" ] && kernel_ssb="found $kernel_ssb in System.map" [ -n "$kernel_ssb" ] && kernel_ssb="found $kernel_ssb in System.map"
fi fi
@@ -121,7 +121,7 @@ check_CVE_2018_3639_linux() {
fi fi
else else
if [ -n "$kernel_ssb" ]; then if [ -n "$kernel_ssb" ]; then
if [ "$cpu_vendor" = ARM ] || [ "$cpu_vendor" = CAVIUM ] || [ "$cpu_vendor" = PHYTIUM ]; then if is_arm64_kernel; then
pvulnstatus "$cve" VULN "no SSB mitigation is active on your system" pvulnstatus "$cve" VULN "no SSB mitigation is active on your system"
explain "ARM CPUs mitigate SSB either through a hardware SSBS bit (ARMv8.5+ CPUs) or through firmware support for SMCCC ARCH_WORKAROUND_2. Your kernel reports SSB status but neither mechanism appears to be active. For CPUs predating ARMv8.5 (such as Cortex-A57 or Cortex-A72), check with your board or SoC vendor for a firmware update that provides SMCCC ARCH_WORKAROUND_2 support." explain "ARM CPUs mitigate SSB either through a hardware SSBS bit (ARMv8.5+ CPUs) or through firmware support for SMCCC ARCH_WORKAROUND_2. Your kernel reports SSB status but neither mechanism appears to be active. For CPUs predating ARMv8.5 (such as Cortex-A57 or Cortex-A72), check with your board or SoC vendor for a firmware update that provides SMCCC ARCH_WORKAROUND_2 support."
else else
@@ -129,7 +129,7 @@ check_CVE_2018_3639_linux() {
explain "Your kernel is recent enough to use the CPU microcode features for mitigation, but your CPU microcode doesn't actually provide the necessary features for the kernel to use. The microcode of your CPU hence needs to be upgraded. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section)." explain "Your kernel is recent enough to use the CPU microcode features for mitigation, but your CPU microcode doesn't actually provide the necessary features for the kernel to use. The microcode of your CPU hence needs to be upgraded. This is usually done at boot time by your kernel (the upgrade is not persistent across reboots which is why it's done at each boot). If you're using a distro, make sure you are up to date, as microcode updates are usually shipped alongside with the distro kernel. Availability of a microcode update for you CPU model depends on your CPU vendor. You can usually find out online if a microcode update is available for your CPU by searching for your CPUID (indicated in the Hardware Check section)."
fi fi
else else
if [ "$cpu_vendor" = ARM ] || [ "$cpu_vendor" = CAVIUM ] || [ "$cpu_vendor" = PHYTIUM ]; then if is_arm64_kernel; then
pvulnstatus "$cve" VULN "your kernel and firmware do not support SSB mitigation" pvulnstatus "$cve" VULN "your kernel and firmware do not support SSB mitigation"
explain "ARM SSB mitigation requires kernel support (CONFIG_ARM64_SSBD) combined with either a hardware SSBS bit (ARMv8.5+ CPUs) or firmware support for SMCCC ARCH_WORKAROUND_2. Ensure you are running a recent kernel compiled with CONFIG_ARM64_SSBD. For CPUs predating ARMv8.5, also check with your board or SoC vendor for a firmware update providing SMCCC ARCH_WORKAROUND_2 support." explain "ARM SSB mitigation requires kernel support (CONFIG_ARM64_SSBD) combined with either a hardware SSBS bit (ARMv8.5+ CPUs) or firmware support for SMCCC ARCH_WORKAROUND_2. Ensure you are running a recent kernel compiled with CONFIG_ARM64_SSBD. For CPUs predating ARMv8.5, also check with your board or SoC vendor for a firmware update providing SMCCC ARCH_WORKAROUND_2 support."
else else

View File

@@ -3,7 +3,7 @@
# CVE-2018-3640, Variant 3a, Rogue System Register Read # CVE-2018-3640, Variant 3a, Rogue System Register Read
check_CVE_2018_3640() { check_CVE_2018_3640() {
local status sys_interface_available msg cve is_arm64_kernel arm_v3a_mitigation local status sys_interface_available msg cve arm_v3a_mitigation
cve='CVE-2018-3640' cve='CVE-2018-3640'
pr_info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m" pr_info "\033[1;34m$cve aka '$(cve2name "$cve")'\033[0m"
@@ -11,21 +11,7 @@ check_CVE_2018_3640() {
sys_interface_available=0 sys_interface_available=0
msg='' msg=''
# Detect whether the target kernel is ARM64, for both live and no-runtime modes. if is_arm64_kernel; then
# In no-runtime cross-inspection (x86 host, ARM kernel), cpu_vendor reflects the host,
# so also check for arm64_sys_ symbols (same pattern used in CVE-2018-3639).
is_arm64_kernel=0
if [ "$cpu_vendor" = ARM ] || [ "$cpu_vendor" = CAVIUM ] || [ "$cpu_vendor" = PHYTIUM ]; then
is_arm64_kernel=1
elif [ -n "$opt_map" ] && grep -q 'arm64_sys_' "$opt_map" 2>/dev/null; then
is_arm64_kernel=1
elif [ -n "$g_kernel" ] && grep -q 'arm64_sys_' "$g_kernel" 2>/dev/null; then
is_arm64_kernel=1
elif [ -n "$opt_config" ] && grep -qw 'CONFIG_ARM64=y' "$opt_config" 2>/dev/null; then
is_arm64_kernel=1
fi
if [ "$is_arm64_kernel" = 1 ]; then
# ARM64: mitigation is via an EL2 indirect trampoline (spectre_v3a_enable_mitigation), # ARM64: mitigation is via an EL2 indirect trampoline (spectre_v3a_enable_mitigation),
# applied automatically at boot for affected CPUs (Cortex-A57, Cortex-A72). # applied automatically at boot for affected CPUs (Cortex-A57, Cortex-A72).
# No microcode update is involved. # No microcode update is involved.