]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
Fixes for 6.5
authorSasha Levin <sashal@kernel.org>
Sat, 23 Sep 2023 12:50:23 +0000 (08:50 -0400)
committerSasha Levin <sashal@kernel.org>
Sat, 23 Sep 2023 12:50:23 +0000 (08:50 -0400)
Signed-off-by: Sasha Levin <sashal@kernel.org>
queue-6.5/netfilter-nf_tables-fix-memleak-when-more-than-255-e.patch [new file with mode: 0644]
queue-6.5/netfilter-nft_set_hash-try-later-when-gc-hits-eagain.patch [new file with mode: 0644]
queue-6.5/netfilter-nft_set_pipapo-call-nft_trans_gc_queue_syn.patch [new file with mode: 0644]
queue-6.5/netfilter-nft_set_pipapo-stop-gc-iteration-if-gc-tra.patch [new file with mode: 0644]
queue-6.5/netfilter-nft_set_rbtree-use-read-spinlock-to-avoid-.patch [new file with mode: 0644]
queue-6.5/series

diff --git a/queue-6.5/netfilter-nf_tables-fix-memleak-when-more-than-255-e.patch b/queue-6.5/netfilter-nf_tables-fix-memleak-when-more-than-255-e.patch
new file mode 100644 (file)
index 0000000..8f19059
--- /dev/null
@@ -0,0 +1,87 @@
+From 4cb8df396e0c661a6b4180e402e83aa8422f5df7 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 18:02:56 +0200
+Subject: netfilter: nf_tables: fix memleak when more than 255 elements expired
+
+From: Florian Westphal <fw@strlen.de>
+
+commit cf5000a7787cbc10341091d37245a42c119d26c5 upstream.
+
+When more than 255 elements expired we're supposed to switch to a new gc
+container structure.
+
+This never happens: u8 type will wrap before reaching the boundary
+and nft_trans_gc_space() always returns true.
+
+This means we recycle the initial gc container structure and
+lose track of the elements that came before.
+
+While at it, don't deref 'gc' after we've passed it to call_rcu.
+
+Fixes: 5f68718b34a5 ("netfilter: nf_tables: GC transaction API to avoid race with control plane")
+Reported-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h |  2 +-
+ net/netfilter/nf_tables_api.c     | 10 ++++++++--
+ 2 files changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index a4455f4995abf..7c816359d5a98 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1682,7 +1682,7 @@ struct nft_trans_gc {
+       struct net              *net;
+       struct nft_set          *set;
+       u32                     seq;
+-      u8                      count;
++      u16                     count;
+       void                    *priv[NFT_TRANS_GC_BATCHCOUNT];
+       struct rcu_head         rcu;
+ };
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index bba8042f721a5..1c2fb32bfa5f6 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -9559,12 +9559,15 @@ static int nft_trans_gc_space(struct nft_trans_gc *trans)
+ struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc,
+                                             unsigned int gc_seq, gfp_t gfp)
+ {
++      struct nft_set *set;
++
+       if (nft_trans_gc_space(gc))
+               return gc;
++      set = gc->set;
+       nft_trans_gc_queue_work(gc);
+-      return nft_trans_gc_alloc(gc->set, gc_seq, gfp);
++      return nft_trans_gc_alloc(set, gc_seq, gfp);
+ }
+ void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
+@@ -9579,15 +9582,18 @@ void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
+ struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp)
+ {
++      struct nft_set *set;
++
+       if (WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net)))
+               return NULL;
+       if (nft_trans_gc_space(gc))
+               return gc;
++      set = gc->set;
+       call_rcu(&gc->rcu, nft_trans_gc_trans_free);
+-      return nft_trans_gc_alloc(gc->set, 0, gfp);
++      return nft_trans_gc_alloc(set, 0, gfp);
+ }
+ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
+-- 
+2.40.1
+
diff --git a/queue-6.5/netfilter-nft_set_hash-try-later-when-gc-hits-eagain.patch b/queue-6.5/netfilter-nft_set_hash-try-later-when-gc-hits-eagain.patch
new file mode 100644 (file)
index 0000000..a0a1bc8
--- /dev/null
@@ -0,0 +1,42 @@
+From c69e067c343b03010f7a36ea1514c3637b39cab2 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 18:02:55 +0200
+Subject: netfilter: nft_set_hash: try later when GC hits EAGAIN on iteration
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit b079155faae94e9b3ab9337e82100a914ebb4e8d upstream.
+
+Skip GC run if iterator rewinds to the beginning with EAGAIN, otherwise GC
+might collect the same element more than once.
+
+Fixes: f6c383b8c31a ("netfilter: nf_tables: adapt set backend to use GC transaction API")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nft_set_hash.c | 9 +++------
+ 1 file changed, 3 insertions(+), 6 deletions(-)
+
+diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
+index eca20dc601384..2013de934cef0 100644
+--- a/net/netfilter/nft_set_hash.c
++++ b/net/netfilter/nft_set_hash.c
+@@ -338,12 +338,9 @@ static void nft_rhash_gc(struct work_struct *work)
+       while ((he = rhashtable_walk_next(&hti))) {
+               if (IS_ERR(he)) {
+-                      if (PTR_ERR(he) != -EAGAIN) {
+-                              nft_trans_gc_destroy(gc);
+-                              gc = NULL;
+-                              goto try_later;
+-                      }
+-                      continue;
++                      nft_trans_gc_destroy(gc);
++                      gc = NULL;
++                      goto try_later;
+               }
+               /* Ruleset has been updated, try later. */
+-- 
+2.40.1
+
diff --git a/queue-6.5/netfilter-nft_set_pipapo-call-nft_trans_gc_queue_syn.patch b/queue-6.5/netfilter-nft_set_pipapo-call-nft_trans_gc_queue_syn.patch
new file mode 100644 (file)
index 0000000..1dc4af8
--- /dev/null
@@ -0,0 +1,132 @@
+From f267b48f5272db451fe84c2f1530184d9d87feef Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 18:02:53 +0200
+Subject: netfilter: nft_set_pipapo: call nft_trans_gc_queue_sync() in catchall
+ GC
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 4a9e12ea7e70223555ec010bec9f711089ce96f6 upstream.
+
+pipapo needs to enqueue GC transactions for catchall elements through
+nft_trans_gc_queue_sync(). Add nft_trans_gc_catchall_sync() and
+nft_trans_gc_catchall_async() to handle GC transaction queueing
+accordingly.
+
+Fixes: 5f68718b34a5 ("netfilter: nf_tables: GC transaction API to avoid race with control plane")
+Fixes: f6c383b8c31a ("netfilter: nf_tables: adapt set backend to use GC transaction API")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ include/net/netfilter/nf_tables.h |  5 +++--
+ net/netfilter/nf_tables_api.c     | 22 +++++++++++++++++++---
+ net/netfilter/nft_set_hash.c      |  2 +-
+ net/netfilter/nft_set_pipapo.c    |  2 +-
+ net/netfilter/nft_set_rbtree.c    |  2 +-
+ 5 files changed, 25 insertions(+), 8 deletions(-)
+
+diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
+index dd40c75011d25..a4455f4995abf 100644
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1700,8 +1700,9 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans);
+ void nft_trans_gc_elem_add(struct nft_trans_gc *gc, void *priv);
+-struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
+-                                         unsigned int gc_seq);
++struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
++                                               unsigned int gc_seq);
++struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc);
+ void nft_setelem_data_deactivate(const struct net *net,
+                                const struct nft_set *set,
+diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
+index a72934f00804e..bba8042f721a5 100644
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -9602,8 +9602,9 @@ void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)
+       call_rcu(&trans->rcu, nft_trans_gc_trans_free);
+ }
+-struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
+-                                         unsigned int gc_seq)
++static struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
++                                                unsigned int gc_seq,
++                                                bool sync)
+ {
+       struct nft_set_elem_catchall *catchall;
+       const struct nft_set *set = gc->set;
+@@ -9619,7 +9620,11 @@ struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
+               nft_set_elem_dead(ext);
+ dead_elem:
+-              gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
++              if (sync)
++                      gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
++              else
++                      gc = nft_trans_gc_queue_async(gc, gc_seq, GFP_ATOMIC);
++
+               if (!gc)
+                       return NULL;
+@@ -9629,6 +9634,17 @@ struct nft_trans_gc *nft_trans_gc_catchall(struct nft_trans_gc *gc,
+       return gc;
+ }
++struct nft_trans_gc *nft_trans_gc_catchall_async(struct nft_trans_gc *gc,
++                                               unsigned int gc_seq)
++{
++      return nft_trans_gc_catchall(gc, gc_seq, false);
++}
++
++struct nft_trans_gc *nft_trans_gc_catchall_sync(struct nft_trans_gc *gc)
++{
++      return nft_trans_gc_catchall(gc, 0, true);
++}
++
+ static void nf_tables_module_autoload_cleanup(struct net *net)
+ {
+       struct nftables_pernet *nft_net = nft_pernet(net);
+diff --git a/net/netfilter/nft_set_hash.c b/net/netfilter/nft_set_hash.c
+index 524763659f251..eca20dc601384 100644
+--- a/net/netfilter/nft_set_hash.c
++++ b/net/netfilter/nft_set_hash.c
+@@ -372,7 +372,7 @@ static void nft_rhash_gc(struct work_struct *work)
+               nft_trans_gc_elem_add(gc, he);
+       }
+-      gc = nft_trans_gc_catchall(gc, gc_seq);
++      gc = nft_trans_gc_catchall_async(gc, gc_seq);
+ try_later:
+       /* catchall list iteration requires rcu read side lock. */
+diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
+index 6af9c9ed4b5c3..10b89ac74476b 100644
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -1610,7 +1610,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
+               }
+       }
+-      gc = nft_trans_gc_catchall(gc, 0);
++      gc = nft_trans_gc_catchall_sync(gc);
+       if (gc) {
+               nft_trans_gc_queue_sync_done(gc);
+               priv->last_gc = jiffies;
+diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
+index 70491ba98decb..487572dcd6144 100644
+--- a/net/netfilter/nft_set_rbtree.c
++++ b/net/netfilter/nft_set_rbtree.c
+@@ -669,7 +669,7 @@ static void nft_rbtree_gc(struct work_struct *work)
+               nft_trans_gc_elem_add(gc, rbe);
+       }
+-      gc = nft_trans_gc_catchall(gc, gc_seq);
++      gc = nft_trans_gc_catchall_async(gc, gc_seq);
+ try_later:
+       read_unlock_bh(&priv->lock);
+-- 
+2.40.1
+
diff --git a/queue-6.5/netfilter-nft_set_pipapo-stop-gc-iteration-if-gc-tra.patch b/queue-6.5/netfilter-nft_set_pipapo-stop-gc-iteration-if-gc-tra.patch
new file mode 100644 (file)
index 0000000..b34ae7a
--- /dev/null
@@ -0,0 +1,37 @@
+From 57a544945fe0427deb8d1e08f8e757c11d36a88f Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 18:02:54 +0200
+Subject: netfilter: nft_set_pipapo: stop GC iteration if GC transaction
+ allocation fails
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 6d365eabce3c018a80f6e0379b17df2abb17405e upstream.
+
+nft_trans_gc_queue_sync() enqueues the GC transaction and it allocates a
+new one. If this allocation fails, then stop this GC sync run and retry
+later.
+
+Fixes: 5f68718b34a5 ("netfilter: nf_tables: GC transaction API to avoid race with control plane")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nft_set_pipapo.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/net/netfilter/nft_set_pipapo.c b/net/netfilter/nft_set_pipapo.c
+index 10b89ac74476b..c0dcc40de358f 100644
+--- a/net/netfilter/nft_set_pipapo.c
++++ b/net/netfilter/nft_set_pipapo.c
+@@ -1596,7 +1596,7 @@ static void pipapo_gc(const struct nft_set *_set, struct nft_pipapo_match *m)
+                       gc = nft_trans_gc_queue_sync(gc, GFP_ATOMIC);
+                       if (!gc)
+-                              break;
++                              return;
+                       nft_pipapo_gc_deactivate(net, set, e);
+                       pipapo_drop(m, rulemap);
+-- 
+2.40.1
+
diff --git a/queue-6.5/netfilter-nft_set_rbtree-use-read-spinlock-to-avoid-.patch b/queue-6.5/netfilter-nft_set_rbtree-use-read-spinlock-to-avoid-.patch
new file mode 100644 (file)
index 0000000..abdd8f5
--- /dev/null
@@ -0,0 +1,48 @@
+From 8c36ca0bb937c96cd0e7a1f817b68da087167299 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Fri, 22 Sep 2023 18:02:52 +0200
+Subject: netfilter: nft_set_rbtree: use read spinlock to avoid datapath
+ contention
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 96b33300fba880ec0eafcf3d82486f3463b4b6da upstream.
+
+rbtree GC does not modify the datastructure, instead it collects expired
+elements and it enqueues a GC transaction. Use a read spinlock instead
+to avoid data contention while GC worker is running.
+
+Fixes: f6c383b8c31a ("netfilter: nf_tables: adapt set backend to use GC transaction API")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Sasha Levin <sashal@kernel.org>
+---
+ net/netfilter/nft_set_rbtree.c | 6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/net/netfilter/nft_set_rbtree.c b/net/netfilter/nft_set_rbtree.c
+index f250b5399344a..70491ba98decb 100644
+--- a/net/netfilter/nft_set_rbtree.c
++++ b/net/netfilter/nft_set_rbtree.c
+@@ -622,8 +622,7 @@ static void nft_rbtree_gc(struct work_struct *work)
+       if (!gc)
+               goto done;
+-      write_lock_bh(&priv->lock);
+-      write_seqcount_begin(&priv->count);
++      read_lock_bh(&priv->lock);
+       for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
+               /* Ruleset has been updated, try later. */
+@@ -673,8 +672,7 @@ static void nft_rbtree_gc(struct work_struct *work)
+       gc = nft_trans_gc_catchall(gc, gc_seq);
+ try_later:
+-      write_seqcount_end(&priv->count);
+-      write_unlock_bh(&priv->lock);
++      read_unlock_bh(&priv->lock);
+       if (gc)
+               nft_trans_gc_queue_async_done(gc);
+-- 
+2.40.1
+
index c62094ac6c1906f9ce1789a2f32b56ba4edbf2a2..303901261fddd2162721009adcd38acc3191dc8e 100644 (file)
@@ -16,3 +16,8 @@ btrfs-remove-bug-after-failure-to-insert-delayed-dir.patch
 ext4-replace-the-traditional-ternary-conditional-ope.patch
 ext4-move-setting-of-trimmed-bit-into-ext4_try_to_tr.patch
 ext4-do-not-let-fstrim-block-system-suspend.patch
+netfilter-nft_set_rbtree-use-read-spinlock-to-avoid-.patch
+netfilter-nft_set_pipapo-call-nft_trans_gc_queue_syn.patch
+netfilter-nft_set_pipapo-stop-gc-iteration-if-gc-tra.patch
+netfilter-nft_set_hash-try-later-when-gc-hits-eagain.patch
+netfilter-nf_tables-fix-memleak-when-more-than-255-e.patch