FlawOpen

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

● CVE-2024-26585 · CVSS 4.7 · Средний
Исследования · FlawOpen

CVE-2024-26585: гонка закрытия TLS в Linux

В kTLS Linux завершение могло разбудить sendmsg/recvmsg до постановки TX-задачи в очередь. Исправление сначала ставит задачу.

💡 Простыми словами (ELI5)

Работник говорит ожидающему коллеге «готово» до того, как добавит последнюю задачу в общую очередь. За это время коллега может закрыть мастерскую и отменить задачи; затем работник добавит задачу слишком поздно. Исправление ядра ставит передачу TLS в очередь до сигнала о завершении.

Ключевые понятия и термины

kTLS
TLS в ядре Linux, обрабатывающий TLS-записи в сетевом стеке ядра.
Асинхронное завершение криптооперации
Callback, запускаемый после окончания асинхронного шифрования TLS.
`complete()`
Примитив завершения Linux, который будит поток, ожидающий окончания операции.
Отложенная TX-задача
Задача ядра в очереди, продолжающая передачу записи TLS после шифрования.

Связи со стандартами

  • Ссылка CWE для слабого места, описанного в этом руководстве: CWE-362

Анализ первопричины

В net/tls/tls_sw.c функция tls_encrypt_done() могла вызвать complete() для ожидающего потока sendmsg()/recvmsg() до планирования отложенной TX-задачи для первой записи. Разбуженный поток может вернуться и закрыть сокет, пока callback ещё собирается поставить задачу в очередь; возникает гонка между закрытием сокета и постановкой TX-задачи. Upstream-коммит e01e3934a1b2 меняет порядок: если запись находится в начале ctx->tx_list, он планирует ctx->tx_work до вызова complete(). В уведомлении CVE описана гонка; приведённые источники не подтверждают прежние утверждения о MSG_ZEROCOPY, освобождённых сетевых страницах, перезаписи памяти или исправлении через refcount_inc_not_zero().

Пошаговый сценарий атаки

Шаг 1

1. Начинается передача TLS

Процесс использует путь передачи kTLS, где шифрование записей может завершаться асинхронно.

Шаг 2

2. Callback проверяет порядок

tls_encrypt_done() проверяет, находится ли завершённая запись в начале ctx->tx_list.

Шаг 3

3. Пробуждение конкурирует с закрытием

До патча callback мог разбудить поток через complete(), а TX-задачу поставить позже; между этими действиями поток мог закрыть сокет.

Шаг 4

4. Патч упорядочивает передачу управления

Исправление сначала ставит отложенную TX-задачу в очередь, затем сигнализирует о завершении, не позволяя потоку продолжить раньше постановки.

Исходный код: Уязвимый vs Защищённый вариант

УЯЗВИМАЯ РЕАЛИЗАЦИЯ
// Порядок операций в net/tls/tls_sw.c до 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);
БЕЗОПАСНЫЙ ИСПРАВЛЕННЫЙ ВАРИАНТ
// Порядок операций в net/tls/tls_sw.c после e01e3934a1b2
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);

Чек-лист по защите системы для инженеров

Источники