diff options
author | Florian Westphal <fw@strlen.de> | 2016-04-01 08:17:28 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-04-13 18:30:37 -0400 |
commit | ce683e5f9d045e5d67d1312a42b359cb2ab2a13c (patch) | |
tree | 74c29eb462a8829b7cffac63a09d2e702788144c /net/netfilter | |
parent | 7ed2abddd20cf8f6bd27f65bd218f26fa5bf7f44 (diff) |
netfilter: x_tables: check for bogus target offset
We're currently asserting that targetoff + targetsize <= nextoff.
Extend it to also check that targetoff is >= sizeof(xt_entry).
Since this is generic code, add an argument pointing to the start of the
match/target, we can then derive the base structure size from the delta.
We also need the e->elems pointer in a followup change to validate matches.
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net/netfilter')
-rw-r--r-- | net/netfilter/x_tables.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index 1cb7a271c024..e2a6f2a9051b 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -546,14 +546,17 @@ struct compat_xt_standard_target { | |||
546 | compat_uint_t verdict; | 546 | compat_uint_t verdict; |
547 | }; | 547 | }; |
548 | 548 | ||
549 | /* see xt_check_entry_offsets */ | 549 | int xt_compat_check_entry_offsets(const void *base, const char *elems, |
550 | int xt_compat_check_entry_offsets(const void *base, | ||
551 | unsigned int target_offset, | 550 | unsigned int target_offset, |
552 | unsigned int next_offset) | 551 | unsigned int next_offset) |
553 | { | 552 | { |
553 | long size_of_base_struct = elems - (const char *)base; | ||
554 | const struct compat_xt_entry_target *t; | 554 | const struct compat_xt_entry_target *t; |
555 | const char *e = base; | 555 | const char *e = base; |
556 | 556 | ||
557 | if (target_offset < size_of_base_struct) | ||
558 | return -EINVAL; | ||
559 | |||
557 | if (target_offset + sizeof(*t) > next_offset) | 560 | if (target_offset + sizeof(*t) > next_offset) |
558 | return -EINVAL; | 561 | return -EINVAL; |
559 | 562 | ||
@@ -577,12 +580,16 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets); | |||
577 | * xt_check_entry_offsets - validate arp/ip/ip6t_entry | 580 | * xt_check_entry_offsets - validate arp/ip/ip6t_entry |
578 | * | 581 | * |
579 | * @base: pointer to arp/ip/ip6t_entry | 582 | * @base: pointer to arp/ip/ip6t_entry |
583 | * @elems: pointer to first xt_entry_match, i.e. ip(6)t_entry->elems | ||
580 | * @target_offset: the arp/ip/ip6_t->target_offset | 584 | * @target_offset: the arp/ip/ip6_t->target_offset |
581 | * @next_offset: the arp/ip/ip6_t->next_offset | 585 | * @next_offset: the arp/ip/ip6_t->next_offset |
582 | * | 586 | * |
583 | * validates that target_offset and next_offset are sane. | 587 | * validates that target_offset and next_offset are sane. |
584 | * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. | 588 | * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. |
585 | * | 589 | * |
590 | * This function does not validate the targets or matches themselves, it | ||
591 | * only tests that all the offsets and sizes are correct. | ||
592 | * | ||
586 | * The arp/ip/ip6t_entry structure @base must have passed following tests: | 593 | * The arp/ip/ip6t_entry structure @base must have passed following tests: |
587 | * - it must point to a valid memory location | 594 | * - it must point to a valid memory location |
588 | * - base to base + next_offset must be accessible, i.e. not exceed allocated | 595 | * - base to base + next_offset must be accessible, i.e. not exceed allocated |
@@ -591,12 +598,18 @@ EXPORT_SYMBOL(xt_compat_check_entry_offsets); | |||
591 | * Return: 0 on success, negative errno on failure. | 598 | * Return: 0 on success, negative errno on failure. |
592 | */ | 599 | */ |
593 | int xt_check_entry_offsets(const void *base, | 600 | int xt_check_entry_offsets(const void *base, |
601 | const char *elems, | ||
594 | unsigned int target_offset, | 602 | unsigned int target_offset, |
595 | unsigned int next_offset) | 603 | unsigned int next_offset) |
596 | { | 604 | { |
605 | long size_of_base_struct = elems - (const char *)base; | ||
597 | const struct xt_entry_target *t; | 606 | const struct xt_entry_target *t; |
598 | const char *e = base; | 607 | const char *e = base; |
599 | 608 | ||
609 | /* target start is within the ip/ip6/arpt_entry struct */ | ||
610 | if (target_offset < size_of_base_struct) | ||
611 | return -EINVAL; | ||
612 | |||
600 | if (target_offset + sizeof(*t) > next_offset) | 613 | if (target_offset + sizeof(*t) > next_offset) |
601 | return -EINVAL; | 614 | return -EINVAL; |
602 | 615 | ||