netfilter: nftables: update table flags from the commit phase
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 18 Mar 2021 00:25:05 +0000 (01:25 +0100)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 18 Mar 2021 00:35:39 +0000 (01:35 +0100)
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>
include/net/netfilter/nf_tables.h
net/netfilter/nf_tables_api.c

index fdec57d862b738feaaae996715a14f8404669821..67bc36f7f4fb7972d0cca2daef680a58aede48f6 100644 (file)
@@ -1498,13 +1498,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;
index 083c112bee0b8338ee9cc576f4d6365439de67c5..bd5e8122ea5e771d96ffd33f85c7b336092d36a2 100644 (file)
@@ -900,6 +900,12 @@ static void nf_tables_table_disable(struct net *net, struct nft_table *table)
        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;
@@ -929,19 +935,17 @@ static int nf_tables_updtable(struct nft_ctx *ctx)
 
        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;
        list_add_tail(&trans->list, &ctx->net->nft.commit_list);
        return 0;
@@ -8068,11 +8072,10 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
                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);
                        }
@@ -8283,11 +8286,9 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
                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);