Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2224885/?format=api
{ "id": 2224885, "url": "http://patchwork.ozlabs.org/api/patches/2224885/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260419104509.42196-1-fw@strlen.de/", "project": { "id": 26, "url": "http://patchwork.ozlabs.org/api/projects/26/?format=api", "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, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260419104509.42196-1-fw@strlen.de>", "list_archive_url": null, "date": "2026-04-19T10:45:05", "name": "[nf] netfilter: x_tables: add late validate callback for nft_compat sake", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "77e5ebfeaa2f762b5b97743471f2b47e0ec552d4", "submitter": { "id": 1025, "url": "http://patchwork.ozlabs.org/api/people/1025/?format=api", "name": "Florian Westphal", "email": "fw@strlen.de" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260419104509.42196-1-fw@strlen.de/mbox/", "series": [ { "id": 500493, "url": "http://patchwork.ozlabs.org/api/series/500493/?format=api", "web_url": "http://patchwork.ozlabs.org/project/netfilter-devel/list/?series=500493", "date": "2026-04-19T10:45:05", "name": "[nf] netfilter: x_tables: add late validate callback for nft_compat sake", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500493/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224885/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224885/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <netfilter-devel+bounces-12026-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 spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c0a:e001:db::12fc:5321; helo=sea.lore.kernel.org;\n envelope-from=netfilter-devel+bounces-12026-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=91.216.245.30", "smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=strlen.de", "smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=Chamillionaire.breakpoint.cc" ], "Received": [ "from sea.lore.kernel.org (sea.lore.kernel.org\n [IPv6:2600:3c0a:e001:db::12fc:5321])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fz4yf5ZbYz1yGs\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 19 Apr 2026 20:45:30 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sea.lore.kernel.org (Postfix) with ESMTP id 5A621300EAB1\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 19 Apr 2026 10:45:22 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 9A848246783;\n\tSun, 19 Apr 2026 10:45:21 +0000 (UTC)", "from Chamillionaire.breakpoint.cc (Chamillionaire.breakpoint.cc\n [91.216.245.30])\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 98BDA19D092\n\tfor <netfilter-devel@vger.kernel.org>; Sun, 19 Apr 2026 10:45:18 +0000 (UTC)", "by Chamillionaire.breakpoint.cc (Postfix, from userid 1003)\n\tid 122A160640; Sun, 19 Apr 2026 12:45:16 +0200 (CEST)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1776595521; cv=none;\n b=s2Y/VO2FEijEa6MxyePfpeK0fl+ZX3CA1CmjjJ7Ecl2EmqgJwTNw+JCzQqJjz+WugGtp5rhOY4r//HaSdI4pBFsx7iZmRl4JQaP2oZwLJiBkVnaDKyHudPIabB29DdUPiBIwsnFhp9J+/UtQ7XRARUAHpKfGLovDT9cSrwIHqjg=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1776595521; c=relaxed/simple;\n\tbh=8Yav3RGYSVs/mUmrmMQX4wgtTX1tVzGIvih/7MzIb3Y=;\n\th=From:To:Cc:Subject:Date:Message-ID:MIME-Version;\n b=KqsfQmYsOQSz5X1wszn7wJjgrCnP65NLBxTFGkVXl8VLc56MJbLa7d71FgSRk/q2QMtuD646YSO29GgkdF0txfCyGCxO3Yfh41UJZzldt4zXR/O5MzSy68RsvTGxeT1DehoODLCMXbtGVKoJS5KV53Zqz4zYdfVl9B5FG9a4oOA=", "ARC-Authentication-Results": "i=1; smtp.subspace.kernel.org;\n dmarc=none (p=none dis=none) header.from=strlen.de;\n spf=pass smtp.mailfrom=Chamillionaire.breakpoint.cc;\n arc=none smtp.client-ip=91.216.245.30", "From": "Florian Westphal <fw@strlen.de>", "To": "<netfilter-devel@vger.kernel.org>", "Cc": "Florian Westphal <fw@strlen.de>,\n\tXiang Mei <xmei5@asu.edu>,\n\tWeiming Shi <bestswngs@gmail.com>", "Subject": "[PATCH nf] netfilter: x_tables: add late validate callback for\n nft_compat sake", "Date": "Sun, 19 Apr 2026 12:45:05 +0200", "Message-ID": "<20260419104509.42196-1-fw@strlen.de>", "X-Mailer": "git-send-email 2.53.0", "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": "x_tables and nftables are fundamentally different.\nIn x_tables, one gets the full ruleset graph via setsockopt().\n->checkentry() gets called at ruleset validation time.\n\nIn nf_tables, you get a transactional request (rule add in this case)\nin netlink format. At this time, it is not yet knowm from which\nbasechain(s) the new expression is reachable.\n\nIn nf_tables, there is one final hook validation pass right before the\npoint-of-no-return when the new state is fully known.\n\nHowever, nft_compat calls the x_tables checkentry functions way too\nearly, at expression instantiation time, when we have the netlink\ninfo available but not the base chain info (not yet known).\n\nAt final validation time we lack the additional compat information\nuserspace provided to us. So we need compat_info + base chain info,\nbut we never have both.\n\nAdd a new .nft_validate_chain callback to x_tables.\nIt is not allowed to have side effects and only performs addititonal\nhook_mask validiation at last possible moment.\nIt is called from nft_compat .validate callbacks.\n\nFixes: 0ca743a55991 (\"netfilter: nf_tables: add compatibility layer for x_tables\")\nReported-by: Xiang Mei <xmei5@asu.edu>\nCc: Weiming Shi <bestswngs@gmail.com>\nSigned-off-by: Florian Westphal <fw@strlen.de>\n---\n Tentative hack to resolve this bug where it originates.\n\n include/linux/netfilter/x_tables.h | 15 ++++++++++++++\n net/netfilter/nft_compat.c | 32 +++++++++++++++++++++++++++---\n net/netfilter/xt_TCPMSS.c | 25 ++++++++++++++++-------\n net/netfilter/xt_addrtype.c | 27 +++++++++++++++++++------\n net/netfilter/xt_devgroup.c | 31 +++++++++++++++++++----------\n net/netfilter/xt_physdev.c | 21 ++++++++++++++++----\n net/netfilter/xt_policy.c | 24 ++++++++++++++++++----\n net/netfilter/xt_set.c | 22 +++++++++++++++-----\n 8 files changed, 158 insertions(+), 39 deletions(-)", "diff": "diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h\nindex 77c778d84d4c..d1dcef359e61 100644\n--- a/include/linux/netfilter/x_tables.h\n+++ b/include/linux/netfilter/x_tables.h\n@@ -146,6 +146,10 @@ struct xt_match {\n \t/* Called when user tries to insert an entry of this type. */\n \tint (*checkentry)(const struct xt_mtchk_param *);\n \n+#if IS_ENABLED(CONFIG_NFT_COMPAT)\n+\t/* only used by nft_compat, must be pure: no side effects allowed */\n+\tbool (*nft_validate_chain)(const void *matchinfo, unsigned int hook_mask);\n+#endif\n \t/* Called when entry of this type deleted. */\n \tvoid (*destroy)(const struct xt_mtdtor_param *);\n #ifdef CONFIG_NETFILTER_XTABLES_COMPAT\n@@ -187,6 +191,10 @@ struct xt_target {\n \t/* Should return 0 on success or an error code otherwise (-Exxxx). */\n \tint (*checkentry)(const struct xt_tgchk_param *);\n \n+#if IS_ENABLED(CONFIG_NFT_COMPAT)\n+\t/* only used by nft_compat, must be pure: no side effects allowed */\n+\tbool (*nft_validate_chain)(const void *targinfo, unsigned int hook_mask);\n+#endif\n \t/* Called when entry of this type deleted. */\n \tvoid (*destroy)(const struct xt_tgdtor_param *);\n #ifdef CONFIG_NETFILTER_XTABLES_COMPAT\n@@ -524,4 +532,11 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems,\n \t\t\t\t unsigned int next_offset);\n \n #endif /* CONFIG_NETFILTER_XTABLES_COMPAT */\n+\n+#if IS_ENABLED(CONFIG_NFT_COMPAT)\n+#define NFT_COMPAT_VALIDATE(fname) .nft_validate_chain = fname,\n+#else\n+#define NFT_COMPAT_VALIDATE(fname)\n+#endif\n+\n #endif /* _X_TABLES_H */\ndiff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c\nindex 27cc983a7cdf..cc4041b1f1d0 100644\n--- a/net/netfilter/nft_compat.c\n+++ b/net/netfilter/nft_compat.c\n@@ -382,6 +382,10 @@ 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\tif (target->nft_validate_chain &&\n+\t\t !target->nft_validate_chain(nft_expr_priv(expr), hook_mask))\n+\t\t\treturn -EINVAL;\n+\n \t\tret = nft_compat_chain_validate_dependency(ctx, target->table);\n \t\tif (ret < 0)\n \t\t\treturn ret;\n@@ -611,10 +615,11 @@ static int nft_match_large_dump(struct sk_buff *skb,\n \treturn __nft_match_dump(skb, e, priv->info);\n }\n \n-static int nft_match_validate(const struct nft_ctx *ctx,\n-\t\t\t const struct nft_expr *expr)\n+static int __nft_match_validate(const struct nft_ctx *ctx,\n+\t\t\t\tconst struct nft_expr *expr,\n+\t\t\t\tconst void *info)\n {\n-\tstruct xt_match *match = expr->ops->data;\n+\tconst struct xt_match *match = expr->ops->data;\n \tunsigned int hook_mask = 0;\n \tint ret;\n \n@@ -643,6 +648,10 @@ 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\tif (match->nft_validate_chain &&\n+\t\t !match->nft_validate_chain(info, hook_mask))\n+\t\t\treturn -EINVAL;\n+\n \t\tret = nft_compat_chain_validate_dependency(ctx, match->table);\n \t\tif (ret < 0)\n \t\t\treturn ret;\n@@ -650,6 +659,22 @@ static int nft_match_validate(const struct nft_ctx *ctx,\n \treturn 0;\n }\n \n+static int nft_match_validate(const struct nft_ctx *ctx,\n+\t\t\t const struct nft_expr *expr)\n+{\n+\tconst void *info = nft_expr_priv(expr);\n+\n+\treturn __nft_match_validate(ctx, expr, info);\n+}\n+\n+static int nft_match_large_validate(const struct nft_ctx *ctx,\n+\t\t\t const struct nft_expr *expr)\n+{\n+\tstruct nft_xt_match_priv *priv = nft_expr_priv(expr);\n+\n+\treturn __nft_match_validate(ctx, expr, priv->info);\n+}\n+\n static int\n nfnl_compat_fill_info(struct sk_buff *skb, u32 portid, u32 seq, u32 type,\n \t\t int event, u16 family, const char *name,\n@@ -838,6 +863,7 @@ nft_match_select_ops(const struct nft_ctx *ctx,\n \t\tops->init = nft_match_large_init;\n \t\tops->destroy = nft_match_large_destroy;\n \t\tops->dump = nft_match_large_dump;\n+\t\tops->validate = nft_match_large_validate;\n \t}\n \n \tops->size = matchsize;\ndiff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c\nindex 116a885adb3c..261115ad4242 100644\n--- a/net/netfilter/xt_TCPMSS.c\n+++ b/net/netfilter/xt_TCPMSS.c\n@@ -260,16 +260,26 @@ static inline bool find_syn_match(const struct xt_entry_match *m)\n \treturn false;\n }\n \n+static bool tcpmss_validate_chain(const void *tginfo, unsigned int hook_mask)\n+{\n+\tconst struct xt_tcpmss_info *info = tginfo;\n+\n+\tif ((info->mss == XT_TCPMSS_CLAMP_PMTU) &&\n+\t (hook_mask & ~((1 << NF_INET_FORWARD) |\n+\t\t\t (1 << NF_INET_LOCAL_OUT) |\n+\t\t\t (1 << NF_INET_POST_ROUTING))) != 0)\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n static int tcpmss_tg4_check(const struct xt_tgchk_param *par)\n {\n \tconst struct xt_tcpmss_info *info = par->targinfo;\n \tconst struct ipt_entry *e = par->entryinfo;\n \tconst struct xt_entry_match *ematch;\n \n-\tif (info->mss == XT_TCPMSS_CLAMP_PMTU &&\n-\t (par->hook_mask & ~((1 << NF_INET_FORWARD) |\n-\t\t\t (1 << NF_INET_LOCAL_OUT) |\n-\t\t\t (1 << NF_INET_POST_ROUTING))) != 0) {\n+\tif (!tcpmss_validate_chain(info, par->hook_mask)) {\n \t\tpr_info_ratelimited(\"path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\\n\");\n \t\treturn -EINVAL;\n \t}\n@@ -291,12 +301,11 @@ static int tcpmss_tg6_check(const struct xt_tgchk_param *par)\n \tconst struct xt_entry_match *ematch;\n \n \tif (info->mss == XT_TCPMSS_CLAMP_PMTU &&\n-\t (par->hook_mask & ~((1 << NF_INET_FORWARD) |\n-\t\t\t (1 << NF_INET_LOCAL_OUT) |\n-\t\t\t (1 << NF_INET_POST_ROUTING))) != 0) {\n+\t !tcpmss_validate_chain(info, par->hook_mask)) {\n \t\tpr_info_ratelimited(\"path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\\n\");\n \t\treturn -EINVAL;\n \t}\n+\n \tif (par->nft_compat)\n \t\treturn 0;\n \n@@ -313,6 +322,7 @@ static struct xt_target tcpmss_tg_reg[] __read_mostly = {\n \t\t.family\t\t= NFPROTO_IPV4,\n \t\t.name\t\t= \"TCPMSS\",\n \t\t.checkentry\t= tcpmss_tg4_check,\n+\t\tNFT_COMPAT_VALIDATE(tcpmss_validate_chain)\n \t\t.target\t\t= tcpmss_tg4,\n \t\t.targetsize\t= sizeof(struct xt_tcpmss_info),\n \t\t.proto\t\t= IPPROTO_TCP,\n@@ -323,6 +333,7 @@ static struct xt_target tcpmss_tg_reg[] __read_mostly = {\n \t\t.family\t\t= NFPROTO_IPV6,\n \t\t.name\t\t= \"TCPMSS\",\n \t\t.checkentry\t= tcpmss_tg6_check,\n+\t\tNFT_COMPAT_VALIDATE(tcpmss_validate_chain)\n \t\t.target\t\t= tcpmss_tg6,\n \t\t.targetsize\t= sizeof(struct xt_tcpmss_info),\n \t\t.proto\t\t= IPPROTO_TCP,\ndiff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c\nindex a77088943107..bd1391bb0853 100644\n--- a/net/netfilter/xt_addrtype.c\n+++ b/net/netfilter/xt_addrtype.c\n@@ -153,6 +153,21 @@ addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn ret;\n }\n \n+static bool addrtype_mt_validate(const void *matchinfo, unsigned int hook_mask)\n+{\n+\tconst struct xt_addrtype_info_v1 *info = matchinfo;\n+\n+\tif (hook_mask & ((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN)) &&\n+\t info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)\n+\t\treturn false;\n+\n+\tif (hook_mask & ((1 << NF_INET_POST_ROUTING) | (1 << NF_INET_LOCAL_OUT)) &&\n+\t info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN)\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)\n {\n \tconst char *errmsg = \"both incoming and outgoing interface limitation cannot be selected\";\n@@ -162,16 +177,14 @@ static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)\n \t info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)\n \t\tgoto err;\n \n-\tif (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |\n-\t (1 << NF_INET_LOCAL_IN)) &&\n-\t info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) {\n+\tif ((info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT) &&\n+\t !addrtype_mt_validate(info, par->hook_mask)) {\n \t\terrmsg = \"output interface limitation not valid in PREROUTING and INPUT\";\n \t\tgoto err;\n \t}\n \n-\tif (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |\n-\t (1 << NF_INET_LOCAL_OUT)) &&\n-\t info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) {\n+\tif ((info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN) &&\n+\t !addrtype_mt_validate(info, par->hook_mask)) {\n \t\terrmsg = \"input interface limitation not valid in POSTROUTING and OUTPUT\";\n \t\tgoto err;\n \t}\n@@ -212,6 +225,7 @@ static struct xt_match addrtype_mt_reg[] __read_mostly = {\n \t\t.revision\t= 1,\n \t\t.match\t\t= addrtype_mt_v1,\n \t\t.checkentry\t= addrtype_mt_checkentry_v1,\n+\t\tNFT_COMPAT_VALIDATE(addrtype_mt_validate)\n \t\t.matchsize\t= sizeof(struct xt_addrtype_info_v1),\n \t\t.me\t\t= THIS_MODULE\n \t},\n@@ -222,6 +236,7 @@ static struct xt_match addrtype_mt_reg[] __read_mostly = {\n \t\t.revision\t= 1,\n \t\t.match\t\t= addrtype_mt_v1,\n \t\t.checkentry\t= addrtype_mt_checkentry_v1,\n+\t\tNFT_COMPAT_VALIDATE(addrtype_mt_validate)\n \t\t.matchsize\t= sizeof(struct xt_addrtype_info_v1),\n \t\t.me\t\t= THIS_MODULE\n \t},\ndiff --git a/net/netfilter/xt_devgroup.c b/net/netfilter/xt_devgroup.c\nindex 9520dd00070b..d6ee83554845 100644\n--- a/net/netfilter/xt_devgroup.c\n+++ b/net/netfilter/xt_devgroup.c\n@@ -33,6 +33,25 @@ static bool devgroup_mt(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn true;\n }\n \n+static bool devgroup_mt_validate(const void *matchinfo, unsigned int hook_mask)\n+{\n+\tconst struct xt_devgroup_info *info = matchinfo;\n+\n+\tif (info->flags & XT_DEVGROUP_MATCH_SRC &&\n+\t hook_mask & ~((1 << NF_INET_PRE_ROUTING) |\n+\t\t\t (1 << NF_INET_LOCAL_IN) |\n+\t\t\t (1 << NF_INET_FORWARD)))\n+\t\treturn false;\n+\n+\tif (info->flags & XT_DEVGROUP_MATCH_DST &&\n+\t hook_mask & ~((1 << NF_INET_FORWARD) |\n+\t\t\t (1 << NF_INET_LOCAL_OUT) |\n+\t\t\t (1 << NF_INET_POST_ROUTING)))\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n static int devgroup_mt_checkentry(const struct xt_mtchk_param *par)\n {\n \tconst struct xt_devgroup_info *info = par->matchinfo;\n@@ -41,16 +60,7 @@ static int devgroup_mt_checkentry(const struct xt_mtchk_param *par)\n \t\t\t XT_DEVGROUP_MATCH_DST | XT_DEVGROUP_INVERT_DST))\n \t\treturn -EINVAL;\n \n-\tif (info->flags & XT_DEVGROUP_MATCH_SRC &&\n-\t par->hook_mask & ~((1 << NF_INET_PRE_ROUTING) |\n-\t\t\t (1 << NF_INET_LOCAL_IN) |\n-\t\t\t (1 << NF_INET_FORWARD)))\n-\t\treturn -EINVAL;\n-\n-\tif (info->flags & XT_DEVGROUP_MATCH_DST &&\n-\t par->hook_mask & ~((1 << NF_INET_FORWARD) |\n-\t\t\t (1 << NF_INET_LOCAL_OUT) |\n-\t\t\t (1 << NF_INET_POST_ROUTING)))\n+\tif (!devgroup_mt_validate(info, par->hook_mask))\n \t\treturn -EINVAL;\n \n \treturn 0;\n@@ -60,6 +70,7 @@ static struct xt_match devgroup_mt_reg __read_mostly = {\n \t.name\t\t= \"devgroup\",\n \t.match\t\t= devgroup_mt,\n \t.checkentry\t= devgroup_mt_checkentry,\n+\tNFT_COMPAT_VALIDATE(devgroup_mt_validate)\n \t.matchsize\t= sizeof(struct xt_devgroup_info),\n \t.family\t\t= NFPROTO_UNSPEC,\n \t.me\t\t= THIS_MODULE\ndiff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c\nindex 343e65f377d4..27dcd7fc7427 100644\n--- a/net/netfilter/xt_physdev.c\n+++ b/net/netfilter/xt_physdev.c\n@@ -91,6 +91,20 @@ physdev_mt(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT));\n }\n \n+static bool physdev_mt_validate(const void *matchinfo, unsigned int hook_mask)\n+{\n+\tconst struct xt_physdev_info *info = matchinfo;\n+\n+\tif (info->bitmask & (XT_PHYSDEV_OP_OUT | XT_PHYSDEV_OP_ISOUT) &&\n+\t (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||\n+\t info->invert & XT_PHYSDEV_OP_BRIDGED) &&\n+\t hook_mask & (1 << NF_INET_LOCAL_OUT)) {\n+\t\treturn false;\n+\t}\n+\n+\treturn true;\n+}\n+\n static int physdev_mt_check(const struct xt_mtchk_param *par)\n {\n \tconst struct xt_physdev_info *info = par->matchinfo;\n@@ -99,10 +113,8 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)\n \tif (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||\n \t info->bitmask & ~XT_PHYSDEV_OP_MASK)\n \t\treturn -EINVAL;\n-\tif (info->bitmask & (XT_PHYSDEV_OP_OUT | XT_PHYSDEV_OP_ISOUT) &&\n-\t (!(info->bitmask & XT_PHYSDEV_OP_BRIDGED) ||\n-\t info->invert & XT_PHYSDEV_OP_BRIDGED) &&\n-\t par->hook_mask & (1 << NF_INET_LOCAL_OUT)) {\n+\n+\tif (!physdev_mt_validate(info, par->hook_mask)) {\n \t\tpr_info_ratelimited(\"--physdev-out and --physdev-is-out only supported in the FORWARD and POSTROUTING chains with bridged traffic\\n\");\n \t\treturn -EINVAL;\n \t}\n@@ -120,6 +132,7 @@ static struct xt_match physdev_mt_reg __read_mostly = {\n \t.revision = 0,\n \t.family = NFPROTO_UNSPEC,\n \t.checkentry = physdev_mt_check,\n+\tNFT_COMPAT_VALIDATE(physdev_mt_validate)\n \t.match = physdev_mt,\n \t.matchsize = sizeof(struct xt_physdev_info),\n \t.me = THIS_MODULE,\ndiff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c\nindex cb6e8279010a..826727ca843c 100644\n--- a/net/netfilter/xt_policy.c\n+++ b/net/netfilter/xt_policy.c\n@@ -126,6 +126,20 @@ policy_mt(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn ret;\n }\n \n+static bool policy_mt_validate(const void *matchinfo, unsigned int hook_mask)\n+{\n+\tconst struct xt_policy_info *info = matchinfo;\n+\n+\tif (hook_mask & ((1 << NF_INET_PRE_ROUTING) |\n+\t (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT)\n+\t\treturn false;\n+\tif (hook_mask & ((1 << NF_INET_POST_ROUTING) |\n+\t (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN)\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n static int policy_mt_check(const struct xt_mtchk_param *par)\n {\n \tconst struct xt_policy_info *info = par->matchinfo;\n@@ -134,13 +148,13 @@ static int policy_mt_check(const struct xt_mtchk_param *par)\n \tif (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))\n \t\tgoto err;\n \n-\tif (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |\n-\t (1 << NF_INET_LOCAL_IN)) && info->flags & XT_POLICY_MATCH_OUT) {\n+\tif ((info->flags & XT_POLICY_MATCH_OUT) &&\n+\t !policy_mt_validate(info, par->hook_mask)) {\n \t\terrmsg = \"output policy not valid in PREROUTING and INPUT\";\n \t\tgoto err;\n \t}\n-\tif (par->hook_mask & ((1 << NF_INET_POST_ROUTING) |\n-\t (1 << NF_INET_LOCAL_OUT)) && info->flags & XT_POLICY_MATCH_IN) {\n+\tif ((info->flags & XT_POLICY_MATCH_IN) &&\n+\t !policy_mt_validate(info, par->hook_mask)) {\n \t\terrmsg = \"input policy not valid in POSTROUTING and OUTPUT\";\n \t\tgoto err;\n \t}\n@@ -159,6 +173,7 @@ static struct xt_match policy_mt_reg[] __read_mostly = {\n \t\t.name\t\t= \"policy\",\n \t\t.family\t\t= NFPROTO_IPV4,\n \t\t.checkentry \t= policy_mt_check,\n+\t\tNFT_COMPAT_VALIDATE(policy_mt_validate)\n \t\t.match\t\t= policy_mt,\n \t\t.matchsize\t= sizeof(struct xt_policy_info),\n \t\t.me\t\t= THIS_MODULE,\n@@ -167,6 +182,7 @@ static struct xt_match policy_mt_reg[] __read_mostly = {\n \t\t.name\t\t= \"policy\",\n \t\t.family\t\t= NFPROTO_IPV6,\n \t\t.checkentry\t= policy_mt_check,\n+\t\tNFT_COMPAT_VALIDATE(policy_mt_validate)\n \t\t.match\t\t= policy_mt,\n \t\t.matchsize\t= sizeof(struct xt_policy_info),\n \t\t.me\t\t= THIS_MODULE,\ndiff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c\nindex 731bc2cafae4..a4ff80fd0223 100644\n--- a/net/netfilter/xt_set.c\n+++ b/net/netfilter/xt_set.c\n@@ -430,6 +430,20 @@ set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)\n \treturn XT_CONTINUE;\n }\n \n+static bool set_target_v3_validate(const void *targinfo, unsigned int hook_mask)\n+{\n+\tconst struct xt_set_info_target_v3 *info = targinfo;\n+\n+\tif (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |\n+\t (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&\n+\t (hook_mask & ~(1 << NF_INET_FORWARD |\n+\t\t\t 1 << NF_INET_LOCAL_OUT |\n+\t\t\t 1 << NF_INET_POST_ROUTING)))\n+\t\treturn false;\n+\n+\treturn true;\n+}\n+\n static int\n set_target_v3_checkentry(const struct xt_tgchk_param *par)\n {\n@@ -464,11 +478,7 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)\n \t\t\tret = -EINVAL;\n \t\t\tgoto cleanup_del;\n \t\t}\n-\t\tif (((info->flags & IPSET_FLAG_MAP_SKBPRIO) |\n-\t\t (info->flags & IPSET_FLAG_MAP_SKBQUEUE)) &&\n-\t\t (par->hook_mask & ~(1 << NF_INET_FORWARD |\n-\t\t\t\t\t 1 << NF_INET_LOCAL_OUT |\n-\t\t\t\t\t 1 << NF_INET_POST_ROUTING))) {\n+\t\tif (!set_target_v3_validate(info, par->hook_mask)) {\n \t\t\tpr_info_ratelimited(\"mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\\n\");\n \t\t\tret = -EINVAL;\n \t\t\tgoto cleanup_del;\n@@ -673,6 +683,7 @@ static struct xt_target set_targets[] __read_mostly = {\n \t\t.target\t\t= set_target_v3,\n \t\t.targetsize\t= sizeof(struct xt_set_info_target_v3),\n \t\t.checkentry\t= set_target_v3_checkentry,\n+\t\tNFT_COMPAT_VALIDATE(set_target_v3_validate)\n \t\t.destroy\t= set_target_v3_destroy,\n \t\t.me\t\t= THIS_MODULE\n \t},\n@@ -683,6 +694,7 @@ static struct xt_target set_targets[] __read_mostly = {\n \t\t.target\t\t= set_target_v3,\n \t\t.targetsize\t= sizeof(struct xt_set_info_target_v3),\n \t\t.checkentry\t= set_target_v3_checkentry,\n+\t\tNFT_COMPAT_VALIDATE(set_target_v3_validate)\n \t\t.destroy\t= set_target_v3_destroy,\n \t\t.me\t\t= THIS_MODULE\n \t},\n", "prefixes": [ "nf" ] }