27 Commits
test ... source

Author SHA1 Message Date
Stéphane Lesimple
9497abbee2 chore: prepare for dev-build renaming to test-build 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
489290be94 chore: set VERSION when building 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
8d1d680202 update dev docs and refactor CVE list in readme 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
d8400c6c4d chore: add .gitignore 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
e451b383c1 chore: adjust workflow for dev-build 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
06a8b3e935 chore: move dist files to the dist/ subdir 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
3088a4f72f feat: implement CVE-2024-36350 CVE-2024-36357 (Transient Scheduler Attack) 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
ce4a019cee doc: update development guidelines 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
1e121086a8 chore: shfmt 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
9e511cd714 dev-build workflow 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
823f42dade use MSR names for read_msr for readability 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
41ab027f86 fix: rework read_msr for values > INT32_MAX (#507) 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
4e3cfc0a18 doc: add a note about the mandatory POSIX compliance of used tools 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
5b7923c957 POSIX compatibility fix: replace sort -V by a manual comparison 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
9dcb3249e9 BSD compatibility fix: stat -f and date -r fallbacks 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
e9f4956764 POSIX compatibility fix: sed -r => sed -E 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
9fca4b6895 POSIX compatibility fix: cut -w => awk 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
39e03373b6 split script in multiple files, reassembled through build.sh 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
63e80e7409 standardize function naming and add doc headers to all of them 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
f373e5217f refactor functions that record/output results 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
fd9d0999af use global readonly vars for common paths/basedirs 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
2b2478b8ef factorize/standardize check_CVE_*() funcs 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
7cd9323681 factorize CVE metadata into a single CVE_REGISTRY global var 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
caa1a025b9 second vars renaming pass 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
f05b5f0fae chore: rename status_* to affected_* 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
7663161edb chore: apply variables naming convention 2026-03-31 20:16:47 +00:00
Stéphane Lesimple
30ef15441d chore: add variables naming convention documentation 2026-03-31 20:16:47 +00:00
4 changed files with 133 additions and 240 deletions

120
dist/README.md vendored
View File

@@ -1,79 +1,34 @@
Spectre & Meltdown Checker Spectre & Meltdown Checker
========================== ==========================
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. 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.
## CVE list CVE | Aliases | Impact | Mitigation | Perf. impact
--- | ------- | ------ | ---------- | ------------
CVE | Name | Aliases [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-5753](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5753) | Bounds Check Bypass | Spectre V1 [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-2017-5715](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5715) | Branch Target Injection | Spectre V2 [CVE-2018-3640](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3640) | Variant 3a | Kernel | Microcode update | Negligible
[CVE-2017-5754](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-5754) | Rogue Data Cache Load | Meltdown [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-3640](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3640) | Rogue System Register Read | Variant 3a [CVE-2018-3615](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3615) | Foreshadow (SGX) | SGX enclaves | Microcode update | Negligible
[CVE-2018-3639](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3639) | Speculative Store Bypass | Variant 4, SSB [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-3615](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3615) | L1 Terminal Fault | Foreshadow (SGX) [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-3620](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3620) | L1 Terminal Fault | Foreshadow-NG (OS/SMM) [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-3646](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3646) | L1 Terminal Fault | Foreshadow-NG (VMM) [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-12126](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12126) | Microarchitectural Store Buffer Data Sampling | MSBDS, Fallout [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-2018-12130](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12130) | Microarchitectural Fill Buffer Data Sampling | MFBDS, ZombieLoad [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-2018-12127](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-12127) | Microarchitectural Load Port Data Sampling | MLPDS, RIDL [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-2019-11091](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11091) | Microarchitectural Data Sampling Uncacheable Memory | MDSUM, RIDL [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-2019-11135](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11135) | TSX Asynchronous Abort | TAA, ZombieLoad V2 [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-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-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-2020-0543](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0543) | Special Register Buffer Data Sampling | SRBDS, CROSSTalk [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-2022-40982](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-40982) | Gather Data Sampling | Downfall, GDS [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-20569](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20569) | Return Address Security | Inception, SRSO [CVE-2023-23583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-23583) | Reptar | All software | Microcode update | Low
[CVE-2023-20593](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-20593) | Cross-Process Information Leak | Zenbleed [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-2023-23583](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-23583) | Redundant Prefix Issue | Reptar [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-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> <details>
<summary>Unfold for more detailed CVE descriptions</summary> <summary>Detailed CVE descriptions</summary>
**CVE-2017-5753 — Bounds Check Bypass (Spectre Variant 1)** **CVE-2017-5753 — Bounds Check Bypass (Spectre Variant 1)**
@@ -155,15 +110,13 @@ On AMD Zen 3 and Zen 4 processors, the CPU's transient scheduler may speculative
</details> </details>
## Scope
Supported operating systems: Supported operating systems:
- Linux (all versions, flavors and distros) - Linux (all versions, flavors and distros)
- FreeBSD, NetBSD, DragonFlyBSD and derivatives (others BSDs are [not supported](FAQ.md#which-bsd-oses-are-supported)) - 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). 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 never be supported](FAQ.md#why-is-my-os-not-supported). Other operating systems such as MacOS, Windows, ESXi, etc. [will most likely never be supported](FAQ.md#why-is-my-os-not-supported).
Supported architectures: Supported architectures:
- `x86` (32 bits) - `x86` (32 bits)
@@ -173,13 +126,15 @@ Supported architectures:
## Frequently Asked Questions (FAQ) ## 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! All these questions (and more) have detailed answers in the [FAQ](FAQ.md), please have a look!
## Running the script ## Easy way to run the script
### Direct way (recommended)
- Get the latest version of the script using `curl` *or* `wget` - Get the latest version of the script using `curl` *or* `wget`
@@ -201,12 +156,9 @@ chmod +x spectre-meltdown-checker.sh
sudo ./spectre-meltdown-checker.sh sudo ./spectre-meltdown-checker.sh
``` ```
### Using a docker container ### Run the script in a docker container
<details> #### With docker-compose
<summary>Unfold for instructions</summary>
Using `docker compose`:
```shell ```shell
docker compose build docker compose build
@@ -216,15 +168,13 @@ docker compose run --rm spectre-meltdown-checker
Note that on older versions of docker, `docker-compose` is a separate command, so you might 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`. need to replace the two `docker compose` occurences above by `docker-compose`.
Using `docker build` directly: #### Without docker-compose
```shell ```shell
docker build -t spectre-meltdown-checker . 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 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 ## Example of script output
- Intel Haswell CPU running under Ubuntu 16.04 LTS - Intel Haswell CPU running under Ubuntu 16.04 LTS

View File

@@ -180,7 +180,7 @@ is_cpu_affected() {
[ -z "$affected_variantl1tf" ] && affected_variantl1tf=immune [ -z "$affected_variantl1tf" ] && affected_variantl1tf=immune
else else
pr_debug "is_cpu_affected: intel family 6 is vuln to l1tf" pr_debug "is_cpu_affected: intel family 6 is vuln to l1tf"
[ -z "$affected_variantl1tf" ] && affected_variantl1tf=vuln affected_variantl1tf=vuln
fi fi
elif [ "$cpu_family" -lt 6 ]; then elif [ "$cpu_family" -lt 6 ]; then
pr_debug "is_cpu_affected: intel family < 6 is immune to l1tf" pr_debug "is_cpu_affected: intel family < 6 is immune to l1tf"
@@ -192,7 +192,6 @@ is_cpu_affected() {
# that they're unaffected by GDS. Also set by hypervisors on virtual CPUs # 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 # 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)" pr_debug "is_cpu_affected: downfall: not affected (GDS_NO)"
affected_downfall=immune
elif [ "$cpu_family" = 6 ]; then elif [ "$cpu_family" = 6 ]; then
# list from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=64094e7e3118aff4b0be8ff713c242303e139834 # list from https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=64094e7e3118aff4b0be8ff713c242303e139834
set -u set -u
@@ -304,7 +303,6 @@ is_cpu_affected() {
# they're not affected to TSA-SQ and TSA-L1 # they're not affected to TSA-SQ and TSA-L1
# these vars are set in check_cpu() # 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" 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 elif [ "$cpu_family" = $((0x19)) ]; then
affected_tsa=vuln affected_tsa=vuln
fi fi

View File

@@ -3,15 +3,13 @@
# SPECTRE 1 SECTION # SPECTRE 1 SECTION
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - entry point # CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - entry point
# Sets: (none directly, delegates to check_cve)
check_CVE_2017_5753() { check_CVE_2017_5753() {
check_cve 'CVE-2017-5753' check_cve 'CVE-2017-5753'
} }
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - Linux mitigation check # 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() { check_CVE_2017_5753_linux() {
local status sys_interface_available msg v1_kernel_mitigated v1_kernel_mitigated_err v1_mask_nospec ret explain_text local status sys_interface_available msg v1_mask_nospec nb_lfence v1_lfence ret explain_text
status=UNK status=UNK
sys_interface_available=0 sys_interface_available=0
msg='' msg=''
@@ -21,140 +19,62 @@ check_CVE_2017_5753_linux() {
# modifying the vulnerabilities/spectre_v1 file. that's bad. we can't trust it when it says Vulnerable :( # 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 # see "silent backport" detection at the bottom of this func
sys_interface_available=1 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 status=$ret_sys_interface_check_status
fi fi
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
# no /sys interface (or offline mode), fallback to our own ways # no /sys interface (or offline mode), fallback to our own ways
pr_info_nol "* Kernel has array_index_mask_nospec: "
# Primary detection: grep for sysfs mitigation strings in the kernel binary. # vanilla: look for the Linus' mask aka array_index_mask_nospec()
# The string "__user pointer sanitization" is present in all kernel versions # that is inlined at least in raw_copy_from_user (__get_user_X symbols)
# that have spectre_v1 sysfs support (x86 v4.16+, ARM64 v5.2+, ARM32 v5.17+), #mov PER_CPU_VAR(current_task), %_ASM_DX
# including RHEL "Load fences" variants. This is cheap and works offline. #cmp TASK_addr_limit(%_ASM_DX),%_ASM_AX
pr_info_nol "* Kernel has spectre_v1 mitigation (kernel image): " #jae bad_get_user
v1_kernel_mitigated='' # /* array_index_mask_nospec() are the 2 opcodes that follow */
v1_kernel_mitigated_err='' #+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 if [ -n "$g_kernel_err" ]; then
v1_kernel_mitigated_err="$g_kernel_err" pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
elif grep -q '__user pointer sanitization' "$g_kernel"; then elif ! command -v perl >/dev/null 2>&1; then
if grep -q 'usercopy/swapgs barriers' "$g_kernel"; then pstatus yellow UNKNOWN "missing 'perl' binary, please install it"
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
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 else
pstatus yellow NO perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found) }' "$g_kernel"
fi ret=$?
if [ "$ret" -gt 0 ]; then
# Fallback for v4.15-era kernels: binary pattern matching for array_index_mask_nospec(). pstatus green YES "$ret occurrence(s) found of x86 64 bits array_index_mask_nospec()"
# The sysfs mitigation strings were not present in the kernel image until v4.16 (x86) v1_mask_nospec="x86 64 bits array_index_mask_nospec"
# 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 else
perl -ne '/\x0f\x83....\x48\x19\xd2\x48\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel" perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found) }' "$g_kernel"
ret=$? ret=$?
if [ "$ret" -eq 0 ]; then if [ "$ret" -gt 0 ]; then
pstatus green YES "x86 64 bits array_index_mask_nospec()" pstatus green YES "$ret occurrence(s) found of x86 32 bits array_index_mask_nospec()"
v1_mask_nospec="x86 64 bits array_index_mask_nospec" v1_mask_nospec="x86 32 bits array_index_mask_nospec"
else else
perl -ne '/\x3b\x82..\x00\x00\x73.\x19\xd2\x21\xd0/ and $found++; END { exit($found ? 0 : 1) }' "$g_kernel" 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)
ret=$? if [ "$ret" -gt 0 ]; then
if [ "$ret" -eq 0 ]; then pstatus green YES "$ret occurrence(s) found of arm 32 bits array_index_mask_nospec()"
pstatus green YES "x86 32 bits array_index_mask_nospec()" v1_mask_nospec="arm 32 bits array_index_mask_nospec"
v1_mask_nospec="x86 32 bits array_index_mask_nospec"
else 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) pstatus yellow NO
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 fi
fi fi
@@ -188,8 +108,8 @@ check_CVE_2017_5753_linux() {
#ffffff8008082e50: d503229f hint #0x14 #ffffff8008082e50: d503229f hint #0x14
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump # /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
# #
# if we already have a detection, don't bother disassembling the kernel, the answer is no. # 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_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then if [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
pstatus yellow NO pstatus yellow NO
elif [ -n "$g_kernel_err" ]; then elif [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
@@ -216,8 +136,8 @@ check_CVE_2017_5753_linux() {
# ffffff8008090a58: d503229f hint #0x14 # ffffff8008090a58: d503229f hint #0x14
# /!\ can also just be "csdb" instead of "hint #0x14" for native objdump # /!\ can also just be "csdb" instead of "hint #0x14" for native objdump
# #
# if we already have a detection, don't bother disassembling the kernel, the answer is no. # 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_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then if [ -n "$v1_mask_nospec" ] || [ "$g_redhat_canonical_spectre" -gt 0 ]; then
pstatus yellow NO pstatus yellow NO
elif [ -n "$g_kernel_err" ]; then elif [ -n "$g_kernel_err" ]; then
pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)" pstatus yellow UNKNOWN "couldn't check ($g_kernel_err)"
@@ -226,7 +146,7 @@ check_CVE_2017_5753_linux() {
elif ! command -v "${opt_arch_prefix}objdump" >/dev/null 2>&1; then 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" pstatus yellow UNKNOWN "missing '${opt_arch_prefix}objdump' tool, please install it, usually it's in the binutils package"
else else
"${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' "${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'
ret=$? ret=$?
if [ "$ret" -eq 9 ]; then if [ "$ret" -eq 9 ]; then
pstatus green YES "array_index_nospec macro is present and used" pstatus green YES "array_index_nospec macro is present and used"
@@ -236,7 +156,36 @@ check_CVE_2017_5753_linux() {
fi fi
fi fi
elif [ "$sys_interface_available" = 0 ]; then 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!
msg="/sys vulnerability interface use forced, but it's not available!" msg="/sys vulnerability interface use forced, but it's not available!"
status=UNK status=UNK
fi fi
@@ -247,26 +196,22 @@ check_CVE_2017_5753_linux() {
pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
elif [ -z "$msg" ]; then elif [ -z "$msg" ]; then
# if msg is empty, sysfs check didn't fill it, rely on our own test # if msg is empty, sysfs check didn't fill it, rely on our own test
if [ "$opt_sysfs_only" != 1 ]; then if [ -n "$v1_mask_nospec" ]; then
if [ -n "$v1_kernel_mitigated" ]; then pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_mask_nospec)"
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_kernel_mitigated)" elif [ "$g_redhat_canonical_spectre" = 1 ] || [ "$g_redhat_canonical_spectre" = 2 ]; then
elif [ -n "$v1_mask_nospec" ]; then pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)"
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability ($v1_mask_nospec)" elif [ "$v1_lfence" = 1 ]; then
elif [ "$g_redhat_canonical_spectre" = 1 ] || [ "$g_redhat_canonical_spectre" = 2 ]; then pvulnstatus "$cve" OK "Kernel source has PROBABLY been patched to mitigate the vulnerability (jump-then-lfence instructions heuristic)"
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (Red Hat/Ubuntu patch)" elif [ -n "$g_kernel_err" ]; then
elif [ -n "$g_kernel_err" ]; then pvulnstatus "$cve" UNK "Couldn't find kernel image or tools missing to execute the checks"
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"
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 else
pvulnstatus "$cve" "$status" "$ret_sys_interface_check_fullmsg" 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 fi
else else
if [ "$msg" = "Vulnerable" ] && { [ -n "$v1_kernel_mitigated" ] || [ -n "$v1_mask_nospec" ]; }; then if [ "$msg" = "Vulnerable" ] && [ -n "$v1_mask_nospec" ]; then
pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (silent backport of spectre_v1 mitigation)" pvulnstatus "$cve" OK "Kernel source has been patched to mitigate the vulnerability (silent backport of array_index_mask_nospec)"
else else
if [ "$msg" = "Vulnerable" ]; then if [ "$msg" = "Vulnerable" ]; then
msg="Kernel source needs to be patched to mitigate the vulnerability" msg="Kernel source needs to be patched to mitigate the vulnerability"
@@ -282,8 +227,9 @@ check_CVE_2017_5753_linux() {
# CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - BSD mitigation check # CVE-2017-5753 Spectre Variant 1 (bounds check bypass) - BSD mitigation check
check_CVE_2017_5753_bsd() { check_CVE_2017_5753_bsd() {
if ! is_cpu_affected "$cve"; then 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" pvulnstatus "$cve" OK "your CPU vendor reported your CPU model as not affected"
else else
pvulnstatus "$cve" UNK "your CPU is affected, but mitigation detection has not yet been implemented for BSD in this script" pvulnstatus "$cve" VULN "no mitigation for BSD yet"
fi fi
} }

View File

@@ -14,7 +14,6 @@ check_CVE_2018_3620_linux() {
# this kernel has the /sys interface, trust it over everything # this kernel has the /sys interface, trust it over everything
sys_interface_available=1 sys_interface_available=1
status=$ret_sys_interface_check_status status=$ret_sys_interface_check_status
msg=$ret_sys_interface_check_fullmsg
fi fi
if [ "$opt_sysfs_only" != 1 ]; then if [ "$opt_sysfs_only" != 1 ]; then
pr_info_nol "* Kernel supports PTE inversion: " pr_info_nol "* Kernel supports PTE inversion: "