netfilter: nf_tables: disallow rule removal from chain binding
[platform/kernel/linux-starfive.git] / net / netfilter / nf_tables_api.c
index 361e98e..895c6e4 100644 (file)
@@ -1432,7 +1432,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
                if (!nft_is_active_next(ctx->net, chain))
                        continue;
 
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        continue;
 
                ctx->chain = chain;
@@ -1477,7 +1477,7 @@ static int nft_flush_table(struct nft_ctx *ctx)
                if (!nft_is_active_next(ctx->net, chain))
                        continue;
 
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        continue;
 
                ctx->chain = chain;
@@ -2910,6 +2910,9 @@ static int nf_tables_delchain(struct sk_buff *skb, const struct nfnl_info *info,
                return PTR_ERR(chain);
        }
 
+       if (nft_chain_binding(chain))
+               return -EOPNOTSUPP;
+
        nft_ctx_init(&ctx, net, skb, info->nlh, family, table, chain, nla);
 
        if (nla[NFTA_CHAIN_HOOK]) {
@@ -3422,6 +3425,18 @@ err:
        nfnetlink_set_err(ctx->net, ctx->portid, NFNLGRP_NFTABLES, -ENOBUFS);
 }
 
+static void audit_log_rule_reset(const struct nft_table *table,
+                                unsigned int base_seq,
+                                unsigned int nentries)
+{
+       char *buf = kasprintf(GFP_ATOMIC, "%s:%u",
+                             table->name, base_seq);
+
+       audit_log_nfcfg(buf, table->family, nentries,
+                       AUDIT_NFT_OP_RULE_RESET, GFP_ATOMIC);
+       kfree(buf);
+}
+
 struct nft_rule_dump_ctx {
        char *table;
        char *chain;
@@ -3468,6 +3483,10 @@ cont:
 cont_skip:
                (*idx)++;
        }
+
+       if (reset && *idx)
+               audit_log_rule_reset(table, cb->seq, *idx);
+
        return 0;
 }
 
@@ -3635,6 +3654,9 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
        if (err < 0)
                goto err_fill_rule_info;
 
+       if (reset)
+               audit_log_rule_reset(table, nft_pernet(net)->base_seq, 1);
+
        return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
 
 err_fill_rule_info:
@@ -3952,6 +3974,11 @@ static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
        }
 
        if (info->nlh->nlmsg_flags & NLM_F_REPLACE) {
+               if (nft_chain_binding(chain)) {
+                       err = -EOPNOTSUPP;
+                       goto err_destroy_flow_rule;
+               }
+
                err = nft_delrule(&ctx, old_rule);
                if (err < 0)
                        goto err_destroy_flow_rule;
@@ -4059,7 +4086,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
                        NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
                        return PTR_ERR(chain);
                }
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        return -EOPNOTSUPP;
        }
 
@@ -4093,7 +4120,7 @@ static int nf_tables_delrule(struct sk_buff *skb, const struct nfnl_info *info,
                list_for_each_entry(chain, &table->chains, list) {
                        if (!nft_is_active_next(net, chain))
                                continue;
-                       if (nft_chain_is_bound(chain))
+                       if (nft_chain_binding(chain))
                                continue;
 
                        ctx.chain = chain;
@@ -5742,8 +5769,6 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
        if (!args.iter.err && args.iter.count == cb->args[0])
                args.iter.err = nft_set_catchall_dump(net, skb, set,
                                                      reset, cb->seq);
-       rcu_read_unlock();
-
        nla_nest_end(skb, nest);
        nlmsg_end(skb, nlh);
 
@@ -5751,6 +5776,8 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
                audit_log_nft_set_reset(table, cb->seq,
                                        args.iter.count - args.iter.skip);
 
+       rcu_read_unlock();
+
        if (args.iter.err && args.iter.err != -EMSGSIZE)
                return args.iter.err;
        if (args.iter.count == cb->args[0])
@@ -11035,7 +11062,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table)
        ctx.family = table->family;
        ctx.table = table;
        list_for_each_entry(chain, &table->chains, list) {
-               if (nft_chain_is_bound(chain))
+               if (nft_chain_binding(chain))
                        continue;
 
                ctx.chain = chain;