Skip to content

CVE-2024-26582: Verified Repro With Script Download

CVE-2024-26582: Linux kernel kTLS Use-After-Free

CVE-2024-26582 is verified against torvalds/linux · github. Affected versions: Linux 6.2.0 through 6.6.18; also 6.1.x before 6.1.82, 6.7.x before 6.7.7. Vulnerability class: Use-After-Free. This high reproduction includes runnable sandbox proof, artifacts, and a plain-text agent view under REPRO-2026-00265.

REPRO-2026-00265 torvalds/linux · github Use-After-Free Variant found Jul 7, 2026 CVE entry ↗ .txt
Severity
HIGH
CVSS
7.8
Confidence
HIGH
Reproduced in
49m 32s
Tool calls
326
Spend
$9.96
01 · Overview

What Is CVE-2024-26582?

CVE-2024-26582 is a high-severity use-after-free vulnerability in the Linux kernel's in-kernel TLS (kTLS) software receive path in net/tls/tls_sw.c. Pruva reproduced it (reproduction REPRO-2026-00265).

02 · Severity & CVSS

CVE-2024-26582 Severity & CVSS Score

CVE-2024-26582 is rated high severity, with a CVSS base score of 7.8 out of 10.

HIGH threat level
7.8 / 10 CVSS base
Weakness CWE-416 — Use After Free

High — serious impact or readily exploitable. Prioritize remediation.

03 · Affected Versions

Affected torvalds/linux Versions

torvalds/linux · github versions Linux 6.2.0 through 6.6.18; also 6.1.x before 6.1.82, 6.7.x before 6.7.7 are affected.

How to Reproduce CVE-2024-26582

$ pruva-verify REPRO-2026-00265
or curl -O https://pruva.dev/api/v1/reproductions/REPRO-2026-00265/artifacts/bundle/repro/reproduction_steps.sh && chmod +x reproduction_steps.sh && ./reproduction_steps.sh
Run in a VM or disposable container. This exploits a real vulnerability.
06 · Proof of Reproduction

Proof of Reproduction for CVE-2024-26582

Memory corruption — reproduced
  • reached the target end-to-end
  • crash observed
  • on the real production code path
  • high confidence
Trigger

kTLS session with async decryption and partial read pattern

Attack chain
  1. tls_sw_recvmsg
  2. tls_decrypt_sg (clear_skb path, darg.zc=false)
  3. tls_do_decryption (async via cryptd)
  4. tls_decrypt_done (frees clear_skb pages via put_page, bug: sgout!=sgin check)
  5. process_rx_list (accesses freed pages, KASAN UAF)
Variants tested

Bypass of the CVE-2024-26582 fix 32b55c5 (free_sgout) on the FIXED Linux v6.6.18 kernel. The async kTLS decrypt use-after-free class is only partially fixed: 32b55c5 corrects the page-free heuristic in tls_decrypt_done() for the normal async (-EINPROGRESS) + partial-read path, but does NOT cover the crypto-backlog (-E…

How the agent worked 813 events · 326 tool calls · 50 min
50 minDuration
326Tool calls
229Reasoning steps
813Events
1Dead-ends
Agent activity over 50 min
Support
17
Repro
492
Judge
39
Variant
261
0:0049:32

Root Cause and Exploit Chain for CVE-2024-26582

Versions: Linux 6.2.0 through 6.6.18 (fixed in 6.6.19+, 6.7.7+, 6.1.82+, 6.8-rc3)

CVE-2024-26582 is a use-after-free vulnerability in the Linux kernel's in-kernel TLS (kTLS) software receive path (net/tls/tls_sw.c). When a kTLS session uses asynchronous decryption and the receiving application performs a partial read (reading fewer bytes than the TLS record size), the tls_decrypt_done() completion callback incorrectly frees pages belonging to the clear_skb buffer. These freed pages are subsequently accessed by process_rx_list() when the application reads the remaining data, triggering a use-after-free. The fix (commit 32b55c5ff9103b8508c1e04bfa5a08c64e7a925f) adds a free_sgout flag to track whether tls_decrypt_sg() actually allocated the destination pages, and only frees them when they were newly allocated.

  • Package/component affected: Linux kernel kTLS software implementation (net/tls/tls_sw.c)
  • Affected versions: Linux 6.2.0 through 6.6.18 (fixed in 6.6.19+, 6.7.7+, 6.1.82+, 6.8-rc3)
  • Risk level: High — kernel-space use-after-free can lead to memory corruption, information leaks, or potentially privilege escalation
  • Consequences: An attacker who can establish a kTLS session and control the read pattern (partial reads) can trigger premature page freeing, leading to use-after-free when the freed pages are accessed. With page poisoning or KASAN, this manifests as data corruption or sanitizer reports. Without sanitizers, this could lead to silent memory corruption or exploitation.

Impact Parity

  • Disclosed/claimed maximum impact: Memory corruption (use-after-free in kernel space)
  • Reproduced impact from this run: Memory corruption confirmed via KASAN use-after-free report and data corruption (page poisoning). The KASAN report shows a read of freed memory in copyout() called from process_rx_list()tls_sw_recvmsg(). Data mismatch detected when freed pages are poisoned.
  • Parity: full — the claimed memory corruption impact is fully reproduced with KASAN detection and data corruption evidence.
  • Not demonstrated: Code execution / privilege escalation (the UAF is demonstrated as memory corruption, not exploit chain to code execution).

Root Cause

The vulnerability is in tls_decrypt_done() in net/tls/tls_sw.c. This function is the async completion callback for AEAD decryption in the kTLS software receive path.

The bug: tls_decrypt_done() uses the check if (sgout != sgin) to determine whether to free destination pages. This check was intended to distinguish in-place decryption (where destination and source scatterlists are the same, so no pages should be freed) from non-in-place decryption (where destination pages were allocated and should be freed). However, the check is incorrect because sgout != sgin is also true when sgout points to pages from clear_skb (allocated by tls_alloc_clrtxt_skb()), not just when pages were newly allocated by tls_decrypt_sg().

The flow:

  1. tls_sw_recvmsg() is called with a partial read (len < record_size)
  2. darg.zc = false because to_decrypt > len (record doesn't fit in user buffer)
  3. tls_decrypt_sg() takes the clear_skb path: allocates clear_skb with pages, sets sgout to point to clear_skb pages
  4. tls_do_decryption() starts async decryption (returns -EINPROGRESS via cryptd workqueue)
  5. The clear_skb is placed on ctx->rx_list for later processing
  6. tls_decrypt_async_wait() waits for async completion
  7. tls_decrypt_done() is called from the workqueue → sees sgout != sgin → calls put_page() on clear_skb pages → pages freed while clear_skb still references them
  8. On the next recv() call, process_rx_list() reads from the clear_skb → accesses freed pages → use-after-free

The fix (commit 32b55c5ff9103b8508c1e04bfa5a08c64e7a925f):

  • Adds bool free_sgout to struct tls_decrypt_ctx
  • Sets dctx->free_sgout = !!pages in tls_decrypt_sg() (only true when pages were actually allocated)
  • Changes the check in tls_decrypt_done() from if (sgout != sgin) to if (dctx->free_sgout)

Fix commit: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=32b55c5ff9103b8508c1e04bfa5a08c64e7a925f

Reproduction Steps

  1. Reference: bundle/repro/reproduction_steps.sh
  2. What the script does:
    • Downloads Linux kernel v6.6.18 source
    • Applies GCC 15 compatibility patches (adds -std=gnu11 to REALMODE_CFLAGS, boot/compressed, and EFI libstub Makefiles)
    • Patches crypto/simd.c to force AEAD decrypt operations through the cryptd workqueue (simulating async crypto behavior that occurs with hardware crypto accelerators or in contexts where SIMD is unavailable)
    • Creates two kernel builds: vulnerable (fix reverted) and fixed (fix present)
    • Both builds include CONFIG_TLS=y, CONFIG_KASAN=y, CONFIG_CRYPTO_AES_NI_INTEL=y, CONFIG_PAGE_POISONING=y
    • Creates a minimal initramfs with a static kTLS test program that:
      • Establishes a loopback TCP connection
      • Configures kTLS with AES-128-GCM (TLS 1.2)
      • Sends 4096-byte records and performs partial reads (100 bytes then 3996 bytes)
      • Checks for data corruption
    • Boots both kernels in QEMU (TCG mode, -cpu max for AES-NI) with page_poison=1
    • Captures serial console output for KASAN reports and corruption detection
  3. Expected evidence:
    • Vulnerable kernel: BUG: KASAN: use-after-free in copyout + Data MISMATCH - corruption detected! + BUG: Bad page state
    • Fixed kernel: No KASAN reports, no corruption, test completes normally

Evidence

  • Vulnerable kernel log: bundle/logs/qemu-vuln-ktls.log
  • Fixed kernel log: bundle/logs/qemu-fixed-ktls.log
  • Reproduction script log: bundle/logs/reproduction_steps.log
Key excerpts from vulnerable kernel:
[    4.956611] BUG: KASAN: use-after-free in copyout+0x2d/0x50
[    4.957007] Read of size 100 at addr ff1100000186000d by task init/58
[    4.957072] Call Trace:
[    4.957072]  copyout+0x2d/0x50
[    4.957072]  _copy_to_iter+0x15b/0x1070
[    4.957072]  __skb_datagram_iter+0x3c7/0x890
[    4.957072]  skb_copy_datagram_iter+0x2f/0x120
[    4.957072]  process_rx_list+0x2b5/0x5f0
[    4.957072]  tls_sw_recvmsg+0x1081/0x17b0
[kTLS] Data MISMATCH - corruption detected!
[    4.969549] BUG: Bad page state in process init  pfn:02efc
Key excerpts from fixed kernel (negative control):
[kTLS] Data matches (no corruption observed yet)
[kTLS] Completed 20 iterations
[kTLS] Test complete. If KASAN is enabled, check dmesg for UAF report.

(No KASAN reports, no corruption, no bad page state)

Environment details:
  • Kernel: Linux 6.6.18 (v6.6.18 with fix reverted for vulnerable, fix present for fixed)
  • Compiler: GCC 15.2.0 with -std=gnu11 compatibility patches
  • QEMU: QEMU 10.2.1, TCG mode, -cpu max (AES-NI emulation), 2 vCPUs, 1024MB RAM
  • KASAN: Generic KASAN with inline instrumentation
  • Page poisoning: enabled (page_poison=1)
  • Crypto: AES-NI GCM with forced async decrypt via cryptd workqueue
  • Test: kTLS AES-128-GCM, TLS 1.2, 4096-byte records, 100-byte partial reads

Recommendations / Next Steps

  • Upgrade: Apply the fix (commit 32b55c5ff9103b8508c1e04bfa5a08c64e7a925f) or upgrade to Linux 6.6.19+, 6.7.7+, 6.1.82+, or 6.8-rc3+.
  • Testing: Enable CONFIG_KASAN and CONFIG_PAGE_POISONING in kernel testing configurations to detect similar use-after-free bugs in the kTLS receive path.
  • Code review: Audit other completion callbacks in the kTLS code that use pointer comparison (sgout != sgin) instead of explicit allocation tracking.
  • Mitigation: If kTLS is used in production with hardware crypto accelerators (which naturally produce async completions), ensure the kernel is patched. The bug only manifests with async decryption, which is the normal case with hardware crypto.

Additional Notes

  • Idempotency: The reproduction script is idempotent — it checks for existing build artifacts and reuses them. Running it multiple times produces the same result.
  • Async path simulation: The crypto/simd.c patch forces AEAD decrypt operations through the cryptd workqueue, simulating the async behavior that occurs naturally with hardware crypto accelerators or in contexts where SIMD/FPU is unavailable (e.g., softirq context). This does not modify the vulnerable code path in tls_sw.c; it only ensures the async completion path is exercised. In production, this async path is triggered by hardware crypto offload or when the crypto operation is deferred.
  • Page poisoning: CONFIG_PAGE_POISONING with page_poison=1 fills freed pages with a poison pattern (0xAA), making the use-after-free visible through data corruption even without KASAN. This provides an additional layer of detection beyond KASAN's shadow memory tracking.
  • GCC 15 compatibility: The v6.6.18 kernel requires minor Makefile patches to build with GCC 15, which defaults to C23 where true/false are keywords. The patches add -std=gnu11 to REALMODE_CFLAGS, boot/compressed, and EFI libstub Makefiles, matching the fix applied in newer kernel versions.

Variant Analysis & Alternative Triggers for CVE-2024-26582

Versions: versions (as tested): Linux v6.6.18 — i.e. any branch that has 32b55c5

A confirmed bypass of the CVE-2024-26582 fix commit 32b55c5ff9103b8508c1e04bfa5a08c64e7a925f (net: tls: fix use-after-free with partial reads and async decrypt, the free_sgout fix) was found and reproduced on the fixed Linux v6.6.18 kernel. The free_sgout fix only corrects the page-freeing heuristic in the async completion callback tls_decrypt_done() (replacing the buggy sgout != sgin test with dctx->free_sgout = !!pages). It does not cover the crypto-backlog error path: when an async kTLS decrypt request is enqueued to the crypto backlog (crypto_aead_decrypt() returns -EBUSY) and a pending async decrypt fails with -EBADMSG (e.g. an attacker-controlled malformed/mismatched-key TLS record), tls_do_decryption() waits for the backlog to drain (tls_decrypt_async_wait()); during that wait tls_decrypt_done() already runs and kfree()s the aead_req/tls_decrypt_ctx block (and frees the destination pages when free_sgout). tls_do_decryption() then returns -EBADMSG, tls_decrypt_sg() jumps to exit_free_pages/exit_free and frees the same memory again → slab-use-after-free / double-free, confirmed by KASAN. This second UAF is fixed upstream by commit 13114dc5543069f7b97991e3b79937b6da05f5b0 (tls: fix use-after-free on failed backlog decryption, adds the async_done flag), which is absent in v6.6.18. We reproduced the UAF on v6.6.18 (32b55c5 present, 13114dc absent) and verified that adapting 13114dc closes it.

Fix Coverage / Assumptions

The original fix 32b55c5 relies on this invariant:

The decision of whether to free the AEAD destination pages in the async completion callback tls_decrypt_done() can be made correctly at submit time by recording whether tls_decrypt_sg() actually allocated those pages (dctx->free_sgout = !!pages), instead of the fragile sgout != sgin pointer comparison.

Code paths 32b55c5 explicitly covers:

  • tls_decrypt_done() (the async AEAD completion callback) — page-free condition changed to if (dctx->free_sgout).
  • All three sgout setup sub-cases in tls_decrypt_sg(): clear_skb (non-ZC, pages=0), out_iov (ZC, pages>0), and out_sg (ZC, pages=0).

What 32b55c5 does NOT cover:

  • The -EBUSY backlog error path in tls_do_decryption(). When crypto_aead_decrypt() returns -EBUSY, tls_do_decryption() calls tls_decrypt_async_wait() and may return an error (-EBADMSG) after the async callback tls_decrypt_done() has already run and released the memory. tls_decrypt_sg()'s error cleanup (exit_free_pagesput_page loop, then exit_freekfree(mem)) then releases the same memory a second time.
  • 32b55c5 only governs whether tls_decrypt_done frees pages; it has no mechanism to tell tls_decrypt_sg()'s error path that the callback already ran. That mechanism (async_done) is exactly what 13114dc adds.

The reproduction's own instrumentation already forces the async path (a crypto/simd.c patch that defers all AEAD decrypts to the cryptd workqueue, simulating an async/hardware crypto accelerator), and v6.6.18 already contains the -EBUSY backlog handling from 859054147318 ("net: tls: handle backlogging of crypto requests"). Only the 13114dc completion of that fix is missing.

Variant / Alternate Trigger

Entry point: recv() / recvmsg() on a kTLS (TLS 1.2) software RX socket — the same syscall surface as the original CVE, but driven through the backlog error sub-path instead of the partial-read process_rx_list() path.

Trigger conditions (all attacker-relevant):

  1. A kTLS TLS 1.2 session with an async-capable AEAD (ctx->async_capable = true; any cipher whose tfm is CRYPTO_ALG_ASYNC, e.g. gcm(aes) via the simd/cryptd wrapper, or a hardware crypto accelerator). TLS 1.3 disables async, so TLS 1.2 is required — same as the original CVE.
  2. A decrypt request that is backlogged (crypto_aead_decrypt()-EBUSY). This is the natural behavior under crypto backlog congestion (the CRYPTO_TFM_REQ_MAY_BACKLOG flag kTLS sets on every AEAD request). With a busy/congested async crypto queue (hardware accelerator or cryptd under load), -EBUSY is returned instead of -EINPROGRESS.
  3. A pending async decrypt that fails with -EBADMSG. An attacker who controls the TLS record bytes on the wire (the trust boundary the original CVE crosses — network-received ciphertext) can send a malformed/corrupt record (bad AEAD tag) so decryption fails. In the reproducer this is simulated with mismatched TX/RX keys (every record fails -EBADMSG), which exercises the identical tls_decrypt_done(... err=-EBADMSG) code path.

Exact code path (files / functions), all in net/tls/tls_sw.c:

__x64_sys_recvfrom -> ... -> tls_sw_recvmsg()
  -> tls_rx_one_record() -> tls_decrypt_sw() -> tls_decrypt_sg()
     -> tls_do_decryption()
        crypto_aead_decrypt() == -EBUSY            [backlog congestion]
        -> tls_decrypt_async_wait()                [waits; tls_decrypt_done() runs on cryptd
                                                    workqueue, frees pages if free_sgout AND
                                                    kfree(aead_req)/dctx block]
        returns -EBADMSG                            [a pending decrypt failed]
     err = -EBADMSG -> goto exit_free_pages:
        for (; pages>0; ...) put_page(sg_page(&sgout[pages]))   [DOUBLE-FREE of ZC pages]
     exit_free: kfree(mem)                          [DOUBLE-FREE / UAF of aead_req||dctx block]

KASAN attributes the freed object to tls_decrypt_done() running on the cryptd workqueue (cryptd_aead_crypt -> cryptd_queue_worker -> process_one_work), and the buggy re-access to tls_decrypt_sg() — exactly the 13114dc bug.

The reproduction additionally forces -EINPROGRESS -> -EBUSY for async decrypts (bundle/vuln_variant/ebusy_force.patch) because the backlog-congestion condition is non-deterministic in a single-CPU loopback QEMU. This is analogous to the reproduction's existing crypto/simd.c patch that forces the cryptd async path; it does not alter the page-freeing (free_sgout) logic — it only makes the backlog (-EBUSY) code path reachable on demand.

  • Package / component affected: Linux kernel kTLS software RX, net/tls/tls_sw.c (tls_do_decryption, tls_decrypt_done, tls_decrypt_sg).
  • Affected versions (as tested): Linux v6.6.18 — i.e. any branch that has 32b55c5 (free_sgout) but not 13114dc (async_done). Concretely v6.6.18 ships 32b55c5 and the backlog handling 859054147318, but predates 13114dc (committed 2024-02-29, after v6.6.18).
  • Risk level: High — kernel-space slab use-after-free / double-free in the kTLS receive path, triggerable by an attacker who can send malformed TLS records to a kTLS peer whose async crypto queue is congested. Same impact class as the parent CVE (memory corruption; potential info leak / privilege escalation).

Impact Parity

  • Disclosed / claimed maximum impact (parent CVE-2024-26582): kernel-space use-after-free / memory corruption in the kTLS async decrypt receive path.
  • Reproduced impact from this variant run: kernel-space slab-use-after-free confirmed by KASAN (BUG: KASAN: slab-use-after-free in tls_decrypt_sg+0x2037/0x29c0), where the freed aead_req/dctx block (kmalloc-512) was freed by tls_decrypt_done() on the cryptd workqueue and re-accessed by tls_decrypt_sg()'s error path. This is a memory-corruption primitive of the same class as the parent CVE, on the fixed (v6.6.18 + 32b55c5) kernel.
  • Parity: full — same component, same async-decrypt UAF class, same trust boundary (network-controlled TLS records), reproduced on the patched code path.
  • Not demonstrated: no exploit chain to privilege escalation / code execution was built; the reproduction demonstrates the memory-corruption primitive (KASAN UAF) only, consistent with the parent CVE's reproduced scope.

Root Cause

tls_decrypt_sg() allocates a single block mem = kmalloc(aead_req || tls_decrypt_ctx) that owns both the AEAD request and the destination scatterlist/free_sgout flag. In the async case the completion callback tls_decrypt_done() is responsible for freeing the destination pages (when free_sgout) and for kfree(aead_req) (the mem block). The error path of tls_decrypt_sg() (exit_free_pages/exit_free) also frees those pages and kfree(mem).

For the normal async path (crypto_aead_decrypt()-EINPROGRESS), tls_do_decryption() returns 0 and tls_decrypt_sg() returns without hitting its error cleanup, so only the callback frees — no double-free. 32b55c5 makes the callback's page-free decision correct.

For the backlog path (-EBUSY), tls_do_decryption() synchronously waits for the backlog to drain (tls_decrypt_async_wait()). By the time the wait returns, tls_decrypt_done() has already executed for the backlogged request and freed its memory. If the wait also observed a failure (ctx->async_wait.err == -EBADMSG), tls_do_decryption() returns -EBADMSG, and tls_decrypt_sg() runs its error cleanup on the already-freed memory → double-free / UAF. 32b55c5 does not provide any signal that the callback already ran, so it cannot prevent this.

The missing fix is upstream commit 13114dc5543069f7b97991e3b79937b6da05f5b0 ("tls: fix use-after-free on failed backlog decryption"), Fixes: 859054147318. It adds bool async_done to tls_decrypt_arg; on the -EBUSY path tls_do_decryption() sets async_done=true and returns the wait result, and tls_decrypt_sg() then skips exit_free_pages/exit_free (goto exit_free_skb) when async_done is set, avoiding the double-free. We verified this exact behavior by adapting 13114dc to v6.6.18: the UAF disappears.

Reproduction Steps

  1. See bundle/vuln_variant/reproduction_steps.sh.
  2. The script builds four v6.6.18 kernels side by side (all have the async-forcing crypto/simd.c patch from the parent reproduction):
    • vuln+ebusy (32b55c5 reverted + ebusy_force.patch) — variant on the vulnerable tree,
    • fixed (32b55c5 present, no backlog forcing) — baseline,
    • fixed+ebusy (32b55c5 + ebusy_force.patch: -EINPROGRESS -> -EBUSY for async decrypts) — bypass,
    • fixed+ebusy+13114dc (also adapts the 13114dc async_done fix) — gap-closure. It builds a static init binary (backlog_variant_test.c) that sets up kTLS TLS 1.2 AES-128-GCM over loopback with mismatched TX/RX keys (so every record fails -EBADMSG during async decrypt), sends 16 records, and recv()s them with a large buffer (zero-copy full reads, darg.zc=true, pages>0, free_sgout=true). It runs each kernel in QEMU (KASAN + page poisoning) and counts BUG: KASAN reports.
  3. Expected evidence: vuln+ebusy and fixed+ebusy both show BUG: KASAN: slab-use-after-free in tls_decrypt_sg; fixed (no backlog) shows none; fixed+ebusy+13114dc shows none. Exit 0 = bypass confirmed on the FIXED kernel. The vuln+ebusy result corroborates that the variant is present on the vulnerable tree too (both lack 13114dc).

Evidence

  • bundle/logs/vuln_variant/qemu-vuln-ebusy-variant.logvariant on vulnerable tree (32b55c5 reverted + ebusy): BUG: KASAN: slab-use-after-free in tls_decrypt_sg (corroborates the variant is the same on the vulnerable tree, which also lacks 13114dc).
  • bundle/logs/vuln_variant/qemu-fixed-ebusy-variant.logbypass: contains BUG: KASAN: slab-use-after-free in tls_decrypt_sg+0x2037/0x29c0 (Read of size 8, 440 bytes into a freed kmalloc-512 region). Allocated by __kmalloc in tls_decrypt_sg; Freed by task 26 via tls_decrypt_done -> cryptd_aead_crypt -> cryptd_queue_worker (async workqueue). Program output: recv returned -1 (errno=74 Bad message).
  • bundle/logs/vuln_variant/qemu-fixed-nobacklog-baseline.logbaseline: same test, no backlog forcing → EBADMSG returned, no KASAN (proves 32b55c5 holds for the normal async path and the -EBUSY condition is the trigger).
  • bundle/logs/vuln_variant/qemu-fixed-ebusy-13114dc.loggap-closure: same test with 13114dc adapted → EBADMSG returned, no KASAN (proves 13114dc closes the bypass).
  • bundle/logs/vuln_variant/kasan_report_excerpt.txt — extracted KASAN report.
  • bundle/logs/vuln_variant/fixed_version.txt — tested source identity (v6.6.18 tarball; free_sgout present, async_done absent).
  • bundle/vuln_variant/ebusy_force.patch, bundle/vuln_variant/apply_fix13114dc.py, bundle/vuln_variant/backlog_variant_test.c — instrumentation / test program.

Recommendations / Next Steps

  • Close the gap: backport / apply commit 13114dc5543069f7b97991e3b79937b6da05f5b0 ("tls: fix use-after-free on failed backlog decryption") to every branch that carries the CVE 2024-26582 free_sgout fix (32b55c5) but not 13114dc (e.g. v6.6.18 / v6.6.19-only branches that took only the first patch). The 32b55c5 fix alone is incomplete for the async-decrypt UAF class. The fix must add an async_done-style signal so tls_decrypt_sg()'s error path skips exit_free_pages/exit_free when the async completion callback has already released the memory.
  • Rule-out matrix (other surfaces inspected, all covered/sync — not bypasses):
    • tls_sw_splice_read() (splice syscall): uses darg.async = false (sync) → uses crypto_req_done, never tls_decrypt_done → not reachable. Not a variant.
    • tls_sw_read_sock() (sendfile / tcp_read_sock): likewise sync. Not a variant.
    • decrypt_skb() / out_sg path (Case C, device fallback): darg = { .zc = true } with async = false (sync) → never tls_decrypt_done. Not a variant.
    • Other ciphers (CHACHA20-POLY1305, AES-256-GCM, AES-128-CCM): the bug is cipher-agnostic (all flow through tls_decrypt_sg/tls_do_decryption/tls_decrypt_done); 32b55c5's free_sgout and the missing 13114dc async_done apply identically. (CHACHA20-POLY1305 exercises a different IV-prep branch at tls_sw.c:1531 but the same sink.) These are alternate triggers of the same sink, all covered by 32b55c5+13114dc; not independent bypasses.
  • Hardening: treat the two CVE-2024-26582 patches (32b55c5 and 13114dc) as a single mandatory unit when backporting; add a regression test that exercises the async decrypt backlog + failure combination (the reproducer in this bundle is a starting point).

Additional Notes

  • Idempotency: bundle/vuln_variant/reproduction_steps.sh was run twice; both runs produced identical results (fixed(no ebusy) KASAN=0 | fixed+ebusy KASAN=1 | fixed+ebusy+13114dc KASAN=0) and exit 0. Kernel builds and the initramfs are cached and skipped on repeat runs; the shared kernel source tree is always restored to pristine (tls_sw.c.orig) after each variant build.
  • Trust boundary: the attacker controls the TLS record bytes received over the network (malformed record → -EBADMSG); the -EBUSY backlog congestion is an environmental condition (busy async crypto), not attacker-controlled, but it is a normal operating condition for systems using async/hardware crypto accelerators. The reproducer forces -EBUSY deterministically because loopback single-CPU QEMU cannot naturally congest the crypto backlog; this mirrors the parent reproduction's crypto/simd.c async-forcing approach.
  • Instrumentation caveat: ebusy_force.patch converts -EINPROGRESS -> -EBUSY for async decrypts to make the backlog path reachable on demand. It does not change free_sgout or any page-freeing logic; the double-free is the genuine v6.6.18 code path, not an artifact of the patch. The 13114dc-adapted kernel shows no UAF under the same forcing, proving the gap is exactly the missing async_done fix.
  • The v6.6.18 source is a kernel.org release tarball (no git metadata); source identity is recorded in bundle/vuln_variant/source_identity.json via release-tag resolution.

CVE-2024-26582 Reproduction Transcript

The agent's step-by-step process — every tool call, every handoff, the moment the exploit fired.

Full session Replay every step — scrub the timeline or play it back.

Event 1/40
0:001:44
0:00
session startedaccounts/fireworks/routers/glm-5p2-fast · CVE-2024-26582 · REPRO-20
0:04
0:06
web search
0:07
web search
0:10
0:56
0:57
web search
1:12
1:13
web search
1:25
1:25
extract_facts
no facts extracted
1:26
1:26
1:26
supportrepro
1:28
1:28
1:28
1:29
1:29
1:29
1:32
1:32
1:32
1:37
1:37
1:37
1:44
1:44
1:44
$cd /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/linux-src && git log --oneline -3 2>/dev/null; echo "---HEAD---"; git rev-parse HEAD 2>/dev/null; echo "---VERSION---"; head -5 Makefile
---HEAD---
---VERSION---
# SPDX-License-Identifier: GPL-2.0
VERSION = 6
PATCHLEVEL = 18
SUBLEVEL = 18
EXTRAVERSION =
1:44
$cd /data/pruva/project-cache/6cba72b6-b104-4ebf-be7b-01f748e87ccf/linux-src-7rc2 && git log --oneline -3 2>/dev/null; echo "---HEAD---"; git rev-parse HEAD 2>/dev/null; echo "---VERSION---"; head -5 Makefile
---HEAD---
---VERSION---
# SPDX-License-Identifier: GPL-2.0
VERSION = 7
PATCHLEVEL = 0
SUBLEVEL = 0
EXTRAVERSION = -rc2
08 · How to Fix

How to Fix CVE-2024-26582

Coming soon

Step-by-step mitigation and hardening guidance for CVE-2024-26582 — configuration checks, workarounds where no patch exists, and how to verify you're protected — is on the way.

10 · FAQ

FAQ: CVE-2024-26582

How does the CVE-2024-26582 use-after-free get triggered?

An attacker who can establish a kTLS session and control the read pattern issues a partial read on data being decrypted asynchronously. tls_decrypt_done() frees the clear_skb pages prematurely, and the subsequent read via process_rx_list() dereferences the already-freed pages, leading to memory corruption, information leaks, or potential further exploitation.

Which Linux kernel versions are affected by CVE-2024-26582, and where is it fixed?

Linux 6.2.0 through 6.6.18 are affected, as well as 6.1.x before 6.1.82 and 6.7.x before 6.7.7. The fix is upstream commit 32b55c5ff9103b8508c1e04bfa5a08c64e7a925f, which adds a free_sgout flag so tls_decrypt_sg()-allocated pages are only freed if they were newly allocated.

How severe is CVE-2024-26582?

It is rated high severity: a kernel-space use-after-free that can lead to memory corruption, information leaks, or potentially privilege escalation, though it requires establishing a kTLS session with async decryption and controlling the read pattern.

How can I reproduce CVE-2024-26582?

Download the verified script from this page and run it in an isolated VM with CONFIG_TLS=y against an affected kernel (6.2.0-6.6.18). It sets up a kTLS session, forces the asynchronous decryption path, and performs a partial read to trigger the premature page free and subsequent use-after-free access, since this is a kernel-space bug that is challenging to reproduce with userspace-only backends.
11 · References

References for CVE-2024-26582

Authoritative sources for CVE-2024-26582 — official vulnerability databases and the upstream advisory. Pruva's reproduction verifies the issue firsthand; these are the primary records to corroborate it.