From e8bad6ef78bd0de571a990a1f776c6abfbd4a263 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 24 Nov 2023 16:26:18 +0000 Subject: [PATCH] 5.10-stable patches 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 --- ...g-dormant-table-state-more-than-once.patch | 56 +++++ ...ter-nf_tables-fix-table-flag-updates.patch | 194 ++++++++++++++++++ ...te-table-flags-from-the-commit-phase.patch | 114 ++++++++++ queue-5.10/series | 3 + 4 files changed, 367 insertions(+) create mode 100644 queue-5.10/netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch create mode 100644 queue-5.10/netfilter-nf_tables-fix-table-flag-updates.patch create mode 100644 queue-5.10/netfilter-nftables-update-table-flags-from-the-commit-phase.patch 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 index 00000000000..c35408beb18 --- /dev/null +++ b/queue-5.10/netfilter-nf_tables-disable-toggling-dormant-table-state-more-than-once.patch @@ -0,0 +1,56 @@ +From stable-owner@vger.kernel.org Tue Nov 21 12:14:05 2023 +From: Pablo Neira Ayuso +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 + +commit c9bd26513b3a11b3adb3c2ed8a31a01a87173ff1 upstream. + +nft -f -< +Cc: Bing-Jhong Billy Jheng +Cc: info@starlabs.sg +Signed-off-by: Florian Westphal +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..7b4242a5678 --- /dev/null +++ b/queue-5.10/netfilter-nf_tables-fix-table-flag-updates.patch @@ -0,0 +1,194 @@ +From stable-owner@vger.kernel.org Tue Nov 21 12:14:05 2023 +From: Pablo Neira Ayuso +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 + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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 index 00000000000..bcd99b7a78b --- /dev/null +++ b/queue-5.10/netfilter-nftables-update-table-flags-from-the-commit-phase.patch @@ -0,0 +1,114 @@ +From stable-owner@vger.kernel.org Tue Nov 21 12:13:57 2023 +From: Pablo Neira Ayuso +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 + +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 +Signed-off-by: Greg Kroah-Hartman +--- + 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); diff --git a/queue-5.10/series b/queue-5.10/series index 792777e3ca8..d319f26b28a 100644 --- a/queue-5.10/series +++ b/queue-5.10/series @@ -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 -- 2.47.3