FlawOpen

flawopen.com/Teardowns/cve-2024-26585-linux-tls-tx-work-close-race

● CVE-2024-26585 · CVSS 4.7 · Medium
FlawOpen Security Research

CVE-2024-26585: Linux TLS Close Race

A Linux kTLS completion woke sendmsg/recvmsg before queuing TX work. The fix schedules work first to close the socket-race window.

💡 Plain English Explainer (ELI5)

A worker tells a waiting colleague “I’m done” before putting its last task on the shared queue. The colleague can close the shop and cancel queued tasks in that gap; the worker then adds a task too late. This kernel fix queues TLS transmit work before signaling completion, so the submitter cannot race ahead to socket close first.

Core Concepts & Subsystem Terms

kTLS
Linux kernel TLS, which handles TLS record processing in the kernel networking path.
Asynchronous crypto completion
A callback that runs after an asynchronous TLS encryption operation finishes.
`complete()`
A Linux completion primitive that wakes a thread waiting for an operation to finish.
Delayed TX work
Queued kernel work that continues TLS record transmission after encryption completes.

Framework mappings

  • CWE reference for the weakness described in this guide: CWE-362

Root Cause Analysis

In net/tls/tls_sw.c, tls_encrypt_done() could call complete() for the submitting sendmsg()/recvmsg() thread before scheduling delayed TX work for the head record. The awakened thread may return and close the socket while the callback is still about to queue that work, racing socket teardown with TX-work scheduling. Upstream commit e01e3934a1b2 reverses the order: if the record is at the head of ctx->tx_list, it schedules ctx->tx_work before calling complete(). The CVE notice describes a race; the cited sources do not substantiate the article’s previous claims about MSG_ZEROCOPY, freed network pages, an overwrite, or a refcount_inc_not_zero() fix.

Step-by-Step Attack Flow

Step 1

1. TLS transmit begins

A process uses the kernel TLS transmit path, where record encryption may complete asynchronously.

Step 2

2. Callback inspects ordering

tls_encrypt_done() checks whether the completed record is at the head of ctx->tx_list.

Step 3

3. Wake races with close

Before the patch, the callback could wake the submitting thread with complete() and only afterward queue TX work; the thread may return and close the socket in between.

Step 4

4. Patch orders the handoff

The fix queues delayed TX work first, then signals completion, so the submitter cannot pass the completion point before scheduling is done.

Source Code: Flaw vs. Secure Implementation

UNPATCHED FLAW
// Relevant ordering in net/tls/tls_sw.c before e01e3934a1b2
bool ready = false;

if (rec == first_rec)
    ready = true;

if (atomic_dec_and_test(&ctx->encrypt_pending))
    complete(&ctx->async_wait.completion);

if (!ready)
    return;

if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
    schedule_delayed_work(&ctx->tx_work.work, 1);
HARDENED SECURE PATCH
// Relevant ordering in net/tls/tls_sw.c after e01e3934a1b2
if (rec == first_rec) {
    // Queue transmit work before waking the submitting thread.
    if (!test_and_set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask))
        schedule_delayed_work(&ctx->tx_work.work, 1);
}

if (atomic_dec_and_test(&ctx->encrypt_pending))
    complete(&ctx->async_wait.completion);

Engineering & System Hardening Checklist

Sources