{"id":2225253,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2225253/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260420174227.13087-1-pablo@netfilter.org/","project":{"id":26,"url":"http://patchwork.ozlabs.org/api/1.1/projects/26/?format=json","name":"Netfilter Development","link_name":"netfilter-devel","list_id":"netfilter-devel.vger.kernel.org","list_email":"netfilter-devel@vger.kernel.org","web_url":null,"scm_url":null,"webscm_url":null},"msgid":"<20260420174227.13087-1-pablo@netfilter.org>","date":"2026-04-20T17:42:27","name":"[nf] netfilter: nft_compat: run checkentry() from .validate","commit_ref":null,"pull_url":null,"state":"changes-requested","archived":false,"hash":"67b10e4ff8d025ada1d508d08ca7444c9d40044e","submitter":{"id":1315,"url":"http://patchwork.ozlabs.org/api/1.1/people/1315/?format=json","name":"Pablo Neira Ayuso","email":"pablo@netfilter.org"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260420174227.13087-1-pablo@netfilter.org/mbox/","series":[{"id":500652,"url":"http://patchwork.ozlabs.org/api/1.1/series/500652/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/list/?series=500652","date":"2026-04-20T17:42:27","name":"[nf] netfilter: nft_compat: run checkentry() from .validate","version":1,"mbox":"http://patchwork.ozlabs.org/series/500652/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2225253/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2225253/checks/","tags":{},"headers":{"Return-Path":"\n <netfilter-devel+bounces-12075-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","netfilter-devel@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=netfilter.org header.i=@netfilter.org\n header.a=rsa-sha256 header.s=2025 header.b=pDrxBY7K;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=netfilter-devel+bounces-12075-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org\n header.b=\"pDrxBY7K\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=217.70.190.124","smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=netfilter.org","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=netfilter.org"],"Received":["from tor.lore.kernel.org (tor.lore.kernel.org\n [IPv6:2600:3c04:e001:36c::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fzt9l5Xp9z1yD4\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 21 Apr 2026 03:42:51 +1000 (AEST)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id D8F81300D171\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 20 Apr 2026 17:42:48 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id D290C3A6F19;\n\tMon, 20 Apr 2026 17:42:46 +0000 (UTC)","from mail.netfilter.org (mail.netfilter.org [217.70.190.124])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id D5A5537FF4B\n\tfor <netfilter-devel@vger.kernel.org>; Mon, 20 Apr 2026 17:42:43 +0000 (UTC)","from localhost.localdomain (mail-agni [217.70.190.124])\n\tby mail.netfilter.org (Postfix) with ESMTPSA id 036E160179;\n\tMon, 20 Apr 2026 19:42:34 +0200 (CEST)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776706966; cv=none;\n b=LZUJR1SQiTsMmeUwrS1xzeK75C/SIZ6z7UOxWIgENjsx8xu/ynAVZmuWQWz+6AkKUV5dN3joKRtPnl/VY6ZjVjHsdY2pLxB6NlAxkOiUVpRfHefhFhMdMyeEg71HXcckVhG3uI951ZYTKuz8aZ0Jl5aV2yqBPwNXEw5M1Ky8vKY=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776706966; c=relaxed/simple;\n\tbh=OrXPi+VJZ2nGN6TxJMJ5CBnK/QM1zQdf5/lBVn8lCgk=;\n\th=From:To:Cc:Subject:Date:Message-ID:MIME-Version;\n b=PIPWmdvANsjolyVit7psql0HliT350ry8RSG/46Ep7jySXuGSFDMXOl4NSZnf+ukTGvMHaNipepBGipF8BQFY93qcDSfas1gZjIRQFYPWIINjaAa6Q/Pa4YyxVqdOqJpar/j8eevjk+PDlwZ+D51gXnPG6HUVpPxH8yu3FznYSI=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=netfilter.org;\n spf=pass smtp.mailfrom=netfilter.org;\n dkim=pass (2048-bit key) header.d=netfilter.org header.i=@netfilter.org\n header.b=pDrxBY7K; arc=none smtp.client-ip=217.70.190.124","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=netfilter.org;\n\ts=2025; t=1776706955;\n\tbh=EB05TBiWRpQQ6qQttaDsrgBS7AXHBEctibsy/6kePaY=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=pDrxBY7KFvURO5z1hxqhJ4yYTIgjYoUr8bZjUh08COaWRdhEhQtSt5MHBC1wwMy8k\n\t atAVv9h7PCqwHSweSSH3BBMV2dbmX/dhgDbTIpHTi9NIWZCT/OjGXIcsl03yBAEe9Z\n\t XYPZpO6bEXOzQqE0ggv28AnRykH76wwhomex44mWt0fYMg5ldiGrEryZP+mcXUX2R8\n\t BNeyg6BiFV1IHxSmd+H9JmC8Xpc3wqxwd3kxnz3CrTiVQBD/g4BVBwlUiFIcsDAkU8\n\t 9EPbQUiJyp1SYMf6EDPvtbpiDWLQJxtYwKJkb/eN/GLP3LYYUegwh6VY5jByNCBywQ\n\t +2yESmZmChbng==","From":"Pablo Neira Ayuso <pablo@netfilter.org>","To":"netfilter-devel@vger.kernel.org","Cc":"fw@strlen.de","Subject":"[PATCH nf] netfilter: nft_compat: run checkentry() from .validate","Date":"Mon, 20 Apr 2026 19:42:27 +0200","Message-ID":"<20260420174227.13087-1-pablo@netfilter.org>","X-Mailer":"git-send-email 2.47.3","Precedence":"bulk","X-Mailing-List":"netfilter-devel@vger.kernel.org","List-Id":"<netfilter-devel.vger.kernel.org>","List-Subscribe":"<mailto:netfilter-devel+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:netfilter-devel+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"Several matches and one target check that the hook is correct from\ncheckentry(), however, the basechain is only available from\nnft_table_validate().\n\nThis patch calls checkentry() for matches and targets from the\nnft_compat expression .validate path for the following matches/target:\n\n- addrtype\n- devgroup\n- physdev\n- policy\n- set\n- TCPMSS\n\nThe xt_match .destroy indirection is also called to restore the\nxt_set refcounts that is performed by .checkentry. The remaining\nextensions provide no .destroy interface.\n\nThis patch sets the table in the nft_ctx struct in nft_table_validate()\nwhich is required by this patch.\n\nThe nft_compat_check_match() and nft_compat_check_target() helper\nfunctions are added to wrap common code used from .init and .validate\npath.\n\nThe protocol and inverse flags are set to always match from the\nexpression .validate path, this is already checked from the init path.\n\nFixes: 0ca743a55991 (\"netfilter: nf_tables: add compatibility layer for x_tables\")\nReported-by: Xiang Mei <xmei5@asu.edu>\nSigned-off-by: Pablo Neira Ayuso <pablo@netfilter.org>\n---\nA more self-contained alternative to Florian's:\nhttps://patchwork.ozlabs.org/project/netfilter-devel/patch/20260419104509.42196-1-fw@strlen.de/\n\n net/netfilter/nf_tables_api.c |   1 +\n net/netfilter/nft_compat.c    | 118 ++++++++++++++++++++++++++++------\n 2 files changed, 100 insertions(+), 19 deletions(-)","diff":"diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c\nindex 00ccc0734ac9..070e97efe7d1 100644\n--- a/net/netfilter/nf_tables_api.c\n+++ b/net/netfilter/nf_tables_api.c\n@@ -4196,6 +4196,7 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)\n \tstruct nft_chain *chain;\n \tstruct nft_ctx ctx = {\n \t\t.net\t= net,\n+\t\t.table\t= (struct nft_table *)table,\n \t\t.family\t= table->family,\n \t};\n \tint err = 0;\ndiff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c\nindex decc725a33c2..2352505fb992 100644\n--- a/net/netfilter/nft_compat.c\n+++ b/net/netfilter/nft_compat.c\n@@ -229,6 +229,20 @@ static int nft_parse_compat(const struct nlattr *attr, u16 *proto, bool *inv)\n \treturn 0;\n }\n \n+static int nft_compat_check_target(const struct nft_ctx *ctx,\n+\t\t\t\t   const struct nft_expr *expr,\n+\t\t\t\t   void *info, size_t size,\n+\t\t\t\t   u16 proto, bool inv)\n+{\n+\tstruct xt_target *target = expr->ops->data;\n+\tstruct xt_tgchk_param par;\n+\tunion nft_entry e = {};\n+\n+\tnft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);\n+\n+\treturn xt_check_target(&par, size, proto, inv);\n+}\n+\n static void nft_compat_wait_for_destructors(struct net *net)\n {\n \t/* xtables matches or targets can have side effects, e.g.\n@@ -244,13 +258,11 @@ static int\n nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,\n \t\tconst struct nlattr * const tb[])\n {\n-\tvoid *info = nft_expr_priv(expr);\n \tstruct xt_target *target = expr->ops->data;\n-\tstruct xt_tgchk_param par;\n \tsize_t size = XT_ALIGN(nla_len(tb[NFTA_TARGET_INFO]));\n-\tu16 proto = 0;\n+\tvoid *info = nft_expr_priv(expr);\n \tbool inv = false;\n-\tunion nft_entry e = {};\n+\tu16 proto = 0;\n \tint ret;\n \n \ttarget_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info);\n@@ -261,11 +273,9 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr,\n \t\t\treturn ret;\n \t}\n \n-\tnft_target_set_tgchk_param(&par, ctx, target, info, &e, proto, inv);\n-\n \tnft_compat_wait_for_destructors(ctx->net);\n \n-\tret = xt_check_target(&par, size, proto, inv);\n+\tret = nft_compat_check_target(ctx, expr, info, size, proto, inv);\n \tif (ret < 0) {\n \t\tif (ret == -ENOENT) {\n \t\t\tconst char *modname = NULL;\n@@ -382,6 +392,26 @@ static int nft_target_validate(const struct nft_ctx *ctx,\n \t\tif (target->hooks && !(hook_mask & target->hooks))\n \t\t\treturn -EINVAL;\n \n+\t\t/* At least one target needs to validate hooks at checkentry()\n+\t\t * stage because such validation depends on the match\n+\t\t * configuration. This cannot be enabled for all matches,\n+\t\t * because some of them perform more than simple validation,\n+\t\t * such as bumping reference counter on objects.\n+\t\t */\n+\t\tif (!strcmp(target->name, \"TCPMSS\")) {\n+\t\t\tstruct xt_target *target = expr->ops->data;\n+\t\t\tsize_t size = XT_ALIGN(target->targetsize);\n+\t\t\tvoid *info = nft_expr_priv(expr);\n+\n+\t\t\t/* nft_target_init() already checked for protocol and\n+\t\t\t * inverse, not available in this patch, lie here.\n+\t\t\t */\n+\t\t\tret = nft_compat_check_target(ctx, expr, info, size,\n+\t\t\t\t\t\t      target->proto, false);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\t\t}\n+\n \t\tret = nft_compat_chain_validate_dependency(ctx, target->table);\n \t\tif (ret < 0)\n \t\t\treturn ret;\n@@ -494,17 +524,29 @@ static void match_compat_from_user(struct xt_match *m, void *in, void *out)\n \t\tmemset(out + m->matchsize, 0, pad);\n }\n \n+static int nft_compat_check_match(const struct nft_ctx *ctx,\n+\t\t\t\t  const struct nft_expr *expr,\n+\t\t\t\t  void *info, size_t size,\n+\t\t\t\t  u16 proto, bool inv)\n+{\n+\tstruct xt_match *match = expr->ops->data;\n+\tstruct xt_mtchk_param par;\n+\tunion nft_entry e = {};\n+\n+\tnft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);\n+\n+\treturn xt_check_match(&par, size, proto, inv);\n+}\n+\n static int\n __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,\n \t\t const struct nlattr * const tb[],\n \t\t void *info)\n {\n-\tstruct xt_match *match = expr->ops->data;\n-\tstruct xt_mtchk_param par;\n \tsize_t size = XT_ALIGN(nla_len(tb[NFTA_MATCH_INFO]));\n-\tu16 proto = 0;\n+\tstruct xt_match *match = expr->ops->data;\n \tbool inv = false;\n-\tunion nft_entry e = {};\n+\tu16 proto = 0;\n \tint ret;\n \n \tmatch_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info);\n@@ -515,11 +557,9 @@ __nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr,\n \t\t\treturn ret;\n \t}\n \n-\tnft_match_set_mtchk_param(&par, ctx, match, info, &e, proto, inv);\n-\n \tnft_compat_wait_for_destructors(ctx->net);\n \n-\treturn xt_check_match(&par, size, proto, inv);\n+\treturn nft_compat_check_match(ctx, expr, info, size, proto, inv);\n }\n \n static int\n@@ -547,12 +587,9 @@ nft_match_large_init(const struct nft_ctx *ctx, const struct nft_expr *expr,\n \treturn ret;\n }\n \n-static void\n-__nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr,\n-\t\t    void *info)\n+static void nft_mt_destroy(const struct nft_ctx *ctx, struct xt_match *match,\n+\t\t\t   void *info)\n {\n-\tstruct xt_match *match = expr->ops->data;\n-\tstruct module *me = match->me;\n \tstruct xt_mtdtor_param par;\n \n \tpar.net = ctx->net;\n@@ -561,7 +598,16 @@ __nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr,\n \tpar.family = ctx->family;\n \tif (par.match->destroy != NULL)\n \t\tpar.match->destroy(&par);\n+}\n \n+static void\n+__nft_match_destroy(const struct nft_ctx *ctx, const struct nft_expr *expr,\n+\t\t    void *info)\n+{\n+\tstruct xt_match *match = expr->ops->data;\n+\tstruct module *me = match->me;\n+\n+\tnft_mt_destroy(ctx, match, info);\n \t__nft_mt_tg_destroy(me, expr);\n }\n \n@@ -643,6 +689,40 @@ static int nft_match_validate(const struct nft_ctx *ctx,\n \t\tif (match->hooks && !(hook_mask & match->hooks))\n \t\t\treturn -EINVAL;\n \n+\t\t/* Several matches need to validate hooks at checkentry() stage\n+\t\t * because such validation depends on the match configuration.\n+\t\t */\n+\t\tif (!strcmp(match->name, \"addrtype\") ||\n+\t\t    !strcmp(match->name, \"devgroup\") ||\n+\t\t    !strcmp(match->name, \"physdev\") ||\n+\t\t    !strcmp(match->name, \"policy\") ||\n+\t\t    !strcmp(match->name, \"set\")) {\n+\t\t\tstruct xt_match *match = expr->ops->data;\n+\t\t\tsize_t size = XT_ALIGN(match->matchsize);\n+\t\t\tvoid *info;\n+\n+\t\t\tif (NFT_EXPR_SIZE(size) > NFT_MATCH_LARGE_THRESH) {\n+\t\t\t\tstruct nft_xt_match_priv *priv = nft_expr_priv(expr);\n+\n+\t\t\t\tinfo = priv->info;\n+\t\t\t} else {\n+\t\t\t\tinfo = nft_expr_priv(expr);\n+\t\t\t}\n+\n+\t\t\t/* __nft_match_init() already checked for protocol and\n+\t\t\t * inverse, not available in this patch, lie here.\n+\t\t\t */\n+\t\t\tret = nft_compat_check_match(ctx, expr, info, size,\n+\t\t\t\t\t\t     match->proto, false);\n+\t\t\tif (ret < 0)\n+\t\t\t\treturn ret;\n+\n+\t\t\t /* The set match bumps reference count, restore after\n+\t\t\t  * this checkentry call.\n+\t\t\t  */\n+\t\t\tnft_mt_destroy(ctx, match, info);\n+\t\t}\n+\n \t\tret = nft_compat_chain_validate_dependency(ctx, match->table);\n \t\tif (ret < 0)\n \t\t\treturn ret;\n","prefixes":["nf"]}