From: Greg Kroah-Hartman Date: Mon, 23 Mar 2026 12:22:46 +0000 (+0100) Subject: 6.1-stable patches X-Git-Tag: v6.1.167~17 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3765ff96544183f46a9cad201f94b283ec089f84;p=thirdparty%2Fkernel%2Fstable-queue.git 6.1-stable patches added patches: netfilter-nf_tables-de-constify-set-commit-ops-function-argument.patch netfilter-nft_set_pipapo-split-gc-into-unlink-and-reclaim-phase.patch --- diff --git a/queue-6.1/netfilter-nf_tables-de-constify-set-commit-ops-function-argument.patch b/queue-6.1/netfilter-nf_tables-de-constify-set-commit-ops-function-argument.patch new file mode 100644 index 0000000000..0d2b54e36c --- /dev/null +++ b/queue-6.1/netfilter-nf_tables-de-constify-set-commit-ops-function-argument.patch @@ -0,0 +1,56 @@ +From 256001672153af5786c6ca148114693d7d76d836 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 13 Oct 2023 14:18:14 +0200 +Subject: netfilter: nf_tables: de-constify set commit ops function argument + +From: Florian Westphal + +commit 256001672153af5786c6ca148114693d7d76d836 upstream. + +The set backend using this already has to work around this via ugly +cast, don't spread this pattern. + +Signed-off-by: Florian Westphal +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netfilter/nf_tables.h | 2 +- + net/netfilter/nft_set_pipapo.c | 7 +++---- + 2 files changed, 4 insertions(+), 5 deletions(-) + +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -470,7 +470,7 @@ struct nft_set_ops { + const struct nft_set *set, + const struct nft_set_elem *elem, + unsigned int flags); +- void (*commit)(const struct nft_set *set); ++ void (*commit)(struct nft_set *set); + void (*abort)(const struct nft_set *set); + u64 (*privsize)(const struct nlattr * const nla[], + const struct nft_set_desc *desc); +--- a/net/netfilter/nft_set_pipapo.c ++++ b/net/netfilter/nft_set_pipapo.c +@@ -1587,12 +1587,11 @@ static void nft_pipapo_gc_deactivate(str + + /** + * pipapo_gc() - Drop expired entries from set, destroy start and end elements +- * @_set: nftables API set representation ++ * @set: nftables API set representation + * @m: Matching data + */ +-static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m) ++static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m) + { +- struct nft_set *set = (struct nft_set *) _set; + struct nft_pipapo *priv = nft_set_priv(set); + struct net *net = read_pnet(&set->net); + u64 tstamp = nft_net_tstamp(net); +@@ -1707,7 +1706,7 @@ static void pipapo_reclaim_match(struct + * We also need to create a new working copy for subsequent insertions and + * deletions. + */ +-static void nft_pipapo_commit(const struct nft_set *set) ++static void nft_pipapo_commit(struct nft_set *set) + { + struct nft_pipapo *priv = nft_set_priv(set); + struct nft_pipapo_match *new_clone, *old; diff --git a/queue-6.1/netfilter-nft_set_pipapo-split-gc-into-unlink-and-reclaim-phase.patch b/queue-6.1/netfilter-nft_set_pipapo-split-gc-into-unlink-and-reclaim-phase.patch new file mode 100644 index 0000000000..f487f85f6e --- /dev/null +++ b/queue-6.1/netfilter-nft_set_pipapo-split-gc-into-unlink-and-reclaim-phase.patch @@ -0,0 +1,206 @@ +From 9df95785d3d8302f7c066050117b04cd3c2048c2 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 3 Mar 2026 16:31:32 +0100 +Subject: netfilter: nft_set_pipapo: split gc into unlink and reclaim phase + +From: Florian Westphal + +commit 9df95785d3d8302f7c066050117b04cd3c2048c2 upstream. + +Yiming Qian reports Use-after-free in the pipapo set type: + Under a large number of expired elements, commit-time GC can run for a very + long time in a non-preemptible context, triggering soft lockup warnings and + RCU stall reports (local denial of service). + +We must split GC in an unlink and a reclaim phase. + +We cannot queue elements for freeing until pointers have been swapped. +Expired elements are still exposed to both the packet path and userspace +dumpers via the live copy of the data structure. + +call_rcu() does not protect us: dump operations or element lookups starting +after call_rcu has fired can still observe the free'd element, unless the +commit phase has made enough progress to swap the clone and live pointers +before any new reader has picked up the old version. + +This a similar approach as done recently for the rbtree backend in commit +35f83a75529a ("netfilter: nft_set_rbtree: don't gc elements on insert"). + +Fixes: 3c4287f62044 ("nf_tables: Add set type for arbitrary concatenation of ranges") +Reported-by: Yiming Qian +Signed-off-by: Florian Westphal +Signed-off-by: Greg Kroah-Hartman +--- + include/net/netfilter/nf_tables.h | 5 +++ + net/netfilter/nf_tables_api.c | 5 --- + net/netfilter/nft_set_pipapo.c | 51 ++++++++++++++++++++++++++++++++------ + net/netfilter/nft_set_pipapo.h | 2 + + 4 files changed, 50 insertions(+), 13 deletions(-) + +--- a/include/net/netfilter/nf_tables.h ++++ b/include/net/netfilter/nf_tables.h +@@ -1693,6 +1693,11 @@ struct nft_trans_gc { + struct rcu_head rcu; + }; + ++static inline int nft_trans_gc_space(const struct nft_trans_gc *trans) ++{ ++ return NFT_TRANS_GC_BATCHCOUNT - trans->count; ++} ++ + struct nft_trans_gc *nft_trans_gc_alloc(struct nft_set *set, + unsigned int gc_seq, gfp_t gfp); + void nft_trans_gc_destroy(struct nft_trans_gc *trans); +--- a/net/netfilter/nf_tables_api.c ++++ b/net/netfilter/nf_tables_api.c +@@ -9382,11 +9382,6 @@ static void nft_trans_gc_queue_work(stru + schedule_work(&trans_gc_work); + } + +-static int nft_trans_gc_space(struct nft_trans_gc *trans) +-{ +- return NFT_TRANS_GC_BATCHCOUNT - trans->count; +-} +- + struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc, + unsigned int gc_seq, gfp_t gfp) + { +--- a/net/netfilter/nft_set_pipapo.c ++++ b/net/netfilter/nft_set_pipapo.c +@@ -1586,11 +1586,11 @@ static void nft_pipapo_gc_deactivate(str + } + + /** +- * pipapo_gc() - Drop expired entries from set, destroy start and end elements ++ * pipapo_gc_scan() - Drop expired entries from set and link them to gc list + * @set: nftables API set representation + * @m: Matching data + */ +-static void pipapo_gc(struct nft_set *set, struct nft_pipapo_match *m) ++static void pipapo_gc_scan(struct nft_set *set, struct nft_pipapo_match *m) + { + struct nft_pipapo *priv = nft_set_priv(set); + struct net *net = read_pnet(&set->net); +@@ -1603,6 +1603,8 @@ static void pipapo_gc(struct nft_set *se + if (!gc) + return; + ++ list_add(&gc->list, &priv->gc_head); ++ + while ((rules_f0 = pipapo_rules_same_key(m->f, first_rule))) { + union nft_pipapo_map_bucket rulemap[NFT_PIPAPO_MAX_FIELDS]; + const struct nft_pipapo_field *f; +@@ -1632,9 +1634,13 @@ static void pipapo_gc(struct nft_set *se + if (__nft_set_elem_expired(&e->ext, tstamp)) { + priv->dirty = true; + +- gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC); +- if (!gc) +- return; ++ if (!nft_trans_gc_space(gc)) { ++ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); ++ if (!gc) ++ return; ++ ++ list_add(&gc->list, &priv->gc_head); ++ } + + nft_pipapo_gc_deactivate(net, set, e); + pipapo_drop(m, rulemap); +@@ -1648,10 +1654,30 @@ static void pipapo_gc(struct nft_set *se + } + } + +- gc = nft_trans_gc_catchall_sync(gc); ++ priv->last_gc = jiffies; ++} ++ ++/** ++ * pipapo_gc_queue() - Free expired elements ++ * @set: nftables API set representation ++ */ ++static void pipapo_gc_queue(struct nft_set *set) ++{ ++ struct nft_pipapo *priv = nft_set_priv(set); ++ struct nft_trans_gc *gc, *next; ++ ++ /* always do a catchall cycle: */ ++ gc = nft_trans_gc_alloc(set, 0, GFP_KERNEL); + if (gc) { ++ gc = nft_trans_gc_catchall_sync(gc); ++ if (gc) ++ nft_trans_gc_queue_sync_done(gc); ++ } ++ ++ /* always purge queued gc elements. */ ++ list_for_each_entry_safe(gc, next, &priv->gc_head, list) { ++ list_del(&gc->list); + nft_trans_gc_queue_sync_done(gc); +- priv->last_gc = jiffies; + } + } + +@@ -1705,6 +1731,10 @@ static void pipapo_reclaim_match(struct + * + * We also need to create a new working copy for subsequent insertions and + * deletions. ++ * ++ * After the live copy has been replaced by the clone, we can safely queue ++ * expired elements that have been collected by pipapo_gc_scan() for ++ * memory reclaim. + */ + static void nft_pipapo_commit(struct nft_set *set) + { +@@ -1712,7 +1742,7 @@ static void nft_pipapo_commit(struct nft + struct nft_pipapo_match *new_clone, *old; + + if (time_after_eq(jiffies, priv->last_gc + nft_set_gc_interval(set))) +- pipapo_gc(set, priv->clone); ++ pipapo_gc_scan(set, priv->clone); + + if (!priv->dirty) + return; +@@ -1729,6 +1759,8 @@ static void nft_pipapo_commit(struct nft + call_rcu(&old->rcu, pipapo_reclaim_match); + + priv->clone = new_clone; ++ ++ pipapo_gc_queue(set); + } + + static bool nft_pipapo_transaction_mutex_held(const struct nft_set *set) +@@ -2204,6 +2236,7 @@ static int nft_pipapo_init(const struct + + priv->dirty = false; + ++ INIT_LIST_HEAD(&priv->gc_head); + rcu_assign_pointer(priv->match, m); + + return 0; +@@ -2256,6 +2289,8 @@ static void nft_pipapo_destroy(const str + struct nft_pipapo_match *m; + int cpu; + ++ WARN_ON_ONCE(!list_empty(&priv->gc_head)); ++ + m = rcu_dereference_protected(priv->match, true); + if (m) { + rcu_barrier(); +--- a/net/netfilter/nft_set_pipapo.h ++++ b/net/netfilter/nft_set_pipapo.h +@@ -165,6 +165,7 @@ struct nft_pipapo_match { + * @width: Total bytes to be matched for one packet, including padding + * @dirty: Working copy has pending insertions or deletions + * @last_gc: Timestamp of last garbage collection run, jiffies ++ * @gc_head: list of nft_trans_gc to queue up for mem reclaim + */ + struct nft_pipapo { + struct nft_pipapo_match __rcu *match; +@@ -172,6 +173,7 @@ struct nft_pipapo { + int width; + bool dirty; + unsigned long last_gc; ++ struct list_head gc_head; + }; + + struct nft_pipapo_elem; diff --git a/queue-6.1/series b/queue-6.1/series index e8d5bce9a6..912c5109a7 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -451,3 +451,5 @@ ksmbd-fix-use-after-free-of-share_conf-in-compound-r.patch drm-i915-gt-check-set_default_submission-before-defe.patch lib-bootconfig-check-xbc_init_node-return-in-overrid.patch tools-bootconfig-fix-fd-leak-in-load_xbc_file-on-fst.patch +netfilter-nf_tables-de-constify-set-commit-ops-function-argument.patch +netfilter-nft_set_pipapo-split-gc-into-unlink-and-reclaim-phase.patch