]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
netfilter: nft_compat: run xt_check_hooks_{match,target}() from .validate
authorPablo Neira Ayuso <pablo@netfilter.org>
Tue, 28 Apr 2026 17:04:07 +0000 (19:04 +0200)
committerPablo Neira Ayuso <pablo@netfilter.org>
Thu, 30 Apr 2026 06:03:22 +0000 (08:03 +0200)
Several matches and one target check that the hook is correct from
checkentry(), however, the basechain is only available from
nft_table_validate().

This patch uses xt_check_hooks_{match,target}() from the nft_compat
expression .validate path.

This patch sets the table in the nft_ctx struct in nft_table_validate()
which is required by this patch.

Based on patch from Florian Westphal.

Fixes: 0ca743a55991 ("netfilter: nf_tables: add compatibility layer for x_tables")
Reported-by: Xiang Mei <xmei5@asu.edu>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
net/netfilter/nf_tables_api.c
net/netfilter/nft_compat.c

index d20ce5c36d31870eb7ba9ac4cffeb525e3a0cbc7..38e33c66c61838f8bc17aef599e541fa5fe5d08b 100644 (file)
@@ -4205,6 +4205,7 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
        struct nft_chain *chain;
        struct nft_ctx ctx = {
                .net    = net,
+               .table  = (struct nft_table *)table,
                .family = table->family,
        };
        int err = 0;
index decc725a33c251f73d8e8370ef8ea666d4aca033..0caa9304d2d0305f1cce0af8c39be91049489280 100644 (file)
@@ -261,10 +261,10 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        return ret;
        }
 
-       nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
-
        nft_compat_wait_for_destructors(ctx->net);
 
+       nft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);
+
        ret = xt_check_target(&par, size, proto, inv);
        if (ret < 0) {
                if (ret == -ENOENT) {
@@ -353,8 +353,6 @@ nla_put_failure:
 static int nft_target_validate(const struct nft_ctx *ctx,
                               const struct nft_expr *expr)
 {
-       struct xt_target *target = expr->ops->data;
-       unsigned int hook_mask = 0;
        int ret;
 
        if (ctx->family != NFPROTO_IPV4 &&
@@ -377,11 +375,21 @@ static int nft_target_validate(const struct nft_ctx *ctx,
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
                const struct nf_hook_ops *ops = &basechain->ops;
+               unsigned int hook_mask = 1 << ops->hooknum;
+               struct xt_target *target = expr->ops->data;
+               void *info = nft_expr_priv(expr);
+               struct xt_tgchk_param par;
+               union nft_entry e = {};
 
-               hook_mask = 1 << ops->hooknum;
                if (target->hooks && !(hook_mask & target->hooks))
                        return -EINVAL;
 
+               nft_target_set_tgchk_param(&par, ctx, target, info, &e, 0, false);
+
+               ret = xt_check_hooks_target(&par);
+               if (ret < 0)
+                       return ret;
+
                ret = nft_compat_chain_validate_dependency(ctx, target->table);
                if (ret < 0)
                        return ret;
@@ -515,10 +523,10 @@ __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
                        return ret;
        }
 
-       nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
-
        nft_compat_wait_for_destructors(ctx->net);
 
+       nft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);
+
        return xt_check_match(&par, size, proto, inv);
 }
 
@@ -614,8 +622,6 @@ static int nft_match_large_dump(struct sk_buff *skb,
 static int nft_match_validate(const struct nft_ctx *ctx,
                              const struct nft_expr *expr)
 {
-       struct xt_match *match = expr->ops->data;
-       unsigned int hook_mask = 0;
        int ret;
 
        if (ctx->family != NFPROTO_IPV4 &&
@@ -638,11 +644,30 @@ static int nft_match_validate(const struct nft_ctx *ctx,
                const struct nft_base_chain *basechain =
                                                nft_base_chain(ctx->chain);
                const struct nf_hook_ops *ops = &basechain->ops;
+               unsigned int hook_mask = 1 << ops->hooknum;
+               struct xt_match *match = expr->ops->data;
+               size_t size = XT_ALIGN(match->matchsize);
+               struct xt_mtchk_param par;
+               union nft_entry e = {};
+               void *info;
 
-               hook_mask = 1 << ops->hooknum;
                if (match->hooks && !(hook_mask & match->hooks))
                        return -EINVAL;
 
+               if (NFT_EXPR_SIZE(size) > NFT_MATCH_LARGE_THRESH) {
+                       struct nft_xt_match_priv *priv = nft_expr_priv(expr);
+
+                       info = priv->info;
+               } else {
+                       info = nft_expr_priv(expr);
+               }
+
+               nft_match_set_mtchk_param(&par, ctx, match, info, &e, 0, false);
+
+               ret = xt_check_hooks_match(&par);
+               if (ret < 0)
+                       return ret;
+
                ret = nft_compat_chain_validate_dependency(ctx, match->table);
                if (ret < 0)
                        return ret;