Re: [PATCH nf] netfilter: ipset: do not update comments from kernel-side hash adds
Jozsef Kadlecsik <[email protected]>
| Newsgroups | gmane.linux.network,gmane.comp.security.firewalls.netfilter.devel,gmane.linux.kernel,gmane.linux.kernel.stable |
|---|---|
| Message-ID | <[email protected]> |
Hi,
On Mon, 13 Jul 2026, David Lee wrote:
> mtype_resize() copies comment pointers with memcpy(), not the comment objects
> themselves. During the window after an entry has been copied but before the
> table swap and backlog replay, the old table is still published for
> packet-side updates while the replacement-table entry already holds the same
> ip_set_comment_rcu pointer.
>
> If xt_SET --add-set ... --exist hits that old entry in this window,
> mtype_add() calls ip_set_init_comment() even though packet-side adds carry no
> comment payload. That call frees the shared comment through the old entry, so
> the replacement-table entry now holds a stale pointer. When the queued add is
> replayed on the new table, mtype_add() calls ip_set_init_comment() again and
> strlen() dereferences the stale pointer.
>
> Fix this in mtype_add() by skipping ip_set_init_comment() when ext->target
> marks a packet-side add. Userspace adds still update comments, while
> packet-side adds can no longer free comment storage shared with a resize copy.
>
> Fixes: f66ee0410b1c ("netfilter: ipset: Fix "INFO: rcu detected stall in hash_xxx" reports")
> Cc: [email protected]
> Signed-off-by: David Lee <[email protected]>
> Assisted-by: Codex:gpt-5.5
> ---
> A reproducer triggers a KASAN slab-use-after-free in strlen() from
> ip_set_init_comment() during hash_ip4_resize().
>
> Trail of Bits has a privilege escalation PoC for this bug on a
> custom kernel, which can be shared further if needed.
>
> net/netfilter/ipset/ip_set_hash_gen.h | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/netfilter/ipset/ip_set_hash_gen.h b/net/netfilter/ipset/ip_set_hash_gen.h
> index 8231317b0f1f..b2d77973272d 100644
> --- a/net/netfilter/ipset/ip_set_hash_gen.h
> +++ b/net/netfilter/ipset/ip_set_hash_gen.h
> @@ -1005,7 +1005,7 @@ mtype_add(struct ip_set *set, void *value, const struct ip_set_ext *ext,
> #endif
> if (SET_WITH_COUNTER(set))
> ip_set_init_counter(ext_counter(data, set), ext);
> - if (SET_WITH_COMMENT(set))
> + if (SET_WITH_COMMENT(set) && !ext->target)
> ip_set_init_comment(set, ext_comment(data, set), ext);
> if (SET_WITH_SKBINFO(set))
> ip_set_init_skbinfo(ext_skbinfo(data, set), ext);
> --
Thanks! Resize is a can of worms for edge cases and hopefully all of them
caught one by one.
Acked-by: Jozsef Kadlecsik <[email protected]>
Best regards,
Jozsef