diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index bcbd45a..72d7470 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -105,7 +105,8 @@ 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 - **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 +- **Kernel architecture detection** (`src/libs/365_kernel_arch.sh`): `is_arm_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 +- **CPU architecture detection** (`src/libs/360_cpu_smt.sh`): `is_x86_cpu`/`is_arm_cpu` - detects the host CPU's architecture via `cpu_vendor`. Use these to gate hardware operations (CPUID, MSR, microcode). Always use positive logic: `if is_x86_cpu` (not `if ! is_arm_cpu`) - **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) - **Vulnerability checks**: 19 `check_CVE__()` functions, each with `_linux()` and `_bsd()` variants. Uses whitelist logic (assumes affected unless proven otherwise) @@ -391,18 +392,30 @@ 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. - **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: + **Architecture awareness:** Kernel symbols, kconfig options, and kernel-image strings are architecture-specific. An x86 host may be inspecting an ARM kernel (or vice versa) in offline mode, so always use positive-logic arch guards from `src/libs/365_kernel_arch.sh` and `src/libs/360_cpu_smt.sh`. This prevents searching for irrelevant strings (e.g. x86 `spec_store_bypass` in an ARM 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). + + Use **positive logic** — always `if is_x86_kernel` (not `if ! is_arm_kernel`) and `if is_x86_cpu` (not `if ! is_arm_cpu`). This ensures unknown architectures (MIPS, RISC-V, PowerPC) are handled safely by defaulting to "skip" rather than "execute." + + Two sets of helpers serve different purposes: + - **`is_x86_kernel`/`is_arm_kernel`**: Gate kernel artifact checks (kernel image strings, kconfig, System.map). + - **`is_x86_cpu`/`is_arm_cpu`**: Gate hardware operations (CPUID, MSR, `/proc/cpuinfo` flags). + + Example: ```sh - # x86-specific kernel image search: skip on ARM64 kernels - if [ -n "$g_kernel" ] && ! is_arm64_kernel; then + # x86-specific kernel image search + if [ -n "$g_kernel" ] && is_x86_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") + # ARM-specific System.map search + if [ -n "$opt_map" ] && is_arm_kernel; then + mitigation=$(grep -w arm_mitigation_function "$opt_map") + fi + # x86-specific hardware read + if is_x86_cpu; then + read_cpuid 0x7 0x0 "$EDX" 26 1 1 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. + 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_arm_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. ```sh @@ -803,7 +816,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). - **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). -- **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. +- **Guard arch-specific checks with positive logic** — use `is_x86_kernel`/`is_arm_kernel` for kernel artifact checks, `is_x86_cpu`/`is_arm_cpu` for hardware operations. Always use positive form (`if is_x86_cpu`, not `if ! is_arm_cpu`) so unknown architectures default to "skip." 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. ## Function documentation headers diff --git a/src/libs/360_cpu_smt.sh b/src/libs/360_cpu_smt.sh index 3a1f8eb..e7f9d31 100644 --- a/src/libs/360_cpu_smt.sh +++ b/src/libs/360_cpu_smt.sh @@ -21,6 +21,28 @@ is_intel() { return 1 } +# Check whether the host CPU is x86/x86_64. +# Use this to gate CPUID, MSR, and microcode operations. +# Returns: 0 if x86, 1 otherwise +is_x86_cpu() { + parse_cpu_details + case "$cpu_vendor" in + GenuineIntel | AuthenticAMD | HygonGenuine | CentaurHauls | Shanghai) return 0 ;; + esac + return 1 +} + +# Check whether the host CPU is ARM/ARM64. +# Use this to gate ARM-specific hardware checks. +# Returns: 0 if ARM, 1 otherwise +is_arm_cpu() { + parse_cpu_details + case "$cpu_vendor" in + ARM | CAVIUM | PHYTIUM) return 0 ;; + esac + return 1 +} + # Check whether SMT (HyperThreading) is enabled on the system # Returns: 0 if SMT enabled, 1 otherwise is_cpu_smt_enabled() { diff --git a/src/libs/365_kernel_arch.sh b/src/libs/365_kernel_arch.sh new file mode 100644 index 0000000..5a80c64 --- /dev/null +++ b/src/libs/365_kernel_arch.sh @@ -0,0 +1,120 @@ +# vim: set ts=4 sw=4 sts=4 et: +############################### +# Kernel architecture detection helpers. +# Detects the target kernel's architecture regardless of the host system, +# enabling correct behavior in offline cross-inspection (e.g. x86 host +# analyzing an ARM kernel image or System.map). + +# Global cache; populated by _detect_kernel_arch on first call. +# Values: 'arm', 'x86', 'unknown' +g_kernel_arch='' + +# Internal: populate g_kernel_arch using all available information sources, +# in order from most to least reliable. +_detect_kernel_arch() { + # Return immediately if already detected + [ -n "$g_kernel_arch" ] && return 0 + + # arm64_sys_ is the ARM64 syscall table symbol prefix; present in any + # ARM64 System.map (or /proc/kallsyms) and in the kernel image itself. + # sys_call_table + vector_swi is the ARM (32-bit) equivalent. + if [ -n "$opt_map" ]; then + if grep -q 'arm64_sys_' "$opt_map" 2>/dev/null; then + g_kernel_arch='arm' + return 0 + fi + if grep -q ' vector_swi$' "$opt_map" 2>/dev/null; then + g_kernel_arch='arm' + return 0 + fi + fi + if [ -n "$g_kernel" ]; then + if grep -q 'arm64_sys_' "$g_kernel" 2>/dev/null; then + g_kernel_arch='arm' + return 0 + fi + fi + + # Kconfig is definitive when available + if [ -n "$opt_config" ]; then + if grep -qE '^CONFIG_(ARM64|ARM)=y' "$opt_config" 2>/dev/null; then + g_kernel_arch='arm' + return 0 + fi + if grep -qE '^CONFIG_X86(_64)?=y' "$opt_config" 2>/dev/null; then + g_kernel_arch='x86' + return 0 + fi + fi + + # Cross-compilation prefix as a last resort (e.g. --arch-prefix aarch64-linux-gnu-) + case "${opt_arch_prefix:-}" in + aarch64-* | arm64-* | arm-* | armv*-) + g_kernel_arch='arm' + return 0 + ;; + x86_64-* | i686-* | i?86-*) + g_kernel_arch='x86' + return 0 + ;; + esac + + # Last resort: if no artifacts identified the arch, assume the target + # kernel matches the host CPU. This covers live mode when no kernel + # image, config, or System.map is available. + if is_x86_cpu; then + g_kernel_arch='x86' + return 0 + fi + if is_arm_cpu; then + g_kernel_arch='arm' + return 0 + fi + + g_kernel_arch='unknown' + return 0 +} + +# Return 0 (true) if the target kernel is ARM (32 or 64-bit), 1 otherwise. +is_arm_kernel() { + _detect_kernel_arch + [ "$g_kernel_arch" = 'arm' ] +} + +# Return 0 (true) if the target kernel is x86/x86_64, 1 otherwise. +is_x86_kernel() { + _detect_kernel_arch + [ "$g_kernel_arch" = 'x86' ] +} + +# Compare the target kernel's architecture against the host CPU. +# If they differ, hardware reads (CPUID, MSR, sysfs) would reflect the host, +# not the target kernel — force no-hw mode to avoid misleading results. +# Sets: g_mode (when mismatch detected) +# Callers: src/main.sh (after check_kernel_info, before check_cpu) +check_kernel_cpu_arch_mismatch() { + local host_arch + _detect_kernel_arch + + host_arch='unknown' + if is_x86_cpu; then + host_arch='x86' + elif is_arm_cpu; then + host_arch='arm' + fi + + # Unsupported CPU architecture (MIPS, RISC-V, PowerPC, ...): force no-hw + # since we have no hardware-level checks for these platforms + if [ "$host_arch" = 'unknown' ]; then + pr_warn "Unsupported CPU architecture (vendor: $cpu_vendor), forcing no-hw mode" + g_mode='no-hw' + return 0 + fi + + # If kernel arch is unknown, we can't tell if there's a mismatch + [ "$g_kernel_arch" = 'unknown' ] && return 0 + [ "$host_arch" = "$g_kernel_arch" ] && return 0 + + pr_warn "Target kernel architecture ($g_kernel_arch) differs from host CPU ($host_arch), forcing no-hw mode" + g_mode='no-hw' +} diff --git a/src/vulns-helpers/check_mds.sh b/src/vulns-helpers/check_mds.sh index 6fcb72f..09b273e 100644 --- a/src/vulns-helpers/check_mds.sh +++ b/src/vulns-helpers/check_mds.sh @@ -132,50 +132,54 @@ check_mds_linux() { fi if [ "$opt_sysfs_only" != 1 ]; then - pr_info_nol "* Kernel supports using MD_CLEAR mitigation: " + # MDS is Intel-only; skip x86-specific kernel/cpuinfo checks on non-x86 kernels kernel_md_clear='' - kernel_md_clear_can_tell=1 - if [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then - kernel_md_clear="md_clear found in $g_procfs/cpuinfo" - pstatus green YES "$kernel_md_clear" - fi - if [ -z "$kernel_md_clear" ]; then - if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then - kernel_md_clear_can_tell=0 - elif [ -n "$g_kernel_err" ]; then - kernel_md_clear_can_tell=0 - elif "${opt_arch_prefix}strings" "$g_kernel" | grep -q 'Clear CPU buffers'; then - pr_debug "md_clear: found 'Clear CPU buffers' string in kernel image" - kernel_md_clear='found md_clear implementation evidence in kernel image' + kernel_md_clear_can_tell=0 + if is_x86_kernel; then + pr_info_nol "* Kernel supports using MD_CLEAR mitigation: " + kernel_md_clear_can_tell=1 + if [ "$opt_runtime" = 1 ] && grep ^flags "$g_procfs/cpuinfo" | grep -qw md_clear; then + kernel_md_clear="md_clear found in $g_procfs/cpuinfo" pstatus green YES "$kernel_md_clear" fi - fi - if [ -z "$kernel_md_clear" ]; then - if [ "$kernel_md_clear_can_tell" = 1 ]; then - pstatus yellow NO - else - pstatus yellow UNKNOWN + if [ -z "$kernel_md_clear" ]; then + if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then + kernel_md_clear_can_tell=0 + elif [ -n "$g_kernel_err" ]; then + kernel_md_clear_can_tell=0 + elif "${opt_arch_prefix}strings" "$g_kernel" | grep -q 'Clear CPU buffers'; then + pr_debug "md_clear: found 'Clear CPU buffers' string in kernel image" + kernel_md_clear='found md_clear implementation evidence in kernel image' + pstatus green YES "$kernel_md_clear" + fi + fi + if [ -z "$kernel_md_clear" ]; then + if [ "$kernel_md_clear_can_tell" = 1 ]; then + pstatus yellow NO + else + pstatus yellow UNKNOWN + fi fi - fi - if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then - pr_info_nol "* Kernel mitigation is enabled and active: " - if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then - mds_mitigated=1 - pstatus green YES - else - mds_mitigated=0 - pstatus yellow NO + if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then + pr_info_nol "* Kernel mitigation is enabled and active: " + if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then + mds_mitigated=1 + pstatus green YES + else + mds_mitigated=0 + pstatus yellow NO + fi + pr_info_nol "* SMT is either mitigated or disabled: " + if echo "$ret_sys_interface_check_fullmsg" | grep -Eq 'SMT (disabled|mitigated)'; then + mds_smt_mitigated=1 + pstatus green YES + else + mds_smt_mitigated=0 + pstatus yellow NO + fi fi - pr_info_nol "* SMT is either mitigated or disabled: " - if echo "$ret_sys_interface_check_fullmsg" | grep -Eq 'SMT (disabled|mitigated)'; then - mds_smt_mitigated=1 - pstatus green YES - else - mds_smt_mitigated=0 - pstatus yellow NO - fi - fi + fi # is_x86_kernel elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" diff --git a/src/vulns-helpers/check_mmio.sh b/src/vulns-helpers/check_mmio.sh index 683c2d5..122462b 100644 --- a/src/vulns-helpers/check_mmio.sh +++ b/src/vulns-helpers/check_mmio.sh @@ -125,61 +125,65 @@ check_mmio_linux() { fi if [ "$opt_sysfs_only" != 1 ]; then - pr_info_nol "* Kernel supports MMIO Stale Data mitigation: " + # MMIO Stale Data is Intel-only; skip x86-specific kernel/MSR checks on non-x86 kernels kernel_mmio='' - kernel_mmio_can_tell=1 - if [ -n "$g_kernel_err" ]; then - kernel_mmio_can_tell=0 - elif grep -q 'mmio_stale_data' "$g_kernel" 2>/dev/null; then - pr_debug "mmio: found 'mmio_stale_data' string in kernel image" - kernel_mmio='found MMIO Stale Data mitigation evidence in kernel image' - pstatus green YES "$kernel_mmio" - fi - if [ -z "$kernel_mmio" ] && [ -n "$opt_config" ] && grep -q '^CONFIG_MITIGATION_MMIO_STALE_DATA=y' "$opt_config"; then - kernel_mmio='found MMIO Stale Data mitigation config option enabled' - pstatus green YES "$kernel_mmio" - fi - if [ -z "$kernel_mmio" ] && [ -n "$opt_map" ]; then - if grep -qE 'mmio_select_mitigation|cpu_show_mmio_stale_data' "$opt_map"; then - kernel_mmio='found MMIO Stale Data mitigation function in System.map' + kernel_mmio_can_tell=0 + if is_x86_kernel; then + pr_info_nol "* Kernel supports MMIO Stale Data mitigation: " + kernel_mmio_can_tell=1 + if [ -n "$g_kernel_err" ]; then + kernel_mmio_can_tell=0 + elif grep -q 'mmio_stale_data' "$g_kernel" 2>/dev/null; then + pr_debug "mmio: found 'mmio_stale_data' string in kernel image" + kernel_mmio='found MMIO Stale Data mitigation evidence in kernel image' pstatus green YES "$kernel_mmio" fi - fi - if [ -z "$kernel_mmio" ]; then - if [ "$kernel_mmio_can_tell" = 1 ]; then - pstatus yellow NO - else + if [ -z "$kernel_mmio" ] && [ -n "$opt_config" ] && grep -q '^CONFIG_MITIGATION_MMIO_STALE_DATA=y' "$opt_config"; then + kernel_mmio='found MMIO Stale Data mitigation config option enabled' + pstatus green YES "$kernel_mmio" + fi + if [ -z "$kernel_mmio" ] && [ -n "$opt_map" ]; then + if grep -qE 'mmio_select_mitigation|cpu_show_mmio_stale_data' "$opt_map"; then + kernel_mmio='found MMIO Stale Data mitigation function in System.map' + pstatus green YES "$kernel_mmio" + fi + fi + if [ -z "$kernel_mmio" ]; then + if [ "$kernel_mmio_can_tell" = 1 ]; then + pstatus yellow NO + else + pstatus yellow UNKNOWN + fi + fi + + pr_info_nol "* CPU microcode supports Fill Buffer clearing: " + if [ "$cap_fb_clear" = -1 ]; then pstatus yellow UNKNOWN - fi - fi - - pr_info_nol "* CPU microcode supports Fill Buffer clearing: " - if [ "$cap_fb_clear" = -1 ]; then - pstatus yellow UNKNOWN - elif [ "$cap_fb_clear" = 1 ]; then - pstatus green YES - else - pstatus yellow NO - fi - - if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then - pr_info_nol "* Kernel mitigation is enabled and active: " - if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then - mmio_mitigated=1 + elif [ "$cap_fb_clear" = 1 ]; then pstatus green YES else - mmio_mitigated=0 pstatus yellow NO fi - pr_info_nol "* SMT is either mitigated or disabled: " - if echo "$ret_sys_interface_check_fullmsg" | grep -Eq 'SMT (disabled|mitigated)'; then - mmio_smt_mitigated=1 - pstatus green YES - else - mmio_smt_mitigated=0 - pstatus yellow NO + + if [ "$opt_runtime" = 1 ] && [ "$sys_interface_available" = 1 ]; then + pr_info_nol "* Kernel mitigation is enabled and active: " + if echo "$ret_sys_interface_check_fullmsg" | grep -qi ^mitigation; then + mmio_mitigated=1 + pstatus green YES + else + mmio_mitigated=0 + pstatus yellow NO + fi + pr_info_nol "* SMT is either mitigated or disabled: " + if echo "$ret_sys_interface_check_fullmsg" | grep -Eq 'SMT (disabled|mitigated)'; then + mmio_smt_mitigated=1 + pstatus green YES + else + mmio_smt_mitigated=0 + pstatus yellow NO + fi fi - fi + fi # is_x86_kernel elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! msg="/sys vulnerability interface use forced, but it's not available!" diff --git a/src/vulns-helpers/check_sls.sh b/src/vulns-helpers/check_sls.sh index b640a8e..058949a 100644 --- a/src/vulns-helpers/check_sls.sh +++ b/src/vulns-helpers/check_sls.sh @@ -173,10 +173,8 @@ check_CVE_0000_0001_linux() { return fi - # --- arm64: no kernel mitigation available --- - local _sls_arch - _sls_arch=$(uname -m 2>/dev/null || echo unknown) - if echo "$_sls_arch" | grep -qw 'aarch64'; then + # --- ARM: no kernel mitigation available --- + if is_arm_kernel; then pvulnstatus "$cve" VULN "no kernel mitigation available for arm64 SLS (CVE-2020-13844)" explain "Your ARM processor is affected by Straight-Line Speculation (CVE-2020-13844).\n" \ "GCC and Clang support -mharden-sls=all for aarch64, which inserts SB (Speculation Barrier)\n" \ @@ -186,7 +184,12 @@ check_CVE_0000_0001_linux() { return fi - # --- method 1: kernel config check (x86_64) --- + # --- x86: config check and binary heuristic --- + if ! is_x86_kernel; then + pvulnstatus "$cve" UNK "SLS mitigation detection not supported for this kernel architecture" + return + fi + local _sls_config='' if [ -n "$opt_config" ] && [ -r "$opt_config" ]; then pr_info_nol " * Kernel compiled with SLS mitigation: " diff --git a/src/vulns/CVE-2017-5715.sh b/src/vulns/CVE-2017-5715.sh index 88b4f81..eb1fc33 100644 --- a/src/vulns/CVE-2017-5715.sh +++ b/src/vulns/CVE-2017-5715.sh @@ -256,631 +256,643 @@ check_CVE_2017_5715_linux() { v2_vuln_module='' v2_is_autoibrs=0 - pr_info "* Mitigation 1" + # Mitigation 1 (IBRS/IBPB) and Mitigation 3 (sub-mitigations) are x86-only. + # On ARM64, only Mitigation 2 (branch predictor hardening) is relevant. + if is_x86_kernel; then - g_ibrs_can_tell=0 - g_ibrs_supported='' - g_ibrs_enabled='' - g_ibpb_can_tell=0 - g_ibpb_supported='' - g_ibpb_enabled='' + pr_info "* Mitigation 1" - if [ "$opt_runtime" = 1 ]; then - # in live mode, we can check for the ibrs_enabled file in debugfs - # all versions of the patches have it (NOT the case of IBPB or KPTI) - g_ibrs_can_tell=1 - mount_debugfs - for dir in \ - $DEBUGFS_BASE \ - $DEBUGFS_BASE/x86 \ - "$g_procfs/sys/kernel"; do - if [ -e "$dir/ibrs_enabled" ]; then - # if the file is there, we have IBRS compiled-in - # $DEBUGFS_BASE/ibrs_enabled: vanilla - # $DEBUGFS_BASE/x86/ibrs_enabled: Red Hat (see https://access.redhat.com/articles/3311301) - # /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed - g_specex_knob_dir=$dir - g_ibrs_supported="$dir/ibrs_enabled exists" - g_ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null) - pr_debug "ibrs: found $dir/ibrs_enabled=$g_ibrs_enabled" - # if ibrs_enabled is there, ibpb_enabled will be in the same dir - if [ -e "$dir/ibpb_enabled" ]; then - # if the file is there, we have IBPB compiled-in (see note above for IBRS) - g_ibpb_supported="$dir/ibpb_enabled exists" - g_ibpb_enabled=$(cat "$dir/ibpb_enabled" 2>/dev/null) - pr_debug "ibpb: found $dir/ibpb_enabled=$g_ibpb_enabled" - else - pr_debug "ibpb: $dir/ibpb_enabled file doesn't exist" - fi - break - else - pr_debug "ibrs: $dir/ibrs_enabled file doesn't exist" - fi - done - # on some newer kernels, the spec_ctrl_ibrs flag in "$g_procfs/cpuinfo" - # is set when ibrs has been administratively enabled (usually from cmdline) - # which in that case means ibrs is supported *and* enabled for kernel & user - # as per the ibrs patch series v3 - if [ -z "$g_ibrs_supported" ]; then - if grep ^flags "$g_procfs/cpuinfo" | grep -qw spec_ctrl_ibrs; then - pr_debug "ibrs: found spec_ctrl_ibrs flag in $g_procfs/cpuinfo" - g_ibrs_supported="spec_ctrl_ibrs flag in $g_procfs/cpuinfo" - # enabled=2 -> kernel & user - g_ibrs_enabled=2 - # XXX and what about ibpb ? - fi - fi - if [ -n "$ret_sys_interface_check_fullmsg" ]; then - # when IBPB is enabled on 4.15+, we can see it in sysfs - if echo "$ret_sys_interface_check_fullmsg" | grep -q 'IBPB'; then - pr_debug "ibpb: found enabled in sysfs" - [ -z "$g_ibpb_supported" ] && g_ibpb_supported='IBPB found enabled in sysfs' - [ -z "$g_ibpb_enabled" ] && g_ibpb_enabled=1 - fi - # when IBRS_FW is enabled on 4.15+, we can see it in sysfs - if echo "$ret_sys_interface_check_fullmsg" | grep -q '[,;] IBRS_FW'; then - pr_debug "ibrs: found IBRS_FW in sysfs" - [ -z "$g_ibrs_supported" ] && g_ibrs_supported='found IBRS_FW in sysfs' - g_ibrs_fw_enabled=1 - fi - # when IBRS is enabled on 4.15+, we can see it in sysfs - # on a more recent kernel, classic "IBRS" is not even longer an option, because of the performance impact. - # only "Enhanced IBRS" is available (on CPUs with the IBRS_ALL flag) - if echo "$ret_sys_interface_check_fullmsg" | grep -q -e '\' -e 'Indirect Branch Restricted Speculation'; then - pr_debug "ibrs: found IBRS in sysfs" - [ -z "$g_ibrs_supported" ] && g_ibrs_supported='found IBRS in sysfs' - [ -z "$g_ibrs_enabled" ] && g_ibrs_enabled=3 - fi - # checking for 'Enhanced IBRS' in sysfs, enabled on CPUs with IBRS_ALL - if echo "$ret_sys_interface_check_fullmsg" | grep -q -e 'Enhanced IBRS'; then - [ -z "$g_ibrs_supported" ] && g_ibrs_supported='found Enhanced IBRS in sysfs' - # 4 isn't actually a valid value of the now extinct "g_ibrs_enabled" flag file, - # that only went from 0 to 3, so we use 4 as "enhanced ibrs is enabled" - g_ibrs_enabled=4 - fi - fi - # in live mode, if ibrs or ibpb is supported and we didn't find these are enabled, then they are not - [ -n "$g_ibrs_supported" ] && [ -z "$g_ibrs_enabled" ] && g_ibrs_enabled=0 - [ -n "$g_ibpb_supported" ] && [ -z "$g_ibpb_enabled" ] && g_ibpb_enabled=0 - fi - if [ -z "$g_ibrs_supported" ]; then - check_redhat_canonical_spectre - if [ "$g_redhat_canonical_spectre" = 1 ]; then - g_ibrs_supported="Red Hat/Ubuntu variant" - g_ibpb_supported="Red Hat/Ubuntu variant" - fi - fi - if [ -z "$g_ibrs_supported" ] && [ -n "$g_kernel" ]; then - if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then - : - else + g_ibrs_can_tell=0 + g_ibrs_supported='' + g_ibrs_enabled='' + g_ibpb_can_tell=0 + g_ibpb_supported='' + g_ibpb_enabled='' + + if [ "$opt_runtime" = 1 ]; then + # in live mode, we can check for the ibrs_enabled file in debugfs + # all versions of the patches have it (NOT the case of IBPB or KPTI) g_ibrs_can_tell=1 - g_ibrs_supported=$("${opt_arch_prefix}strings" "$g_kernel" | grep -Fw -e '[,;] IBRS_FW' | head -n1) - if [ -n "$g_ibrs_supported" ]; then - pr_debug "ibrs: found ibrs evidence in kernel image ($g_ibrs_supported)" - g_ibrs_supported="found '$g_ibrs_supported' in kernel image" + mount_debugfs + for dir in \ + $DEBUGFS_BASE \ + $DEBUGFS_BASE/x86 \ + "$g_procfs/sys/kernel"; do + if [ -e "$dir/ibrs_enabled" ]; then + # if the file is there, we have IBRS compiled-in + # $DEBUGFS_BASE/ibrs_enabled: vanilla + # $DEBUGFS_BASE/x86/ibrs_enabled: Red Hat (see https://access.redhat.com/articles/3311301) + # /proc/sys/kernel/ibrs_enabled: OpenSUSE tumbleweed + g_specex_knob_dir=$dir + g_ibrs_supported="$dir/ibrs_enabled exists" + g_ibrs_enabled=$(cat "$dir/ibrs_enabled" 2>/dev/null) + pr_debug "ibrs: found $dir/ibrs_enabled=$g_ibrs_enabled" + # if ibrs_enabled is there, ibpb_enabled will be in the same dir + if [ -e "$dir/ibpb_enabled" ]; then + # if the file is there, we have IBPB compiled-in (see note above for IBRS) + g_ibpb_supported="$dir/ibpb_enabled exists" + g_ibpb_enabled=$(cat "$dir/ibpb_enabled" 2>/dev/null) + pr_debug "ibpb: found $dir/ibpb_enabled=$g_ibpb_enabled" + else + pr_debug "ibpb: $dir/ibpb_enabled file doesn't exist" + fi + break + else + pr_debug "ibrs: $dir/ibrs_enabled file doesn't exist" + fi + done + # on some newer kernels, the spec_ctrl_ibrs flag in "$g_procfs/cpuinfo" + # is set when ibrs has been administratively enabled (usually from cmdline) + # which in that case means ibrs is supported *and* enabled for kernel & user + # as per the ibrs patch series v3 + if [ -z "$g_ibrs_supported" ]; then + if grep ^flags "$g_procfs/cpuinfo" | grep -qw spec_ctrl_ibrs; then + pr_debug "ibrs: found spec_ctrl_ibrs flag in $g_procfs/cpuinfo" + g_ibrs_supported="spec_ctrl_ibrs flag in $g_procfs/cpuinfo" + # enabled=2 -> kernel & user + g_ibrs_enabled=2 + # XXX and what about ibpb ? + fi + fi + if [ -n "$ret_sys_interface_check_fullmsg" ]; then + # when IBPB is enabled on 4.15+, we can see it in sysfs + if echo "$ret_sys_interface_check_fullmsg" | grep -q 'IBPB'; then + pr_debug "ibpb: found enabled in sysfs" + [ -z "$g_ibpb_supported" ] && g_ibpb_supported='IBPB found enabled in sysfs' + [ -z "$g_ibpb_enabled" ] && g_ibpb_enabled=1 + fi + # when IBRS_FW is enabled on 4.15+, we can see it in sysfs + if echo "$ret_sys_interface_check_fullmsg" | grep -q '[,;] IBRS_FW'; then + pr_debug "ibrs: found IBRS_FW in sysfs" + [ -z "$g_ibrs_supported" ] && g_ibrs_supported='found IBRS_FW in sysfs' + g_ibrs_fw_enabled=1 + fi + # when IBRS is enabled on 4.15+, we can see it in sysfs + # on a more recent kernel, classic "IBRS" is not even longer an option, because of the performance impact. + # only "Enhanced IBRS" is available (on CPUs with the IBRS_ALL flag) + if echo "$ret_sys_interface_check_fullmsg" | grep -q -e '\' -e 'Indirect Branch Restricted Speculation'; then + pr_debug "ibrs: found IBRS in sysfs" + [ -z "$g_ibrs_supported" ] && g_ibrs_supported='found IBRS in sysfs' + [ -z "$g_ibrs_enabled" ] && g_ibrs_enabled=3 + fi + # checking for 'Enhanced IBRS' in sysfs, enabled on CPUs with IBRS_ALL + if echo "$ret_sys_interface_check_fullmsg" | grep -q -e 'Enhanced IBRS'; then + [ -z "$g_ibrs_supported" ] && g_ibrs_supported='found Enhanced IBRS in sysfs' + # 4 isn't actually a valid value of the now extinct "g_ibrs_enabled" flag file, + # that only went from 0 to 3, so we use 4 as "enhanced ibrs is enabled" + g_ibrs_enabled=4 + fi + fi + # in live mode, if ibrs or ibpb is supported and we didn't find these are enabled, then they are not + [ -n "$g_ibrs_supported" ] && [ -z "$g_ibrs_enabled" ] && g_ibrs_enabled=0 + [ -n "$g_ibpb_supported" ] && [ -z "$g_ibpb_enabled" ] && g_ibpb_enabled=0 + fi + if [ -z "$g_ibrs_supported" ]; then + check_redhat_canonical_spectre + if [ "$g_redhat_canonical_spectre" = 1 ]; then + g_ibrs_supported="Red Hat/Ubuntu variant" + g_ibpb_supported="Red Hat/Ubuntu variant" fi fi - fi - if [ -z "$g_ibrs_supported" ] && [ -n "$opt_map" ]; then - g_ibrs_can_tell=1 - if grep -q spec_ctrl "$opt_map"; then - g_ibrs_supported="found spec_ctrl in symbols file" - pr_debug "ibrs: found '*spec_ctrl*' symbol in $opt_map" - elif grep -q -e spectre_v2_select_mitigation -e spectre_v2_apply_mitigation "$opt_map"; then - # spectre_v2_select_mitigation exists since v4.15; split into - # spectre_v2_select_mitigation + spectre_v2_apply_mitigation in v6.16 - g_ibrs_supported="found spectre_v2 mitigation function in symbols file" - pr_debug "ibrs: found spectre_v2_*_mitigation symbol in $opt_map" - fi - fi - # CONFIG_CPU_IBRS_ENTRY (v5.19) / CONFIG_MITIGATION_IBRS_ENTRY (v6.9): kernel IBRS on entry - if [ -z "$g_ibrs_supported" ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then - g_ibrs_can_tell=1 - if grep -q '^CONFIG_\(CPU_\|MITIGATION_\)IBRS_ENTRY=y' "$opt_config"; then - g_ibrs_supported="CONFIG_CPU_IBRS_ENTRY/CONFIG_MITIGATION_IBRS_ENTRY found in kernel config" - pr_debug "ibrs: found IBRS entry config option in $opt_config" - fi - fi - # recent (4.15) vanilla kernels have IBPB but not IBRS, and without the debugfs tunables of Red Hat - # we can detect it directly in the image - if [ -z "$g_ibpb_supported" ] && [ -n "$g_kernel" ]; then - if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then - : - else - g_ibpb_can_tell=1 - g_ibpb_supported=$("${opt_arch_prefix}strings" "$g_kernel" | grep -Fw -e 'ibpb' -e ', IBPB' | head -n1) - if [ -n "$g_ibpb_supported" ]; then - pr_debug "ibpb: found ibpb evidence in kernel image ($g_ibpb_supported)" - g_ibpb_supported="found '$g_ibpb_supported' in kernel image" + if [ -z "$g_ibrs_supported" ] && [ -n "$g_kernel" ]; then + if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then + : + else + g_ibrs_can_tell=1 + g_ibrs_supported=$("${opt_arch_prefix}strings" "$g_kernel" | grep -Fw -e '[,;] IBRS_FW' | head -n1) + if [ -n "$g_ibrs_supported" ]; then + pr_debug "ibrs: found ibrs evidence in kernel image ($g_ibrs_supported)" + g_ibrs_supported="found '$g_ibrs_supported' in kernel image" + fi fi fi - fi - - pr_info_nol " * Kernel is compiled with IBRS support: " - if [ -z "$g_ibrs_supported" ]; then - if [ "$g_ibrs_can_tell" = 1 ]; then - pstatus yellow NO - else - # problem obtaining/inspecting kernel or strings not installed, but if the later is true, - # then readelf is not installed either (both in binutils) which makes the former true, so - # either way g_kernel_err should be set - pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" + if [ -z "$g_ibrs_supported" ] && [ -n "$opt_map" ]; then + g_ibrs_can_tell=1 + if grep -q spec_ctrl "$opt_map"; then + g_ibrs_supported="found spec_ctrl in symbols file" + pr_debug "ibrs: found '*spec_ctrl*' symbol in $opt_map" + elif grep -q -e spectre_v2_select_mitigation -e spectre_v2_apply_mitigation "$opt_map"; then + # spectre_v2_select_mitigation exists since v4.15; split into + # spectre_v2_select_mitigation + spectre_v2_apply_mitigation in v6.16 + g_ibrs_supported="found spectre_v2 mitigation function in symbols file" + pr_debug "ibrs: found spectre_v2_*_mitigation symbol in $opt_map" + fi fi - else - if [ "$opt_verbose" -ge 2 ]; then - pstatus green YES "$g_ibrs_supported" - else - pstatus green YES + # CONFIG_CPU_IBRS_ENTRY (v5.19) / CONFIG_MITIGATION_IBRS_ENTRY (v6.9): kernel IBRS on entry + if [ -z "$g_ibrs_supported" ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then + g_ibrs_can_tell=1 + if grep -q '^CONFIG_\(CPU_\|MITIGATION_\)IBRS_ENTRY=y' "$opt_config"; then + g_ibrs_supported="CONFIG_CPU_IBRS_ENTRY/CONFIG_MITIGATION_IBRS_ENTRY found in kernel config" + pr_debug "ibrs: found IBRS entry config option in $opt_config" + fi + fi + # recent (4.15) vanilla kernels have IBPB but not IBRS, and without the debugfs tunables of Red Hat + # we can detect it directly in the image + if [ -z "$g_ibpb_supported" ] && [ -n "$g_kernel" ]; then + if ! command -v "${opt_arch_prefix}strings" >/dev/null 2>&1; then + : + else + g_ibpb_can_tell=1 + g_ibpb_supported=$("${opt_arch_prefix}strings" "$g_kernel" | grep -Fw -e 'ibpb' -e ', IBPB' | head -n1) + if [ -n "$g_ibpb_supported" ]; then + pr_debug "ibpb: found ibpb evidence in kernel image ($g_ibpb_supported)" + g_ibpb_supported="found '$g_ibpb_supported' in kernel image" + fi + fi fi - fi - pr_info_nol " * IBRS enabled and active: " - if [ "$opt_runtime" = 1 ]; then - if [ "$g_ibpb_enabled" = 2 ]; then - # if ibpb=2, ibrs is forcefully=0 - pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints" + pr_info_nol " * Kernel is compiled with IBRS support: " + if [ -z "$g_ibrs_supported" ]; then + if [ "$g_ibrs_can_tell" = 1 ]; then + pstatus yellow NO + else + # problem obtaining/inspecting kernel or strings not installed, but if the later is true, + # then readelf is not installed either (both in binutils) which makes the former true, so + # either way g_kernel_err should be set + pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" + fi else - # 0 means disabled - # 1 is enabled only for kernel space - # 2 is enabled for kernel and user space - # 3 is enabled - # 4 is enhanced ibrs enabled - case "$g_ibrs_enabled" in - 0) - if [ "$g_ibrs_fw_enabled" = 1 ]; then - pstatus blue YES "for firmware code only" + if [ "$opt_verbose" -ge 2 ]; then + pstatus green YES "$g_ibrs_supported" + else + pstatus green YES + fi + fi + + pr_info_nol " * IBRS enabled and active: " + if [ "$opt_runtime" = 1 ]; then + if [ "$g_ibpb_enabled" = 2 ]; then + # if ibpb=2, ibrs is forcefully=0 + pstatus blue NO "IBPB used instead of IBRS in all kernel entrypoints" + else + # 0 means disabled + # 1 is enabled only for kernel space + # 2 is enabled for kernel and user space + # 3 is enabled + # 4 is enhanced ibrs enabled + case "$g_ibrs_enabled" in + 0) + if [ "$g_ibrs_fw_enabled" = 1 ]; then + pstatus blue YES "for firmware code only" + else + pstatus yellow NO + fi + ;; + 1) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel space and firmware code"; else pstatus green YES "for kernel space"; fi ;; + 2) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel, user space, and firmware code"; else pstatus green YES "for both kernel and user space"; fi ;; + 3) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel and firmware code"; else pstatus green YES; fi ;; + 4) pstatus green YES "Enhanced flavor, performance impact will be greatly reduced" ;; + *) if [ "$cap_ibrs" != 'SPEC_CTRL' ] && [ "$cap_ibrs" != 'IBRS_SUPPORT' ] && [ "$cap_spec_ctrl" != -1 ]; then + pstatus yellow NO + pr_debug "ibrs: known cpu not supporting SPEC-CTRL or IBRS" + else + pstatus yellow UNKNOWN + fi ;; + esac + fi + else + pstatus blue N/A "not testable in no-runtime mode" + fi + + pr_info_nol " * Kernel is compiled with IBPB support: " + if [ -z "$g_ibpb_supported" ]; then + if [ "$g_ibpb_can_tell" = 1 ]; then + pstatus yellow NO + else + # if we're in no-runtime mode without System.map, we can't really know + pstatus yellow UNKNOWN "in no-runtime mode, we need the kernel image to be able to tell" + fi + else + if [ "$opt_verbose" -ge 2 ]; then + pstatus green YES "$g_ibpb_supported" + else + pstatus green YES + fi + fi + + pr_info_nol " * IBPB enabled and active: " + if [ "$opt_runtime" = 1 ]; then + case "$g_ibpb_enabled" in + "") + if [ "$g_ibrs_supported" = 1 ]; then + pstatus yellow UNKNOWN else pstatus yellow NO fi ;; - 1) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel space and firmware code"; else pstatus green YES "for kernel space"; fi ;; - 2) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel, user space, and firmware code"; else pstatus green YES "for both kernel and user space"; fi ;; - 3) if [ "$g_ibrs_fw_enabled" = 1 ]; then pstatus green YES "for kernel and firmware code"; else pstatus green YES; fi ;; - 4) pstatus green YES "Enhanced flavor, performance impact will be greatly reduced" ;; - *) if [ "$cap_ibrs" != 'SPEC_CTRL' ] && [ "$cap_ibrs" != 'IBRS_SUPPORT' ] && [ "$cap_spec_ctrl" != -1 ]; then + 0) pstatus yellow NO - pr_debug "ibrs: known cpu not supporting SPEC-CTRL or IBRS" - else - pstatus yellow UNKNOWN - fi ;; + ;; + 1) pstatus green YES ;; + 2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints" ;; + *) pstatus yellow UNKNOWN ;; esac - fi - else - pstatus blue N/A "not testable in no-runtime mode" - fi - - pr_info_nol " * Kernel is compiled with IBPB support: " - if [ -z "$g_ibpb_supported" ]; then - if [ "$g_ibpb_can_tell" = 1 ]; then - pstatus yellow NO else - # if we're in no-runtime mode without System.map, we can't really know - pstatus yellow UNKNOWN "in no-runtime mode, we need the kernel image to be able to tell" + pstatus blue N/A "not testable in no-runtime mode" fi - else - if [ "$opt_verbose" -ge 2 ]; then - pstatus green YES "$g_ibpb_supported" - else - pstatus green YES - fi - fi - pr_info_nol " * IBPB enabled and active: " - if [ "$opt_runtime" = 1 ]; then - case "$g_ibpb_enabled" in - "") - if [ "$g_ibrs_supported" = 1 ]; then - pstatus yellow UNKNOWN - else - pstatus yellow NO - fi - ;; - 0) - pstatus yellow NO - ;; - 1) pstatus green YES ;; - 2) pstatus green YES "IBPB used instead of IBRS in all kernel entrypoints" ;; - *) pstatus yellow UNKNOWN ;; - esac - else - pstatus blue N/A "not testable in no-runtime mode" - fi + fi # is_x86_kernel (Mitigation 1) - pr_info "* Mitigation 2" - pr_info_nol " * Kernel has branch predictor hardening (arm): " bp_harden_can_tell=0 bp_harden='' - if [ -r "$opt_config" ]; then - bp_harden_can_tell=1 - bp_harden=$(grep -w 'CONFIG_HARDEN_BRANCH_PREDICTOR=y' "$opt_config") - if [ -n "$bp_harden" ]; then - pstatus green YES - pr_debug "bp_harden: found '$bp_harden' in $opt_config" - fi - fi - if [ -z "$bp_harden" ] && [ -n "$opt_map" ]; then - bp_harden_can_tell=1 - bp_harden=$(grep -w bp_hardening_data "$opt_map") - if [ -n "$bp_harden" ]; then - pstatus green YES - pr_debug "bp_harden: found '$bp_harden' in $opt_map" - fi - fi - if [ -z "$bp_harden" ]; then - if [ "$bp_harden_can_tell" = 1 ]; then - pstatus yellow NO - else - pstatus yellow UNKNOWN - fi - fi - - pr_info_nol " * Kernel compiled with retpoline option: " - # We check the RETPOLINE kernel options - retpoline=0 - if [ -r "$opt_config" ]; then - if grep -q '^CONFIG_\(MITIGATION_\)\?RETPOLINE=y' "$opt_config"; then - pstatus green YES - retpoline=1 - # shellcheck disable=SC2046 - pr_debug 'retpoline: found '$(grep '^CONFIG_\(MITIGATION_\)\?RETPOLINE' "$opt_config")" in $opt_config" - else - pstatus yellow NO - fi - else - pstatus yellow UNKNOWN "couldn't read your kernel configuration" - fi - - if [ "$retpoline" = 1 ]; then - # Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm - # For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles) - # See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79 - # In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_MITIGATION_RETPOLINE is set - # *AND* if the compiler is retpoline-compliant, so look for that symbol. The name of this kernel config - # option before version 6.9-rc1 is CONFIG_RETPOLINE. - # - # if there is "retpoline" in the file and NOT "minimal", then it's full retpoline - # (works for vanilla and Red Hat variants) - # - # since 5.15.28, this is now "Retpolines" as the implementation was switched to a generic one, - # so we look for both "retpoline" and "retpolines" - if [ "$opt_runtime" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then - if echo "$ret_sys_interface_check_fullmsg" | grep -qwi -e retpoline -e retpolines; then - if echo "$ret_sys_interface_check_fullmsg" | grep -qwi minimal; then - retpoline_compiler=0 - retpoline_compiler_reason="kernel reports minimal retpoline compilation" - else - retpoline_compiler=1 - retpoline_compiler_reason="kernel reports full retpoline compilation" - fi - fi - elif [ -n "$opt_map" ]; then - # look for the symbol - if grep -qw noretpoline_setup "$opt_map"; then - retpoline_compiler=1 - retpoline_compiler_reason="noretpoline_setup symbol found in System.map" - fi - elif [ -n "$g_kernel" ]; then - # look for the symbol - if command -v "${opt_arch_prefix}nm" >/dev/null 2>&1; then - # the proper way: use nm and look for the symbol - if "${opt_arch_prefix}nm" "$g_kernel" 2>/dev/null | grep -qw 'noretpoline_setup'; then - retpoline_compiler=1 - retpoline_compiler_reason="noretpoline_setup found in kernel symbols" - fi - elif grep -q noretpoline_setup "$g_kernel"; then - # if we don't have nm, nevermind, the symbol name is long enough to not have - # any false positive using good old grep directly on the binary - retpoline_compiler=1 - retpoline_compiler_reason="noretpoline_setup found in kernel" - fi - fi - if [ -n "$retpoline_compiler" ]; then - pr_info_nol " * Kernel compiled with a retpoline-aware compiler: " - if [ "$retpoline_compiler" = 1 ]; then - if [ -n "$retpoline_compiler_reason" ]; then - pstatus green YES "$retpoline_compiler_reason" - else - pstatus green YES - fi - else - if [ -n "$retpoline_compiler_reason" ]; then - pstatus red NO "$retpoline_compiler_reason" - else - pstatus red NO - fi - fi - fi - fi - - # only Red Hat has a tunable to disable it on runtime - retp_enabled=-1 - if [ "$opt_runtime" = 1 ]; then - if [ -e "$g_specex_knob_dir/retp_enabled" ]; then - retp_enabled=$(cat "$g_specex_knob_dir/retp_enabled" 2>/dev/null) - pr_debug "retpoline: found $g_specex_knob_dir/retp_enabled=$retp_enabled" - pr_info_nol " * Retpoline is enabled: " - if [ "$retp_enabled" = 1 ]; then + if is_arm_kernel; then + pr_info "* Mitigation 2" + pr_info_nol " * Kernel has branch predictor hardening (arm): " + if [ -r "$opt_config" ]; then + bp_harden_can_tell=1 + bp_harden=$(grep -w 'CONFIG_HARDEN_BRANCH_PREDICTOR=y' "$opt_config") + if [ -n "$bp_harden" ]; then pstatus green YES + pr_debug "bp_harden: found '$bp_harden' in $opt_config" + fi + fi + if [ -z "$bp_harden" ] && [ -n "$opt_map" ]; then + bp_harden_can_tell=1 + bp_harden=$(grep -w bp_hardening_data "$opt_map") + if [ -n "$bp_harden" ]; then + pstatus green YES + pr_debug "bp_harden: found '$bp_harden' in $opt_map" + fi + fi + if [ -z "$bp_harden" ]; then + if [ "$bp_harden_can_tell" = 1 ]; then + pstatus yellow NO + else + pstatus yellow UNKNOWN + fi + fi + fi + + if is_x86_kernel; then + + pr_info_nol " * Kernel compiled with retpoline option: " + # We check the RETPOLINE kernel options + retpoline=0 + if [ -r "$opt_config" ]; then + if grep -q '^CONFIG_\(MITIGATION_\)\?RETPOLINE=y' "$opt_config"; then + pstatus green YES + retpoline=1 + # shellcheck disable=SC2046 + pr_debug 'retpoline: found '$(grep '^CONFIG_\(MITIGATION_\)\?RETPOLINE' "$opt_config")" in $opt_config" else pstatus yellow NO fi - fi - fi - - # only for information, in verbose mode - if [ "$opt_verbose" -ge 2 ]; then - pr_info_nol " * Local gcc is retpoline-aware: " - if command -v gcc >/dev/null 2>&1; then - if [ -n "$(gcc -mindirect-branch=thunk-extern --version 2>&1 >/dev/null)" ]; then - pstatus blue NO - else - pstatus green YES - fi else - pstatus blue NO "gcc is not installed" + pstatus yellow UNKNOWN "couldn't read your kernel configuration" fi - fi - if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then - pr_info_nol " * Kernel supports RSB filling: " - rsb_filling=0 - if [ "$opt_runtime" = 1 ] && [ "$opt_no_sysfs" != 1 ]; then - # if we're live and we aren't denied looking into /sys, let's do it - if echo "$ret_sys_interface_check_fullmsg" | grep -qw RSB; then - rsb_filling=1 - pstatus green YES + if [ "$retpoline" = 1 ]; then + # Now check if the compiler used to compile the kernel knows how to insert retpolines in generated asm + # For gcc, this is -mindirect-branch=thunk-extern (detected by the kernel makefiles) + # See gcc commit https://github.com/hjl-tools/gcc/commit/23b517d4a67c02d3ef80b6109218f2aadad7bd79 + # In latest retpoline LKML patches, the noretpoline_setup symbol exists only if CONFIG_MITIGATION_RETPOLINE is set + # *AND* if the compiler is retpoline-compliant, so look for that symbol. The name of this kernel config + # option before version 6.9-rc1 is CONFIG_RETPOLINE. + # + # if there is "retpoline" in the file and NOT "minimal", then it's full retpoline + # (works for vanilla and Red Hat variants) + # + # since 5.15.28, this is now "Retpolines" as the implementation was switched to a generic one, + # so we look for both "retpoline" and "retpolines" + if [ "$opt_runtime" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then + if echo "$ret_sys_interface_check_fullmsg" | grep -qwi -e retpoline -e retpolines; then + if echo "$ret_sys_interface_check_fullmsg" | grep -qwi minimal; then + retpoline_compiler=0 + retpoline_compiler_reason="kernel reports minimal retpoline compilation" + else + retpoline_compiler=1 + retpoline_compiler_reason="kernel reports full retpoline compilation" + fi + fi + elif [ -n "$opt_map" ]; then + # look for the symbol + if grep -qw noretpoline_setup "$opt_map"; then + retpoline_compiler=1 + retpoline_compiler_reason="noretpoline_setup symbol found in System.map" + fi + elif [ -n "$g_kernel" ]; then + # look for the symbol + if command -v "${opt_arch_prefix}nm" >/dev/null 2>&1; then + # the proper way: use nm and look for the symbol + if "${opt_arch_prefix}nm" "$g_kernel" 2>/dev/null | grep -qw 'noretpoline_setup'; then + retpoline_compiler=1 + retpoline_compiler_reason="noretpoline_setup found in kernel symbols" + fi + elif grep -q noretpoline_setup "$g_kernel"; then + # if we don't have nm, nevermind, the symbol name is long enough to not have + # any false positive using good old grep directly on the binary + retpoline_compiler=1 + retpoline_compiler_reason="noretpoline_setup found in kernel" + fi + fi + if [ -n "$retpoline_compiler" ]; then + pr_info_nol " * Kernel compiled with a retpoline-aware compiler: " + if [ "$retpoline_compiler" = 1 ]; then + if [ -n "$retpoline_compiler_reason" ]; then + pstatus green YES "$retpoline_compiler_reason" + else + pstatus green YES + fi + else + if [ -n "$retpoline_compiler_reason" ]; then + pstatus red NO "$retpoline_compiler_reason" + else + pstatus red NO + fi + fi fi fi - if [ "$rsb_filling" = 0 ]; 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 - rsb_filling=1 + + # only Red Hat has a tunable to disable it on runtime + retp_enabled=-1 + if [ "$opt_runtime" = 1 ]; then + if [ -e "$g_specex_knob_dir/retp_enabled" ]; then + retp_enabled=$(cat "$g_specex_knob_dir/retp_enabled" 2>/dev/null) + pr_debug "retpoline: found $g_specex_knob_dir/retp_enabled=$retp_enabled" + pr_info_nol " * Retpoline is enabled: " + if [ "$retp_enabled" = 1 ]; then pstatus green YES else - rsb_filling=0 pstatus yellow NO fi fi fi - fi - # Mitigation 3: derive structured mitigation variables for the verdict. - # These are set from sysfs fields (when available) with hardware fallbacks. - pr_info "* Mitigation 3 (sub-mitigations)" - - # --- v2_base_mode: which base Spectre v2 mitigation is active --- - pr_info_nol " * Base Spectre v2 mitigation mode: " - if [ -n "$ret_sys_interface_check_fullmsg" ]; then - # Parse from sysfs (handle all mainline, stable, and RHEL variants) - case "$ret_sys_interface_check_fullmsg" in - *"Enhanced / Automatic IBRS + LFENCE"* | *"Enhanced IBRS + LFENCE"*) v2_base_mode=eibrs_lfence ;; - *"Enhanced / Automatic IBRS + Retpolines"* | *"Enhanced IBRS + Retpolines"*) v2_base_mode=eibrs_retpoline ;; - *"Enhanced / Automatic IBRS"* | *"Enhanced IBRS"*) v2_base_mode=eibrs ;; - *"Mitigation: IBRS (kernel and user space)"*) v2_base_mode=ibrs ;; - *"Mitigation: IBRS (kernel)"*) v2_base_mode=ibrs ;; - *"Mitigation: IBRS"*) v2_base_mode=ibrs ;; - *"Mitigation: Retpolines"* | *"Full generic retpoline"* | *"Full retpoline"* | *"Full AMD retpoline"*) v2_base_mode=retpoline ;; - *"Vulnerable: LFENCE"* | *"Mitigation: LFENCE"*) v2_base_mode=lfence ;; - *"Vulnerable"*) v2_base_mode=none ;; - *) v2_base_mode=unknown ;; - esac - fi - # Fallback to existing variables if sysfs didn't provide a base mode - if [ -z "$v2_base_mode" ] || [ "$v2_base_mode" = "unknown" ]; then - if [ "$g_ibrs_enabled" = 4 ]; then - v2_base_mode=eibrs - elif [ -n "$g_ibrs_enabled" ] && [ "$g_ibrs_enabled" -ge 1 ] 2>/dev/null; then - v2_base_mode=ibrs - elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ]; then - v2_base_mode=retpoline - elif [ "$retpoline" = 1 ]; then - v2_base_mode=retpoline - fi - fi - case "$v2_base_mode" in - eibrs) pstatus green "Enhanced / Automatic IBRS" ;; - eibrs_lfence) pstatus green "Enhanced / Automatic IBRS + LFENCE" ;; - eibrs_retpoline) pstatus green "Enhanced / Automatic IBRS + Retpolines" ;; - ibrs) pstatus green "IBRS" ;; - retpoline) pstatus green "Retpolines" ;; - lfence) pstatus red "LFENCE (insufficient)" ;; - none) pstatus yellow "None" ;; - *) pstatus yellow UNKNOWN ;; - esac - - # --- v2_is_autoibrs: AMD AutoIBRS vs Intel eIBRS --- - case "$v2_base_mode" in - eibrs | eibrs_lfence | eibrs_retpoline) - if [ "$cap_autoibrs" = 1 ] || { (is_amd || is_hygon) && [ "$cap_ibrs_all" != 1 ]; }; then - v2_is_autoibrs=1 + # only for information, in verbose mode + if [ "$opt_verbose" -ge 2 ]; then + pr_info_nol " * Local gcc is retpoline-aware: " + if command -v gcc >/dev/null 2>&1; then + if [ -n "$(gcc -mindirect-branch=thunk-extern --version 2>&1 >/dev/null)" ]; then + pstatus blue NO + else + pstatus green YES + fi + else + pstatus blue NO "gcc is not installed" fi - ;; - esac + fi - # --- v2_ibpb_mode --- - pr_info_nol " * IBPB mode: " - if [ -n "$ret_sys_interface_check_fullmsg" ]; then - case "$ret_sys_interface_check_fullmsg" in - *"IBPB: always-on"*) v2_ibpb_mode=always-on ;; - *"IBPB: conditional"*) v2_ibpb_mode=conditional ;; - *"IBPB: disabled"*) v2_ibpb_mode=disabled ;; - *", IBPB"* | *"; IBPB"*) v2_ibpb_mode=conditional ;; - *) v2_ibpb_mode=disabled ;; + if is_vulnerable_to_empty_rsb || [ "$opt_verbose" -ge 2 ]; then + pr_info_nol " * Kernel supports RSB filling: " + rsb_filling=0 + if [ "$opt_runtime" = 1 ] && [ "$opt_no_sysfs" != 1 ]; then + # if we're live and we aren't denied looking into /sys, let's do it + if echo "$ret_sys_interface_check_fullmsg" | grep -qw RSB; then + rsb_filling=1 + pstatus green YES + fi + fi + if [ "$rsb_filling" = 0 ]; 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 + rsb_filling=1 + pstatus green YES + else + rsb_filling=0 + pstatus yellow NO + fi + fi + fi + fi + + # Mitigation 3: derive structured mitigation variables for the verdict. + # These are set from sysfs fields (when available) with hardware fallbacks. + pr_info "* Mitigation 3 (sub-mitigations)" + + # --- v2_base_mode: which base Spectre v2 mitigation is active --- + pr_info_nol " * Base Spectre v2 mitigation mode: " + if [ -n "$ret_sys_interface_check_fullmsg" ]; then + # Parse from sysfs (handle all mainline, stable, and RHEL variants) + case "$ret_sys_interface_check_fullmsg" in + *"Enhanced / Automatic IBRS + LFENCE"* | *"Enhanced IBRS + LFENCE"*) v2_base_mode=eibrs_lfence ;; + *"Enhanced / Automatic IBRS + Retpolines"* | *"Enhanced IBRS + Retpolines"*) v2_base_mode=eibrs_retpoline ;; + *"Enhanced / Automatic IBRS"* | *"Enhanced IBRS"*) v2_base_mode=eibrs ;; + *"Mitigation: IBRS (kernel and user space)"*) v2_base_mode=ibrs ;; + *"Mitigation: IBRS (kernel)"*) v2_base_mode=ibrs ;; + *"Mitigation: IBRS"*) v2_base_mode=ibrs ;; + *"Mitigation: Retpolines"* | *"Full generic retpoline"* | *"Full retpoline"* | *"Full AMD retpoline"*) v2_base_mode=retpoline ;; + *"Vulnerable: LFENCE"* | *"Mitigation: LFENCE"*) v2_base_mode=lfence ;; + *"Vulnerable"*) v2_base_mode=none ;; + *) v2_base_mode=unknown ;; + esac + fi + # Fallback to existing variables if sysfs didn't provide a base mode + if [ -z "$v2_base_mode" ] || [ "$v2_base_mode" = "unknown" ]; then + if [ "$g_ibrs_enabled" = 4 ]; then + v2_base_mode=eibrs + elif [ -n "$g_ibrs_enabled" ] && [ "$g_ibrs_enabled" -ge 1 ] 2>/dev/null; then + v2_base_mode=ibrs + elif [ "$retpoline" = 1 ] && [ "$retpoline_compiler" = 1 ]; then + v2_base_mode=retpoline + elif [ "$retpoline" = 1 ]; then + v2_base_mode=retpoline + fi + fi + case "$v2_base_mode" in + eibrs) pstatus green "Enhanced / Automatic IBRS" ;; + eibrs_lfence) pstatus green "Enhanced / Automatic IBRS + LFENCE" ;; + eibrs_retpoline) pstatus green "Enhanced / Automatic IBRS + Retpolines" ;; + ibrs) pstatus green "IBRS" ;; + retpoline) pstatus green "Retpolines" ;; + lfence) pstatus red "LFENCE (insufficient)" ;; + none) pstatus yellow "None" ;; + *) pstatus yellow UNKNOWN ;; esac - elif [ "$opt_runtime" = 1 ]; then - case "$g_ibpb_enabled" in - 2) v2_ibpb_mode=always-on ;; - 1) v2_ibpb_mode=conditional ;; - 0) v2_ibpb_mode=disabled ;; - *) v2_ibpb_mode=unknown ;; + + # --- v2_is_autoibrs: AMD AutoIBRS vs Intel eIBRS --- + case "$v2_base_mode" in + eibrs | eibrs_lfence | eibrs_retpoline) + if [ "$cap_autoibrs" = 1 ] || { (is_amd || is_hygon) && [ "$cap_ibrs_all" != 1 ]; }; then + v2_is_autoibrs=1 + fi + ;; esac - else - v2_ibpb_mode=unknown - fi - case "$v2_ibpb_mode" in - always-on) pstatus green YES "always-on" ;; - conditional) pstatus green YES "conditional" ;; - disabled) pstatus yellow NO "disabled" ;; - *) pstatus yellow UNKNOWN ;; - esac - # --- SMT state (used in STIBP inference and verdict) --- - is_cpu_smt_enabled - smt_enabled=$? - # smt_enabled: 0=enabled, 1=disabled, 2=unknown + # --- v2_ibpb_mode --- + pr_info_nol " * IBPB mode: " + if [ -n "$ret_sys_interface_check_fullmsg" ]; then + case "$ret_sys_interface_check_fullmsg" in + *"IBPB: always-on"*) v2_ibpb_mode=always-on ;; + *"IBPB: conditional"*) v2_ibpb_mode=conditional ;; + *"IBPB: disabled"*) v2_ibpb_mode=disabled ;; + *", IBPB"* | *"; IBPB"*) v2_ibpb_mode=conditional ;; + *) v2_ibpb_mode=disabled ;; + esac + elif [ "$opt_runtime" = 1 ]; then + case "$g_ibpb_enabled" in + 2) v2_ibpb_mode=always-on ;; + 1) v2_ibpb_mode=conditional ;; + 0) v2_ibpb_mode=disabled ;; + *) v2_ibpb_mode=unknown ;; + esac + else + v2_ibpb_mode=unknown + fi + case "$v2_ibpb_mode" in + always-on) pstatus green YES "always-on" ;; + conditional) pstatus green YES "conditional" ;; + disabled) pstatus yellow NO "disabled" ;; + *) pstatus yellow UNKNOWN ;; + esac - # --- v2_stibp_status --- - pr_info_nol " * STIBP status: " - if [ -n "$ret_sys_interface_check_fullmsg" ]; then - case "$ret_sys_interface_check_fullmsg" in - *"STIBP: always-on"*) v2_stibp_status=always-on ;; - *"STIBP: forced"*) v2_stibp_status=forced ;; - *"STIBP: conditional"*) v2_stibp_status=conditional ;; - *"STIBP: disabled"*) v2_stibp_status=disabled ;; - *", STIBP"* | *"; STIBP"*) v2_stibp_status=forced ;; - *) - # No STIBP field: Intel eIBRS suppresses it (implicit cross-thread protection) + # --- SMT state (used in STIBP inference and verdict) --- + is_cpu_smt_enabled + smt_enabled=$? + # smt_enabled: 0=enabled, 1=disabled, 2=unknown + + # --- v2_stibp_status --- + pr_info_nol " * STIBP status: " + if [ -n "$ret_sys_interface_check_fullmsg" ]; then + case "$ret_sys_interface_check_fullmsg" in + *"STIBP: always-on"*) v2_stibp_status=always-on ;; + *"STIBP: forced"*) v2_stibp_status=forced ;; + *"STIBP: conditional"*) v2_stibp_status=conditional ;; + *"STIBP: disabled"*) v2_stibp_status=disabled ;; + *", STIBP"* | *"; STIBP"*) v2_stibp_status=forced ;; + *) + # No STIBP field: Intel eIBRS suppresses it (implicit cross-thread protection) + case "$v2_base_mode" in + eibrs | eibrs_lfence | eibrs_retpoline) + if [ "$v2_is_autoibrs" != 1 ]; then + v2_stibp_status=eibrs-implicit + else + v2_stibp_status=unknown + fi + ;; + *) v2_stibp_status=unknown ;; + esac + ;; + esac + else + # No sysfs: use hardware capability + context to infer STIBP status + if [ "$smt_enabled" != 0 ]; then + # SMT disabled or unknown: STIBP is not needed + v2_stibp_status=not-needed + else case "$v2_base_mode" in eibrs | eibrs_lfence | eibrs_retpoline) if [ "$v2_is_autoibrs" != 1 ]; then + # Intel eIBRS provides implicit cross-thread protection v2_stibp_status=eibrs-implicit - else + elif [ -n "$cap_stibp" ]; then + # AMD AutoIBRS: CPU supports STIBP but can't confirm runtime state v2_stibp_status=unknown + else + # No STIBP support on this CPU + v2_stibp_status=unavailable + fi + ;; + *) + if [ -n "$cap_stibp" ]; then + # CPU supports STIBP but can't confirm runtime state without sysfs + v2_stibp_status=unknown + else + # CPU does not support STIBP at all + v2_stibp_status=unavailable fi ;; - *) v2_stibp_status=unknown ;; esac - ;; - esac - else - # No sysfs: use hardware capability + context to infer STIBP status - if [ "$smt_enabled" != 0 ]; then - # SMT disabled or unknown: STIBP is not needed - v2_stibp_status=not-needed - else - case "$v2_base_mode" in - eibrs | eibrs_lfence | eibrs_retpoline) - if [ "$v2_is_autoibrs" != 1 ]; then - # Intel eIBRS provides implicit cross-thread protection - v2_stibp_status=eibrs-implicit - elif [ -n "$cap_stibp" ]; then - # AMD AutoIBRS: CPU supports STIBP but can't confirm runtime state - v2_stibp_status=unknown - else - # No STIBP support on this CPU - v2_stibp_status=unavailable - fi - ;; - *) - if [ -n "$cap_stibp" ]; then - # CPU supports STIBP but can't confirm runtime state without sysfs - v2_stibp_status=unknown - else - # CPU does not support STIBP at all - v2_stibp_status=unavailable - fi - ;; - esac + fi fi - fi - case "$v2_stibp_status" in - always-on) pstatus green YES "always-on" ;; - forced) pstatus green YES "forced" ;; - conditional) pstatus green YES "conditional" ;; - eibrs-implicit) pstatus green YES "implicit via eIBRS" ;; - not-needed) pstatus green YES "not needed (SMT disabled)" ;; - unavailable) pstatus red NO "CPU does not support STIBP" ;; - disabled) pstatus yellow NO "disabled" ;; - *) pstatus yellow UNKNOWN ;; - esac + case "$v2_stibp_status" in + always-on) pstatus green YES "always-on" ;; + forced) pstatus green YES "forced" ;; + conditional) pstatus green YES "conditional" ;; + eibrs-implicit) pstatus green YES "implicit via eIBRS" ;; + not-needed) pstatus green YES "not needed (SMT disabled)" ;; + unavailable) pstatus red NO "CPU does not support STIBP" ;; + disabled) pstatus yellow NO "disabled" ;; + *) pstatus yellow UNKNOWN ;; + esac - # --- v2_pbrsb_status (only relevant for eIBRS) --- - case "$v2_base_mode" in - eibrs | eibrs_lfence | eibrs_retpoline) - pr_info_nol " * PBRSB-eIBRS mitigation: " - if [ -n "$ret_sys_interface_check_fullmsg" ]; then - case "$ret_sys_interface_check_fullmsg" in - *"PBRSB-eIBRS: Not affected"*) v2_pbrsb_status=not-affected ;; - *"PBRSB-eIBRS: SW sequence"*) v2_pbrsb_status=sw-sequence ;; - *"PBRSB-eIBRS: Vulnerable"*) v2_pbrsb_status=vulnerable ;; - *) v2_pbrsb_status=unknown ;; - esac - elif [ "$opt_runtime" != 1 ] && [ -n "$g_kernel" ]; then - if grep -q 'PBRSB-eIBRS' "$g_kernel" 2>/dev/null; then - v2_pbrsb_status=sw-sequence + # --- v2_pbrsb_status (only relevant for eIBRS) --- + case "$v2_base_mode" in + eibrs | eibrs_lfence | eibrs_retpoline) + pr_info_nol " * PBRSB-eIBRS mitigation: " + if [ -n "$ret_sys_interface_check_fullmsg" ]; then + case "$ret_sys_interface_check_fullmsg" in + *"PBRSB-eIBRS: Not affected"*) v2_pbrsb_status=not-affected ;; + *"PBRSB-eIBRS: SW sequence"*) v2_pbrsb_status=sw-sequence ;; + *"PBRSB-eIBRS: Vulnerable"*) v2_pbrsb_status=vulnerable ;; + *) v2_pbrsb_status=unknown ;; + esac + elif [ "$opt_runtime" != 1 ] && [ -n "$g_kernel" ]; then + if grep -q 'PBRSB-eIBRS' "$g_kernel" 2>/dev/null; then + v2_pbrsb_status=sw-sequence + else + v2_pbrsb_status=unknown + fi else v2_pbrsb_status=unknown fi - else - v2_pbrsb_status=unknown - fi - case "$v2_pbrsb_status" in - not-affected) pstatus green "Not affected" ;; - sw-sequence) pstatus green "SW sequence" ;; - vulnerable) pstatus red "Vulnerable" ;; - *) pstatus yellow UNKNOWN ;; - esac - ;; - *) v2_pbrsb_status=n/a ;; - esac - - # --- v2_bhi_status --- - pr_info_nol " * BHI mitigation: " - if [ -n "$ret_sys_interface_check_fullmsg" ]; then - case "$ret_sys_interface_check_fullmsg" in - *"BHI: Not affected"*) v2_bhi_status=not-affected ;; - *"BHI: BHI_DIS_S"*) v2_bhi_status=bhi_dis_s ;; - *"BHI: SW loop"*) v2_bhi_status=sw-loop ;; - *"BHI: Retpoline"*) v2_bhi_status=retpoline ;; - *"BHI: Vulnerable, KVM: SW loop"*) v2_bhi_status=vuln-kvm-loop ;; - *"BHI: Vulnerable"*) v2_bhi_status=vulnerable ;; - *) v2_bhi_status=unknown ;; + case "$v2_pbrsb_status" in + not-affected) pstatus green "Not affected" ;; + sw-sequence) pstatus green "SW sequence" ;; + vulnerable) pstatus red "Vulnerable" ;; + *) pstatus yellow UNKNOWN ;; + esac + ;; + *) v2_pbrsb_status=n/a ;; esac - elif [ "$opt_runtime" != 1 ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then - if grep -q '^CONFIG_\(MITIGATION_\)\?SPECTRE_BHI' "$opt_config"; then - if [ "$cap_bhi" = 1 ]; then - v2_bhi_status=bhi_dis_s + + # --- v2_bhi_status --- + pr_info_nol " * BHI mitigation: " + if [ -n "$ret_sys_interface_check_fullmsg" ]; then + case "$ret_sys_interface_check_fullmsg" in + *"BHI: Not affected"*) v2_bhi_status=not-affected ;; + *"BHI: BHI_DIS_S"*) v2_bhi_status=bhi_dis_s ;; + *"BHI: SW loop"*) v2_bhi_status=sw-loop ;; + *"BHI: Retpoline"*) v2_bhi_status=retpoline ;; + *"BHI: Vulnerable, KVM: SW loop"*) v2_bhi_status=vuln-kvm-loop ;; + *"BHI: Vulnerable"*) v2_bhi_status=vulnerable ;; + *) v2_bhi_status=unknown ;; + esac + elif [ "$opt_runtime" != 1 ] && [ -n "$opt_config" ] && [ -r "$opt_config" ]; then + if grep -q '^CONFIG_\(MITIGATION_\)\?SPECTRE_BHI' "$opt_config"; then + if [ "$cap_bhi" = 1 ]; then + v2_bhi_status=bhi_dis_s + else + v2_bhi_status=sw-loop + fi else - v2_bhi_status=sw-loop + v2_bhi_status=unknown fi else v2_bhi_status=unknown fi - else - v2_bhi_status=unknown - fi - case "$v2_bhi_status" in - not-affected) pstatus green "Not affected" ;; - bhi_dis_s) pstatus green "BHI_DIS_S (hardware)" ;; - sw-loop) pstatus green "SW loop" ;; - retpoline) pstatus green "Retpoline" ;; - vuln-kvm-loop) pstatus yellow "Vulnerable (KVM: SW loop)" ;; - vulnerable) pstatus red "Vulnerable" ;; - *) pstatus yellow UNKNOWN ;; - esac + case "$v2_bhi_status" in + not-affected) pstatus green "Not affected" ;; + bhi_dis_s) pstatus green "BHI_DIS_S (hardware)" ;; + sw-loop) pstatus green "SW loop" ;; + retpoline) pstatus green "Retpoline" ;; + vuln-kvm-loop) pstatus yellow "Vulnerable (KVM: SW loop)" ;; + vulnerable) pstatus red "Vulnerable" ;; + *) pstatus yellow UNKNOWN ;; + esac - # --- v2_vuln_module --- - if [ "$opt_runtime" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then - pr_info_nol " * Non-retpoline module loaded: " - if echo "$ret_sys_interface_check_fullmsg" | grep -q 'vulnerable module loaded'; then - v2_vuln_module=1 - pstatus red YES - else - v2_vuln_module=0 - pstatus green NO + # --- v2_vuln_module --- + if [ "$opt_runtime" = 1 ] && [ -n "$ret_sys_interface_check_fullmsg" ]; then + pr_info_nol " * Non-retpoline module loaded: " + if echo "$ret_sys_interface_check_fullmsg" | grep -q 'vulnerable module loaded'; then + v2_vuln_module=1 + pstatus red YES + else + v2_vuln_module=0 + pstatus green NO + fi fi - fi + + fi # is_x86_kernel (retpoline + Mitigation 3) elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! @@ -903,9 +915,9 @@ check_CVE_2017_5715_linux() { # ARM branch predictor hardening (unchanged) if [ -n "$bp_harden" ]; then pvulnstatus "$cve" OK "Branch predictor hardening mitigates the vulnerability" - elif [ -z "$bp_harden" ] && is_arm64_kernel; then + elif [ -z "$bp_harden" ] && is_arm_kernel; then 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 does not have branch predictor hardening. On kernels v5.10+, this code is compiled unconditionally so you may need a newer kernel. On older kernels (v4.16 to v5.9), recompile with the CONFIG_HARDEN_BRANCH_PREDICTOR option enabled." # LFENCE-only is always VULN (reclassified in v5.17) elif [ "$v2_base_mode" = "lfence" ]; then diff --git a/src/vulns/CVE-2017-5754.sh b/src/vulns/CVE-2017-5754.sh index 2eb4f88..8376197 100644 --- a/src/vulns/CVE-2017-5754.sh +++ b/src/vulns/CVE-2017-5754.sh @@ -153,7 +153,10 @@ check_CVE_2017_5754_linux() { pstatus blue N/A "not testable in no-runtime mode" fi - pti_performance_check + # PCID/INVPCID are x86-only CPU features + if is_x86_cpu; then + pti_performance_check + fi elif [ "$sys_interface_available" = 0 ]; then # we have no sysfs but were asked to use it only! diff --git a/src/vulns/CVE-2018-12207.sh b/src/vulns/CVE-2018-12207.sh index 4300965..2a072b8 100644 --- a/src/vulns/CVE-2018-12207.sh +++ b/src/vulns/CVE-2018-12207.sh @@ -24,7 +24,7 @@ check_CVE_2018_12207_linux() { if [ -n "$g_kernel_err" ]; then kernel_itlbmh_err="$g_kernel_err" # commit 5219505fcbb640e273a0d51c19c38de0100ec5a9 - elif grep -q 'itlb_multihit' "$g_kernel"; then + elif is_x86_kernel && grep -q 'itlb_multihit' "$g_kernel"; then kernel_itlbmh="found itlb_multihit in kernel image" fi if [ -n "$kernel_itlbmh" ]; then diff --git a/src/vulns/CVE-2018-3639.sh b/src/vulns/CVE-2018-3639.sh index 5948ff6..3762904 100644 --- a/src/vulns/CVE-2018-3639.sh +++ b/src/vulns/CVE-2018-3639.sh @@ -24,13 +24,13 @@ check_CVE_2018_3639_linux() { pr_debug "found Speculation.Store.Bypass: in $g_procfs/self/status" fi fi - # arm64 kernels can have cpu_show_spec_store_bypass with ARM64_SSBD, so exclude them - if [ -z "$kernel_ssb" ] && [ -n "$g_kernel" ] && ! is_arm64_kernel; then + # spec_store_bypass is x86-specific; ARM kernels use ARM64_SSBD instead + if [ -z "$kernel_ssb" ] && [ -n "$g_kernel" ] && is_x86_kernel; then kernel_ssb=$("${opt_arch_prefix}strings" "$g_kernel" | grep spec_store_bypass | head -n1) [ -n "$kernel_ssb" ] && kernel_ssb="found $kernel_ssb in kernel" fi - # arm64 kernels can have cpu_show_spec_store_bypass with ARM64_SSBD, so exclude them - if [ -z "$kernel_ssb" ] && [ -n "$opt_map" ] && ! is_arm64_kernel; then + # spec_store_bypass is x86-specific; ARM kernels use ARM64_SSBD instead + if [ -z "$kernel_ssb" ] && [ -n "$opt_map" ] && is_x86_kernel; then kernel_ssb=$(grep spec_store_bypass "$opt_map" | awk '{print $3}' | head -n1) [ -n "$kernel_ssb" ] && kernel_ssb="found $kernel_ssb in System.map" fi @@ -121,7 +121,7 @@ check_CVE_2018_3639_linux() { fi else if [ -n "$kernel_ssb" ]; then - if is_arm64_kernel; then + if is_arm_kernel; then 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." 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)." fi else - if is_arm64_kernel; then + if is_arm_kernel; then 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." else diff --git a/src/vulns/CVE-2018-3640.sh b/src/vulns/CVE-2018-3640.sh index 88d5da3..cceeffc 100644 --- a/src/vulns/CVE-2018-3640.sh +++ b/src/vulns/CVE-2018-3640.sh @@ -11,7 +11,7 @@ check_CVE_2018_3640() { sys_interface_available=0 msg='' - if is_arm64_kernel; then + if is_arm_kernel; then # ARM64: mitigation is via an EL2 indirect trampoline (spectre_v3a_enable_mitigation), # applied automatically at boot for affected CPUs (Cortex-A57, Cortex-A72). # No microcode update is involved. diff --git a/src/vulns/CVE-2019-11135.sh b/src/vulns/CVE-2019-11135.sh index 2d72ce1..96fcdcd 100644 --- a/src/vulns/CVE-2019-11135.sh +++ b/src/vulns/CVE-2019-11135.sh @@ -21,7 +21,7 @@ check_CVE_2019_11135_linux() { kernel_taa='' if [ -n "$g_kernel_err" ]; then kernel_taa_err="$g_kernel_err" - elif grep -q 'tsx_async_abort' "$g_kernel"; then + elif is_x86_kernel && grep -q 'tsx_async_abort' "$g_kernel"; then kernel_taa="found tsx_async_abort in kernel image" fi if [ -n "$kernel_taa" ]; then diff --git a/src/vulns/CVE-2020-0543.sh b/src/vulns/CVE-2020-0543.sh index 894361b..195de65 100644 --- a/src/vulns/CVE-2020-0543.sh +++ b/src/vulns/CVE-2020-0543.sh @@ -21,7 +21,7 @@ check_CVE_2020_0543_linux() { kernel_srbds='' if [ -n "$g_kernel_err" ]; then kernel_srbds_err="$g_kernel_err" - elif grep -q 'Dependent on hypervisor' "$g_kernel"; then + elif is_x86_kernel && grep -q 'Dependent on hypervisor' "$g_kernel"; then kernel_srbds="found SRBDS implementation evidence in kernel image. Your kernel is up to date for SRBDS mitigation" fi if [ -n "$kernel_srbds" ]; then diff --git a/src/vulns/CVE-2022-40982.sh b/src/vulns/CVE-2022-40982.sh index 954ca44..b23279b 100644 --- a/src/vulns/CVE-2022-40982.sh +++ b/src/vulns/CVE-2022-40982.sh @@ -119,17 +119,17 @@ check_CVE_2022_40982_linux() { kernel_gds_err='' if [ -n "$g_kernel_err" ]; then kernel_gds_err="$g_kernel_err" - elif grep -q 'gather_data_sampling' "$g_kernel"; then + elif is_x86_kernel && grep -q 'gather_data_sampling' "$g_kernel"; then kernel_gds="found gather_data_sampling in kernel image" fi - if [ -z "$kernel_gds" ] && [ -r "$opt_config" ]; then + if [ -z "$kernel_gds" ] && is_x86_kernel && [ -r "$opt_config" ]; then if grep -q '^CONFIG_GDS_FORCE_MITIGATION=y' "$opt_config" || grep -q '^CONFIG_MITIGATION_GDS_FORCE=y' "$opt_config" || grep -q '^CONFIG_MITIGATION_GDS=y' "$opt_config"; then kernel_gds="GDS mitigation config option found enabled in kernel config" fi fi - if [ -z "$kernel_gds" ] && [ -n "$opt_map" ]; then + if [ -z "$kernel_gds" ] && is_x86_kernel && [ -n "$opt_map" ]; then if grep -q 'gds_select_mitigation' "$opt_map"; then kernel_gds="found gds_select_mitigation in System.map" fi @@ -152,10 +152,10 @@ check_CVE_2022_40982_linux() { if [ "$dmesgret" -eq 0 ]; then kernel_avx_disabled="AVX disabled by the kernel (dmesg)" pstatus green YES "$kernel_avx_disabled" - elif [ "$cap_avx2" = 0 ]; then + elif [ "$cap_avx2" = 0 ] && is_x86_cpu; then # Find out by ourselves # cpuinfo says we don't have AVX2, query - # the CPU directly about AVX2 support + # the CPU directly about AVX2 support (x86-only) read_cpuid 0x7 0x0 "$EBX" 5 1 1 ret=$? if [ "$ret" -eq "$READ_CPUID_RET_OK" ]; then diff --git a/src/vulns/CVE-2023-20588.sh b/src/vulns/CVE-2023-20588.sh index 3013c67..ce1e466 100644 --- a/src/vulns/CVE-2023-20588.sh +++ b/src/vulns/CVE-2023-20588.sh @@ -88,10 +88,10 @@ check_CVE_2023_20588_linux() { kernel_mitigated='' if [ -n "$g_kernel_err" ]; then pstatus yellow UNKNOWN "$g_kernel_err" - elif grep -q 'amd_clear_divider' "$g_kernel"; then + elif is_x86_kernel && grep -q 'amd_clear_divider' "$g_kernel"; then kernel_mitigated="found amd_clear_divider in kernel image" pstatus green YES "$kernel_mitigated" - elif [ -n "$opt_map" ] && grep -q 'amd_clear_divider' "$opt_map"; then + elif is_x86_kernel && [ -n "$opt_map" ] && grep -q 'amd_clear_divider' "$opt_map"; then kernel_mitigated="found amd_clear_divider in System.map" pstatus green YES "$kernel_mitigated" else diff --git a/src/vulns/CVE-2023-28746.sh b/src/vulns/CVE-2023-28746.sh index 70a54e8..922404b 100644 --- a/src/vulns/CVE-2023-28746.sh +++ b/src/vulns/CVE-2023-28746.sh @@ -83,17 +83,17 @@ check_CVE_2023_28746_linux() { kernel_rfds_err='' if [ -n "$g_kernel_err" ]; then kernel_rfds_err="$g_kernel_err" - elif grep -q 'Clear Register File' "$g_kernel"; then + elif is_x86_kernel && grep -q 'Clear Register File' "$g_kernel"; then kernel_rfds="found 'Clear Register File' string in kernel image" - elif grep -q 'reg_file_data_sampling' "$g_kernel"; then + elif is_x86_kernel && grep -q 'reg_file_data_sampling' "$g_kernel"; then kernel_rfds="found reg_file_data_sampling in kernel image" fi - if [ -z "$kernel_rfds" ] && [ -r "$opt_config" ]; then + if [ -z "$kernel_rfds" ] && is_x86_kernel && [ -r "$opt_config" ]; then if grep -q '^CONFIG_MITIGATION_RFDS=y' "$opt_config"; then kernel_rfds="RFDS mitigation config option found enabled in kernel config" fi fi - if [ -z "$kernel_rfds" ] && [ -n "$opt_map" ]; then + if [ -z "$kernel_rfds" ] && is_x86_kernel && [ -n "$opt_map" ]; then if grep -q 'rfds_select_mitigation' "$opt_map"; then kernel_rfds="found rfds_select_mitigation in System.map" fi diff --git a/src/vulns/CVE-2024-28956.sh b/src/vulns/CVE-2024-28956.sh index 0b869f4..804f2bd 100644 --- a/src/vulns/CVE-2024-28956.sh +++ b/src/vulns/CVE-2024-28956.sh @@ -92,15 +92,15 @@ check_CVE_2024_28956_linux() { kernel_its_err='' if [ -n "$g_kernel_err" ]; then kernel_its_err="$g_kernel_err" - elif grep -q 'indirect_target_selection' "$g_kernel"; then + elif is_x86_kernel && grep -q 'indirect_target_selection' "$g_kernel"; then kernel_its="found indirect_target_selection in kernel image" fi - if [ -z "$kernel_its" ] && [ -r "$opt_config" ]; then + if [ -z "$kernel_its" ] && is_x86_kernel && [ -r "$opt_config" ]; then if grep -q '^CONFIG_MITIGATION_ITS=y' "$opt_config"; then kernel_its="ITS mitigation config option found enabled in kernel config" fi fi - if [ -z "$kernel_its" ] && [ -n "$opt_map" ]; then + if [ -z "$kernel_its" ] && is_x86_kernel && [ -n "$opt_map" ]; then if grep -q 'its_select_mitigation' "$opt_map"; then kernel_its="found its_select_mitigation in System.map" fi diff --git a/src/vulns/CVE-2024-36350.sh b/src/vulns/CVE-2024-36350.sh index 89cbe2e..e656714 100644 --- a/src/vulns/CVE-2024-36350.sh +++ b/src/vulns/CVE-2024-36350.sh @@ -72,15 +72,15 @@ check_CVE_2024_36350_linux() { if [ -n "$g_kernel_err" ]; then kernel_tsa_err="$g_kernel_err" # commit d8010d4ba43e: "Transient Scheduler Attacks:" is printed by tsa_select_mitigation() - elif grep -q 'Transient Scheduler Attacks' "$g_kernel"; then + elif is_x86_kernel && grep -q 'Transient Scheduler Attacks' "$g_kernel"; then kernel_tsa="found TSA mitigation message in kernel image" fi - if [ -z "$kernel_tsa" ] && [ -r "$opt_config" ]; then + if [ -z "$kernel_tsa" ] && is_x86_kernel && [ -r "$opt_config" ]; then if grep -q '^CONFIG_MITIGATION_TSA=y' "$opt_config"; then kernel_tsa="CONFIG_MITIGATION_TSA=y found in kernel config" fi fi - if [ -z "$kernel_tsa" ] && [ -n "$opt_map" ]; then + if [ -z "$kernel_tsa" ] && is_x86_kernel && [ -n "$opt_map" ]; then if grep -q 'tsa_select_mitigation' "$opt_map"; then kernel_tsa="found tsa_select_mitigation in System.map" fi diff --git a/src/vulns/CVE-2024-36357.sh b/src/vulns/CVE-2024-36357.sh index dc0e0fa..ec38d38 100644 --- a/src/vulns/CVE-2024-36357.sh +++ b/src/vulns/CVE-2024-36357.sh @@ -72,15 +72,15 @@ check_CVE_2024_36357_linux() { if [ -n "$g_kernel_err" ]; then kernel_tsa_err="$g_kernel_err" # commit d8010d4ba43e: "Transient Scheduler Attacks:" is printed by tsa_select_mitigation() - elif grep -q 'Transient Scheduler Attacks' "$g_kernel"; then + elif is_x86_kernel && grep -q 'Transient Scheduler Attacks' "$g_kernel"; then kernel_tsa="found TSA mitigation message in kernel image" fi - if [ -z "$kernel_tsa" ] && [ -r "$opt_config" ]; then + if [ -z "$kernel_tsa" ] && is_x86_kernel && [ -r "$opt_config" ]; then if grep -q '^CONFIG_MITIGATION_TSA=y' "$opt_config"; then kernel_tsa="CONFIG_MITIGATION_TSA=y found in kernel config" fi fi - if [ -z "$kernel_tsa" ] && [ -n "$opt_map" ]; then + if [ -z "$kernel_tsa" ] && is_x86_kernel && [ -n "$opt_map" ]; then if grep -q 'tsa_select_mitigation' "$opt_map"; then kernel_tsa="found tsa_select_mitigation in System.map" fi diff --git a/src/vulns/CVE-2025-40300.sh b/src/vulns/CVE-2025-40300.sh index b8d153a..a0959af 100644 --- a/src/vulns/CVE-2025-40300.sh +++ b/src/vulns/CVE-2025-40300.sh @@ -85,15 +85,15 @@ check_CVE_2025_40300_linux() { kernel_vmscape_err='' if [ -n "$g_kernel_err" ]; then kernel_vmscape_err="$g_kernel_err" - elif grep -q 'vmscape' "$g_kernel"; then + elif is_x86_kernel && grep -q 'vmscape' "$g_kernel"; then kernel_vmscape="found vmscape in kernel image" fi - if [ -z "$kernel_vmscape" ] && [ -r "$opt_config" ]; then + if [ -z "$kernel_vmscape" ] && is_x86_kernel && [ -r "$opt_config" ]; then if grep -q '^CONFIG_MITIGATION_VMSCAPE=y' "$opt_config"; then kernel_vmscape="VMScape mitigation config option found enabled in kernel config" fi fi - if [ -z "$kernel_vmscape" ] && [ -n "$opt_map" ]; then + if [ -z "$kernel_vmscape" ] && is_x86_kernel && [ -n "$opt_map" ]; then if grep -q 'vmscape_select_mitigation' "$opt_map"; then kernel_vmscape="found vmscape_select_mitigation in System.map" fi