FlawOpen

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

● CVE-2024-26585 · CVSS 4.7 · 中危
安全研究 · FlawOpen

CVE-2024-26585:Linux TLS 关闭竞态

Linux kTLS 的完成回调可能先唤醒 sendmsg/recvmsg,再排入 TX 工作。补丁调整顺序,先调度工作。

💡 通俗易懂的原理解析 (ELI5)

一名工人先告诉等待的同事“完成了”,却还没把最后一项任务放进共享队列。同事可能趁此关店并取消队列中的任务,工人随后才补入任务。内核补丁先排入 TLS 发送工作,再发出完成信号。

核心概念与专有名词

kTLS
Linux 内核中的 TLS 功能,在内核网络路径中处理 TLS 记录。
异步加密完成
TLS 异步加密操作结束后运行的回调。
`complete()`
Linux completion 原语,用于唤醒等待操作结束的线程。
延迟 TX 工作
排入内核队列、在加密完成后继续发送 TLS 记录的工作项。

框架映射

  • 本指南所述弱点的 CWE 参考: CWE-362

根本原因剖析 (Root Cause)

在 net/tls/tls_sw.c 中,tls_encrypt_done() 可能先对等待中的 sendmsg()/recvmsg() 线程调用 complete(),再为队首记录调度延迟 TX 工作。被唤醒的线程可能返回并关闭 socket,而回调仍准备排入该工作,因此 socket 关闭与 TX 工作调度会发生竞态。上游提交 e01e3934a1b2 调整顺序:若记录位于 ctx->tx_list 队首,就先调度 ctx->tx_work,再调用 complete()。CVE 公告描述的是竞态;引用来源并未证实先前关于 MSG_ZEROCOPY、网络页释放、内存覆盖或 refcount_inc_not_zero() 修复的说法。

攻击执行流程分解

步骤 1

1. TLS 发送开始

进程使用 kTLS 发送路径,记录加密可能异步完成。

步骤 2

2. 回调检查顺序

tls_encrypt_done() 检查已完成的记录是否位于 ctx->tx_list 队首。

步骤 3

3. 唤醒与关闭发生竞态

补丁前,回调可能先通过 complete() 唤醒线程,之后才排入 TX 工作;线程可能在间隙中关闭 socket。

步骤 4

4. 补丁调整交接顺序

修复先排入延迟 TX 工作,再发出完成信号,避免线程在调度完成前继续执行。

源代码对比:漏洞与安全实现

存在漏洞的实现
// e01e3934a1b2 之前 net/tls/tls_sw.c 中的相关顺序
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);
加固后的安全修复
// e01e3934a1b2 之后 net/tls/tls_sw.c 中的相关顺序
if (rec == first_rec) {
    // 先将发送工作加入队列,再唤醒提交该工作的线程。
    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);

工程与系统安全加固清单

参考来源