netfilter: nf_tables_offload: incorrect flow offload action array size

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: be2861dc36 ("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>
This commit is contained in:
Pablo Neira Ayuso 2022-02-17 23:41:20 +01:00
Родитель 2874b79111
Коммит b1a5983f56
6 изменённых файлов: 26 добавлений и 5 удалений

Просмотреть файл

@ -905,9 +905,9 @@ struct nft_expr_ops {
int (*offload)(struct nft_offload_ctx *ctx, int (*offload)(struct nft_offload_ctx *ctx,
struct nft_flow_rule *flow, struct nft_flow_rule *flow,
const struct nft_expr *expr); const struct nft_expr *expr);
bool (*offload_action)(const struct nft_expr *expr);
void (*offload_stats)(struct nft_expr *expr, void (*offload_stats)(struct nft_expr *expr,
const struct flow_stats *stats); const struct flow_stats *stats);
u32 offload_flags;
const struct nft_expr_type *type; const struct nft_expr_type *type;
void *data; void *data;
}; };

Просмотреть файл

@ -67,8 +67,6 @@ struct nft_flow_rule {
struct flow_rule *rule; struct flow_rule *rule;
}; };
#define NFT_OFFLOAD_F_ACTION (1 << 0)
void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow, void nft_flow_rule_set_addr_type(struct nft_flow_rule *flow,
enum flow_dissector_key_id addr_type); enum flow_dissector_key_id addr_type);

Просмотреть файл

@ -94,7 +94,8 @@ struct nft_flow_rule *nft_flow_rule_create(struct net *net,
expr = nft_expr_first(rule); expr = nft_expr_first(rule);
while (nft_expr_more(rule, expr)) { 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++; num_actions++;
expr = nft_expr_next(expr); expr = nft_expr_next(expr);

Просмотреть файл

@ -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); 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 struct nft_expr_type nft_dup_netdev_type;
static const struct nft_expr_ops nft_dup_netdev_ops = { static const struct nft_expr_ops nft_dup_netdev_ops = {
.type = &nft_dup_netdev_type, .type = &nft_dup_netdev_type,
@ -75,6 +80,7 @@ static const struct nft_expr_ops nft_dup_netdev_ops = {
.init = nft_dup_netdev_init, .init = nft_dup_netdev_init,
.dump = nft_dup_netdev_dump, .dump = nft_dup_netdev_dump,
.offload = nft_dup_netdev_offload, .offload = nft_dup_netdev_offload,
.offload_action = nft_dup_netdev_offload_action,
}; };
static struct nft_expr_type nft_dup_netdev_type __read_mostly = { static struct nft_expr_type nft_dup_netdev_type __read_mostly = {

Просмотреть файл

@ -79,6 +79,11 @@ static int nft_fwd_netdev_offload(struct nft_offload_ctx *ctx,
return nft_fwd_dup_netdev_offload(ctx, flow, FLOW_ACTION_REDIRECT, oif); 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 { struct nft_fwd_neigh {
u8 sreg_dev; u8 sreg_dev;
u8 sreg_addr; u8 sreg_addr;
@ -222,6 +227,7 @@ static const struct nft_expr_ops nft_fwd_netdev_ops = {
.dump = nft_fwd_netdev_dump, .dump = nft_fwd_netdev_dump,
.validate = nft_fwd_validate, .validate = nft_fwd_validate,
.offload = nft_fwd_netdev_offload, .offload = nft_fwd_netdev_offload,
.offload_action = nft_fwd_netdev_offload_action,
}; };
static const struct nft_expr_ops * static const struct nft_expr_ops *

Просмотреть файл

@ -213,6 +213,16 @@ static int nft_immediate_offload(struct nft_offload_ctx *ctx,
return 0; 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 = { static const struct nft_expr_ops nft_imm_ops = {
.type = &nft_imm_type, .type = &nft_imm_type,
.size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), .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, .dump = nft_immediate_dump,
.validate = nft_immediate_validate, .validate = nft_immediate_validate,
.offload = nft_immediate_offload, .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 = { struct nft_expr_type nft_imm_type __read_mostly = {