When a new filter is created with TCA_U32_LINK, u32_set_parms() resolves
the linked hash table and increments its reference count, storing it in
n->ht_down.
If u32_replace_hw_knode() subsequently fails, execution jumps to the
errunbind label which frees the node with kfree(n) but never drops the
reference on n->ht_down. This leaves the tc_u_hnode refcount permanently
elevated, preventing it from being freed when the hash table is later
deleted.
Drop the ht_down reference at errunbind before freeing the node.
Cc: <redacted>
Reported-by: Sashiko <sashiko-bot@kernel.org>
Closes: https://sashiko.dev/#/patchset/20260807100356.1083774-1-jedrzej.jagielski%40intel.com
Fixes: af69afc51a56 ("net/sched: cls_u32: Fix reference counter leak leading to overflow")
Reviewed-by: Aleksandr Loktionov <redacted>
Signed-off-by: Jedrzej Jagielski <redacted>
---
net/sched/cls_u32.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c
index dc6e455e64ec..9539dce217df 100644
--- a/net/sched/cls_u32.c
+++ b/net/sched/cls_u32.c
@@ -875,7 +875,7 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
struct netlink_ext_ack *extack)
{
struct tc_u_common *tp_c = tp->data;
- struct tc_u_hnode *ht;
+ struct tc_u_hnode *ht, *ht_down;
struct tc_u_knode *n;
struct tc_u32_sel *s;
struct nlattr *opt = tca[TCA_OPTIONS];@@ -1185,6 +1185,9 @@ static int u32_change(struct net *net, struct sk_buff *in_skb,
errunbind:
u32_unbind_filter(tp, n, tb);
+ ht_down = rtnl_dereference(n->ht_down);
+ if (ht_down && refcount_dec_and_test(&ht_down->refcnt))
+ kfree(ht_down);
#ifdef CONFIG_CLS_U32_MARK
free_percpu(n->pcpu_success);
--
2.31.1