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

## Summary

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.

## Impact

- **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.
