{"id":2230047,"url":"http://patchwork.ozlabs.org/api/1.1/patches/2230047/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/patch/20260429055529.104504-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":"<20260429055529.104504-1-pablo@netfilter.org>","date":"2026-04-29T05:55:28","name":"[nf,v2,1/2] netfilter: x_tables: add .check_hooks to matches and targets","commit_ref":null,"pull_url":null,"state":"superseded","archived":false,"hash":"796a2f57417cca9264fe7fe3dfe150863bc9bf7a","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/20260429055529.104504-1-pablo@netfilter.org/mbox/","series":[{"id":501988,"url":"http://patchwork.ozlabs.org/api/1.1/series/501988/?format=json","web_url":"http://patchwork.ozlabs.org/project/netfilter-devel/list/?series=501988","date":"2026-04-29T05:55:29","name":"[nf,v2,1/2] netfilter: x_tables: add .check_hooks to matches and targets","version":2,"mbox":"http://patchwork.ozlabs.org/series/501988/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2230047/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2230047/checks/","tags":{},"headers":{"Return-Path":"\n <netfilter-devel+bounces-12281-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=lwhGbvMH;\n\tdkim-atps=neutral","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-12281-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=\"lwhGbvMH\"","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 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)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g56493R5dz1yHX\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 15:56:09 +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 90050303A13D\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 29 Apr 2026 05:55:40 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id CEF0633E360;\n\tWed, 29 Apr 2026 05:55:39 +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 19118283C83\n\tfor <netfilter-devel@vger.kernel.org>; Wed, 29 Apr 2026 05:55:35 +0000 (UTC)","from localhost.localdomain (mail-agni [217.70.190.124])\n\tby mail.netfilter.org (Postfix) with ESMTPSA id E102B600B5;\n\tWed, 29 Apr 2026 07:55:32 +0200 (CEST)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1777442139; cv=none;\n b=h2yI4sUgfyY68Sr7JExyPYURu4EWTGR5bP5BdumD5Gma6ALolRVRf3xPyfzi/zVfHBteovUA1zlAhoaW+eypQVY8AlGYjP4lE1Q8cWw8/4+zUw4lsjxRHGCtRlhelBpa0kVy6zRpfoghC+Nk3MBG3rJHZOisU5B7vs+1/wMX5HM=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1777442139; c=relaxed/simple;\n\tbh=4DY6aBOxbVPVjH5YOie67bCJcYdryD0cNG8kT7VJBLY=;\n\th=From:To:Cc:Subject:Date:Message-ID:MIME-Version;\n b=U4ZNfvpSDfIWHvuCRm/Uv9C+GnzxgG9GxpuM2ovSevMDshjwCkq8BVgoUYBLPZhXdGenG3uaUHaWBEKhfLACZk6j35T7DhQyzgGQCJLHpyyBlv3zq1WUXlfcOKQ2VDSrOjSUv5BVw/BIwCes7yLxdbZaJ+KCoo34wTDMf34uyFs=","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=lwhGbvMH; 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=1777442133;\n\tbh=0GNWNfZMKYLYgBzO49OCCDOzQGPPFsIUQV5/Yk0xTwM=;\n\th=From:To:Cc:Subject:Date:From;\n\tb=lwhGbvMHmOY0IQqm4GgRIdXyCgwDM88+eQbmnkOksecrIzQjhx9rDmgtqOLDQ/QWx\n\t l1Qh3n4oq0hfLVR4K/qrbRHAzRtthscoiMg3URPGf5QThiRpotICmytBlIgDpHphB0\n\t FivKPX1x9mvr+sBdW/FhLuHJxOF9dyxxmg3Tt3dCuJF+r0sd48dtMyfcs4nE4iUB2+\n\t Uq9IVRgzZ0F9JnI1NOr88BaqBKqQYCA5U1z0uFj5w68Xtt5S7pK2HefZA8MB73SuQ6\n\t 7qThlRsdRxUnMMc85AQ45CKEYc5QzjYu7tIFR8M6lWw3IqxcdsEuelgy3WbyBnv6l2\n\t M6urUAe077c6w==","From":"Pablo Neira Ayuso <pablo@netfilter.org>","To":"netfilter-devel@vger.kernel.org","Cc":"fw@strlen.de","Subject":"[PATCH nf,v2 1/2] netfilter: x_tables: add .check_hooks to matches\n and targets","Date":"Wed, 29 Apr 2026 07:55:28 +0200","Message-ID":"<20260429055529.104504-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":"Add a new .check_hooks interface for checking if the match/target is\nused from the validate hook according to its configuration.\n\nMove existing conditional hook check based on the match/target\nconfiguration from .checkentry to .check_hooks for the following\nmatches/targets:\n\n- addrtype\n- devgroup\n- physdev\n- policy\n- set\n- TCPMSS\n- SET\n\nThis is a preparation patch to fix nft_compat, not functional changes\nare intended.\n\nBased on patch from Florian Westphal.\n\nSigned-off-by: Pablo Neira Ayuso <pablo@netfilter.org>\n---\nv2: missing .check_hooks for xt_policy.\n\n include/linux/netfilter/x_tables.h |  8 +++\n net/netfilter/x_tables.c           | 79 +++++++++++++++++++++++++++---\n net/netfilter/xt_TCPMSS.c          | 33 +++++++------\n net/netfilter/xt_addrtype.c        | 25 +++++++---\n net/netfilter/xt_devgroup.c        | 18 +++++--\n net/netfilter/xt_physdev.c         | 20 ++++++--\n net/netfilter/xt_policy.c          | 24 +++++++--\n net/netfilter/xt_set.c             | 39 +++++++++------\n 8 files changed, 187 insertions(+), 59 deletions(-)","diff":"diff --git a/include/linux/netfilter/x_tables.h b/include/linux/netfilter/x_tables.h\nindex 77c778d84d4c..a81b46af5118 100644\n--- a/include/linux/netfilter/x_tables.h\n+++ b/include/linux/netfilter/x_tables.h\n@@ -146,6 +146,9 @@ 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+\t/* Called to validate hooks based on the match configuration. */\n+\tint (*check_hooks)(const struct xt_mtchk_param *);\n+\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 +190,9 @@ 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+\t/* Called to validate hooks based on the target configuration. */\n+\tint (*check_hooks)(const struct xt_tgchk_param *);\n+\n \t/* Called when entry of this type deleted. */\n \tvoid (*destroy)(const struct xt_tgdtor_param *);\n #ifdef CONFIG_NETFILTER_XTABLES_COMPAT\n@@ -279,8 +285,10 @@ bool xt_find_jump_offset(const unsigned int *offsets,\n \n int xt_check_proc_name(const char *name, unsigned int size);\n \n+int xt_check_hooks_match(struct xt_mtchk_param *par);\n int xt_check_match(struct xt_mtchk_param *, unsigned int size, u16 proto,\n \t\t   bool inv_proto);\n+int xt_check_hooks_target(struct xt_tgchk_param *par);\n int xt_check_target(struct xt_tgchk_param *, unsigned int size, u16 proto,\n \t\t    bool inv_proto);\n \ndiff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c\nindex 9f837fb5ceb4..2c67c2e6b132 100644\n--- a/net/netfilter/x_tables.c\n+++ b/net/netfilter/x_tables.c\n@@ -477,11 +477,9 @@ int xt_check_proc_name(const char *name, unsigned int size)\n }\n EXPORT_SYMBOL(xt_check_proc_name);\n \n-int xt_check_match(struct xt_mtchk_param *par,\n-\t\t   unsigned int size, u16 proto, bool inv_proto)\n+static int xt_check_match_common(struct xt_mtchk_param *par,\n+\t\t\t\t unsigned int size, u16 proto, bool inv_proto)\n {\n-\tint ret;\n-\n \tif (XT_ALIGN(par->match->matchsize) != size &&\n \t    par->match->matchsize != -1) {\n \t\t/*\n@@ -530,6 +528,14 @@ int xt_check_match(struct xt_mtchk_param *par,\n \t\t\t\t    par->match->proto);\n \t\treturn -EINVAL;\n \t}\n+\n+\treturn 0;\n+}\n+\n+static int xt_checkentry_match(struct xt_mtchk_param *par)\n+{\n+\tint ret;\n+\n \tif (par->match->checkentry != NULL) {\n \t\tret = par->match->checkentry(par);\n \t\tif (ret < 0)\n@@ -538,8 +544,34 @@ int xt_check_match(struct xt_mtchk_param *par,\n \t\t\t/* Flag up potential errors. */\n \t\t\treturn -EIO;\n \t}\n+\n+\treturn 0;\n+}\n+\n+int xt_check_hooks_match(struct xt_mtchk_param *par)\n+{\n+\tif (par->match->check_hooks != NULL)\n+\t\treturn par->match->check_hooks(par);\n+\n \treturn 0;\n }\n+EXPORT_SYMBOL_GPL(xt_check_hooks_match);\n+\n+int xt_check_match(struct xt_mtchk_param *par,\n+\t\t   unsigned int size, u16 proto, bool inv_proto)\n+{\n+\tint ret;\n+\n+\tret = xt_check_match_common(par, size, proto, inv_proto);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = xt_check_hooks_match(par);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\treturn xt_checkentry_match(par);\n+}\n EXPORT_SYMBOL_GPL(xt_check_match);\n \n /** xt_check_entry_match - check that matches end before start of target\n@@ -1012,11 +1044,9 @@ bool xt_find_jump_offset(const unsigned int *offsets,\n }\n EXPORT_SYMBOL(xt_find_jump_offset);\n \n-int xt_check_target(struct xt_tgchk_param *par,\n-\t\t    unsigned int size, u16 proto, bool inv_proto)\n+static int xt_check_target_common(struct xt_tgchk_param *par,\n+\t\t\t\t  unsigned int size, u16 proto, bool inv_proto)\n {\n-\tint ret;\n-\n \tif (XT_ALIGN(par->target->targetsize) != size) {\n \t\tpr_err_ratelimited(\"%s_tables: %s.%u target: invalid size %u (kernel) != (user) %u\\n\",\n \t\t\t\t   xt_prefix[par->family], par->target->name,\n@@ -1061,6 +1091,23 @@ int xt_check_target(struct xt_tgchk_param *par,\n \t\t\t\t    par->target->proto);\n \t\treturn -EINVAL;\n \t}\n+\n+\treturn 0;\n+}\n+\n+int xt_check_hooks_target(struct xt_tgchk_param *par)\n+{\n+\tif (par->target->check_hooks != NULL)\n+\t\treturn par->target->check_hooks(par);\n+\n+\treturn 0;\n+}\n+EXPORT_SYMBOL_GPL(xt_check_hooks_target);\n+\n+static int xt_checkentry_target(struct xt_tgchk_param *par)\n+{\n+\tint ret;\n+\n \tif (par->target->checkentry != NULL) {\n \t\tret = par->target->checkentry(par);\n \t\tif (ret < 0)\n@@ -1071,6 +1118,22 @@ int xt_check_target(struct xt_tgchk_param *par,\n \t}\n \treturn 0;\n }\n+\n+int xt_check_target(struct xt_tgchk_param *par,\n+\t\t    unsigned int size, u16 proto, bool inv_proto)\n+{\n+\tint ret;\n+\n+\tret = xt_check_target_common(par, size, proto, inv_proto);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\tret = xt_check_hooks_target(par);\n+\tif (ret < 0)\n+\t\treturn ret;\n+\n+\treturn xt_checkentry_target(par);\n+}\n EXPORT_SYMBOL_GPL(xt_check_target);\n \n /**\ndiff --git a/net/netfilter/xt_TCPMSS.c b/net/netfilter/xt_TCPMSS.c\nindex 116a885adb3c..80e1634bc51f 100644\n--- a/net/netfilter/xt_TCPMSS.c\n+++ b/net/netfilter/xt_TCPMSS.c\n@@ -247,6 +247,21 @@ tcpmss_tg6(struct sk_buff *skb, const struct xt_action_param *par)\n }\n #endif\n \n+static int tcpmss_tg4_check_hooks(const struct xt_tgchk_param *par)\n+{\n+\tconst struct xt_tcpmss_info *info = par->targinfo;\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\tpr_info_ratelimited(\"path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\\n\");\n+\t\treturn -EINVAL;\n+\t}\n+\n+\treturn 0;\n+}\n+\n /* Must specify -p tcp --syn */\n static inline bool find_syn_match(const struct xt_entry_match *m)\n {\n@@ -262,17 +277,9 @@ static inline bool find_syn_match(const struct xt_entry_match *m)\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-\t\tpr_info_ratelimited(\"path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\\n\");\n-\t\treturn -EINVAL;\n-\t}\n \tif (par->nft_compat)\n \t\treturn 0;\n \n@@ -286,17 +293,9 @@ static int tcpmss_tg4_check(const struct xt_tgchk_param *par)\n #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)\n static int tcpmss_tg6_check(const struct xt_tgchk_param *par)\n {\n-\tconst struct xt_tcpmss_info *info = par->targinfo;\n \tconst struct ip6t_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-\t\tpr_info_ratelimited(\"path-MTU clamping only supported in FORWARD, OUTPUT and POSTROUTING hooks\\n\");\n-\t\treturn -EINVAL;\n-\t}\n \tif (par->nft_compat)\n \t\treturn 0;\n \n@@ -312,6 +311,7 @@ static struct xt_target tcpmss_tg_reg[] __read_mostly = {\n \t{\n \t\t.family\t\t= NFPROTO_IPV4,\n \t\t.name\t\t= \"TCPMSS\",\n+\t\t.check_hooks\t= tcpmss_tg4_check_hooks,\n \t\t.checkentry\t= tcpmss_tg4_check,\n \t\t.target\t\t= tcpmss_tg4,\n \t\t.targetsize\t= sizeof(struct xt_tcpmss_info),\n@@ -322,6 +322,7 @@ static struct xt_target tcpmss_tg_reg[] __read_mostly = {\n \t{\n \t\t.family\t\t= NFPROTO_IPV6,\n \t\t.name\t\t= \"TCPMSS\",\n+\t\t.check_hooks\t= tcpmss_tg4_check_hooks,\n \t\t.checkentry\t= tcpmss_tg6_check,\n \t\t.target\t\t= tcpmss_tg6,\n \t\t.targetsize\t= sizeof(struct xt_tcpmss_info),\ndiff --git a/net/netfilter/xt_addrtype.c b/net/netfilter/xt_addrtype.c\nindex a77088943107..913dbe3aa5e2 100644\n--- a/net/netfilter/xt_addrtype.c\n+++ b/net/netfilter/xt_addrtype.c\n@@ -153,14 +153,10 @@ addrtype_mt_v1(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn ret;\n }\n \n-static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)\n+static int addrtype_mt_check_hooks(const struct xt_mtchk_param *par)\n {\n-\tconst char *errmsg = \"both incoming and outgoing interface limitation cannot be selected\";\n \tstruct xt_addrtype_info_v1 *info = par->matchinfo;\n-\n-\tif (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&\n-\t    info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)\n-\t\tgoto err;\n+\tconst char *errmsg;\n \n \tif (par->hook_mask & ((1 << NF_INET_PRE_ROUTING) |\n \t    (1 << NF_INET_LOCAL_IN)) &&\n@@ -176,6 +172,21 @@ static int addrtype_mt_checkentry_v1(const struct xt_mtchk_param *par)\n \t\tgoto err;\n \t}\n \n+\treturn 0;\n+err:\n+\tpr_info_ratelimited(\"%s\\n\", errmsg);\n+\treturn -EINVAL;\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+\tstruct xt_addrtype_info_v1 *info = par->matchinfo;\n+\n+\tif (info->flags & XT_ADDRTYPE_LIMIT_IFACE_IN &&\n+\t    info->flags & XT_ADDRTYPE_LIMIT_IFACE_OUT)\n+\t\tgoto err;\n+\n #if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)\n \tif (par->family == NFPROTO_IPV6) {\n \t\tif ((info->source | info->dest) & XT_ADDRTYPE_BLACKHOLE) {\n@@ -211,6 +222,7 @@ static struct xt_match addrtype_mt_reg[] __read_mostly = {\n \t\t.family\t\t= NFPROTO_IPV4,\n \t\t.revision\t= 1,\n \t\t.match\t\t= addrtype_mt_v1,\n+\t\t.check_hooks\t= addrtype_mt_check_hooks,\n \t\t.checkentry\t= addrtype_mt_checkentry_v1,\n \t\t.matchsize\t= sizeof(struct xt_addrtype_info_v1),\n \t\t.me\t\t= THIS_MODULE\n@@ -221,6 +233,7 @@ static struct xt_match addrtype_mt_reg[] __read_mostly = {\n \t\t.family\t\t= NFPROTO_IPV6,\n \t\t.revision\t= 1,\n \t\t.match\t\t= addrtype_mt_v1,\n+\t\t.check_hooks\t= addrtype_mt_check_hooks,\n \t\t.checkentry\t= addrtype_mt_checkentry_v1,\n \t\t.matchsize\t= sizeof(struct xt_addrtype_info_v1),\n \t\t.me\t\t= THIS_MODULE\ndiff --git a/net/netfilter/xt_devgroup.c b/net/netfilter/xt_devgroup.c\nindex 9520dd00070b..6d1a44ab5eee 100644\n--- a/net/netfilter/xt_devgroup.c\n+++ b/net/netfilter/xt_devgroup.c\n@@ -33,14 +33,10 @@ static bool devgroup_mt(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn true;\n }\n \n-static int devgroup_mt_checkentry(const struct xt_mtchk_param *par)\n+static int devgroup_mt_check_hooks(const struct xt_mtchk_param *par)\n {\n \tconst struct xt_devgroup_info *info = par->matchinfo;\n \n-\tif (info->flags & ~(XT_DEVGROUP_MATCH_SRC | XT_DEVGROUP_INVERT_SRC |\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@@ -56,9 +52,21 @@ static int devgroup_mt_checkentry(const struct xt_mtchk_param *par)\n \treturn 0;\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+\n+\tif (info->flags & ~(XT_DEVGROUP_MATCH_SRC | XT_DEVGROUP_INVERT_SRC |\n+\t\t\t    XT_DEVGROUP_MATCH_DST | XT_DEVGROUP_INVERT_DST))\n+\t\treturn -EINVAL;\n+\n+\treturn 0;\n+}\n+\n static struct xt_match devgroup_mt_reg __read_mostly = {\n \t.name\t\t= \"devgroup\",\n \t.match\t\t= devgroup_mt,\n+\t.check_hooks\t= devgroup_mt_check_hooks,\n \t.checkentry\t= devgroup_mt_checkentry,\n \t.matchsize\t= sizeof(struct xt_devgroup_info),\n \t.family\t\t= NFPROTO_UNSPEC,\ndiff --git a/net/netfilter/xt_physdev.c b/net/netfilter/xt_physdev.c\nindex d2b0b52434fa..dd98f758176c 100644\n--- a/net/netfilter/xt_physdev.c\n+++ b/net/netfilter/xt_physdev.c\n@@ -91,14 +91,10 @@ 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 int physdev_mt_check(const struct xt_mtchk_param *par)\n+static int physdev_mt_check_hooks(const struct xt_mtchk_param *par)\n {\n \tconst struct xt_physdev_info *info = par->matchinfo;\n-\tstatic bool brnf_probed __read_mostly;\n \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@@ -107,6 +103,18 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)\n \t\treturn -EINVAL;\n \t}\n \n+\treturn 0;\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+\tstatic bool brnf_probed __read_mostly;\n+\n+\tif (!(info->bitmask & XT_PHYSDEV_OP_MASK) ||\n+\t    info->bitmask & ~XT_PHYSDEV_OP_MASK)\n+\t\treturn -EINVAL;\n+\n #define X(memb) strnlen(info->memb, sizeof(info->memb)) >= sizeof(info->memb)\n \tif (info->bitmask & XT_PHYSDEV_OP_IN) {\n \t\tif (info->physindev[0] == '\\0')\n@@ -141,6 +149,7 @@ static struct xt_match physdev_mt_reg[] __read_mostly = {\n \t{\n \t\t.name\t\t= \"physdev\",\n \t\t.family\t\t= NFPROTO_IPV4,\n+\t\t.check_hooks\t= physdev_mt_check_hooks,\n \t\t.checkentry\t= physdev_mt_check,\n \t\t.match\t\t= physdev_mt,\n \t\t.matchsize\t= sizeof(struct xt_physdev_info),\n@@ -149,6 +158,7 @@ static struct xt_match physdev_mt_reg[] __read_mostly = {\n \t{\n \t\t.name\t\t= \"physdev\",\n \t\t.family\t\t= NFPROTO_IPV6,\n+\t\t.check_hooks\t= physdev_mt_check_hooks,\n \t\t.checkentry\t= physdev_mt_check,\n \t\t.match\t\t= physdev_mt,\n \t\t.matchsize\t= sizeof(struct xt_physdev_info),\ndiff --git a/net/netfilter/xt_policy.c b/net/netfilter/xt_policy.c\nindex b5fa65558318..ff54e3a8581e 100644\n--- a/net/netfilter/xt_policy.c\n+++ b/net/netfilter/xt_policy.c\n@@ -126,13 +126,10 @@ policy_mt(const struct sk_buff *skb, struct xt_action_param *par)\n \treturn ret;\n }\n \n-static int policy_mt_check(const struct xt_mtchk_param *par)\n+static int policy_mt_check_hooks(const struct xt_mtchk_param *par)\n {\n \tconst struct xt_policy_info *info = par->matchinfo;\n-\tconst char *errmsg = \"neither incoming nor outgoing policy selected\";\n-\n-\tif (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))\n-\t\tgoto err;\n+\tconst char *errmsg;\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@@ -144,6 +141,21 @@ static int policy_mt_check(const struct xt_mtchk_param *par)\n \t\terrmsg = \"input policy not valid in POSTROUTING and OUTPUT\";\n \t\tgoto err;\n \t}\n+\n+\treturn 0;\n+err:\n+\tpr_info_ratelimited(\"%s\\n\", errmsg);\n+\treturn -EINVAL;\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+\tconst char *errmsg = \"neither incoming nor outgoing policy selected\";\n+\n+\tif (!(info->flags & (XT_POLICY_MATCH_IN|XT_POLICY_MATCH_OUT)))\n+\t\tgoto err;\n+\n \tif (info->len > XT_POLICY_MAX_ELEM) {\n \t\terrmsg = \"too many policy elements\";\n \t\tgoto err;\n@@ -158,6 +170,7 @@ static struct xt_match policy_mt_reg[] __read_mostly = {\n \t{\n \t\t.name\t\t= \"policy\",\n \t\t.family\t\t= NFPROTO_IPV4,\n+\t\t.check_hooks\t= policy_mt_check_hooks,\n \t\t.checkentry \t= policy_mt_check,\n \t\t.match\t\t= policy_mt,\n \t\t.matchsize\t= sizeof(struct xt_policy_info),\n@@ -166,6 +179,7 @@ static struct xt_match policy_mt_reg[] __read_mostly = {\n \t{\n \t\t.name\t\t= \"policy\",\n \t\t.family\t\t= NFPROTO_IPV6,\n+\t\t.check_hooks\t= policy_mt_check_hooks,\n \t\t.checkentry\t= policy_mt_check,\n \t\t.match\t\t= policy_mt,\n \t\t.matchsize\t= sizeof(struct xt_policy_info),\ndiff --git a/net/netfilter/xt_set.c b/net/netfilter/xt_set.c\nindex 731bc2cafae4..4ae04bba9358 100644\n--- a/net/netfilter/xt_set.c\n+++ b/net/netfilter/xt_set.c\n@@ -430,6 +430,29 @@ set_target_v3(struct sk_buff *skb, const struct xt_action_param *par)\n \treturn XT_CONTINUE;\n }\n \n+static int\n+set_target_v3_check_hooks(const struct xt_tgchk_param *par)\n+{\n+\tconst struct xt_set_info_target_v3 *info = par->targinfo;\n+\n+\tif (info->map_set.index != IPSET_INVALID_ID) {\n+\t\tif (strncmp(par->table, \"mangle\", 7)) {\n+\t\t\tpr_info_ratelimited(\"--map-set only usable from mangle table\\n\");\n+\t\t\treturn -EINVAL;\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\t\tpr_info_ratelimited(\"mapping of prio or/and queue is allowed only from OUTPUT/FORWARD/POSTROUTING chains\\n\");\n+\t\t\treturn -EINVAL;\n+\t\t}\n+\t}\n+\n+\treturn 0;\n+}\n+\n static int\n set_target_v3_checkentry(const struct xt_tgchk_param *par)\n {\n@@ -459,20 +482,6 @@ set_target_v3_checkentry(const struct xt_tgchk_param *par)\n \t}\n \n \tif (info->map_set.index != IPSET_INVALID_ID) {\n-\t\tif (strncmp(par->table, \"mangle\", 7)) {\n-\t\t\tpr_info_ratelimited(\"--map-set only usable from mangle table\\n\");\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\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-\t\t}\n \t\tindex = ip_set_nfnl_get_byindex(par->net,\n \t\t\t\t\t\tinfo->map_set.index);\n \t\tif (index == IPSET_INVALID_ID) {\n@@ -672,6 +681,7 @@ static struct xt_target set_targets[] __read_mostly = {\n \t\t.family\t\t= NFPROTO_IPV4,\n \t\t.target\t\t= set_target_v3,\n \t\t.targetsize\t= sizeof(struct xt_set_info_target_v3),\n+\t\t.check_hooks\t= set_target_v3_check_hooks,\n \t\t.checkentry\t= set_target_v3_checkentry,\n \t\t.destroy\t= set_target_v3_destroy,\n \t\t.me\t\t= THIS_MODULE\n@@ -682,6 +692,7 @@ static struct xt_target set_targets[] __read_mostly = {\n \t\t.family\t\t= NFPROTO_IPV6,\n \t\t.target\t\t= set_target_v3,\n \t\t.targetsize\t= sizeof(struct xt_set_info_target_v3),\n+\t\t.check_hooks\t= set_target_v3_check_hooks,\n \t\t.checkentry\t= set_target_v3_checkentry,\n \t\t.destroy\t= set_target_v3_destroy,\n \t\t.me\t\t= THIS_MODULE\n","prefixes":["nf","v2","1/2"]}