]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
netfilter: nf_conntrack_helper: pass helper to expect cleanup
authorQi Tang <tpluszz77@gmail.com>
Sun, 29 Mar 2026 16:50:36 +0000 (00:50 +0800)
committerPablo Neira Ayuso <pablo@netfilter.org>
Wed, 1 Apr 2026 09:55:29 +0000 (11:55 +0200)
nf_conntrack_helper_unregister() calls nf_ct_expect_iterate_destroy()
to remove expectations belonging to the helper being unregistered.
However, it passes NULL instead of the helper pointer as the data
argument, so expect_iter_me() never matches any expectation and all
of them survive the cleanup.

After unregister returns, nfnl_cthelper_del() frees the helper
object immediately.  Subsequent expectation dumps or packet-driven
init_conntrack() calls then dereference the freed exp->helper,
causing a use-after-free.

Pass the actual helper pointer so expectations referencing it are
properly destroyed before the helper object is freed.

  BUG: KASAN: slab-use-after-free in string+0x38f/0x430
  Read of size 1 at addr ffff888003b14d20 by task poc/103
  Call Trace:
   string+0x38f/0x430
   vsnprintf+0x3cc/0x1170
   seq_printf+0x17a/0x240
   exp_seq_show+0x2e5/0x560
   seq_read_iter+0x419/0x1280
   proc_reg_read+0x1ac/0x270
   vfs_read+0x179/0x930
   ksys_read+0xef/0x1c0
  Freed by task 103:
  The buggy address is located 32 bytes inside of
   freed 192-byte region [ffff888003b14d00ffff888003b14dc0)

Fixes: ac7b84839003 ("netfilter: expect: add and use nf_ct_expect_iterate helpers")
Signed-off-by: Qi Tang <tpluszz77@gmail.com>
Reviewed-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_conntrack_helper.c

index 1b330ba6613bb2c6d37dabdced8df03c179292ba..a715304a53d8c2b9e7a54bc8073a9a7aff1ad318 100644 (file)
@@ -415,7 +415,7 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me)
         */
        synchronize_rcu();
 
-       nf_ct_expect_iterate_destroy(expect_iter_me, NULL);
+       nf_ct_expect_iterate_destroy(expect_iter_me, me);
        nf_ct_iterate_destroy(unhelp, me);
 
        /* nf_ct_iterate_destroy() does an unconditional synchronize_rcu() as