diff options
author | Florian Westphal <fw@strlen.de> | 2016-05-31 20:04:44 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2016-06-02 08:09:33 -0400 |
commit | 7b7eba0f3515fca3296b8881d583f7c1042f5226 (patch) | |
tree | f40d9356a7e4e27fe84b4edec024327e3a16e367 /net | |
parent | 14b84e8654c89ed59f433654e6bb64c886d095cd (diff) |
netfilter: x_tables: don't reject valid target size on some architectures
Quoting John Stultz:
In updating a 32bit arm device from 4.6 to Linus' current HEAD, I
noticed I was having some trouble with networking, and realized that
/proc/net/ip_tables_names was suddenly empty.
Digging through the registration process, it seems we're catching on the:
if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 &&
target_offset + sizeof(struct xt_standard_target) != next_offset)
return -EINVAL;
Where next_offset seems to be 4 bytes larger then the
offset + standard_target struct size.
next_offset needs to be aligned via XT_ALIGN (so we can access all members
of ip(6)t_entry struct).
This problem didn't show up on i686 as it only needs 4-byte alignment for
u64, but iptables userspace on other 32bit arches does insert extra padding.
Reported-by: John Stultz <john.stultz@linaro.org>
Tested-by: John Stultz <john.stultz@linaro.org>
Fixes: 7ed2abddd20cf ("netfilter: x_tables: check standard target size too")
Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/x_tables.c | 4 |
1 files changed, 2 insertions, 2 deletions
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c index c69c892231d7..2675d580c490 100644 --- a/net/netfilter/x_tables.c +++ b/net/netfilter/x_tables.c | |||
@@ -612,7 +612,7 @@ int xt_compat_check_entry_offsets(const void *base, const char *elems, | |||
612 | return -EINVAL; | 612 | return -EINVAL; |
613 | 613 | ||
614 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && | 614 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && |
615 | target_offset + sizeof(struct compat_xt_standard_target) != next_offset) | 615 | COMPAT_XT_ALIGN(target_offset + sizeof(struct compat_xt_standard_target)) != next_offset) |
616 | return -EINVAL; | 616 | return -EINVAL; |
617 | 617 | ||
618 | /* compat_xt_entry match has less strict aligment requirements, | 618 | /* compat_xt_entry match has less strict aligment requirements, |
@@ -694,7 +694,7 @@ int xt_check_entry_offsets(const void *base, | |||
694 | return -EINVAL; | 694 | return -EINVAL; |
695 | 695 | ||
696 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && | 696 | if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && |
697 | target_offset + sizeof(struct xt_standard_target) != next_offset) | 697 | XT_ALIGN(target_offset + sizeof(struct xt_standard_target)) != next_offset) |
698 | return -EINVAL; | 698 | return -EINVAL; |
699 | 699 | ||
700 | return xt_check_entry_match(elems, base + target_offset, | 700 | return xt_check_entry_match(elems, base + target_offset, |