tls_device_down() moves each context to tls_device_down_list while holding tls_device_lock. It then drops its reference and removes the context after releasing the lock. tls_device_queue_ctx_destruction() removes contexts from the same list under tls_device_lock. If it removes an adjacent context while tls_device_down() is deleting its node, the two list updates can interleave. One update can then target a context freed by the other path, causing a use-after-free write. Drop the reference and remove the context in the existing tls_device_lock critical section. Keep tls_device_free_ctx() after releasing the lock. This issue was found with a static analysis tool. Fixes: f6336724a4d4 ("net/tls: Remove the context from the list in tls_device_down") Cc: stable@vger.kernel.org Signed-off-by: Jaeyeong Lee --- Reproduced with a deterministic KUnit harness under KASAN in a 2-vCPU x86_64 QEMU guest. The unpatched kernel reported: BUG: KASAN: slab-use-after-free in tls_device_racy_list_del Write of size 8 The patched tls_device.o was compile-tested against current net/main with KASAN and DEBUG_LIST enabled. net/tls/tls_device.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/net/tls/tls_device.c b/net/tls/tls_device.c index 4cdfbb57ecff0..fa7170cd4fd10 100644 --- a/net/tls/tls_device.c +++ b/net/tls/tls_device.c @@ -1350,6 +1350,8 @@ static int tls_device_down(struct net_device *netdev) spin_unlock_irqrestore(&tls_device_lock, flags); list_for_each_entry_safe(ctx, tmp, &list, list) { + bool free_ctx; + /* Stop offloaded TX and switch to the fallback. * tls_is_skb_tx_device_offloaded will return false. */ @@ -1387,17 +1389,19 @@ static int tls_device_down(struct net_device *netdev) */ spin_lock_irqsave(&tls_device_lock, flags); list_move_tail(&ctx->list, &tls_device_down_list); + /* Serialize the final removal with sk_destruct. */ + free_ctx = refcount_dec_and_test(&ctx->refcount); + if (free_ctx) + list_del(&ctx->list); spin_unlock_irqrestore(&tls_device_lock, flags); /* Device contexts for RX and TX will be freed in on sk_destruct * by tls_device_free_ctx. rx_conf and tx_conf stay in TLS_HW. - * Now release the ref taken above. */ - if (refcount_dec_and_test(&ctx->refcount)) { + if (free_ctx) { /* sk_destruct ran after tls_device_down took a ref, and * it returned early. Complete the destruction here. */ - list_del(&ctx->list); tls_device_free_ctx(ctx); } } -- 2.43.0