diff options
-rw-r--r-- | net/netfilter/nft_compat.c | 75 |
1 files changed, 66 insertions, 9 deletions
diff --git a/net/netfilter/nft_compat.c b/net/netfilter/nft_compat.c index 44ae273b4391..0480f57a4eb6 100644 --- a/net/netfilter/nft_compat.c +++ b/net/netfilter/nft_compat.c | |||
@@ -19,9 +19,52 @@ | |||
19 | #include <linux/netfilter/x_tables.h> | 19 | #include <linux/netfilter/x_tables.h> |
20 | #include <linux/netfilter_ipv4/ip_tables.h> | 20 | #include <linux/netfilter_ipv4/ip_tables.h> |
21 | #include <linux/netfilter_ipv6/ip6_tables.h> | 21 | #include <linux/netfilter_ipv6/ip6_tables.h> |
22 | #include <asm/uaccess.h> /* for set_fs */ | ||
23 | #include <net/netfilter/nf_tables.h> | 22 | #include <net/netfilter/nf_tables.h> |
24 | 23 | ||
24 | static const struct { | ||
25 | const char *name; | ||
26 | u8 type; | ||
27 | } table_to_chaintype[] = { | ||
28 | { "filter", NFT_CHAIN_T_DEFAULT }, | ||
29 | { "raw", NFT_CHAIN_T_DEFAULT }, | ||
30 | { "security", NFT_CHAIN_T_DEFAULT }, | ||
31 | { "mangle", NFT_CHAIN_T_ROUTE }, | ||
32 | { "nat", NFT_CHAIN_T_NAT }, | ||
33 | { }, | ||
34 | }; | ||
35 | |||
36 | static int nft_compat_table_to_chaintype(const char *table) | ||
37 | { | ||
38 | int i; | ||
39 | |||
40 | for (i = 0; table_to_chaintype[i].name != NULL; i++) { | ||
41 | if (strcmp(table_to_chaintype[i].name, table) == 0) | ||
42 | return table_to_chaintype[i].type; | ||
43 | } | ||
44 | |||
45 | return -1; | ||
46 | } | ||
47 | |||
48 | static int nft_compat_chain_validate_dependency(const char *tablename, | ||
49 | const struct nft_chain *chain) | ||
50 | { | ||
51 | enum nft_chain_type type; | ||
52 | const struct nft_base_chain *basechain; | ||
53 | |||
54 | if (!tablename || !(chain->flags & NFT_BASE_CHAIN)) | ||
55 | return 0; | ||
56 | |||
57 | type = nft_compat_table_to_chaintype(tablename); | ||
58 | if (type < 0) | ||
59 | return -EINVAL; | ||
60 | |||
61 | basechain = nft_base_chain(chain); | ||
62 | if (basechain->type->type != type) | ||
63 | return -EINVAL; | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
25 | union nft_entry { | 68 | union nft_entry { |
26 | struct ipt_entry e4; | 69 | struct ipt_entry e4; |
27 | struct ip6t_entry e6; | 70 | struct ip6t_entry e6; |
@@ -153,6 +196,10 @@ nft_target_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
153 | union nft_entry e = {}; | 196 | union nft_entry e = {}; |
154 | int ret; | 197 | int ret; |
155 | 198 | ||
199 | ret = nft_compat_chain_validate_dependency(target->table, ctx->chain); | ||
200 | if (ret < 0) | ||
201 | goto err; | ||
202 | |||
156 | target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); | 203 | target_compat_from_user(target, nla_data(tb[NFTA_TARGET_INFO]), info); |
157 | 204 | ||
158 | if (ctx->nla[NFTA_RULE_COMPAT]) { | 205 | if (ctx->nla[NFTA_RULE_COMPAT]) { |
@@ -218,6 +265,7 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
218 | { | 265 | { |
219 | struct xt_target *target = expr->ops->data; | 266 | struct xt_target *target = expr->ops->data; |
220 | unsigned int hook_mask = 0; | 267 | unsigned int hook_mask = 0; |
268 | int ret; | ||
221 | 269 | ||
222 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 270 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
223 | const struct nft_base_chain *basechain = | 271 | const struct nft_base_chain *basechain = |
@@ -225,11 +273,13 @@ static int nft_target_validate(const struct nft_ctx *ctx, | |||
225 | const struct nf_hook_ops *ops = &basechain->ops[0]; | 273 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
226 | 274 | ||
227 | hook_mask = 1 << ops->hooknum; | 275 | hook_mask = 1 << ops->hooknum; |
228 | if (hook_mask & target->hooks) | 276 | if (!(hook_mask & target->hooks)) |
229 | return 0; | 277 | return -EINVAL; |
230 | 278 | ||
231 | /* This target is being called from an invalid chain */ | 279 | ret = nft_compat_chain_validate_dependency(target->table, |
232 | return -EINVAL; | 280 | ctx->chain); |
281 | if (ret < 0) | ||
282 | return ret; | ||
233 | } | 283 | } |
234 | return 0; | 284 | return 0; |
235 | } | 285 | } |
@@ -324,6 +374,10 @@ nft_match_init(const struct nft_ctx *ctx, const struct nft_expr *expr, | |||
324 | union nft_entry e = {}; | 374 | union nft_entry e = {}; |
325 | int ret; | 375 | int ret; |
326 | 376 | ||
377 | ret = nft_compat_chain_validate_dependency(match->name, ctx->chain); | ||
378 | if (ret < 0) | ||
379 | goto err; | ||
380 | |||
327 | match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); | 381 | match_compat_from_user(match, nla_data(tb[NFTA_MATCH_INFO]), info); |
328 | 382 | ||
329 | if (ctx->nla[NFTA_RULE_COMPAT]) { | 383 | if (ctx->nla[NFTA_RULE_COMPAT]) { |
@@ -383,6 +437,7 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
383 | { | 437 | { |
384 | struct xt_match *match = expr->ops->data; | 438 | struct xt_match *match = expr->ops->data; |
385 | unsigned int hook_mask = 0; | 439 | unsigned int hook_mask = 0; |
440 | int ret; | ||
386 | 441 | ||
387 | if (ctx->chain->flags & NFT_BASE_CHAIN) { | 442 | if (ctx->chain->flags & NFT_BASE_CHAIN) { |
388 | const struct nft_base_chain *basechain = | 443 | const struct nft_base_chain *basechain = |
@@ -390,11 +445,13 @@ static int nft_match_validate(const struct nft_ctx *ctx, | |||
390 | const struct nf_hook_ops *ops = &basechain->ops[0]; | 445 | const struct nf_hook_ops *ops = &basechain->ops[0]; |
391 | 446 | ||
392 | hook_mask = 1 << ops->hooknum; | 447 | hook_mask = 1 << ops->hooknum; |
393 | if (hook_mask & match->hooks) | 448 | if (!(hook_mask & match->hooks)) |
394 | return 0; | 449 | return -EINVAL; |
395 | 450 | ||
396 | /* This match is being called from an invalid chain */ | 451 | ret = nft_compat_chain_validate_dependency(match->name, |
397 | return -EINVAL; | 452 | ctx->chain); |
453 | if (ret < 0) | ||
454 | return ret; | ||
398 | } | 455 | } |
399 | return 0; | 456 | return 0; |
400 | } | 457 | } |