]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
5.10-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Nov 2023 16:26:18 +0000 (16:26 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 24 Nov 2023 16:26:18 +0000 (16:26 +0000)
added patches:
netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch
netfilter-nf_tables-fix-table-flag-updates.patch
netfilter-nftables-update-table-flags-from-the-commit-phase.patch

queue-5.10/netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch [new file with mode: 0644]
queue-5.10/netfilter-nf_tables-fix-table-flag-updates.patch [new file with mode: 0644]
queue-5.10/netfilter-nftables-update-table-flags-from-the-commit-phase.patch [new file with mode: 0644]
queue-5.10/series

diff --git a/queue-5.10/netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch b/queue-5.10/netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch
new file mode 100644 (file)
index 0000000..c35408b
--- /dev/null
@@ -0,0 +1,56 @@
+From stable-owner@vger.kernel.org Tue Nov 21 12:14:05 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Tue, 21 Nov 2023 13:13:32 +0100
+Subject: netfilter: nf_tables: disable toggling dormant table state more than once
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20231121121333.294238-26-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit c9bd26513b3a11b3adb3c2ed8a31a01a87173ff1 upstream.
+
+nft -f -<<EOF
+add table ip t
+add table ip t { flags dormant; }
+add chain ip t c { type filter hook input priority 0; }
+add table ip t
+EOF
+
+Triggers a splat from nf core on next table delete because we lose
+track of right hook register state:
+
+WARNING: CPU: 2 PID: 1597 at net/netfilter/core.c:501 __nf_unregister_net_hook
+RIP: 0010:__nf_unregister_net_hook+0x41b/0x570
+ nf_unregister_net_hook+0xb4/0xf0
+ __nf_tables_unregister_hook+0x160/0x1d0
+[..]
+
+The above should have table in *active* state, but in fact no
+hooks were registered.
+
+Reject on/off/on games rather than attempting to fix this.
+
+Fixes: 179d9ba5559a ("netfilter: nf_tables: fix table flag updates")
+Reported-by: "Lee, Cherie-Anne" <cherie.lee@starlabs.sg>
+Cc: Bing-Jhong Billy Jheng <billy@starlabs.sg>
+Cc: info@starlabs.sg
+Signed-off-by: Florian Westphal <fw@strlen.de>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/netfilter/nf_tables_api.c |    4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -1099,6 +1099,10 @@ static int nf_tables_updtable(struct nft
+       if (flags == ctx->table->flags)
+               return 0;
++      /* No dormant off/on/off/on games in single transaction */
++      if (ctx->table->flags & __NFT_TABLE_F_UPDATE)
++              return -EINVAL;
++
+       trans = nft_trans_alloc(ctx, NFT_MSG_NEWTABLE,
+                               sizeof(struct nft_trans_table));
+       if (trans == NULL)
diff --git a/queue-5.10/netfilter-nf_tables-fix-table-flag-updates.patch b/queue-5.10/netfilter-nf_tables-fix-table-flag-updates.patch
new file mode 100644 (file)
index 0000000..7b4242a
--- /dev/null
@@ -0,0 +1,194 @@
+From stable-owner@vger.kernel.org Tue Nov 21 12:14:05 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Tue, 21 Nov 2023 13:13:31 +0100
+Subject: netfilter: nf_tables: fix table flag updates
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20231121121333.294238-25-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 179d9ba5559a756f4322583388b3213fe4e391b0 upstream.
+
+The dormant flag need to be updated from the preparation phase,
+otherwise, two consecutive requests to dorm a table in the same batch
+might try to remove the same hooks twice, resulting in the following
+warning:
+
+ hook not found, pf 3 num 0
+ WARNING: CPU: 0 PID: 334 at net/netfilter/core.c:480 __nf_unregister_net_hook+0x1eb/0x610 net/netfilter/core.c:480
+ Modules linked in:
+ CPU: 0 PID: 334 Comm: kworker/u4:5 Not tainted 5.12.0-syzkaller #0
+ Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
+ Workqueue: netns cleanup_net
+ RIP: 0010:__nf_unregister_net_hook+0x1eb/0x610 net/netfilter/core.c:480
+
+This patch is a partial revert of 0ce7cf4127f1 ("netfilter: nftables:
+update table flags from the commit phase") to restore the previous
+behaviour.
+
+However, there is still another problem: A batch containing a series of
+dorm-wakeup-dorm table and vice-versa also trigger the warning above
+since hook unregistration happens from the preparation phase, while hook
+registration occurs from the commit phase.
+
+To fix this problem, this patch adds two internal flags to annotate the
+original dormant flag status which are __NFT_TABLE_F_WAS_DORMANT and
+__NFT_TABLE_F_WAS_AWAKEN, to restore it from the abort path.
+
+The __NFT_TABLE_F_UPDATE bitmask allows to handle the dormant flag update
+with one single transaction.
+
+Reported-by: syzbot+7ad5cd1615f2d89c6e7e@syzkaller.appspotmail.com
+Fixes: 0ce7cf4127f1 ("netfilter: nftables: update table flags from the commit phase")
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h        |    6 ---
+ include/uapi/linux/netfilter/nf_tables.h |    1 
+ net/netfilter/nf_tables_api.c            |   59 +++++++++++++++++++++----------
+ 3 files changed, 41 insertions(+), 25 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1479,16 +1479,10 @@ struct nft_trans_chain {
+ struct nft_trans_table {
+       bool                            update;
+-      u8                              state;
+-      u32                             flags;
+ };
+ #define nft_trans_table_update(trans) \
+       (((struct nft_trans_table *)trans->data)->update)
+-#define nft_trans_table_state(trans)  \
+-      (((struct nft_trans_table *)trans->data)->state)
+-#define nft_trans_table_flags(trans)  \
+-      (((struct nft_trans_table *)trans->data)->flags)
+ struct nft_trans_elem {
+       struct nft_set                  *set;
+--- a/include/uapi/linux/netfilter/nf_tables.h
++++ b/include/uapi/linux/netfilter/nf_tables.h
+@@ -165,6 +165,7 @@ enum nft_hook_attributes {
+ enum nft_table_flags {
+       NFT_TABLE_F_DORMANT     = 0x1,
+ };
++#define NFT_TABLE_F_MASK       (NFT_TABLE_F_DORMANT)
+ /**
+  * enum nft_table_attributes - nf_tables table netlink attributes
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -863,7 +863,8 @@ static int nf_tables_fill_table_info(str
+               goto nla_put_failure;
+       if (nla_put_string(skb, NFTA_TABLE_NAME, table->name) ||
+-          nla_put_be32(skb, NFTA_TABLE_FLAGS, htonl(table->flags)) ||
++          nla_put_be32(skb, NFTA_TABLE_FLAGS,
++                       htonl(table->flags & NFT_TABLE_F_MASK)) ||
+           nla_put_be32(skb, NFTA_TABLE_USE, htonl(table->use)) ||
+           nla_put_be64(skb, NFTA_TABLE_HANDLE, cpu_to_be64(table->handle),
+                        NFTA_TABLE_PAD))
+@@ -1071,20 +1072,22 @@ err_register_hooks:
+ static void nf_tables_table_disable(struct net *net, struct nft_table *table)
+ {
++      table->flags &= ~NFT_TABLE_F_DORMANT;
+       nft_table_disable(net, table, 0);
++      table->flags |= NFT_TABLE_F_DORMANT;
+ }
+-enum {
+-      NFT_TABLE_STATE_UNCHANGED       = 0,
+-      NFT_TABLE_STATE_DORMANT,
+-      NFT_TABLE_STATE_WAKEUP
+-};
++#define __NFT_TABLE_F_INTERNAL                (NFT_TABLE_F_MASK + 1)
++#define __NFT_TABLE_F_WAS_DORMANT     (__NFT_TABLE_F_INTERNAL << 0)
++#define __NFT_TABLE_F_WAS_AWAKEN      (__NFT_TABLE_F_INTERNAL << 1)
++#define __NFT_TABLE_F_UPDATE          (__NFT_TABLE_F_WAS_DORMANT | \
++                                       __NFT_TABLE_F_WAS_AWAKEN)
+ static int nf_tables_updtable(struct nft_ctx *ctx)
+ {
+       struct nft_trans *trans;
+       u32 flags;
+-      int ret = 0;
++      int ret;
+       if (!ctx->nla[NFTA_TABLE_FLAGS])
+               return 0;
+@@ -1103,21 +1106,27 @@ static int nf_tables_updtable(struct nft
+       if ((flags & NFT_TABLE_F_DORMANT) &&
+           !(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
+-              nft_trans_table_state(trans) = NFT_TABLE_STATE_DORMANT;
++              ctx->table->flags |= NFT_TABLE_F_DORMANT;
++              if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE))
++                      ctx->table->flags |= __NFT_TABLE_F_WAS_AWAKEN;
+       } else if (!(flags & NFT_TABLE_F_DORMANT) &&
+                  ctx->table->flags & NFT_TABLE_F_DORMANT) {
+-              ret = nf_tables_table_enable(ctx->net, ctx->table);
+-              if (ret >= 0)
+-                      nft_trans_table_state(trans) = NFT_TABLE_STATE_WAKEUP;
++              ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
++              if (!(ctx->table->flags & __NFT_TABLE_F_UPDATE)) {
++                      ret = nf_tables_table_enable(ctx->net, ctx->table);
++                      if (ret < 0)
++                              goto err_register_hooks;
++
++                      ctx->table->flags |= __NFT_TABLE_F_WAS_DORMANT;
++              }
+       }
+-      if (ret < 0)
+-              goto err;
+-      nft_trans_table_flags(trans) = flags;
+       nft_trans_table_update(trans) = true;
+       nft_trans_commit_list_add_tail(ctx->net, trans);
++
+       return 0;
+-err:
++
++err_register_hooks:
+       nft_trans_destroy(trans);
+       return ret;
+ }
+@@ -8479,10 +8488,14 @@ static int nf_tables_commit(struct net *
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWTABLE:
+                       if (nft_trans_table_update(trans)) {
+-                              if (nft_trans_table_state(trans) == NFT_TABLE_STATE_DORMANT)
++                              if (!(trans->ctx.table->flags & __NFT_TABLE_F_UPDATE)) {
++                                      nft_trans_destroy(trans);
++                                      break;
++                              }
++                              if (trans->ctx.table->flags & NFT_TABLE_F_DORMANT)
+                                       nf_tables_table_disable(net, trans->ctx.table);
+-                              trans->ctx.table->flags = nft_trans_table_flags(trans);
++                              trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE;
+                       } else {
+                               nft_clear(net, trans->ctx.table);
+                       }
+@@ -8731,9 +8744,17 @@ static int __nf_tables_abort(struct net
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWTABLE:
+                       if (nft_trans_table_update(trans)) {
+-                              if (nft_trans_table_state(trans) == NFT_TABLE_STATE_WAKEUP)
++                              if (!(trans->ctx.table->flags & __NFT_TABLE_F_UPDATE)) {
++                                      nft_trans_destroy(trans);
++                                      break;
++                              }
++                              if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_DORMANT) {
+                                       nf_tables_table_disable(net, trans->ctx.table);
+-
++                                      trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
++                              } else if (trans->ctx.table->flags & __NFT_TABLE_F_WAS_AWAKEN) {
++                                      trans->ctx.table->flags &= ~NFT_TABLE_F_DORMANT;
++                              }
++                              trans->ctx.table->flags &= ~__NFT_TABLE_F_UPDATE;
+                               nft_trans_destroy(trans);
+                       } else {
+                               list_del_rcu(&trans->ctx.table->list);
diff --git a/queue-5.10/netfilter-nftables-update-table-flags-from-the-commit-phase.patch b/queue-5.10/netfilter-nftables-update-table-flags-from-the-commit-phase.patch
new file mode 100644 (file)
index 0000000..bcd99b7
--- /dev/null
@@ -0,0 +1,114 @@
+From stable-owner@vger.kernel.org Tue Nov 21 12:13:57 2023
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+Date: Tue, 21 Nov 2023 13:13:30 +0100
+Subject: netfilter: nftables: update table flags from the commit phase
+To: netfilter-devel@vger.kernel.org
+Cc: gregkh@linuxfoundation.org, sashal@kernel.org, stable@vger.kernel.org
+Message-ID: <20231121121333.294238-24-pablo@netfilter.org>
+
+From: Pablo Neira Ayuso <pablo@netfilter.org>
+
+commit 0ce7cf4127f14078ca598ba9700d813178a59409 upstream.
+
+Do not update table flags from the preparation phase. Store the flags
+update into the transaction, then update the flags from the commit
+phase.
+
+Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/netfilter/nf_tables.h |    9 ++++++---
+ net/netfilter/nf_tables_api.c     |   31 ++++++++++++++++---------------
+ 2 files changed, 22 insertions(+), 18 deletions(-)
+
+--- a/include/net/netfilter/nf_tables.h
++++ b/include/net/netfilter/nf_tables.h
+@@ -1479,13 +1479,16 @@ struct nft_trans_chain {
+ struct nft_trans_table {
+       bool                            update;
+-      bool                            enable;
++      u8                              state;
++      u32                             flags;
+ };
+ #define nft_trans_table_update(trans) \
+       (((struct nft_trans_table *)trans->data)->update)
+-#define nft_trans_table_enable(trans) \
+-      (((struct nft_trans_table *)trans->data)->enable)
++#define nft_trans_table_state(trans)  \
++      (((struct nft_trans_table *)trans->data)->state)
++#define nft_trans_table_flags(trans)  \
++      (((struct nft_trans_table *)trans->data)->flags)
+ struct nft_trans_elem {
+       struct nft_set                  *set;
+--- a/net/netfilter/nf_tables_api.c
++++ b/net/netfilter/nf_tables_api.c
+@@ -1074,6 +1074,12 @@ static void nf_tables_table_disable(stru
+       nft_table_disable(net, table, 0);
+ }
++enum {
++      NFT_TABLE_STATE_UNCHANGED       = 0,
++      NFT_TABLE_STATE_DORMANT,
++      NFT_TABLE_STATE_WAKEUP
++};
++
+ static int nf_tables_updtable(struct nft_ctx *ctx)
+ {
+       struct nft_trans *trans;
+@@ -1097,19 +1103,17 @@ static int nf_tables_updtable(struct nft
+       if ((flags & NFT_TABLE_F_DORMANT) &&
+           !(ctx->table->flags & NFT_TABLE_F_DORMANT)) {
+-              nft_trans_table_enable(trans) = false;
++              nft_trans_table_state(trans) = NFT_TABLE_STATE_DORMANT;
+       } else if (!(flags & NFT_TABLE_F_DORMANT) &&
+                  ctx->table->flags & NFT_TABLE_F_DORMANT) {
+-              ctx->table->flags &= ~NFT_TABLE_F_DORMANT;
+               ret = nf_tables_table_enable(ctx->net, ctx->table);
+               if (ret >= 0)
+-                      nft_trans_table_enable(trans) = true;
+-              else
+-                      ctx->table->flags |= NFT_TABLE_F_DORMANT;
++                      nft_trans_table_state(trans) = NFT_TABLE_STATE_WAKEUP;
+       }
+       if (ret < 0)
+               goto err;
++      nft_trans_table_flags(trans) = flags;
+       nft_trans_table_update(trans) = true;
+       nft_trans_commit_list_add_tail(ctx->net, trans);
+       return 0;
+@@ -8475,11 +8479,10 @@ static int nf_tables_commit(struct net *
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWTABLE:
+                       if (nft_trans_table_update(trans)) {
+-                              if (!nft_trans_table_enable(trans)) {
+-                                      nf_tables_table_disable(net,
+-                                                              trans->ctx.table);
+-                                      trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
+-                              }
++                              if (nft_trans_table_state(trans) == NFT_TABLE_STATE_DORMANT)
++                                      nf_tables_table_disable(net, trans->ctx.table);
++
++                              trans->ctx.table->flags = nft_trans_table_flags(trans);
+                       } else {
+                               nft_clear(net, trans->ctx.table);
+                       }
+@@ -8728,11 +8731,9 @@ static int __nf_tables_abort(struct net
+               switch (trans->msg_type) {
+               case NFT_MSG_NEWTABLE:
+                       if (nft_trans_table_update(trans)) {
+-                              if (nft_trans_table_enable(trans)) {
+-                                      nf_tables_table_disable(net,
+-                                                              trans->ctx.table);
+-                                      trans->ctx.table->flags |= NFT_TABLE_F_DORMANT;
+-                              }
++                              if (nft_trans_table_state(trans) == NFT_TABLE_STATE_WAKEUP)
++                                      nf_tables_table_disable(net, trans->ctx.table);
++
+                               nft_trans_destroy(trans);
+                       } else {
+                               list_del_rcu(&trans->ctx.table->list);
index 792777e3ca8e47ef3d6a6951d19ea0fe85d648b2..d319f26b28aaa3bb94d22c5b782c1eb4ae3c1568 100644 (file)
@@ -197,3 +197,6 @@ drm-amd-display-change-the-dmcub-mailbox-memory-location-from-fb-to-inbox.patch
 io_uring-fdinfo-lock-sq-thread-while-retrieving-thread-cpu-pid.patch
 powerpc-powernv-fix-fortify-source-warnings-in-opal-prd.c.patch
 tracing-have-trace_event_file-have-ref-counters.patch
+netfilter-nftables-update-table-flags-from-the-commit-phase.patch
+netfilter-nf_tables-fix-table-flag-updates.patch
+netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch