flawopen.com/Teardowns/cve-2024-26585-linux-tls-zerocopy-use-after-free
Технический анализ исходного кода и защитные инженерные меры для vulnerabilidade: How an asynchronous cryptographic callback race condition in net/tls/tls_sw.c freed network pages while still queued for zero-copy transmission.
Наглядная аналогия: Imagine you order a meal for delivery. The chef starts cooking, but you call and cancel the order. Because the kitchen staff wasn't notified properly, the delivery driver picks up an empty plate, drives to a new customer's house, and serves them whatever was left on the counter, contaminating the new customer's food.
Kernel TLS (kTLS)Zero-Copy NetworkingAsynchronous Crypto (aead_request)Slab Corruptionkmalloc-512), destabilizing kernel execution.Основная причина заключается в невалидированных граничных параметрах в системах с открытым исходным кодом, что приводит к рассинхронизации состояний и обходу средств безопасности.
Технический механизм эксплуатации уязвимости: The attacker creates a TLS socket and enables kernel encryption offload via setsockopt(TCP_ULP, "tls").
Технический механизм эксплуатации уязвимости: The attacker sends data using MSG_ZEROCOPY, queuing pages for hardware crypto.
Технический механизм эксплуатации уязвимости: The attacker closes the socket before the crypto accelerator completes its async callback.
Технический механизм эксплуатации уязвимости: The cleanup handler frees memory pages that the delayed hardware callback subsequently overwrites.
// VULNERABLE: net/tls/tls_sw.c before patch
static void tls_encrypt_done(void *data, int err) {
struct tls_context *ctx = data;
struct tls_sw_context_tx *ctx_tx = tls_sw_ctx_tx(ctx);
// ROOT CAUSE:
// Asynchronous completion callback assumes socket context is still locked!
// If the socket was closed while crypto was in flight, ctx_tx is already freed!
clear_bit(TLS_TX_SYNC_MORE, &ctx_tx->tx_bitmask);
tls_free_open_rec(ctx);
}
// SECURE: net/tls/tls_sw.c patch
static void tls_encrypt_done(void *data, int err) {
struct tls_context *ctx = data;
// 1. Verify context reference counter before dereferencing context pointers
if (!refcount_inc_not_zero(&ctx->refcount)) {
return; // Socket is already dying, abort callback safely!
}
struct tls_sw_context_tx *ctx_tx = tls_sw_ctx_tx(ctx);
clear_bit(TLS_TX_SYNC_MORE, &ctx_tx->tx_bitmask);
tls_free_open_rec(ctx);
// 2. Drop reference cleanly
refcount_dec(&ctx->refcount);
}
refcount_inc_not_zero() on shared context handles inside asynchronous completion handlers.