FlawOpen

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

● CVE-2024-26585 · CVSS 4.7 · Media
Investigación · FlawOpen

CVE-2024-26585: carrera al cerrar TLS en Linux

En kTLS de Linux, la finalización podía despertar sendmsg/recvmsg antes de encolar el trabajo TX. El parche lo programa primero.

💡 Explicación en Lenguaje Sencillo (ELI5)

Un trabajador avisa a un compañero «he terminado» antes de poner su última tarea en la cola compartida. En ese intervalo, el compañero puede cerrar el taller y cancelar las tareas pendientes; luego el trabajador añade una tarea demasiado tarde. La corrección del kernel encola el trabajo de transmisión TLS antes de señalar la finalización.

Conceptos Clave y Términos

kTLS
TLS en el kernel Linux, que procesa registros TLS en la ruta de red del kernel.
Finalización criptográfica asíncrona
Callback que se ejecuta cuando termina una operación asíncrona de cifrado TLS.
`complete()`
Primitiva de finalización de Linux que despierta a un hilo que espera a que termine una operación.
Trabajo TX diferido
Trabajo encolado del kernel que continúa la transmisión del registro TLS tras el cifrado.

Mapeos de marcos

  • Referencia CWE para la debilidad descrita en esta guía: CWE-362

Análisis de Causa Raíz

En net/tls/tls_sw.c, tls_encrypt_done() podía llamar a complete() para el hilo que ejecutaba sendmsg()/recvmsg() antes de programar el trabajo TX diferido del registro situado al frente. El hilo despertado puede retornar y cerrar el socket mientras el callback aún va a encolar ese trabajo, creando una carrera entre el cierre del socket y la programación TX. El commit upstream e01e3934a1b2 invierte el orden: si el registro está al frente de ctx->tx_list, programa ctx->tx_work antes de llamar a complete(). El aviso describe una carrera; las fuentes citadas no respaldan las antiguas afirmaciones sobre MSG_ZEROCOPY, páginas de red liberadas, sobrescritura ni una corrección con refcount_inc_not_zero().

Flujo de Ataque Paso a Paso

Paso 1

1. Comienza la transmisión TLS

Un proceso usa la ruta de transmisión kTLS, donde el cifrado de registros puede finalizar de forma asíncrona.

Paso 2

2. El callback comprueba el orden

tls_encrypt_done() comprueba si el registro completado está al frente de ctx->tx_list.

Paso 3

3. El despertar compite con el cierre

Antes del parche, el callback podía despertar al hilo con complete() y encolar el trabajo TX después; el hilo podía cerrar el socket en medio.

Paso 4

4. El parche ordena la entrega

La corrección encola primero el trabajo TX diferido y después señala la finalización, para que el hilo no avance antes del encolado.

Código Fuente: Vulnerable vs. Seguro

IMPLEMENTACIÓN VULNERABLE
// Orden relevante en net/tls/tls_sw.c antes de 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);
PARCHE SEGURO Y ROBUSTO
// Orden relevante en net/tls/tls_sw.c después de e01e3934a1b2
if (rec == first_rec) {
    // Encole el trabajo de transmisión antes de despertar al hilo que lo envió.
    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);

Lista de Verificación de Seguridad para Ingeniería

Fuentes