Эх сурвалжийг харах

netfilter: nf_tables: restrict nat/masq expressions to nat chain type

This adds the missing validation code to avoid the use of nat/masq from
non-nat chains. The validation assumes two possible configuration
scenarios:

1) Use of nat from base chain that is not of nat type. Reject this
   configuration from the nft_*_init() path of the expression.

2) Use of nat from non-base chain. In this case, we have to wait until
   the non-base chain is referenced by at least one base chain via
   jump/goto. This is resolved from the nft_*_validate() path which is
   called from nf_tables_check_loops().

The user gets an -EOPNOTSUPP in both cases.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Pablo Neira Ayuso 10 жил өмнө
parent
commit
7210e4e38f

+ 3 - 0
include/net/netfilter/nf_tables.h

@@ -530,6 +530,9 @@ enum nft_chain_type {
 	NFT_CHAIN_T_MAX
 	NFT_CHAIN_T_MAX
 };
 };
 
 
+int nft_chain_validate_dependency(const struct nft_chain *chain,
+				  enum nft_chain_type type);
+
 struct nft_stats {
 struct nft_stats {
 	u64			bytes;
 	u64			bytes;
 	u64			pkts;
 	u64			pkts;

+ 3 - 0
include/net/netfilter/nft_masq.h

@@ -13,4 +13,7 @@ int nft_masq_init(const struct nft_ctx *ctx,
 
 
 int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr);
 int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr);
 
 
+int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
+		      const struct nft_data **data);
+
 #endif /* _NFT_MASQ_H_ */
 #endif /* _NFT_MASQ_H_ */

+ 1 - 0
net/ipv4/netfilter/nft_masq_ipv4.c

@@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv4_ops = {
 	.eval		= nft_masq_ipv4_eval,
 	.eval		= nft_masq_ipv4_eval,
 	.init		= nft_masq_init,
 	.init		= nft_masq_init,
 	.dump		= nft_masq_dump,
 	.dump		= nft_masq_dump,
+	.validate	= nft_masq_validate,
 };
 };
 
 
 static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {
 static struct nft_expr_type nft_masq_ipv4_type __read_mostly = {

+ 1 - 0
net/ipv6/netfilter/nft_masq_ipv6.c

@@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv6_ops = {
 	.eval		= nft_masq_ipv6_eval,
 	.eval		= nft_masq_ipv6_eval,
 	.init		= nft_masq_init,
 	.init		= nft_masq_init,
 	.dump		= nft_masq_dump,
 	.dump		= nft_masq_dump,
+	.validate	= nft_masq_validate,
 };
 };
 
 
 static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {
 static struct nft_expr_type nft_masq_ipv6_type __read_mostly = {

+ 14 - 0
net/netfilter/nf_tables_api.c

@@ -3744,6 +3744,20 @@ static const struct nfnetlink_subsystem nf_tables_subsys = {
 	.abort		= nf_tables_abort,
 	.abort		= nf_tables_abort,
 };
 };
 
 
+int nft_chain_validate_dependency(const struct nft_chain *chain,
+				  enum nft_chain_type type)
+{
+	const struct nft_base_chain *basechain;
+
+	if (chain->flags & NFT_BASE_CHAIN) {
+		basechain = nft_base_chain(chain);
+		if (basechain->type->type != type)
+			return -EOPNOTSUPP;
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nft_chain_validate_dependency);
+
 /*
 /*
  * Loop detection - walk through the ruleset beginning at the destination chain
  * Loop detection - walk through the ruleset beginning at the destination chain
  * of a new jump until either the source chain is reached (loop) or all
  * of a new jump until either the source chain is reached (loop) or all

+ 12 - 0
net/netfilter/nft_masq.c

@@ -26,6 +26,11 @@ int nft_masq_init(const struct nft_ctx *ctx,
 		  const struct nlattr * const tb[])
 		  const struct nlattr * const tb[])
 {
 {
 	struct nft_masq *priv = nft_expr_priv(expr);
 	struct nft_masq *priv = nft_expr_priv(expr);
+	int err;
+
+	err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+	if (err < 0)
+		return err;
 
 
 	if (tb[NFTA_MASQ_FLAGS] == NULL)
 	if (tb[NFTA_MASQ_FLAGS] == NULL)
 		return 0;
 		return 0;
@@ -55,5 +60,12 @@ nla_put_failure:
 }
 }
 EXPORT_SYMBOL_GPL(nft_masq_dump);
 EXPORT_SYMBOL_GPL(nft_masq_dump);
 
 
+int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr,
+		      const struct nft_data **data)
+{
+	return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+}
+EXPORT_SYMBOL_GPL(nft_masq_validate);
+
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");
 MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>");

+ 12 - 0
net/netfilter/nft_nat.c

@@ -95,6 +95,10 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
 	u32 family;
 	u32 family;
 	int err;
 	int err;
 
 
+	err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+	if (err < 0)
+		return err;
+
 	if (tb[NFTA_NAT_TYPE] == NULL)
 	if (tb[NFTA_NAT_TYPE] == NULL)
 		return -EINVAL;
 		return -EINVAL;
 
 
@@ -205,6 +209,13 @@ nla_put_failure:
 	return -1;
 	return -1;
 }
 }
 
 
+static int nft_nat_validate(const struct nft_ctx *ctx,
+			    const struct nft_expr *expr,
+			    const struct nft_data **data)
+{
+	return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT);
+}
+
 static struct nft_expr_type nft_nat_type;
 static struct nft_expr_type nft_nat_type;
 static const struct nft_expr_ops nft_nat_ops = {
 static const struct nft_expr_ops nft_nat_ops = {
 	.type           = &nft_nat_type,
 	.type           = &nft_nat_type,
@@ -212,6 +223,7 @@ static const struct nft_expr_ops nft_nat_ops = {
 	.eval           = nft_nat_eval,
 	.eval           = nft_nat_eval,
 	.init           = nft_nat_init,
 	.init           = nft_nat_init,
 	.dump           = nft_nat_dump,
 	.dump           = nft_nat_dump,
+	.validate	= nft_nat_validate,
 };
 };
 
 
 static struct nft_expr_type nft_nat_type __read_mostly = {
 static struct nft_expr_type nft_nat_type __read_mostly = {