Files
SKELETONKEY/docs/KEV_CROSSREF.md
T
KaraZajac e46a32f11e
build / build (clang / debug) (push) Waiting to run
build / build (clang / default) (push) Waiting to run
build / build (gcc / debug) (push) Waiting to run
build / build (gcc / default) (push) Waiting to run
build / sanitizers (ASan + UBSan) (push) Waiting to run
build / clang-tidy (push) Waiting to run
build / drift-check (CISA KEV + Debian tracker) (push) Waiting to run
build / static-build (push) Waiting to run
modules: add refluxfs (CVE-2026-64600, "RefluXFS" XFS reflink CoW ILOCK race)
Adds the corpus's first XFS module and its first data-oriented kernel bug —
every other kernel entry corrupts memory; this one corrupts file contents.

xfs_direct_write_iomap_begin() reads the data-fork extent map under ILOCK,
then xfs_reflink_fill_cow_hole() drops ILOCK to wait for transaction log
space. On reacquiring it, the code re-queries the refcount btree at the
ORIGINAL imap->br_startblock and never re-reads the data fork. A second
O_DIRECT writer holding only IOLOCK completes a whole CoW cycle in that
window, so the first writer's stale mapping sees refcount 1, treats a
still-shared block as private, and writes to it in place — landing its data
on the reflink source file's on-disk blocks.

The primitive is an arbitrary overwrite of the on-disk contents of any
readable file, which has three consequences that drive the design:
  - No offsets, no ROP, no KASLR/SMEP/SMAP; SELinux, containers and seccomp
    are all irrelevant.
  - The victim's inode is never written, so mtime/ctime/size never change
    and nothing is logged — FIM and `-w /etc/passwd -p wa` cannot see it.
  - The change persists across reboots.

Introduced 4.11 (3c68d44a2b49); fixed 2f4acd0fcd86 (mainline 7.2-rc4,
merged 2026-07-16), stable backports 7.1.4 / 6.18.39 / 6.12.96. Exposure is
distro-shaped: RHEL/CentOS/Rocky/Alma/Oracle/CloudLinux 8-10, Fedora Server
>= 31 and Amazon Linux 2023 ship XFS+reflink by default.

detect() is not a pure version gate — reachability here is safely
observable, so it pairs the backport table with a real storage precondition
(writable XFS via statfs XFS_SUPER_MAGIC, deliberately not via a successful
FICLONE since btrfs implements that too and is unaffected). --active
confirms reflink via FICLONE; SKELETONKEY_XFS_ASSUME_REFLINK=1/0 overrides.
On rpm-family hosts it warns that vendors backport without bumping the
upstream version, so the verdict speaks only to the upstream base.

exploit() forks a child that works only in a private mkdtemp scratch dir on
two files it owns: it establishes a shared extent (FICLONE, corroborated by
FIEMAP_EXTENT_SHARED) plus an O_DIRECT gate, then races a hard-bounded
8 writers / 2 helpers / 16 rounds / 2s and stops, reading the donor back
with O_DIRECT. Deliberately under-driven, and it never clones or targets a
file it does not own — the /etc/passwd overwrite -> su -> root step is
documented but NOT bundled. Always returns EXPLOIT_FAIL.

Safety rank 55, far above bad_epoll (12) and ghostlock (11): a won race
corrupts 4 KiB of our own scratch file and cannot touch kernel memory, so
there is no oops/KASAN/panic path.

Detection inverts the usual advice. auditd/sigma anchor on ioctl request
0x40049409 (FICLONE, matched exactly) and openat O_DIRECT; falco adds the
cross-uid reflink condition; and the yara rule is genuinely the right tool
here, matching the on-disk artifact because FIM is structurally blind.

VM-VERIFIED 2026-07-23 — the corpus's first rpm-family verification, taking
the empirical count to 29 of 41 CVEs. Rocky Linux 9.8 /
5.14.0-687.10.1.el9_8.0.1.x86_64 under qemu/KVM, stock GenericCloud layout
with no provisioner changes (root is XFS with reflink=1 out of the box).
detect() -> VULNERABLE, --active FICLONE witness confirmed reflink, phase A
observed FIEMAP_EXTENT_SHARED on a real shared extent, scratch self-cleaned,
clean build on el9 gcc. The underlying bug was separately confirmed winnable
on that kernel via tools/verify-vm/refluxfs_verify.c at the public PoC's
parameters (32 writers / 8 helpers, 60s): 4/4 runs won, first divergence
after 69/114/170/494 rounds. The shipped under-driven trigger did NOT win in
its 2s budget on that same vulnerable kernel — intended behaviour, and
exactly why a non-win must never be read as "patched".

14 new detect() unit rows (148 tests total, 0 failures). Bumps to v0.9.14.

Credit: Qualys Threat Research Unit (blog by Saeed Abbasi; the technical
advisory credits model-assisted kernel analysis performed with Anthropic),
and the upstream XFS maintainers who fixed it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0118iUgHY44hdRtANgyCmu7y
2026-07-23 17:49:40 -04:00

3.1 KiB

CISA KEV Cross-Reference

Which SKELETONKEY modules cover CVEs that CISA has observed exploited in the wild per the Known Exploited Vulnerabilities catalog. Refreshed via tools/refresh-cve-metadata.py.

13 of 41 modules cover KEV-listed CVEs.

In KEV (prioritize patching)

CVE Date added to KEV CWE Module
CVE-2019-13272 2021-12-10 ? ptrace_traceme_cve_2019_13272
CVE-2016-5195 2022-03-03 CWE-362 dirty_cow_cve_2016_5195
CVE-2021-3156 2022-04-06 CWE-193 sudo_samedit_cve_2021_3156
CVE-2022-0847 2022-04-25 CWE-665 dirty_pipe_cve_2022_0847
CVE-2021-4034 2022-06-27 CWE-787 pwnkit_cve_2021_4034
CVE-2021-3493 2022-10-20 CWE-270 overlayfs_cve_2021_3493
CVE-2024-1086 2024-05-30 CWE-416 nf_tables_cve_2024_1086
CVE-2022-0185 2024-08-21 CWE-190 fuse_legacy_cve_2022_0185
CVE-2023-0386 2025-06-17 CWE-282 overlayfs_setuid_cve_2023_0386
CVE-2025-32463 2025-09-29 CWE-829 sudo_chwoot_cve_2025_32463
CVE-2021-22555 2025-10-06 CWE-787 netfilter_xtcompat_cve_2021_22555
CVE-2018-14634 2026-01-26 CWE-190 mutagen_astronomy_cve_2018_14634
CVE-2022-0492 2026-06-02 CWE-287 cgroup_release_agent_cve_2022_0492

Not in KEV

Not observed exploited per CISA — but several have public PoC code and are technically reachable. "Not in KEV" is not the same as "safe to ignore".

CVE CWE Module
CVE-2017-7308 CWE-681 af_packet_cve_2017_7308
CVE-2019-14287 CWE-755 sudo_runas_neg1_cve_2019_14287
CVE-2020-14386 CWE-250 af_packet2_cve_2020_14386
CVE-2020-29661 CWE-416 tioscpgrp_cve_2020_29661
CVE-2021-33909 CWE-190 sequoia_cve_2021_33909
CVE-2022-25636 CWE-269 nft_fwd_dup_cve_2022_25636
CVE-2022-2588 CWE-416 cls_route4_cve_2022_2588
CVE-2023-0179 CWE-190 nft_payload_cve_2023_0179
CVE-2023-0458 CWE-476 entrybleed_cve_2023_0458
CVE-2023-2008 CWE-129 vmwgfx_cve_2023_2008
CVE-2023-22809 CWE-269 sudoedit_editor_cve_2023_22809
CVE-2023-32233 CWE-416 nft_set_uaf_cve_2023_32233
CVE-2023-3269 CWE-416 stackrot_cve_2023_3269
CVE-2023-4622 CWE-416 af_unix_gc_cve_2023_4622
CVE-2024-26581 ? nft_pipapo_cve_2024_26581
CVE-2024-50264 CWE-416 vsock_uaf_cve_2024_50264
CVE-2025-32462 CWE-863 sudo_host_cve_2025_32462
CVE-2025-6019 CWE-250 udisks_libblockdev_cve_2025_6019
CVE-2026-23111 CWE-416 nft_catchall_cve_2026_23111
CVE-2026-31635 CWE-130 dirtydecrypt_cve_2026_31635
CVE-2026-41651 CWE-367 pack2theroot_cve_2026_41651
CVE-2026-43494 ? pintheft_cve_2026_43494
CVE-2026-43499 CWE-416 ghostlock_cve_2026_43499
CVE-2026-46242 CWE-416 bad_epoll_cve_2026_46242
CVE-2026-46243 CWE-20 cifswitch_cve_2026_46243
CVE-2026-46300 CWE-787 fragnesia_cve_2026_46300
CVE-2026-46333 CWE-269 ptrace_pidfd_cve_2026_46333
CVE-2026-64600 ? refluxfs_cve_2026_64600