diff options
| author | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-10-13 13:50:22 -0400 |
|---|---|---|
| committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2014-10-13 14:42:00 -0400 |
| commit | 7210e4e38f945dfa173c4a4e59ad827c9ecad541 (patch) | |
| tree | f86826588257abd66235761163e113bfdd82594f | |
| parent | ab2d7251d666995740da17b2a51ca545ac5dd037 (diff) | |
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>
| -rw-r--r-- | include/net/netfilter/nf_tables.h | 3 | ||||
| -rw-r--r-- | include/net/netfilter/nft_masq.h | 3 | ||||
| -rw-r--r-- | net/ipv4/netfilter/nft_masq_ipv4.c | 1 | ||||
| -rw-r--r-- | net/ipv6/netfilter/nft_masq_ipv6.c | 1 | ||||
| -rw-r--r-- | net/netfilter/nf_tables_api.c | 14 | ||||
| -rw-r--r-- | net/netfilter/nft_masq.c | 12 | ||||
| -rw-r--r-- | net/netfilter/nft_nat.c | 12 |
7 files changed, 46 insertions, 0 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h index 3d7292392fac..845c596bf594 100644 --- a/include/net/netfilter/nf_tables.h +++ b/include/net/netfilter/nf_tables.h | |||
| @@ -530,6 +530,9 @@ enum nft_chain_type { | |||
| 530 | NFT_CHAIN_T_MAX | 530 | NFT_CHAIN_T_MAX |
| 531 | }; | 531 | }; |
| 532 | 532 | ||
| 533 | int nft_chain_validate_dependency(const struct nft_chain *chain, | ||
| 534 | enum nft_chain_type type); | ||
| 535 | |||
| 533 | struct nft_stats { | 536 | struct nft_stats { |
| 534 | u64 bytes; | 537 | u64 bytes; |
| 535 | u64 pkts; | 538 | u64 pkts; |
diff --git a/include/net/netfilter/nft_masq.h b/include/net/netfilter/nft_masq.h index c72729f954f4..e2a518b60e19 100644 --- a/include/net/netfilter/nft_masq.h +++ b/include/net/netfilter/nft_masq.h | |||
| @@ -13,4 +13,7 @@ int nft_masq_init(const struct nft_ctx *ctx, | |||
| 13 | 13 | ||
| 14 | int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); | 14 | int nft_masq_dump(struct sk_buff *skb, const struct nft_expr *expr); |
| 15 | 15 | ||
| 16 | int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
| 17 | const struct nft_data **data); | ||
| 18 | |||
| 16 | #endif /* _NFT_MASQ_H_ */ | 19 | #endif /* _NFT_MASQ_H_ */ |
diff --git a/net/ipv4/netfilter/nft_masq_ipv4.c b/net/ipv4/netfilter/nft_masq_ipv4.c index 1c636d6b5b50..c1023c445920 100644 --- a/net/ipv4/netfilter/nft_masq_ipv4.c +++ b/net/ipv4/netfilter/nft_masq_ipv4.c | |||
| @@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv4_ops = { | |||
| 39 | .eval = nft_masq_ipv4_eval, | 39 | .eval = nft_masq_ipv4_eval, |
| 40 | .init = nft_masq_init, | 40 | .init = nft_masq_init, |
| 41 | .dump = nft_masq_dump, | 41 | .dump = nft_masq_dump, |
| 42 | .validate = nft_masq_validate, | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { | 45 | static struct nft_expr_type nft_masq_ipv4_type __read_mostly = { |
diff --git a/net/ipv6/netfilter/nft_masq_ipv6.c b/net/ipv6/netfilter/nft_masq_ipv6.c index 556262f40761..8a7ac685076d 100644 --- a/net/ipv6/netfilter/nft_masq_ipv6.c +++ b/net/ipv6/netfilter/nft_masq_ipv6.c | |||
| @@ -39,6 +39,7 @@ static const struct nft_expr_ops nft_masq_ipv6_ops = { | |||
| 39 | .eval = nft_masq_ipv6_eval, | 39 | .eval = nft_masq_ipv6_eval, |
| 40 | .init = nft_masq_init, | 40 | .init = nft_masq_init, |
| 41 | .dump = nft_masq_dump, | 41 | .dump = nft_masq_dump, |
| 42 | .validate = nft_masq_validate, | ||
| 42 | }; | 43 | }; |
| 43 | 44 | ||
| 44 | static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { | 45 | static struct nft_expr_type nft_masq_ipv6_type __read_mostly = { |
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c index 556a0dfa4abc..65eb2a1160d5 100644 --- a/net/netfilter/nf_tables_api.c +++ b/net/netfilter/nf_tables_api.c | |||
| @@ -3744,6 +3744,20 @@ static const struct nfnetlink_subsystem nf_tables_subsys = { | |||
| 3744 | .abort = nf_tables_abort, | 3744 | .abort = nf_tables_abort, |
| 3745 | }; | 3745 | }; |
| 3746 | 3746 | ||
| 3747 | int nft_chain_validate_dependency(const struct nft_chain *chain, | ||
| 3748 | enum nft_chain_type type) | ||
| 3749 | { | ||
| 3750 | const struct nft_base_chain *basechain; | ||
| 3751 | |||
| 3752 | if (chain->flags & NFT_BASE_CHAIN) { | ||
| 3753 | basechain = nft_base_chain(chain); | ||
| 3754 | if (basechain->type->type != type) | ||
| 3755 | return -EOPNOTSUPP; | ||
| 3756 | } | ||
| 3757 | return 0; | ||
| 3758 | } | ||
| 3759 | EXPORT_SYMBOL_GPL(nft_chain_validate_dependency); | ||
| 3760 | |||
| 3747 | /* | 3761 | /* |
| 3748 | * Loop detection - walk through the ruleset beginning at the destination chain | 3762 | * Loop detection - walk through the ruleset beginning at the destination chain |
| 3749 | * of a new jump until either the source chain is reached (loop) or all | 3763 | * of a new jump until either the source chain is reached (loop) or all |
diff --git a/net/netfilter/nft_masq.c b/net/netfilter/nft_masq.c index 6637bab00567..d1ffd5eb3a9b 100644 --- a/net/netfilter/nft_masq.c +++ b/net/netfilter/nft_masq.c | |||
| @@ -26,6 +26,11 @@ int nft_masq_init(const struct nft_ctx *ctx, | |||
| 26 | const struct nlattr * const tb[]) | 26 | const struct nlattr * const tb[]) |
| 27 | { | 27 | { |
| 28 | struct nft_masq *priv = nft_expr_priv(expr); | 28 | struct nft_masq *priv = nft_expr_priv(expr); |
| 29 | int err; | ||
| 30 | |||
| 31 | err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
| 32 | if (err < 0) | ||
| 33 | return err; | ||
| 29 | 34 | ||
| 30 | if (tb[NFTA_MASQ_FLAGS] == NULL) | 35 | if (tb[NFTA_MASQ_FLAGS] == NULL) |
| 31 | return 0; | 36 | return 0; |
| @@ -55,5 +60,12 @@ nla_put_failure: | |||
| 55 | } | 60 | } |
| 56 | EXPORT_SYMBOL_GPL(nft_masq_dump); | 61 | EXPORT_SYMBOL_GPL(nft_masq_dump); |
| 57 | 62 | ||
| 63 | int nft_masq_validate(const struct nft_ctx *ctx, const struct nft_expr *expr, | ||
| 64 | const struct nft_data **data) | ||
| 65 | { | ||
| 66 | return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
| 67 | } | ||
| 68 | EXPORT_SYMBOL_GPL(nft_masq_validate); | ||
| 69 | |||
| 58 | MODULE_LICENSE("GPL"); | 70 | MODULE_LICENSE("GPL"); |
| 59 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); | 71 | MODULE_AUTHOR("Arturo Borrero Gonzalez <arturo.borrero.glez@gmail.com>"); |
diff --git a/net/netfilter/nft_nat.c b/net/netfilter/nft_nat.c index 799550b476fb..0f0af6e86fb8 100644 --- a/net/netfilter/nft_nat.c +++ b/net/netfilter/nft_nat.c | |||
| @@ -95,6 +95,10 @@ static int nft_nat_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
| 95 | u32 family; | 95 | u32 family; |
| 96 | int err; | 96 | int err; |
| 97 | 97 | ||
| 98 | err = nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
| 99 | if (err < 0) | ||
| 100 | return err; | ||
| 101 | |||
| 98 | if (tb[NFTA_NAT_TYPE] == NULL) | 102 | if (tb[NFTA_NAT_TYPE] == NULL) |
| 99 | return -EINVAL; | 103 | return -EINVAL; |
| 100 | 104 | ||
| @@ -205,6 +209,13 @@ nla_put_failure: | |||
| 205 | return -1; | 209 | return -1; |
| 206 | } | 210 | } |
| 207 | 211 | ||
| 212 | static int nft_nat_validate(const struct nft_ctx *ctx, | ||
| 213 | const struct nft_expr *expr, | ||
| 214 | const struct nft_data **data) | ||
| 215 | { | ||
| 216 | return nft_chain_validate_dependency(ctx->chain, NFT_CHAIN_T_NAT); | ||
| 217 | } | ||
| 218 | |||
| 208 | static struct nft_expr_type nft_nat_type; | 219 | static struct nft_expr_type nft_nat_type; |
| 209 | static const struct nft_expr_ops nft_nat_ops = { | 220 | static const struct nft_expr_ops nft_nat_ops = { |
| 210 | .type = &nft_nat_type, | 221 | .type = &nft_nat_type, |
| @@ -212,6 +223,7 @@ static const struct nft_expr_ops nft_nat_ops = { | |||
| 212 | .eval = nft_nat_eval, | 223 | .eval = nft_nat_eval, |
| 213 | .init = nft_nat_init, | 224 | .init = nft_nat_init, |
| 214 | .dump = nft_nat_dump, | 225 | .dump = nft_nat_dump, |
| 226 | .validate = nft_nat_validate, | ||
| 215 | }; | 227 | }; |
| 216 | 228 | ||
| 217 | static struct nft_expr_type nft_nat_type __read_mostly = { | 229 | static struct nft_expr_type nft_nat_type __read_mostly = { |
