mirror of
https://github.com/speed47/spectre-meltdown-checker.git
synced 2026-04-01 12:47:07 +02:00
Compare commits
14 Commits
source-bui
...
test-build
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
151dd12e3e | ||
|
|
15ea90f312 | ||
|
|
5fd6a20ebb | ||
|
|
e7df6a3e30 | ||
|
|
ba24551c56 | ||
|
|
7c2699c01a | ||
|
|
6663b6422e | ||
|
|
fe55c70658 | ||
|
|
d0822e1f9d | ||
|
|
10e5b5749e | ||
|
|
4f7f83a40e | ||
|
|
4bbbd71564 | ||
|
|
c174a8b754 | ||
|
|
0f36203b5f |
120
README.md
120
README.md
@@ -1,34 +1,79 @@
|
||||
Spectre & Meltdown Checker
|
||||
==========================
|
||||
|
||||
A shell script to assess your system's resilience against the several [transient execution](https://en.wikipedia.org/wiki/Transient_execution_CPU_vulnerability) CVEs that were published since early 2018, and give you guidance as to how to mitigate them.
|
||||
A self-contained shell script to assess your system's resilience against the several [transient execution](https://en.wikipedia.org/wiki/Transient_execution_CPU_vulnerability) CVEs that were published since early 2018, and give you guidance as to how to mitigate them.
|
||||
|
||||
CVE | Aliases | Impact | Mitigation | Perf. impact
|
||||
--- | ------- | ------ | ---------- | ------------
|
||||
[CVE-2017-5753](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5753) | Spectre V1 | Kernel & all software | Recompile with LFENCE-inserting compiler | Negligible
|
||||
[CVE-2017-5715](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715) | Spectre V2 | Kernel | Microcode (IBRS) and/or retpoline | Medium to high
|
||||
[CVE-2017-5754](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5754) | Meltdown | Kernel | Kernel update (PTI/KPTI) | Low to medium
|
||||
[CVE-2018-3640](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3640) | Variant 3a | Kernel | Microcode update | Negligible
|
||||
[CVE-2018-3639](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639) | Variant 4, SSB | JIT software | Microcode + kernel update | Low to medium
|
||||
[CVE-2018-3615](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3615) | Foreshadow (SGX) | SGX enclaves | Microcode update | Negligible
|
||||
[CVE-2018-3620](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3620) | Foreshadow-NG (OS/SMM) | Kernel & SMM | Kernel update (PTE inversion) | Negligible
|
||||
[CVE-2018-3646](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3646) | Foreshadow-NG (VMM) | VMM/hypervisors | Kernel update (L1d flush) or disable EPT/SMT | Low to significant
|
||||
[CVE-2018-12126](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12126) | MSBDS, Fallout | Kernel | Microcode + kernel update (MDS group) | Low to significant
|
||||
[CVE-2018-12130](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12130) | MFBDS, ZombieLoad | Kernel | Microcode + kernel update (MDS group) | Low to significant
|
||||
[CVE-2018-12127](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12127) | MLPDS, RIDL | Kernel | Microcode + kernel update (MDS group) | Low to significant
|
||||
[CVE-2019-11091](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11091) | MDSUM, RIDL | Kernel | Microcode + kernel update (MDS group) | Low to significant
|
||||
[CVE-2019-11135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11135) | TAA, ZombieLoad V2 | Kernel | Microcode + kernel update | Low to significant
|
||||
[CVE-2018-12207](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12207) | iTLB Multihit, No eXcuses | VMM/hypervisors | Disable hugepages or update hypervisor | Low to significant
|
||||
[CVE-2020-0543](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0543) | SRBDS, CROSSTalk | All software (RDRAND/RDSEED) | Microcode + kernel update | Low
|
||||
[CVE-2022-40982](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-40982) | Downfall, GDS | Kernel & all software | Microcode update or disable AVX | Negligible to significant (AVX-heavy)
|
||||
[CVE-2023-20569](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20569) | Inception, SRSO | Kernel & all software | Kernel + microcode update | Low to significant
|
||||
[CVE-2023-20593](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20593) | Zenbleed | Kernel & all software | Kernel (MSR bit) or microcode update | Negligible
|
||||
[CVE-2023-23583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-23583) | Reptar | All software | Microcode update | Low
|
||||
[CVE-2024-36350](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36350) | TSA-SQ | Kernel & all software (AMD) | Microcode + kernel update; SMT increases exposure | Low to medium
|
||||
[CVE-2024-36357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36357) | TSA-L1 | Kernel & all software (AMD) | Microcode + kernel update | Low to medium
|
||||
## CVE list
|
||||
|
||||
CVE | Name | Aliases
|
||||
--- | ---- | -------
|
||||
[CVE-2017-5753](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5753) | Bounds Check Bypass | Spectre V1
|
||||
[CVE-2017-5715](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715) | Branch Target Injection | Spectre V2
|
||||
[CVE-2017-5754](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5754) | Rogue Data Cache Load | Meltdown
|
||||
[CVE-2018-3640](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3640) | Rogue System Register Read | Variant 3a
|
||||
[CVE-2018-3639](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639) | Speculative Store Bypass | Variant 4, SSB
|
||||
[CVE-2018-3615](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3615) | L1 Terminal Fault | Foreshadow (SGX)
|
||||
[CVE-2018-3620](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3620) | L1 Terminal Fault | Foreshadow-NG (OS/SMM)
|
||||
[CVE-2018-3646](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3646) | L1 Terminal Fault | Foreshadow-NG (VMM)
|
||||
[CVE-2018-12126](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12126) | Microarchitectural Store Buffer Data Sampling | MSBDS, Fallout
|
||||
[CVE-2018-12130](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12130) | Microarchitectural Fill Buffer Data Sampling | MFBDS, ZombieLoad
|
||||
[CVE-2018-12127](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12127) | Microarchitectural Load Port Data Sampling | MLPDS, RIDL
|
||||
[CVE-2019-11091](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11091) | Microarchitectural Data Sampling Uncacheable Memory | MDSUM, RIDL
|
||||
[CVE-2019-11135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11135) | TSX Asynchronous Abort | TAA, ZombieLoad V2
|
||||
[CVE-2018-12207](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12207) | Machine Check Exception on Page Size Changes | iTLB Multihit, No eXcuses
|
||||
[CVE-2020-0543](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0543) | Special Register Buffer Data Sampling | SRBDS, CROSSTalk
|
||||
[CVE-2022-40982](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-40982) | Gather Data Sampling | Downfall, GDS
|
||||
[CVE-2023-20569](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20569) | Return Address Security | Inception, SRSO
|
||||
[CVE-2023-20593](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20593) | Cross-Process Information Leak | Zenbleed
|
||||
[CVE-2023-23583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-23583) | Redundant Prefix Issue | Reptar
|
||||
[CVE-2024-36350](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36350) | Transient Scheduler Attack, Store Queue | TSA-SQ
|
||||
[CVE-2024-36357](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36357) | Transient Scheduler Attack, L1 | TSA-L1
|
||||
|
||||
## Am I at risk?
|
||||
|
||||
Depending on your situation, the table below answers whether an attacker in a given position can extract data from a given target.
|
||||
The "Userland → Kernel" column also applies within a VM (VM userland vs. VM kernel), since the same CPU mechanisms are at play regardless of virtualization.
|
||||
|
||||
Vulnerability | Userland → Kernel | Userland → Userland | VM → Host | VM → VM | Mitigation
|
||||
------------ | :---------------: | :-----------------: | :-------: | :-----: | ----------
|
||||
CVE-2017-5753 (Spectre V1) | 💥 | 💥 | 💥 | 💥 | Recompile everything with LFENCE
|
||||
CVE-2017-5715 (Spectre V2) | 💥 | 💥 | 💥 | 💥 | Microcode + kernel update (or retpoline)
|
||||
CVE-2017-5754 (Meltdown) | 💥 | ✅ | ✅ | ✅ | Kernel update
|
||||
CVE-2018-3640 (Variant 3a) | 💥 | ✅ | ✅ | ✅ | Microcode update
|
||||
CVE-2018-3639 (Variant 4, SSB) | ✅ | 💥 | ✅ | ✅ | Microcode + kernel update
|
||||
CVE-2018-3615 (Foreshadow, SGX) | ✅ (3) | ✅ (3) | ✅ (3) | ✅ (3) | Microcode update
|
||||
CVE-2018-3620 (Foreshadow-NG, OS/SMM) | 💥 | ✅ | ✅ | ✅ | Kernel update
|
||||
CVE-2018-3646 (Foreshadow-NG, VMM) | ✅ | ✅ | 💥 | 💥 | Kernel update (or disable EPT/SMT)
|
||||
CVE-2018-12126 (MSBDS, Fallout) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2018-12130 (MFBDS, ZombieLoad) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2018-12127 (MLPDS, RIDL) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2019-11091 (MDSUM, RIDL) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2019-11135 (TAA, ZombieLoad V2) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2018-12207 (iTLB Multihit, No eXcuses) | ✅ | ✅ | ☠️ | ✅ | Hypervisor update (or disable hugepages)
|
||||
CVE-2020-0543 (SRBDS, CROSSTalk) | 💥 (2) | 💥 (2) | 💥 (2) | 💥 (2) | Microcode + kernel update
|
||||
CVE-2022-40982 (Downfall, GDS) | 💥 | 💥 | 💥 | 💥 | Microcode update (or disable AVX)
|
||||
CVE-2023-20569 (Inception, SRSO) | 💥 | ✅ | 💥 | ✅ | Microcode + kernel update
|
||||
CVE-2023-20593 (Zenbleed) | 💥 | 💥 | 💥 | 💥 | Microcode update (or kernel workaround)
|
||||
CVE-2023-23583 (Reptar) | ☠️ | ☠️ | ☠️ | ☠️ | Microcode update
|
||||
CVE-2024-36350 (TSA-SQ) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
CVE-2024-36357 (TSA-L1) | 💥 | 💥 (1) | 💥 | 💥 (1) | Microcode + kernel update
|
||||
|
||||
> 💥 Data can be leaked across this boundary.
|
||||
|
||||
> ✅ Not affected in this scenario.
|
||||
|
||||
> ☠️ Denial of service (system crash or unpredictable behavior), no data leak.
|
||||
|
||||
> (1) Cross-process leakage requires SMT (Hyper-Threading) to be active — attacker and victim must share a physical core.
|
||||
|
||||
> (2) Only leaks RDRAND/RDSEED output, not arbitrary memory; still allows recovering cryptographic material from any victim.
|
||||
|
||||
> (3) CVE-2018-3615 (Foreshadow SGX) inverts the normal trust model: the OS reads SGX enclave data. It is irrelevant unless the system runs SGX enclaves, and the attacker must already have OS-level access.
|
||||
|
||||
## Detailed CVE descriptions
|
||||
|
||||
<details>
|
||||
<summary>Detailed CVE descriptions</summary>
|
||||
<summary>Unfold for more detailed CVE descriptions</summary>
|
||||
|
||||
**CVE-2017-5753 — Bounds Check Bypass (Spectre Variant 1)**
|
||||
|
||||
@@ -110,13 +155,15 @@ On AMD Zen 3 and Zen 4 processors, the CPU's transient scheduler may speculative
|
||||
|
||||
</details>
|
||||
|
||||
## Scope
|
||||
|
||||
Supported operating systems:
|
||||
- Linux (all versions, flavors and distros)
|
||||
- FreeBSD, NetBSD, DragonFlyBSD and derivatives (others BSDs are [not supported](FAQ.md#which-bsd-oses-are-supported))
|
||||
|
||||
For Linux systems, the tool will detect mitigations, including backported non-vanilla patches, regardless of the advertised kernel version number and the distribution (such as Debian, Ubuntu, CentOS, RHEL, Fedora, openSUSE, Arch, ...), it also works if you've compiled your own kernel. More information [here](FAQ.md#how-does-this-script-work).
|
||||
|
||||
Other operating systems such as MacOS, Windows, ESXi, etc. [will most likely never be supported](FAQ.md#why-is-my-os-not-supported).
|
||||
Other operating systems such as MacOS, Windows, ESXi, etc. [will never be supported](FAQ.md#why-is-my-os-not-supported).
|
||||
|
||||
Supported architectures:
|
||||
- `x86` (32 bits)
|
||||
@@ -126,15 +173,13 @@ Supported architectures:
|
||||
|
||||
## Frequently Asked Questions (FAQ)
|
||||
|
||||
- What is the purpose of this tool?
|
||||
- Why was it written?
|
||||
- How can it be useful to me?
|
||||
- How does it work?
|
||||
- What can I expect from it?
|
||||
What is the purpose of this tool? Why was it written? How can it be useful to me? How does it work? What can I expect from it?
|
||||
|
||||
All these questions (and more) have detailed answers in the [FAQ](FAQ.md), please have a look!
|
||||
|
||||
## Easy way to run the script
|
||||
## Running the script
|
||||
|
||||
### Direct way (recommended)
|
||||
|
||||
- Get the latest version of the script using `curl` *or* `wget`
|
||||
|
||||
@@ -156,9 +201,12 @@ chmod +x spectre-meltdown-checker.sh
|
||||
sudo ./spectre-meltdown-checker.sh
|
||||
```
|
||||
|
||||
### Run the script in a docker container
|
||||
### Using a docker container
|
||||
|
||||
#### With docker-compose
|
||||
<details>
|
||||
<summary>Unfold for instructions</summary>
|
||||
|
||||
Using `docker compose`:
|
||||
|
||||
```shell
|
||||
docker compose build
|
||||
@@ -168,13 +216,15 @@ docker compose run --rm spectre-meltdown-checker
|
||||
Note that on older versions of docker, `docker-compose` is a separate command, so you might
|
||||
need to replace the two `docker compose` occurences above by `docker-compose`.
|
||||
|
||||
#### Without docker-compose
|
||||
Using `docker build` directly:
|
||||
|
||||
```shell
|
||||
docker build -t spectre-meltdown-checker .
|
||||
docker run --rm --privileged -v /boot:/boot:ro -v /dev/cpu:/dev/cpu:ro -v /lib/modules:/lib/modules:ro spectre-meltdown-checker
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## Example of script output
|
||||
|
||||
- Intel Haswell CPU running under Ubuntu 16.04 LTS
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#
|
||||
# Stephane Lesimple
|
||||
#
|
||||
VERSION='26.21.0331845'
|
||||
VERSION='26.21.0331950'
|
||||
|
||||
# --- Common paths and basedirs ---
|
||||
readonly VULN_SYSFS_BASE="/sys/devices/system/cpu/vulnerabilities"
|
||||
@@ -546,7 +546,7 @@ is_cpu_affected() {
|
||||
[ -z "$affected_variantl1tf" ] && affected_variantl1tf=immune
|
||||
else
|
||||
pr_debug "is_cpu_affected: intel family 6 is vuln to l1tf"
|
||||
affected_variantl1tf=vuln
|
||||
[ -z "$affected_variantl1tf" ] && affected_variantl1tf=vuln
|
||||
fi
|
||||
elif [ "$cpu_family" -lt 6 ]; then
|
||||
pr_debug "is_cpu_affected: intel family < 6 is immune to l1tf"
|
||||
@@ -558,6 +558,7 @@ is_cpu_affected() {
|
||||
# that they're unaffected by GDS. Also set by hypervisors on virtual CPUs
|
||||
# so that the guest kernel doesn't try to mitigate GDS when it's already mitigated on the host
|
||||
pr_debug "is_cpu_affected: downfall: not affected (GDS_NO)"
|
||||
affected_downfall=immune
|
||||
elif [ "$cpu_family" = 6 ]; then
|
||||
# list from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=64094e7e3118aff4b0be8ff713c242303e139834
|
||||
set -u
|
||||
@@ -669,6 +670,7 @@ is_cpu_affected() {
|
||||
# they're not affected to TSA-SQ and TSA-L1
|
||||
# these vars are set in check_cpu()
|
||||
pr_debug "is_cpu_affected: TSA_SQ_NO and TSA_L1_NO are set so not vuln to TSA"
|
||||
affected_tsa=immune
|
||||
elif [ "$cpu_family" = $((0x19)) ]; then
|
||||
affected_tsa=vuln
|
||||
fi
|
||||
@@ -5108,13 +5110,15 @@ check_CVE_2017_5715_bsd() {
|
||||
# SPECTRE 1 SECTION
|
||||
|
||||
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - entry point
|
||||
# Sets: (none directly, delegates to check_cve)
|
||||
check_CVE_2017_5753() {
|
||||
check_cve 'CVE-2017-5753'
|
||||
}
|
||||
|
||||
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - Linux mitigation check
|
||||
# Sets: g_redhat_canonical_spectre (via check_redhat_canonical_spectre)
|
||||
check_CVE_2017_5753_linux() {
|
||||
local status sys_interface_available msg v1_mask_nospec nb_lfence v1_lfence ret explain_text
|
||||
local status sys_interface_available msg v1_kernel_mitigated v1_kernel_mitigated_err v1_mask_nospec ret explain_text
|
||||
status=UNK
|
||||
sys_interface_available=0
|
||||
msg=''
|
||||
@@ -5124,62 +5128,140 @@ check_CVE_2017_5753_linux() {
|
||||
# modifying the vulnerabilities/spectre_v1 file. that's bad. we can't trust it when it says Vulnerable :(
|
||||
# see "silent backport" detection at the bottom of this func
|
||||
sys_interface_available=1
|
||||
#
|
||||
# Complete sysfs message inventory for spectre_v1, traced via git blame:
|
||||
#
|
||||
# all versions:
|
||||
# "Not affected" (cpu_show_common, pre-existing)
|
||||
#
|
||||
# --- x86 mainline ---
|
||||
# 61dc0f555b5c (v4.15, initial spectre_v1 sysfs):
|
||||
# "Vulnerable"
|
||||
# edfbae53dab8 (v4.16, report get_user mitigation):
|
||||
# "Mitigation: __user pointer sanitization"
|
||||
# a2059825986a (v5.3, swapgs awareness via spectre_v1_strings[]):
|
||||
# "Vulnerable: __user pointer sanitization and usercopy barriers only; no swapgs barriers"
|
||||
# "Mitigation: usercopy/swapgs barriers and __user pointer sanitization"
|
||||
# ca01c0d8d030 (v6.12, CONFIG_MITIGATION_SPECTRE_V1 controls default):
|
||||
# same strings as v5.3+
|
||||
# All stable branches (4.4.y through 6.12.y) have v5.3+ strings backported.
|
||||
#
|
||||
# --- x86 RHEL (centos6, centos7 branches) ---
|
||||
# "Vulnerable: Load fences, __user pointer sanitization and usercopy barriers only; no swapgs barriers"
|
||||
# "Mitigation: Load fences, usercopy/swapgs barriers and __user pointer sanitization"
|
||||
#
|
||||
# --- ARM64 ---
|
||||
# 3891ebccace1 (v5.2, first arm64 spectre_v1 sysfs, backported to 4.14.y+):
|
||||
# "Mitigation: __user pointer sanitization" (hardcoded)
|
||||
# 455697adefdb (v5.10, moved to proton-pack.c):
|
||||
# same string
|
||||
# Before v5.2: no sysfs override (generic "Not affected" fallback).
|
||||
# Actual mitigation (array_index_mask_nospec with CSDB) landed in v4.16.
|
||||
#
|
||||
# --- ARM32 ---
|
||||
# 9dd78194a372 (v5.17+):
|
||||
# "Mitigation: __user pointer sanitization" (hardcoded)
|
||||
#
|
||||
# all messages start with either "Not affected", "Mitigation", or "Vulnerable"
|
||||
status=$ret_sys_interface_check_status
|
||||
fi
|
||||
if [ "$opt_sysfs_only" != 1 ]; then
|
||||
# no /sys interface (or offline mode), fallback to our own ways
|
||||
pr_info_nol "* Kernel has array_index_mask_nospec: "
|
||||
# vanilla: look for the Linus' mask aka array_index_mask_nospec()
|
||||
# that is inlined at least in raw_copy_from_user (__get_user_X symbols)
|
||||
#mov PER_CPU_VAR(current_task), %_ASM_DX
|
||||
#cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
|
||||
#jae bad_get_user
|
||||
# /* array_index_mask_nospec() are the 2 opcodes that follow */
|
||||
#+sbb %_ASM_DX, %_ASM_DX
|
||||
#+and %_ASM_DX, %_ASM_AX
|
||||
#ASM_STAC
|
||||
# x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0)
|
||||
# x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0)
|
||||
#
|
||||
# arm32
|
||||
##ifdef CONFIG_THUMB2_KERNEL
|
||||
##define CSDB ".inst.w 0xf3af8014"
|
||||
##else
|
||||
##define CSDB ".inst 0xe320f014" e320f014
|
||||
##endif
|
||||
#asm volatile(
|
||||
# "cmp %1, %2\n" e1500003
|
||||
#" sbc %0, %1, %1\n" e0c03000
|
||||
#CSDB
|
||||
#: "=r" (mask)
|
||||
#: "r" (idx), "Ir" (sz)
|
||||
#: "cc");
|
||||
#
|
||||
# http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855
|
||||
v1_mask_nospec=''
|
||||
|
||||
# Primary detection: grep for sysfs mitigation strings in the kernel binary.
|
||||
# The string "__user pointer sanitization" is present in all kernel versions
|
||||
# that have spectre_v1 sysfs support (x86 v4.16+, ARM64 v5.2+, ARM32 v5.17+),
|
||||
# including RHEL "Load fences" variants. This is cheap and works offline.
|
||||
pr_info_nol "* Kernel has spectre_v1 mitigation (kernel image): "
|
||||
v1_kernel_mitigated=''
|
||||
v1_kernel_mitigated_err=''
|
||||
if [ -n "$g_kernel_err" ]; then
|
||||
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
||||
elif ! command -v perl >/dev/null 2>&1; then
|
||||
pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
|
||||
else
|
||||
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$g_kernel"
|
||||
ret=$?
|
||||
if [ "$ret" -gt 0 ]; then
|
||||
pstatus green YES "$ret occurrence(s) found of x86 64 bits array_index_mask_nospec()"
|
||||
v1_mask_nospec="x86 64 bits array_index_mask_nospec"
|
||||
v1_kernel_mitigated_err="$g_kernel_err"
|
||||
elif grep -q '__user pointer sanitization' "$g_kernel"; then
|
||||
if grep -q 'usercopy/swapgs barriers' "$g_kernel"; then
|
||||
v1_kernel_mitigated="usercopy/swapgs barriers and target sanitization"
|
||||
elif grep -q 'Load fences' "$g_kernel"; then
|
||||
v1_kernel_mitigated="RHEL Load fences mitigation"
|
||||
else
|
||||
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$g_kernel"
|
||||
v1_kernel_mitigated="__user pointer sanitization"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$v1_kernel_mitigated" ] && [ -r "$opt_config" ]; then
|
||||
if grep -q '^CONFIG_MITIGATION_SPECTRE_V1=y' "$opt_config"; then
|
||||
v1_kernel_mitigated="CONFIG_MITIGATION_SPECTRE_V1 found in kernel config"
|
||||
fi
|
||||
fi
|
||||
if [ -z "$v1_kernel_mitigated" ] && [ -n "$opt_map" ]; then
|
||||
if grep -q 'spectre_v1_select_mitigation' "$opt_map"; then
|
||||
v1_kernel_mitigated="found spectre_v1_select_mitigation in System.map"
|
||||
fi
|
||||
fi
|
||||
if [ -n "$v1_kernel_mitigated" ]; then
|
||||
pstatus green YES "$v1_kernel_mitigated"
|
||||
elif [ -n "$v1_kernel_mitigated_err" ]; then
|
||||
pstatus yellow UNKNOWN "couldn't check ($v1_kernel_mitigated_err)"
|
||||
else
|
||||
pstatus yellow NO
|
||||
fi
|
||||
|
||||
# Fallback for v4.15-era kernels: binary pattern matching for array_index_mask_nospec().
|
||||
# The sysfs mitigation strings were not present in the kernel image until v4.16 (x86)
|
||||
# and v5.2 (ARM64), but the actual mitigation code landed in v4.15 (x86) and v4.16 (ARM64).
|
||||
# For offline analysis of these old kernels, match the specific instruction patterns.
|
||||
if [ -z "$v1_kernel_mitigated" ]; then
|
||||
pr_info_nol "* Kernel has array_index_mask_nospec (v4.15 binary pattern): "
|
||||
# vanilla: look for the Linus' mask aka array_index_mask_nospec()
|
||||
# that is inlined at least in raw_copy_from_user (__get_user_X symbols)
|
||||
#mov PER_CPU_VAR(current_task), %_ASM_DX
|
||||
#cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
|
||||
#jae bad_get_user
|
||||
# /* array_index_mask_nospec() are the 2 opcodes that follow */
|
||||
#+sbb %_ASM_DX, %_ASM_DX
|
||||
#+and %_ASM_DX, %_ASM_AX
|
||||
#ASM_STAC
|
||||
# x86 64bits: jae(0x0f 0x83 0x?? 0x?? 0x?? 0x??) sbb(0x48 0x19 0xd2) and(0x48 0x21 0xd0)
|
||||
# x86 32bits: cmp(0x3b 0x82 0x?? 0x?? 0x00 0x00) jae(0x73 0x??) sbb(0x19 0xd2) and(0x21 0xd0)
|
||||
#
|
||||
# arm32
|
||||
##ifdef CONFIG_THUMB2_KERNEL
|
||||
##define CSDB ".inst.w 0xf3af8014"
|
||||
##else
|
||||
##define CSDB ".inst 0xe320f014" e320f014
|
||||
##endif
|
||||
#asm volatile(
|
||||
# "cmp %1, %2\n" e1500003
|
||||
#" sbc %0, %1, %1\n" e0c03000
|
||||
#CSDB
|
||||
#: "=r" (mask)
|
||||
#: "r" (idx), "Ir" (sz)
|
||||
#: "cc");
|
||||
#
|
||||
# http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?h=spectre&id=a78d156587931a2c3b354534aa772febf6c9e855
|
||||
v1_mask_nospec=''
|
||||
if [ -n "$g_kernel_err" ]; then
|
||||
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
||||
elif ! command -v perl >/dev/null 2>&1; then
|
||||
pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
|
||||
else
|
||||
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel"
|
||||
ret=$?
|
||||
if [ "$ret" -gt 0 ]; then
|
||||
pstatus green YES "$ret occurrence(s) found of x86 32 bits array_index_mask_nospec()"
|
||||
v1_mask_nospec="x86 32 bits array_index_mask_nospec"
|
||||
if [ "$ret" -eq 0 ]; then
|
||||
pstatus green YES "x86 64 bits array_index_mask_nospec()"
|
||||
v1_mask_nospec="x86 64 bits array_index_mask_nospec"
|
||||
else
|
||||
ret=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp)
|
||||
if [ "$ret" -gt 0 ]; then
|
||||
pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
|
||||
v1_mask_nospec="arm 32 bits array_index_mask_nospec"
|
||||
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel"
|
||||
ret=$?
|
||||
if [ "$ret" -eq 0 ]; then
|
||||
pstatus green YES "x86 32 bits array_index_mask_nospec()"
|
||||
v1_mask_nospec="x86 32 bits array_index_mask_nospec"
|
||||
else
|
||||
pstatus yellow NO
|
||||
ret=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | grep -w -e f3af8014 -e e320f014 -B2 | grep -B1 -w sbc | grep -w -c cmp)
|
||||
if [ "$ret" -gt 0 ]; then
|
||||
pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
|
||||
v1_mask_nospec="arm 32 bits array_index_mask_nospec"
|
||||
else
|
||||
pstatus yellow NO
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -5213,8 +5295,8 @@ check_CVE_2017_5753_linux() {
|
||||
#ffffff8008082e50: d503229f hint #0x14
|
||||
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
|
||||
#
|
||||
# if we have v1_mask_nospec or g_redhat_canonical_spectre>0, don't bother disassembling the kernel, the answer is no.
|
||||
if [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
|
||||
# if we already have a detection, don't bother disassembling the kernel, the answer is no.
|
||||
if [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
|
||||
pstatus yellow NO
|
||||
elif [ -n "$g_kernel_err" ]; then
|
||||
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
||||
@@ -5241,8 +5323,8 @@ check_CVE_2017_5753_linux() {
|
||||
# ffffff8008090a58: d503229f hint #0x14
|
||||
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
|
||||
#
|
||||
# if we have v1_mask_nospec or g_redhat_canonical_spectre>0, don't bother disassembling the kernel, the answer is no.
|
||||
if [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
|
||||
# if we already have a detection, don't bother disassembling the kernel, the answer is no.
|
||||
if [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
|
||||
pstatus yellow NO
|
||||
elif [ -n "$g_kernel_err" ]; then
|
||||
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
||||
@@ -5251,7 +5333,7 @@ check_CVE_2017_5753_linux() {
|
||||
elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
|
||||
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
|
||||
else
|
||||
"${opt_arch_prefix}objdump" -d "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\smov\s+(w\d+),\s+(w\d+)/ && $r[1]=~/\scmp\s+(x\d+),\s+(x\d+)/ && $r[2]=~/\sngc\s+$2,/ && exit(9); shift @r if @r>3'
|
||||
"${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" | perl -ne 'push @r, $_; /\s(hint|csdb)\s/ && $r[0]=~/\smov\s+(w\d+),\s+(w\d+)/ && $r[1]=~/\scmp\s+(x\d+),\s+(x\d+)/ && $r[2]=~/\sngc\s+$2,/ && exit(9); shift @r if @r>3'
|
||||
ret=$?
|
||||
if [ "$ret" -eq 9 ]; then
|
||||
pstatus green YES "array_index_nospec macro is present and used"
|
||||
@@ -5261,36 +5343,7 @@ check_CVE_2017_5753_linux() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$opt_verbose" -ge 2 ] || { [ -z "$v1_mask_nospec" ] && [ "$g_redhat_canonical_spectre" != 1 ] && [ "$g_redhat_canonical_spectre" != 2 ]; }; then
|
||||
# this is a slow heuristic and we don't need it if we already know the kernel is patched
|
||||
# but still show it in verbose mode
|
||||
pr_info_nol "* Checking count of LFENCE instructions following a jump in kernel... "
|
||||
if [ -n "$g_kernel_err" ]; then
|
||||
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
|
||||
else
|
||||
if ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then
|
||||
pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
|
||||
else
|
||||
# here we disassemble the kernel and count the number of occurrences of the LFENCE opcode
|
||||
# in non-patched kernels, this has been empirically determined as being around 40-50
|
||||
# in patched kernels, this is more around 70-80, sometimes way higher (100+)
|
||||
# v0.13: 68 found in a 3.10.23-xxxx-std-ipv6-64 (with lots of modules compiled-in directly), which doesn't have the LFENCE patches,
|
||||
# so let's push the threshold to 70.
|
||||
# v0.33+: now only count lfence opcodes after a jump, way less error-prone
|
||||
# non patched kernel have between 0 and 20 matches, patched ones have at least 40-45
|
||||
nb_lfence=$("${opt_arch_prefix}objdump" "$g_objdump_options" "$g_kernel" 2>/dev/null | grep -w -B1 lfence | grep -Ewc 'jmp|jne|je')
|
||||
if [ "$nb_lfence" -lt 30 ]; then
|
||||
pstatus yellow NO "only $nb_lfence jump-then-lfence instructions found, should be >= 30 (heuristic)"
|
||||
else
|
||||
v1_lfence=1
|
||||
pstatus green YES "$nb_lfence jump-then-lfence instructions found, which is >= 30 (heuristic)"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
# we have no sysfs but were asked to use it only!
|
||||
elif [ "$sys_interface_available" = 0 ]; then
|
||||
msg="/sys vulnerability interface use forced, but it's not available!"
|
||||
status=UNK
|
||||
fi
|
||||
@@ -5301,22 +5354,26 @@ check_CVE_2017_5753_linux() {
|
||||
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
||||
elif [ -z "$msg" ]; then
|
||||
# if msg is empty, sysfs check didn't fill it, rely on our own test
|
||||
if [ -n "$v1_mask_nospec" ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_mask_nospec)"
|
||||
elif [ "$g_redhat_canonical_spectre" = 1 ] || [ "$g_redhat_canonical_spectre" = 2 ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)"
|
||||
elif [ "$v1_lfence" = 1 ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)"
|
||||
elif [ -n "$g_kernel_err" ]; then
|
||||
pvulnstatus "$cve" UNK "Couldn't find kernel image or tools missing to execute the checks"
|
||||
explain "Re-run this script with root privileges, after installing the missing tools indicated above"
|
||||
if [ "$opt_sysfs_only" != 1 ]; then
|
||||
if [ -n "$v1_kernel_mitigated" ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_kernel_mitigated)"
|
||||
elif [ -n "$v1_mask_nospec" ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_mask_nospec)"
|
||||
elif [ "$g_redhat_canonical_spectre" = 1 ] || [ "$g_redhat_canonical_spectre" = 2 ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)"
|
||||
elif [ -n "$g_kernel_err" ]; then
|
||||
pvulnstatus "$cve" UNK "Couldn't find kernel image or tools missing to execute the checks"
|
||||
explain "Re-run this script with root privileges, after installing the missing tools indicated above"
|
||||
else
|
||||
pvulnstatus "$cve" VULN "Kernel source needs to be patched to mitigate the vulnerability"
|
||||
explain "Your kernel is too old to have the mitigation for Variant 1, you should upgrade to a newer kernel. If you're using a Linux distro and didn't compile the kernel yourself, you should upgrade your distro to get a newer kernel."
|
||||
fi
|
||||
else
|
||||
pvulnstatus "$cve" VULN "Kernel source needs to be patched to mitigate the vulnerability"
|
||||
explain "Your kernel is too old to have the mitigation for Variant 1, you should upgrade to a newer kernel. If you're using a Linux distro and didn't compile the kernel yourself, you should upgrade your distro to get a newer kernel."
|
||||
pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg"
|
||||
fi
|
||||
else
|
||||
if [ "$msg" = "Vulnerable" ] && [ -n "$v1_mask_nospec" ]; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (silent backport of array_index_mask_nospec)"
|
||||
if [ "$msg" = "Vulnerable" ] && { [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ]; }; then
|
||||
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (silent backport of spectre_v1 mitigation)"
|
||||
else
|
||||
if [ "$msg" = "Vulnerable" ]; then
|
||||
msg="Kernel source needs to be patched to mitigate the vulnerability"
|
||||
@@ -5332,10 +5389,9 @@ check_CVE_2017_5753_linux() {
|
||||
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - BSD mitigation check
|
||||
check_CVE_2017_5753_bsd() {
|
||||
if ! is_cpu_affected "$cve"; then
|
||||
# override status & msg in case CPU is not vulnerable after all
|
||||
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
|
||||
else
|
||||
pvulnstatus "$cve" VULN "no mitigation for BSD yet"
|
||||
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -5827,6 +5883,7 @@ check_CVE_2018_3620_linux() {
|
||||
# this kernel has the /sys interface, trust it over everything
|
||||
sys_interface_available=1
|
||||
status=$ret_sys_interface_check_status
|
||||
msg=$ret_sys_interface_check_fullmsg
|
||||
fi
|
||||
if [ "$opt_sysfs_only" != 1 ]; then
|
||||
pr_info_nol "* Kernel supports PTE inversion: "
|
||||
|
||||
Reference in New Issue
Block a user