Share
## https://sploitus.com/exploit?id=8BC9638E-19FB-5CC8-ADA0-8873C15D274C
# CVE Checker for Copy Fail (CVE-2026-31431)

Authors: Chris Foley & Patrick Doyle

Single statically-linked Go binary that classifies a Linux host's exposure
to **CVE-2026-31431**.

The tool is **passive**. It does not exploit the bug. The mechanism probe
(see safety statement below) issues exactly two syscalls and never touches
the vulnerable code path.

---

## What it checks

| Signal | Source | Flag |
|---|---|---|
| Kernel version vs. upstream fix | `uname(2)` | `--kernel-version` |
| Distro changelog mentions the CVE | `apt`/`rpm`/`apk` or on-disk `changelog.Debian.gz` | `--changelog` |
| `algif_aead` module status | `/proc/modules`, `modprobe.d`, `/lib/modules` | `--module` |
| Vulnerable surface reachable | `socket(AF_ALG)` + `bind(authencesn(...))` | `--mechanism` |
| Compiled into vmlinux | `/boot/config-$(uname -r)` or `/proc/config.gz` | (part of `--module`) |

If no check flags are given, all four run.

---

## Output modes

| Mode | Trigger | Use case |
|---|---|---|
| **Pretty styled** (Default) | TTY stdout, no `--format` override, no `NO_COLOR` env | Interactive shell runs |
| **Plain text** | non-TTY stdout, OR `--format=text`, OR `NO_COLOR=1`, OR `--no-color` | Shell Scripts, Pipes |
| **JSON** | `--format=json` | Syslog/SIEM ingest, Shell Scripts |
| **Quiet** | `--quiet` | Exit code only (automation/scripts) |

Force pretty when piped: `cvecheck --pretty | tee report.txt`.
Force plain in a TTY: `cvecheck --no-color` or `NO_COLOR=1 cvecheck`.

---

## Safety statement (mechanism probe)

The probe issues exactly two syscalls `socket(AF_ALG, SOCK_SEQPACKET, 0)`,
and `bind(fd, &SockaddrALG{Type:"aead", Name:"authencesn(hmac(sha256),
cbc(aes))"})`. It's then followed by `close(fd)`. It performs **no** `setsockopt`
for a key, **no** `accept`, **no** `sendmsg`, **no** `splice`, and **no**
pipe creation. The vulnerable code path requires `sendmsg` of crypto data
combined with a `splice` from a page-cache-backed file descriptor; none of
those operations occur, so the bug cannot trigger.

A successful probe means the surface is reachable. Whether the kernel still
contains the bug is decided by the kernel-version + changelog signals.

**Side effect**: a successful `bind` autoloads `algif_aead` via the kernel
module autoloader. The module check runs *before* the mechanism probe so
the loaded-state report is pre-probe. To suppress autoload entirely,
blacklist `algif_aead` first.

---

## Exit codes

| Code | Meaning |
|---|---|
| `0` | `PATCHED` / `NOT_VULNERABLE` / `MITIGATED` / `LIKELY_NOT_EXPLOITABLE` |
| `2` | `VULNERABLE` or `MECHANISM_REACHABLE` (partial scan, kernel-version not checked) |
| `3` | `INCONCLUSIVE` (insufficient signals) |

---

## Distro coverage

| Distro | Detect | Kernel pkg | Notes |
|---|---|---|---|
| Ubuntu / Debian / Mint / Pop!_OS | `apt` | `linux-image-$(uname -r)` | Disk-first changelog read avoids `apt changelog` network fragility on signed kernels |
| RHEL / CentOS / Rocky / Alma / Fedora / Amazon Linux | `rpm` | `kernel` | Ships `algif_aead` built-in (`CONFIG_..._AEAD=y`); blacklist mitigation **not effective** |
| Oracle Linux | `rpm` | `kernel` or `kernel-uek` | UEK detected via `uek` substring in `uname -r` |
| openSUSE / SLES | `rpm` | `kernel-default` | |
| Alpine | `apk` | `linux-lts` / `linux-virt` / etc. | Flavor picked from release suffix |
| Arch / CachyOS / Manjaro / Endeavour / Gentoo | none | n/a | Rolling/source: relies on kernel-version check |

---

## Deploy

### Download Binary

Download the latest binary from releases (amd64/arm64/x86).


### Build from Source

```bash
make build-all                             # bin/cvecheck-linux-{x86_64,arm64,x86}
scp bin/cvecheck-linux-x86_64 host:/tmp/   # ~3 MiB, static, no glibc dep
ssh host /tmp/cvecheck                     # pretty styled report
ssh host /tmp/cvecheck --format=json | jq  # SIEM-friendly
```

For container/chroot scans, mount the host root somewhere readable and
pass `--root`:

```bash
docker run --rm -v /:/host:ro alpine /tmp/cvecheck --root /host
```

`--root` controls all on-disk lookups (`/etc/os-release`, `modprobe.d`,
`/lib/modules`, `/boot/config-*`, changelog files). The kernel-version and
mechanism probes still touch the **running** kernel via `uname(2)` and
`socket(AF_ALG, ...)`, both necessarily host-bound.

---

## Verdict ladder

Resolved in this precedence (first match wins):

1. `PATCHED`: distro changelog references the CVE ID
2. `NOT_VULNERABLE`: running kernel โ‰ฅ upstream fixed version
3. `MITIGATED`: `algif_aead` blacklisted *and* not loaded *and* not built into vmlinux
4. `LIKELY_NOT_EXPLOITABLE`: `AF_ALG` unavailable and module not on disk
5. `MECHANISM_REACHABLE`: surface reachable but kernel version not checked
6. `VULNERABLE`: kernel in vuln range and mechanism reachable
7. `INCONCLUSIVE`: none of the above

If `--mechanism` runs alongside `--kernel-version` and both signal
trouble, the result is `VULNERABLE` with a remediation hint.

---

## Remediation hints

- **Loadable-module distros (Debian, Ubuntu, SUSE, Alpine, Arch)**: blacklist
  `algif_aead` until kernel upgrade lands.
  ```bash
  echo 'blacklist algif_aead' | sudo tee /etc/modprobe.d/cve-2026-31431.conf
  sudo rmmod algif_aead 2>/dev/null
  ```
- **Built-in distros (RHEL, CentOS, Rocky, Alma, Oracle, Amazon)**: blacklist
  files are no-ops because `CONFIG_CRYPTO_USER_API_AEAD=y` puts the symbol
  inside `vmlinux`. Only a kernel upgrade (or `kpatch`-style live patch)
  resolves exposure. The tool detects this.

---

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| `changelog: error="apt: exit status 100 ... Changelog unavailable for linux-signed-amd64"` | Debian/Ubuntu signed kernel; `apt` mirror does not serve the source-pkg changelog | Error appears only when the on-disk file is missing in addition to the mirror being inaccessable, install `apt-doc` or wait for the mirror. |
| `module: ... config_src=""` | No kernel config readable (no `/boot/config-*`, no `/proc/config.gz`, `/boot` is root-only) | Run as root, or accept that `BuiltIn` cannot be determined. Verdict may still resolves via other signals. |
| `mechanism: error="EAFNOSUPPORT"` | Kernel built without `CONFIG_CRYPTO_USER_API`, so the host is not vulnerable via `AF_ALG` | Verdict will be `LIKELY_NOT_EXPLOITABLE`. |

---

## Build / develop

```bash
make all                # vet, test, build
make test               # race-detector tests
make lint               # golangci-lint run (uses .golangci.yml)
make cover              # coverage report (HTML in coverage.html)
make build-all          # cross-compile linux/amd64 + linux/arm64 + linux/386
make fmt fmt-check      # gofmt -s -w  /  fail on diff
make fuzz               # run every Fuzz* for FUZZ_TIME (default 30s)
make bench              # benchmarks
make update-golden      # regenerate text+pretty golden files
make version            # print just the version string
BUILD_NUMBER=42 make build   # override build number
```

External deps: `golang.org/x/sys/unix`, `golang.org/x/term`,
`charm.land/lipgloss/v2`. Static build via `CGO_ENABLED=0`; same binary
runs on glibc *and* musl distros.

---

## Sources

- [NIST CVE Database](https://nvd.nist.gov/vuln/detail/CVE-2026-31431)
- [Official Copy.Fail Site](https://copy.fail/)
- [Official Technical Write-up](https://xint.io/blog/copy-fail-linux-distributions)
- [oss-security advisory](https://www.openwall.com/lists/oss-security/2026/04/29/23)
- [Theori writeup](https://xint.io/blog/copy-fail-linux-distributions)
- [Bugcrowd summary](https://www.bugcrowd.com/blog/what-we-know-about-copy-fail-cve-2026-31431/)