netfilter: nf_tables: Introduce nf_tables_getrule_single()
authorPhil Sutter <phil@nwl.cc>
Thu, 19 Oct 2023 14:03:35 +0000 (16:03 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Tue, 24 Oct 2023 11:16:29 +0000 (13:16 +0200)
Outsource the reply skb preparation for non-dump getrule requests into a
distinct function. Prep work for rule reset locking.

Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_tables_api.c

index ce3bb38262c4485b5fdda716f83eb6864b89f8b8..d39990c3ae1d542a36fa7f5703091a965c3a7264 100644 (file)
@@ -3586,65 +3586,81 @@ static int nf_tables_dump_rules_done(struct netlink_callback *cb)
 }
 
 /* called with rcu_read_lock held */
-static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
-                            const struct nlattr * const nla[])
+static struct sk_buff *
+nf_tables_getrule_single(u32 portid, const struct nfnl_info *info,
+                        const struct nlattr * const nla[], bool reset)
 {
-       struct nftables_pernet *nft_net = nft_pernet(info->net);
        struct netlink_ext_ack *extack = info->extack;
        u8 genmask = nft_genmask_cur(info->net);
        u8 family = info->nfmsg->nfgen_family;
-       u32 portid = NETLINK_CB(skb).portid;
        const struct nft_chain *chain;
        const struct nft_rule *rule;
        struct net *net = info->net;
        struct nft_table *table;
        struct sk_buff *skb2;
-       bool reset = false;
-       char *buf;
        int err;
 
-       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
-               struct netlink_dump_control c = {
-                       .start= nf_tables_dump_rules_start,
-                       .dump = nf_tables_dump_rules,
-                       .done = nf_tables_dump_rules_done,
-                       .module = THIS_MODULE,
-                       .data = (void *)nla,
-               };
-
-               return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
-       }
-
        table = nft_table_lookup(net, nla[NFTA_RULE_TABLE], family, genmask, 0);
        if (IS_ERR(table)) {
                NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_TABLE]);
-               return PTR_ERR(table);
+               return ERR_CAST(table);
        }
 
        chain = nft_chain_lookup(net, table, nla[NFTA_RULE_CHAIN], genmask);
        if (IS_ERR(chain)) {
                NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_CHAIN]);
-               return PTR_ERR(chain);
+               return ERR_CAST(chain);
        }
 
        rule = nft_rule_lookup(chain, nla[NFTA_RULE_HANDLE]);
        if (IS_ERR(rule)) {
                NL_SET_BAD_ATTR(extack, nla[NFTA_RULE_HANDLE]);
-               return PTR_ERR(rule);
+               return ERR_CAST(rule);
        }
 
        skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
        if (!skb2)
-               return -ENOMEM;
-
-       if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET)
-               reset = true;
+               return ERR_PTR(-ENOMEM);
 
        err = nf_tables_fill_rule_info(skb2, net, portid,
                                       info->nlh->nlmsg_seq, NFT_MSG_NEWRULE, 0,
                                       family, table, chain, rule, 0, reset);
-       if (err < 0)
-               goto err_fill_rule_info;
+       if (err < 0) {
+               kfree_skb(skb2);
+               return ERR_PTR(err);
+       }
+
+       return skb2;
+}
+
+static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
+                            const struct nlattr * const nla[])
+{
+       struct nftables_pernet *nft_net = nft_pernet(info->net);
+       u32 portid = NETLINK_CB(skb).portid;
+       struct net *net = info->net;
+       struct sk_buff *skb2;
+       bool reset = false;
+       char *buf;
+
+       if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
+               struct netlink_dump_control c = {
+                       .start= nf_tables_dump_rules_start,
+                       .dump = nf_tables_dump_rules,
+                       .done = nf_tables_dump_rules_done,
+                       .module = THIS_MODULE,
+                       .data = (void *)nla,
+               };
+
+               return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
+       }
+
+       if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET)
+               reset = true;
+
+       skb2 = nf_tables_getrule_single(portid, info, nla, reset);
+       if (IS_ERR(skb2))
+               return PTR_ERR(skb2);
 
        if (!reset)
                return nfnetlink_unicast(skb2, net, portid);
@@ -3658,10 +3674,6 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
        kfree(buf);
 
        return nfnetlink_unicast(skb2, net, portid);
-
-err_fill_rule_info:
-       kfree_skb(skb2);
-       return err;
 }
 
 void nf_tables_rule_destroy(const struct nft_ctx *ctx, struct nft_rule *rule)