netfilter: nf_tables_offload: incorrect flow offload action array size
authorPablo Neira Ayuso <pablo@netfilter.org>
Thu, 17 Feb 2022 22:41:20 +0000 (23:41 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 2 Mar 2022 10:47:51 +0000 (11:47 +0100)
commit b1a5983f56e371046dcf164f90bfaf704d2b89f6 upstream.

immediate verdict expression needs to allocate one slot in the flow offload
action array, however, immediate data expression does not need to do so.

fwd and dup expression need to allocate one slot, this is missing.

Add a new offload_action interface to report if this expression needs to
allocate one slot in the flow offload action array.

Fixes: be2861dc36d7 ("netfilter: nft_{fwd,dup}_netdev: add offload support")
Reported-and-tested-by: Nick Gregory <Nick.Gregory@Sophos.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/net/netfilter/nf_tables.h
include/net/netfilter/nf_tables_offload.h
net/netfilter/nf_tables_offload.c
net/netfilter/nft_dup_netdev.c
net/netfilter/nft_fwd_netdev.c
net/netfilter/nft_immediate.c

index a16171c5fd9ebc8c9cb214e700584ca34eb1a016..d52a5d776e764e1214873c064c8b790e09b332ee 100644 (file)
@@ -883,9 +883,9 @@ struct nft_expr_ops {
        int                             (*offload)(struct nft_offload_ctx *ctx,
                                                   struct nft_flow_rule *flow,
                                                   const struct nft_expr *expr);
+       bool                            (*offload_action)(const struct nft_expr *expr);
        void                            (*offload_stats)(struct nft_expr *expr,
                                                         const struct flow_stats *stats);
-       u32                             offload_flags;
        const struct nft_expr_type      *type;
        void                            *data;
 };
index f9d95ff82df834a257296285488835cf8271743e..7971478439580c6a7db49892d021e1abfc9e9321 100644 (file)
@@ -67,8 +67,6 @@ struct nft_flow_rule {
        struct flow_rule        *rule;
 };
 
-#define NFT_OFFLOAD_F_ACTION   (1 << 0)
-
 void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
                                 enum flow_dissector_key_id addr_type);
 
index 9656c1646222201a1ffef46eec24af5478afec3d..2d36952b13920d149110e7d90dff8d7069e78ff8 100644 (file)
@@ -94,7 +94,8 @@ struct nft_flow_rule *nft_flow_rule_create(struct net *net,
 
        expr = nft_expr_first(rule);
        while (nft_expr_more(rule, expr)) {
-               if (expr->ops->offload_flags & NFT_OFFLOAD_F_ACTION)
+               if (expr->ops->offload_action &&
+                   expr->ops->offload_action(expr))
                        num_actions++;
 
                expr = nft_expr_next(expr);
index bbf3fcba3df4019ad7e1934b6ba6e9c6ae33c057..5b5c607fbf83f020f1b8929c4fa7a36d6a20471a 100644 (file)
@@ -67,6 +67,11 @@ static int nft_dup_netdev_offload(struct nft_offload_ctx *ctx,
        return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_MIRRED, oif);
 }
 
+static bool nft_dup_netdev_offload_action(const struct nft_expr *expr)
+{
+       return true;
+}
+
 static struct nft_expr_type nft_dup_netdev_type;
 static const struct nft_expr_ops nft_dup_netdev_ops = {
        .type           = &nft_dup_netdev_type,
@@ -75,6 +80,7 @@ static const struct nft_expr_ops nft_dup_netdev_ops = {
        .init           = nft_dup_netdev_init,
        .dump           = nft_dup_netdev_dump,
        .offload        = nft_dup_netdev_offload,
+       .offload_action = nft_dup_netdev_offload_action,
 };
 
 static struct nft_expr_type nft_dup_netdev_type __read_mostly = {
index cd59afde5b2f8ce2660ca2a7b03fa41c0d8a064e..7730409f6f091126c253021de12d2ad917a1b041 100644 (file)
@@ -77,6 +77,11 @@ static int nft_fwd_netdev_offload(struct nft_offload_ctx *ctx,
        return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_REDIRECT, oif);
 }
 
+static bool nft_fwd_netdev_offload_action(const struct nft_expr *expr)
+{
+       return true;
+}
+
 struct nft_fwd_neigh {
        u8                      sreg_dev;
        u8                      sreg_addr;
@@ -219,6 +224,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
        .dump           = nft_fwd_netdev_dump,
        .validate       = nft_fwd_validate,
        .offload        = nft_fwd_netdev_offload,
+       .offload_action = nft_fwd_netdev_offload_action,
 };
 
 static const struct nft_expr_ops *
index 90c64d27ae53228a1c0fe3acbd40aa5ba288a7b6..d0f67d325bdfd384cd70a95d527d9ce7bc690b2d 100644 (file)
@@ -213,6 +213,16 @@ static int nft_immediate_offload(struct nft_offload_ctx *ctx,
        return 0;
 }
 
+static bool nft_immediate_offload_action(const struct nft_expr *expr)
+{
+       const struct nft_immediate_expr *priv = nft_expr_priv(expr);
+
+       if (priv->dreg == NFT_REG_VERDICT)
+               return true;
+
+       return false;
+}
+
 static const struct nft_expr_ops nft_imm_ops = {
        .type           = &nft_imm_type,
        .size           = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
@@ -224,7 +234,7 @@ static const struct nft_expr_ops nft_imm_ops = {
        .dump           = nft_immediate_dump,
        .validate       = nft_immediate_validate,
        .offload        = nft_immediate_offload,
-       .offload_flags  = NFT_OFFLOAD_F_ACTION,
+       .offload_action = nft_immediate_offload_action,
 };
 
 struct nft_expr_type nft_imm_type __read_mostly = {