[SRU][N][PATCH v2 1/1] tls: Fix race condition in tls_sw_cancel_work_tx()

Jian Hui Lee jianhui.lee at canonical.com
Thu Jun 25 10:59:54 UTC 2026


On Wed, Jun 24, 2026 at 5:52 AM Cengiz Can via kernel-team
<kernel-team at lists.ubuntu.com> wrote:
>
> From: Hyunwoo Kim <imv4bel at gmail.com>
>
> This issue was discovered during a code audit.
>
> After cancel_delayed_work_sync() is called from tls_sk_proto_close(),
> tx_work_handler() can still be scheduled from paths such as the
> Delayed ACK handler or ksoftirqd.
> As a result, the tx_work_handler() worker may dereference a freed
> TLS object.
>
> The following is a simple race scenario:
>
>           cpu0                         cpu1
>
> tls_sk_proto_close()
>   tls_sw_cancel_work_tx()
>                                  tls_write_space()
>                                    tls_sw_write_space()
>                                      if (!test_and_set_bit(BIT_TX_SCHEDULED, &tx_ctx->tx_bitmask))
>     set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask);
>     cancel_delayed_work_sync(&ctx->tx_work.work);
>                                      schedule_delayed_work(&tx_ctx->tx_work.work, 0);
>
> To prevent this race condition, cancel_delayed_work_sync() is
> replaced with disable_delayed_work_sync().
>
> Fixes: f87e62d45e51 ("net/tls: remove close callback sock unlock/lock around TX work flush")
> Signed-off-by: Hyunwoo Kim <imv4bel at gmail.com>
> Reviewed-by: Simon Horman <horms at kernel.org>
> Reviewed-by: Sabrina Dubroca <sd at queasysnail.net>
> Link: https://patch.msgid.link/aZgsFO6nfylfvLE7@v4bel
> Signed-off-by: Jakub Kicinski <kuba at kernel.org>
> (backported from commit 7bb09315f93dce6acc54bf59e5a95ba7365c2be4)
> [bot_kybele: disable_delayed_work_sync() does not exist in 6.8 (added upstream
>  in 6.10); replaced it with a
>  while(cancel_delayed_work_sync(&ctx->tx_work.work)) loop, which drains a
>  concurrent in-flight re-arm while the already-set, never-cleared
>  (BIT_TX_CLOSING) BIT_TX_SCHEDULED bit blocks new tls_sw_write_space() arming,
>  preserving the no-re-arm-after-cancel UAF fix.]
> CVE-2026-23240
> Assisted-by: kybele:claude-opus-4.8
> Signed-off-by: Cengiz Can <cengiz.can at canonical.com>
> ---
>  net/tls/tls_sw.c | 10 +++++++++-
>  1 file changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/net/tls/tls_sw.c b/net/tls/tls_sw.c
> index 057da95f0fc6..5be450f17b19 100644
> --- a/net/tls/tls_sw.c
> +++ b/net/tls/tls_sw.c
> @@ -2510,7 +2510,15 @@ void tls_sw_cancel_work_tx(struct tls_context *tls_ctx)
>
>         set_bit(BIT_TX_CLOSING, &ctx->tx_bitmask);
>         set_bit(BIT_TX_SCHEDULED, &ctx->tx_bitmask);
> -       cancel_delayed_work_sync(&ctx->tx_work.work);
> +       /* disable_delayed_work_sync() is not available on this kernel. The
> +        * BIT_TX_SCHEDULED bit set above stays set (tx_work_handler() bails on
> +        * BIT_TX_CLOSING without clearing it), so no new tls_sw_write_space()
> +        * can re-arm the work. Loop cancel_delayed_work_sync() to also drain a
> +        * concurrent in-flight schedule_delayed_work(), preserving the same
> +        * "no re-arm after cancel" guarantee that fixes the UAF race.
> +        */
> +       while (cancel_delayed_work_sync(&ctx->tx_work.work))
> +               ;
>  }

hi cengiz,

could you explain more context about why looping is going to help
here? because it seems that the looping cannot promise the paused cpu
stopping committing the queue and falls into the same situation.

>
>  void tls_sw_release_resources_tx(struct sock *sk)
> --
> 2.43.0
>
>
> --
> kernel-team mailing list
> kernel-team at lists.ubuntu.com
> https://lists.ubuntu.com/mailman/listinfo/kernel-team



More information about the kernel-team mailing list