From b0e21a98f1002d07cb45611aefa43b2f9ad4a0f4 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 22 Jun 2016 15:25:43 -0700 Subject: [PATCH] 3.14-stable patches added patches: netfilter-x_tables-add-and-use-xt_check_entry_offsets.patch netfilter-x_tables-add-compat-version-of-xt_check_entry_offsets.patch netfilter-x_tables-assert-minimum-target-size.patch netfilter-x_tables-check-for-bogus-target-offset.patch netfilter-x_tables-check-standard-target-size-too.patch netfilter-x_tables-don-t-reject-valid-target-size-on-some-architectures.patch netfilter-x_tables-kill-check_entry-helper.patch netfilter-x_tables-validate-all-offsets-and-sizes-in-a-rule.patch netfilter-x_tables-validate-e-target_offset-early.patch --- ...s-add-and-use-xt_check_entry_offsets.patch | 157 ++++++++++++++ ...at-version-of-xt_check_entry_offsets.patch | 111 ++++++++++ ...-x_tables-assert-minimum-target-size.patch | 31 +++ ...tables-check-for-bogus-target-offset.patch | 170 +++++++++++++++ ...ables-check-standard-target-size-too.patch | 66 ++++++ ...don-t-move-to-non-existent-next-rule.patch | 2 +- ...id-target-size-on-some-architectures.patch | 59 ++++++ ...er-x_tables-fix-unconditional-helper.patch | 12 +- ...ter-x_tables-kill-check_entry-helper.patch | 155 ++++++++++++++ ...xt_offset-covers-remaining-blob-size.patch | 18 +- ...date-all-offsets-and-sizes-in-a-rule.patch | 143 +++++++++++++ ...ables-validate-e-target_offset-early.patch | 197 ++++++++++++++++++ queue-3.14/series | 9 + 13 files changed, 1114 insertions(+), 16 deletions(-) create mode 100644 queue-3.14/netfilter-x_tables-add-and-use-xt_check_entry_offsets.patch create mode 100644 queue-3.14/netfilter-x_tables-add-compat-version-of-xt_check_entry_offsets.patch create mode 100644 queue-3.14/netfilter-x_tables-assert-minimum-target-size.patch create mode 100644 queue-3.14/netfilter-x_tables-check-for-bogus-target-offset.patch create mode 100644 queue-3.14/netfilter-x_tables-check-standard-target-size-too.patch create mode 100644 queue-3.14/netfilter-x_tables-don-t-reject-valid-target-size-on-some-architectures.patch create mode 100644 queue-3.14/netfilter-x_tables-kill-check_entry-helper.patch create mode 100644 queue-3.14/netfilter-x_tables-validate-all-offsets-and-sizes-in-a-rule.patch create mode 100644 queue-3.14/netfilter-x_tables-validate-e-target_offset-early.patch diff --git a/queue-3.14/netfilter-x_tables-add-and-use-xt_check_entry_offsets.patch b/queue-3.14/netfilter-x_tables-add-and-use-xt_check_entry_offsets.patch new file mode 100644 index 00000000000..dbf0470b0d4 --- /dev/null +++ b/queue-3.14/netfilter-x_tables-add-and-use-xt_check_entry_offsets.patch @@ -0,0 +1,157 @@ +From 7d35812c3214afa5b37a675113555259cfd67b98 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:23 +0200 +Subject: netfilter: x_tables: add and use xt_check_entry_offsets + +From: Florian Westphal + +commit 7d35812c3214afa5b37a675113555259cfd67b98 upstream. + +Currently arp/ip and ip6tables each implement a short helper to check that +the target offset is large enough to hold one xt_entry_target struct and +that t->u.target_size fits within the current rule. + +Unfortunately these checks are not sufficient. + +To avoid adding new tests to all of ip/ip6/arptables move the current +checks into a helper, then extend this helper in followup patches. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/netfilter/x_tables.h | 4 ++++ + net/ipv4/netfilter/arp_tables.c | 11 +---------- + net/ipv4/netfilter/ip_tables.c | 12 +----------- + net/ipv6/netfilter/ip6_tables.c | 12 +----------- + net/netfilter/x_tables.c | 34 ++++++++++++++++++++++++++++++++++ + 5 files changed, 41 insertions(+), 32 deletions(-) + +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -239,6 +239,10 @@ void xt_unregister_match(struct xt_match + int xt_register_matches(struct xt_match *match, unsigned int n); + void xt_unregister_matches(struct xt_match *match, unsigned int n); + ++int xt_check_entry_offsets(const void *base, ++ unsigned int target_offset, ++ unsigned int next_offset); ++ + int xt_check_match(struct xt_mtchk_param *, unsigned int size, u_int8_t proto, + bool inv_proto); + int xt_check_target(struct xt_tgchk_param *, unsigned int size, u_int8_t proto, +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -492,19 +492,10 @@ static int mark_source_chains(const stru + + static inline int check_entry(const struct arpt_entry *e) + { +- const struct xt_entry_target *t; +- + if (!arp_checkentry(&e->arp)) + return -EINVAL; + +- if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset) +- return -EINVAL; +- +- t = arpt_get_target_c(e); +- if (e->target_offset + t->u.target_size > e->next_offset) +- return -EINVAL; +- +- return 0; ++ return xt_check_entry_offsets(e, e->target_offset, e->next_offset); + } + + static inline int check_target(struct arpt_entry *e, const char *name) +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -586,20 +586,10 @@ static void cleanup_match(struct xt_entr + static int + check_entry(const struct ipt_entry *e) + { +- const struct xt_entry_target *t; +- + if (!ip_checkentry(&e->ip)) + return -EINVAL; + +- if (e->target_offset + sizeof(struct xt_entry_target) > +- e->next_offset) +- return -EINVAL; +- +- t = ipt_get_target_c(e); +- if (e->target_offset + t->u.target_size > e->next_offset) +- return -EINVAL; +- +- return 0; ++ return xt_check_entry_offsets(e, e->target_offset, e->next_offset); + } + + static int +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -596,20 +596,10 @@ static void cleanup_match(struct xt_entr + static int + check_entry(const struct ip6t_entry *e) + { +- const struct xt_entry_target *t; +- + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + +- if (e->target_offset + sizeof(struct xt_entry_target) > +- e->next_offset) +- return -EINVAL; +- +- t = ip6t_get_target_c(e); +- if (e->target_offset + t->u.target_size > e->next_offset) +- return -EINVAL; +- +- return 0; ++ return xt_check_entry_offsets(e, e->target_offset, e->next_offset); + } + + static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -560,6 +560,40 @@ int xt_compat_match_to_user(const struct + EXPORT_SYMBOL_GPL(xt_compat_match_to_user); + #endif /* CONFIG_COMPAT */ + ++/** ++ * xt_check_entry_offsets - validate arp/ip/ip6t_entry ++ * ++ * @base: pointer to arp/ip/ip6t_entry ++ * @target_offset: the arp/ip/ip6_t->target_offset ++ * @next_offset: the arp/ip/ip6_t->next_offset ++ * ++ * validates that target_offset and next_offset are sane. ++ * ++ * The arp/ip/ip6t_entry structure @base must have passed following tests: ++ * - it must point to a valid memory location ++ * - base to base + next_offset must be accessible, i.e. not exceed allocated ++ * length. ++ * ++ * Return: 0 on success, negative errno on failure. ++ */ ++int xt_check_entry_offsets(const void *base, ++ unsigned int target_offset, ++ unsigned int next_offset) ++{ ++ const struct xt_entry_target *t; ++ const char *e = base; ++ ++ if (target_offset + sizeof(*t) > next_offset) ++ return -EINVAL; ++ ++ t = (void *)(e + target_offset); ++ if (target_offset + t->u.target_size > next_offset) ++ return -EINVAL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(xt_check_entry_offsets); ++ + int xt_check_target(struct xt_tgchk_param *par, + unsigned int size, u_int8_t proto, bool inv_proto) + { diff --git a/queue-3.14/netfilter-x_tables-add-compat-version-of-xt_check_entry_offsets.patch b/queue-3.14/netfilter-x_tables-add-compat-version-of-xt_check_entry_offsets.patch new file mode 100644 index 00000000000..5ba69c1df0d --- /dev/null +++ b/queue-3.14/netfilter-x_tables-add-compat-version-of-xt_check_entry_offsets.patch @@ -0,0 +1,111 @@ +From fc1221b3a163d1386d1052184202d5dc50d302d1 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:26 +0200 +Subject: netfilter: x_tables: add compat version of xt_check_entry_offsets + +From: Florian Westphal + +commit fc1221b3a163d1386d1052184202d5dc50d302d1 upstream. + +32bit rulesets have different layout and alignment requirements, so once +more integrity checks get added to xt_check_entry_offsets it will reject +well-formed 32bit rulesets. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/netfilter/x_tables.h | 3 +++ + net/ipv4/netfilter/arp_tables.c | 3 ++- + net/ipv4/netfilter/ip_tables.c | 3 ++- + net/ipv6/netfilter/ip6_tables.c | 3 ++- + net/netfilter/x_tables.c | 22 ++++++++++++++++++++++ + 5 files changed, 31 insertions(+), 3 deletions(-) + +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -435,6 +435,9 @@ void xt_compat_target_from_user(struct x + unsigned int *size); + int xt_compat_target_to_user(const struct xt_entry_target *t, + void __user **dstptr, unsigned int *size); ++int xt_compat_check_entry_offsets(const void *base, ++ unsigned int target_offset, ++ unsigned int next_offset); + + #endif /* CONFIG_COMPAT */ + #endif /* _X_TABLES_H */ +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -1244,7 +1244,8 @@ check_compat_entry_size_and_hooks(struct + if (!arp_checkentry(&e->arp)) + return -EINVAL; + +- ret = xt_check_entry_offsets(e, e->target_offset, e->next_offset); ++ ret = xt_compat_check_entry_offsets(e, e->target_offset, ++ e->next_offset); + if (ret) + return ret; + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -1509,7 +1509,8 @@ check_compat_entry_size_and_hooks(struct + if (!ip_checkentry(&e->ip)) + return -EINVAL; + +- ret = xt_check_entry_offsets(e, e->target_offset, e->next_offset); ++ ret = xt_compat_check_entry_offsets(e, ++ e->target_offset, e->next_offset); + if (ret) + return ret; + +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -1521,7 +1521,8 @@ check_compat_entry_size_and_hooks(struct + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + +- ret = xt_check_entry_offsets(e, e->target_offset, e->next_offset); ++ ret = xt_compat_check_entry_offsets(e, ++ e->target_offset, e->next_offset); + if (ret) + return ret; + +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -558,6 +558,27 @@ int xt_compat_match_to_user(const struct + return 0; + } + EXPORT_SYMBOL_GPL(xt_compat_match_to_user); ++ ++int xt_compat_check_entry_offsets(const void *base, ++ unsigned int target_offset, ++ unsigned int next_offset) ++{ ++ const struct compat_xt_entry_target *t; ++ const char *e = base; ++ ++ if (target_offset + sizeof(*t) > next_offset) ++ return -EINVAL; ++ ++ t = (void *)(e + target_offset); ++ if (t->u.target_size < sizeof(*t)) ++ return -EINVAL; ++ ++ if (target_offset + t->u.target_size > next_offset) ++ return -EINVAL; ++ ++ return 0; ++} ++EXPORT_SYMBOL(xt_compat_check_entry_offsets); + #endif /* CONFIG_COMPAT */ + + /** +@@ -568,6 +589,7 @@ EXPORT_SYMBOL_GPL(xt_compat_match_to_use + * @next_offset: the arp/ip/ip6_t->next_offset + * + * validates that target_offset and next_offset are sane. ++ * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. + * + * The arp/ip/ip6t_entry structure @base must have passed following tests: + * - it must point to a valid memory location diff --git a/queue-3.14/netfilter-x_tables-assert-minimum-target-size.patch b/queue-3.14/netfilter-x_tables-assert-minimum-target-size.patch new file mode 100644 index 00000000000..88d99c9bfe9 --- /dev/null +++ b/queue-3.14/netfilter-x_tables-assert-minimum-target-size.patch @@ -0,0 +1,31 @@ +From a08e4e190b866579896c09af59b3bdca821da2cd Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:25 +0200 +Subject: netfilter: x_tables: assert minimum target size + +From: Florian Westphal + +commit a08e4e190b866579896c09af59b3bdca821da2cd upstream. + +The target size includes the size of the xt_entry_target struct. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/netfilter/x_tables.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -587,6 +587,9 @@ int xt_check_entry_offsets(const void *b + return -EINVAL; + + t = (void *)(e + target_offset); ++ if (t->u.target_size < sizeof(*t)) ++ return -EINVAL; ++ + if (target_offset + t->u.target_size > next_offset) + return -EINVAL; + diff --git a/queue-3.14/netfilter-x_tables-check-for-bogus-target-offset.patch b/queue-3.14/netfilter-x_tables-check-for-bogus-target-offset.patch new file mode 100644 index 00000000000..c1b0d99f8ed --- /dev/null +++ b/queue-3.14/netfilter-x_tables-check-for-bogus-target-offset.patch @@ -0,0 +1,170 @@ +From ce683e5f9d045e5d67d1312a42b359cb2ab2a13c Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:28 +0200 +Subject: netfilter: x_tables: check for bogus target offset + +From: Florian Westphal + +commit ce683e5f9d045e5d67d1312a42b359cb2ab2a13c upstream. + +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 +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + include/linux/netfilter/x_tables.h | 4 ++-- + net/ipv4/netfilter/arp_tables.c | 5 +++-- + net/ipv4/netfilter/ip_tables.c | 5 +++-- + net/ipv6/netfilter/ip6_tables.c | 5 +++-- + net/netfilter/x_tables.c | 17 +++++++++++++++-- + 5 files changed, 26 insertions(+), 10 deletions(-) + +--- a/include/linux/netfilter/x_tables.h ++++ b/include/linux/netfilter/x_tables.h +@@ -239,7 +239,7 @@ void xt_unregister_match(struct xt_match + int xt_register_matches(struct xt_match *match, unsigned int n); + void xt_unregister_matches(struct xt_match *match, unsigned int n); + +-int xt_check_entry_offsets(const void *base, ++int xt_check_entry_offsets(const void *base, const char *elems, + unsigned int target_offset, + unsigned int next_offset); + +@@ -435,7 +435,7 @@ void xt_compat_target_from_user(struct x + unsigned int *size); + int xt_compat_target_to_user(const struct xt_entry_target *t, + void __user **dstptr, unsigned int *size); +-int xt_compat_check_entry_offsets(const void *base, ++int xt_compat_check_entry_offsets(const void *base, const char *elems, + unsigned int target_offset, + unsigned int next_offset); + +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -582,7 +582,8 @@ static inline int check_entry_size_and_h + if (!arp_checkentry(&e->arp)) + return -EINVAL; + +- err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); ++ err = xt_check_entry_offsets(e, e->elems, e->target_offset, ++ e->next_offset); + if (err) + return err; + +@@ -1244,7 +1245,7 @@ check_compat_entry_size_and_hooks(struct + if (!arp_checkentry(&e->arp)) + return -EINVAL; + +- ret = xt_compat_check_entry_offsets(e, e->target_offset, ++ ret = xt_compat_check_entry_offsets(e, e->elems, e->target_offset, + e->next_offset); + if (ret) + return ret; +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -742,7 +742,8 @@ check_entry_size_and_hooks(struct ipt_en + if (!ip_checkentry(&e->ip)) + return -EINVAL; + +- err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); ++ err = xt_check_entry_offsets(e, e->elems, e->target_offset, ++ e->next_offset); + if (err) + return err; + +@@ -1509,7 +1510,7 @@ check_compat_entry_size_and_hooks(struct + if (!ip_checkentry(&e->ip)) + return -EINVAL; + +- ret = xt_compat_check_entry_offsets(e, ++ ret = xt_compat_check_entry_offsets(e, e->elems, + e->target_offset, e->next_offset); + if (ret) + return ret; +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -753,7 +753,8 @@ check_entry_size_and_hooks(struct ip6t_e + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + +- err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); ++ err = xt_check_entry_offsets(e, e->elems, e->target_offset, ++ e->next_offset); + if (err) + return err; + +@@ -1521,7 +1522,7 @@ check_compat_entry_size_and_hooks(struct + if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; + +- ret = xt_compat_check_entry_offsets(e, ++ ret = xt_compat_check_entry_offsets(e, e->elems, + e->target_offset, e->next_offset); + if (ret) + return ret; +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -565,14 +565,17 @@ struct compat_xt_standard_target { + compat_uint_t verdict; + }; + +-/* see xt_check_entry_offsets */ +-int xt_compat_check_entry_offsets(const void *base, ++int xt_compat_check_entry_offsets(const void *base, const char *elems, + unsigned int target_offset, + unsigned int next_offset) + { ++ long size_of_base_struct = elems - (const char *)base; + const struct compat_xt_entry_target *t; + const char *e = base; + ++ if (target_offset < size_of_base_struct) ++ return -EINVAL; ++ + if (target_offset + sizeof(*t) > next_offset) + return -EINVAL; + +@@ -596,12 +599,16 @@ EXPORT_SYMBOL(xt_compat_check_entry_offs + * xt_check_entry_offsets - validate arp/ip/ip6t_entry + * + * @base: pointer to arp/ip/ip6t_entry ++ * @elems: pointer to first xt_entry_match, i.e. ip(6)t_entry->elems + * @target_offset: the arp/ip/ip6_t->target_offset + * @next_offset: the arp/ip/ip6_t->next_offset + * + * validates that target_offset and next_offset are sane. + * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. + * ++ * This function does not validate the targets or matches themselves, it ++ * only tests that all the offsets and sizes are correct. ++ * + * The arp/ip/ip6t_entry structure @base must have passed following tests: + * - it must point to a valid memory location + * - base to base + next_offset must be accessible, i.e. not exceed allocated +@@ -610,12 +617,18 @@ EXPORT_SYMBOL(xt_compat_check_entry_offs + * Return: 0 on success, negative errno on failure. + */ + int xt_check_entry_offsets(const void *base, ++ const char *elems, + unsigned int target_offset, + unsigned int next_offset) + { ++ long size_of_base_struct = elems - (const char *)base; + const struct xt_entry_target *t; + const char *e = base; + ++ /* target start is within the ip/ip6/arpt_entry struct */ ++ if (target_offset < size_of_base_struct) ++ return -EINVAL; ++ + if (target_offset + sizeof(*t) > next_offset) + return -EINVAL; + diff --git a/queue-3.14/netfilter-x_tables-check-standard-target-size-too.patch b/queue-3.14/netfilter-x_tables-check-standard-target-size-too.patch new file mode 100644 index 00000000000..7116a47f9ef --- /dev/null +++ b/queue-3.14/netfilter-x_tables-check-standard-target-size-too.patch @@ -0,0 +1,66 @@ +From 7ed2abddd20cf8f6bd27f65bd218f26fa5bf7f44 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:27 +0200 +Subject: netfilter: x_tables: check standard target size too + +From: Florian Westphal + +commit 7ed2abddd20cf8f6bd27f65bd218f26fa5bf7f44 upstream. + +We have targets and standard targets -- the latter carries a verdict. + +The ip/ip6tables validation functions will access t->verdict for the +standard targets to fetch the jump offset or verdict for chainloop +detection, but this happens before the targets get checked/validated. + +Thus we also need to check for verdict presence here, else t->verdict +can point right after a blob. + +Spotted with UBSAN while testing malformed blobs. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/netfilter/x_tables.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -559,6 +559,13 @@ int xt_compat_match_to_user(const struct + } + EXPORT_SYMBOL_GPL(xt_compat_match_to_user); + ++/* non-compat version may have padding after verdict */ ++struct compat_xt_standard_target { ++ struct compat_xt_entry_target t; ++ compat_uint_t verdict; ++}; ++ ++/* see xt_check_entry_offsets */ + int xt_compat_check_entry_offsets(const void *base, + unsigned int target_offset, + unsigned int next_offset) +@@ -576,6 +583,10 @@ int xt_compat_check_entry_offsets(const + if (target_offset + t->u.target_size > next_offset) + return -EINVAL; + ++ if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && ++ target_offset + sizeof(struct compat_xt_standard_target) != next_offset) ++ return -EINVAL; ++ + return 0; + } + EXPORT_SYMBOL(xt_compat_check_entry_offsets); +@@ -615,6 +626,10 @@ int xt_check_entry_offsets(const void *b + if (target_offset + t->u.target_size > next_offset) + return -EINVAL; + ++ if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && ++ target_offset + sizeof(struct xt_standard_target) != next_offset) ++ return -EINVAL; ++ + return 0; + } + EXPORT_SYMBOL(xt_check_entry_offsets); diff --git a/queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch b/queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch index d19e00f2e44..1e11625c96d 100644 --- a/queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch +++ b/queue-3.14/netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch @@ -52,7 +52,7 @@ Signed-off-by: Greg Kroah-Hartman } e = (struct arpt_entry *) (entry0 + newpos); -@@ -681,10 +685,8 @@ static int translate_table(struct xt_tab +@@ -680,10 +684,8 @@ static int translate_table(struct xt_tab } } diff --git a/queue-3.14/netfilter-x_tables-don-t-reject-valid-target-size-on-some-architectures.patch b/queue-3.14/netfilter-x_tables-don-t-reject-valid-target-size-on-some-architectures.patch new file mode 100644 index 00000000000..39fd676959b --- /dev/null +++ b/queue-3.14/netfilter-x_tables-don-t-reject-valid-target-size-on-some-architectures.patch @@ -0,0 +1,59 @@ +From 7b7eba0f3515fca3296b8881d583f7c1042f5226 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Wed, 1 Jun 2016 02:04:44 +0200 +Subject: netfilter: x_tables: don't reject valid target size on some architectures + +From: Florian Westphal + +commit 7b7eba0f3515fca3296b8881d583f7c1042f5226 upstream. + +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 +Tested-by: John Stultz +Fixes: 7ed2abddd20cf ("netfilter: x_tables: check standard target size too") +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/netfilter/x_tables.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -628,7 +628,7 @@ int xt_compat_check_entry_offsets(const + return -EINVAL; + + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && +- target_offset + sizeof(struct compat_xt_standard_target) != next_offset) ++ COMPAT_XT_ALIGN(target_offset + sizeof(struct compat_xt_standard_target)) != next_offset) + return -EINVAL; + + /* compat_xt_entry match has less strict aligment requirements, +@@ -710,7 +710,7 @@ int xt_check_entry_offsets(const void *b + return -EINVAL; + + if (strcmp(t->u.user.name, XT_STANDARD_TARGET) == 0 && +- target_offset + sizeof(struct xt_standard_target) != next_offset) ++ XT_ALIGN(target_offset + sizeof(struct xt_standard_target)) != next_offset) + return -EINVAL; + + return xt_check_entry_match(elems, base + target_offset, diff --git a/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch b/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch index dd100a59d7b..48658de35eb 100644 --- a/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch +++ b/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch @@ -73,7 +73,7 @@ Signed-off-by: Greg Kroah-Hartman unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, -@@ -547,7 +547,7 @@ static bool check_underflow(const struct +@@ -541,7 +541,7 @@ static bool check_underflow(const struct const struct xt_entry_target *t; unsigned int verdict; @@ -82,7 +82,7 @@ Signed-off-by: Greg Kroah-Hartman return false; t = arpt_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) -@@ -589,9 +589,9 @@ static inline int check_entry_size_and_h +@@ -588,9 +588,9 @@ static inline int check_entry_size_and_h newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { if (!check_underflow(e)) { @@ -140,7 +140,7 @@ Signed-off-by: Greg Kroah-Hartman unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, -@@ -709,7 +708,7 @@ static bool check_underflow(const struct +@@ -703,7 +702,7 @@ static bool check_underflow(const struct const struct xt_entry_target *t; unsigned int verdict; @@ -149,7 +149,7 @@ Signed-off-by: Greg Kroah-Hartman return false; t = ipt_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) -@@ -752,9 +751,9 @@ check_entry_size_and_hooks(struct ipt_en +@@ -751,9 +750,9 @@ check_entry_size_and_hooks(struct ipt_en newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { if (!check_underflow(e)) { @@ -207,7 +207,7 @@ Signed-off-by: Greg Kroah-Hartman unsigned int oldpos, size; if ((strcmp(t->target.u.user.name, -@@ -720,7 +719,7 @@ static bool check_underflow(const struct +@@ -714,7 +713,7 @@ static bool check_underflow(const struct const struct xt_entry_target *t; unsigned int verdict; @@ -216,7 +216,7 @@ Signed-off-by: Greg Kroah-Hartman return false; t = ip6t_get_target_c(e); if (strcmp(t->u.user.name, XT_STANDARD_TARGET) != 0) -@@ -763,9 +762,9 @@ check_entry_size_and_hooks(struct ip6t_e +@@ -762,9 +761,9 @@ check_entry_size_and_hooks(struct ip6t_e newinfo->hook_entry[h] = hook_entries[h]; if ((unsigned char *)e - base == underflows[h]) { if (!check_underflow(e)) { diff --git a/queue-3.14/netfilter-x_tables-kill-check_entry-helper.patch b/queue-3.14/netfilter-x_tables-kill-check_entry-helper.patch new file mode 100644 index 00000000000..5fbf52eb5bc --- /dev/null +++ b/queue-3.14/netfilter-x_tables-kill-check_entry-helper.patch @@ -0,0 +1,155 @@ +From aa412ba225dd3bc36d404c28cdc3d674850d80d0 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:24 +0200 +Subject: netfilter: x_tables: kill check_entry helper + +From: Florian Westphal + +commit aa412ba225dd3bc36d404c28cdc3d674850d80d0 upstream. + +Once we add more sanity testing to xt_check_entry_offsets it +becomes relvant if we're expecting a 32bit 'config_compat' blob +or a normal one. + +Since we already have a lot of similar-named functions (check_entry, +compat_check_entry, find_and_check_entry, etc.) and the current +incarnation is short just fold its contents into the callers. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/netfilter/arp_tables.c | 19 ++++++++----------- + net/ipv4/netfilter/ip_tables.c | 20 ++++++++------------ + net/ipv6/netfilter/ip6_tables.c | 20 ++++++++------------ + 3 files changed, 24 insertions(+), 35 deletions(-) + +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -490,14 +490,6 @@ static int mark_source_chains(const stru + return 1; + } + +-static inline int check_entry(const struct arpt_entry *e) +-{ +- if (!arp_checkentry(&e->arp)) +- return -EINVAL; +- +- return xt_check_entry_offsets(e, e->target_offset, e->next_offset); +-} +- + static inline int check_target(struct arpt_entry *e, const char *name) + { + struct xt_entry_target *t = arpt_get_target(e); +@@ -587,7 +579,10 @@ static inline int check_entry_size_and_h + return -EINVAL; + } + +- err = check_entry(e); ++ if (!arp_checkentry(&e->arp)) ++ return -EINVAL; ++ ++ err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); + if (err) + return err; + +@@ -1246,8 +1241,10 @@ check_compat_entry_size_and_hooks(struct + return -EINVAL; + } + +- /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct arpt_entry *)e); ++ if (!arp_checkentry(&e->arp)) ++ return -EINVAL; ++ ++ ret = xt_check_entry_offsets(e, e->target_offset, e->next_offset); + if (ret) + return ret; + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -584,15 +584,6 @@ static void cleanup_match(struct xt_entr + } + + static int +-check_entry(const struct ipt_entry *e) +-{ +- if (!ip_checkentry(&e->ip)) +- return -EINVAL; +- +- return xt_check_entry_offsets(e, e->target_offset, e->next_offset); +-} +- +-static int + check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) + { + const struct ipt_ip *ip = par->entryinfo; +@@ -748,7 +739,10 @@ check_entry_size_and_hooks(struct ipt_en + return -EINVAL; + } + +- err = check_entry(e); ++ if (!ip_checkentry(&e->ip)) ++ return -EINVAL; ++ ++ err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); + if (err) + return err; + +@@ -1512,8 +1506,10 @@ check_compat_entry_size_and_hooks(struct + return -EINVAL; + } + +- /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct ipt_entry *)e); ++ if (!ip_checkentry(&e->ip)) ++ return -EINVAL; ++ ++ ret = xt_check_entry_offsets(e, e->target_offset, e->next_offset); + if (ret) + return ret; + +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -593,15 +593,6 @@ static void cleanup_match(struct xt_entr + module_put(par.match->me); + } + +-static int +-check_entry(const struct ip6t_entry *e) +-{ +- if (!ip6_checkentry(&e->ipv6)) +- return -EINVAL; +- +- return xt_check_entry_offsets(e, e->target_offset, e->next_offset); +-} +- + static int check_match(struct xt_entry_match *m, struct xt_mtchk_param *par) + { + const struct ip6t_ip6 *ipv6 = par->entryinfo; +@@ -759,7 +750,10 @@ check_entry_size_and_hooks(struct ip6t_e + return -EINVAL; + } + +- err = check_entry(e); ++ if (!ip6_checkentry(&e->ipv6)) ++ return -EINVAL; ++ ++ err = xt_check_entry_offsets(e, e->target_offset, e->next_offset); + if (err) + return err; + +@@ -1524,8 +1518,10 @@ check_compat_entry_size_and_hooks(struct + return -EINVAL; + } + +- /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct ip6t_entry *)e); ++ if (!ip6_checkentry(&e->ipv6)) ++ return -EINVAL; ++ ++ ret = xt_check_entry_offsets(e, e->target_offset, e->next_offset); + if (ret) + return ret; + diff --git a/queue-3.14/netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch b/queue-3.14/netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch index 1a8614ce0dc..482fc170286 100644 --- a/queue-3.14/netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch +++ b/queue-3.14/netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch @@ -21,8 +21,8 @@ Signed-off-by: Greg Kroah-Hartman --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c -@@ -568,7 +568,8 @@ static inline int check_entry_size_and_h - unsigned int h; +@@ -563,7 +563,8 @@ static inline int check_entry_size_and_h + int err; if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || - (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { @@ -31,7 +31,7 @@ Signed-off-by: Greg Kroah-Hartman duprintf("Bad offset %p\n", e); return -EINVAL; } -@@ -1224,7 +1225,8 @@ check_compat_entry_size_and_hooks(struct +@@ -1223,7 +1224,8 @@ check_compat_entry_size_and_hooks(struct duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_arpt_entry) != 0 || @@ -43,8 +43,8 @@ Signed-off-by: Greg Kroah-Hartman } --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c -@@ -731,7 +731,8 @@ check_entry_size_and_hooks(struct ipt_en - unsigned int h; +@@ -726,7 +726,8 @@ check_entry_size_and_hooks(struct ipt_en + int err; if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || - (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { @@ -53,7 +53,7 @@ Signed-off-by: Greg Kroah-Hartman duprintf("Bad offset %p\n", e); return -EINVAL; } -@@ -1490,7 +1491,8 @@ check_compat_entry_size_and_hooks(struct +@@ -1489,7 +1490,8 @@ check_compat_entry_size_and_hooks(struct duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_ipt_entry) != 0 || @@ -65,8 +65,8 @@ Signed-off-by: Greg Kroah-Hartman } --- a/net/ipv6/netfilter/ip6_tables.c +++ b/net/ipv6/netfilter/ip6_tables.c -@@ -742,7 +742,8 @@ check_entry_size_and_hooks(struct ip6t_e - unsigned int h; +@@ -737,7 +737,8 @@ check_entry_size_and_hooks(struct ip6t_e + int err; if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || - (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { @@ -75,7 +75,7 @@ Signed-off-by: Greg Kroah-Hartman duprintf("Bad offset %p\n", e); return -EINVAL; } -@@ -1502,7 +1503,8 @@ check_compat_entry_size_and_hooks(struct +@@ -1501,7 +1502,8 @@ check_compat_entry_size_and_hooks(struct duprintf("check_compat_entry_size_and_hooks %p\n", e); if ((unsigned long)e % __alignof__(struct compat_ip6t_entry) != 0 || diff --git a/queue-3.14/netfilter-x_tables-validate-all-offsets-and-sizes-in-a-rule.patch b/queue-3.14/netfilter-x_tables-validate-all-offsets-and-sizes-in-a-rule.patch new file mode 100644 index 00000000000..ec867053c8c --- /dev/null +++ b/queue-3.14/netfilter-x_tables-validate-all-offsets-and-sizes-in-a-rule.patch @@ -0,0 +1,143 @@ +From 13631bfc604161a9d69cd68991dff8603edd66f9 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Fri, 1 Apr 2016 14:17:29 +0200 +Subject: netfilter: x_tables: validate all offsets and sizes in a rule + +From: Florian Westphal + +commit 13631bfc604161a9d69cd68991dff8603edd66f9 upstream. + +Validate that all matches (if any) add up to the beginning of +the target and that each match covers at least the base structure size. + +The compat path should be able to safely re-use the function +as the structures only differ in alignment; added a +BUILD_BUG_ON just in case we have an arch that adds padding as well. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/netfilter/x_tables.c | 81 ++++++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 76 insertions(+), 5 deletions(-) + +--- a/net/netfilter/x_tables.c ++++ b/net/netfilter/x_tables.c +@@ -435,6 +435,47 @@ int xt_check_match(struct xt_mtchk_param + } + EXPORT_SYMBOL_GPL(xt_check_match); + ++/** xt_check_entry_match - check that matches end before start of target ++ * ++ * @match: beginning of xt_entry_match ++ * @target: beginning of this rules target (alleged end of matches) ++ * @alignment: alignment requirement of match structures ++ * ++ * Validates that all matches add up to the beginning of the target, ++ * and that each match covers at least the base structure size. ++ * ++ * Return: 0 on success, negative errno on failure. ++ */ ++static int xt_check_entry_match(const char *match, const char *target, ++ const size_t alignment) ++{ ++ const struct xt_entry_match *pos; ++ int length = target - match; ++ ++ if (length == 0) /* no matches */ ++ return 0; ++ ++ pos = (struct xt_entry_match *)match; ++ do { ++ if ((unsigned long)pos % alignment) ++ return -EINVAL; ++ ++ if (length < (int)sizeof(struct xt_entry_match)) ++ return -EINVAL; ++ ++ if (pos->u.match_size < sizeof(struct xt_entry_match)) ++ return -EINVAL; ++ ++ if (pos->u.match_size > length) ++ return -EINVAL; ++ ++ length -= pos->u.match_size; ++ pos = ((void *)((char *)(pos) + (pos)->u.match_size)); ++ } while (length > 0); ++ ++ return 0; ++} ++ + #ifdef CONFIG_COMPAT + int xt_compat_add_offset(u_int8_t af, unsigned int offset, int delta) + { +@@ -590,7 +631,14 @@ int xt_compat_check_entry_offsets(const + target_offset + sizeof(struct compat_xt_standard_target) != next_offset) + return -EINVAL; + +- return 0; ++ /* compat_xt_entry match has less strict aligment requirements, ++ * otherwise they are identical. In case of padding differences ++ * we need to add compat version of xt_check_entry_match. ++ */ ++ BUILD_BUG_ON(sizeof(struct compat_xt_entry_match) != sizeof(struct xt_entry_match)); ++ ++ return xt_check_entry_match(elems, base + target_offset, ++ __alignof__(struct compat_xt_entry_match)); + } + EXPORT_SYMBOL(xt_compat_check_entry_offsets); + #endif /* CONFIG_COMPAT */ +@@ -603,17 +651,39 @@ EXPORT_SYMBOL(xt_compat_check_entry_offs + * @target_offset: the arp/ip/ip6_t->target_offset + * @next_offset: the arp/ip/ip6_t->next_offset + * +- * validates that target_offset and next_offset are sane. +- * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. ++ * validates that target_offset and next_offset are sane and that all ++ * match sizes (if any) align with the target offset. + * + * This function does not validate the targets or matches themselves, it +- * only tests that all the offsets and sizes are correct. ++ * only tests that all the offsets and sizes are correct, that all ++ * match structures are aligned, and that the last structure ends where ++ * the target structure begins. ++ * ++ * Also see xt_compat_check_entry_offsets for CONFIG_COMPAT version. + * + * The arp/ip/ip6t_entry structure @base must have passed following tests: + * - it must point to a valid memory location + * - base to base + next_offset must be accessible, i.e. not exceed allocated + * length. + * ++ * A well-formed entry looks like this: ++ * ++ * ip(6)t_entry match [mtdata] match [mtdata] target [tgdata] ip(6)t_entry ++ * e->elems[]-----' | | ++ * matchsize | | ++ * matchsize | | ++ * | | ++ * target_offset---------------------------------' | ++ * next_offset---------------------------------------------------' ++ * ++ * elems[]: flexible array member at end of ip(6)/arpt_entry struct. ++ * This is where matches (if any) and the target reside. ++ * target_offset: beginning of target. ++ * next_offset: start of the next rule; also: size of this rule. ++ * Since targets have a minimum size, target_offset + minlen <= next_offset. ++ * ++ * Every match stores its size, sum of sizes must not exceed target_offset. ++ * + * Return: 0 on success, negative errno on failure. + */ + int xt_check_entry_offsets(const void *base, +@@ -643,7 +713,8 @@ int xt_check_entry_offsets(const void *b + target_offset + sizeof(struct xt_standard_target) != next_offset) + return -EINVAL; + +- return 0; ++ return xt_check_entry_match(elems, base + target_offset, ++ __alignof__(struct xt_entry_match)); + } + EXPORT_SYMBOL(xt_check_entry_offsets); + diff --git a/queue-3.14/netfilter-x_tables-validate-e-target_offset-early.patch b/queue-3.14/netfilter-x_tables-validate-e-target_offset-early.patch new file mode 100644 index 00000000000..680e9ab361a --- /dev/null +++ b/queue-3.14/netfilter-x_tables-validate-e-target_offset-early.patch @@ -0,0 +1,197 @@ +From bdf533de6968e9686df777dc178486f600c6e617 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 22 Mar 2016 18:02:49 +0100 +Subject: netfilter: x_tables: validate e->target_offset early + +From: Florian Westphal + +commit bdf533de6968e9686df777dc178486f600c6e617 upstream. + +We should check that e->target_offset is sane before +mark_source_chains gets called since it will fetch the target entry +for loop detection. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/netfilter/arp_tables.c | 17 ++++++++--------- + net/ipv4/netfilter/ip_tables.c | 17 ++++++++--------- + net/ipv6/netfilter/ip6_tables.c | 17 ++++++++--------- + 3 files changed, 24 insertions(+), 27 deletions(-) + +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -470,14 +470,12 @@ static int mark_source_chains(const stru + return 1; + } + +-static inline int check_entry(const struct arpt_entry *e, const char *name) ++static inline int check_entry(const struct arpt_entry *e) + { + const struct xt_entry_target *t; + +- if (!arp_checkentry(&e->arp)) { +- duprintf("arp_tables: arp check failed %p %s.\n", e, name); ++ if (!arp_checkentry(&e->arp)) + return -EINVAL; +- } + + if (e->target_offset + sizeof(struct xt_entry_target) > e->next_offset) + return -EINVAL; +@@ -518,10 +516,6 @@ find_check_entry(struct arpt_entry *e, c + struct xt_target *target; + int ret; + +- ret = check_entry(e, name); +- if (ret) +- return ret; +- + t = arpt_get_target(e); + target = xt_request_find_target(NFPROTO_ARP, t->u.user.name, + t->u.user.revision); +@@ -566,6 +560,7 @@ static inline int check_entry_size_and_h + unsigned int valid_hooks) + { + unsigned int h; ++ int err; + + if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || + (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { +@@ -580,6 +575,10 @@ static inline int check_entry_size_and_h + return -EINVAL; + } + ++ err = check_entry(e); ++ if (err) ++ return err; ++ + /* Check hooks & underflows */ + for (h = 0; h < NF_ARP_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) +@@ -1237,7 +1236,7 @@ check_compat_entry_size_and_hooks(struct + } + + /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct arpt_entry *)e, name); ++ ret = check_entry((struct arpt_entry *)e); + if (ret) + return ret; + +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -565,14 +565,12 @@ static void cleanup_match(struct xt_entr + } + + static int +-check_entry(const struct ipt_entry *e, const char *name) ++check_entry(const struct ipt_entry *e) + { + const struct xt_entry_target *t; + +- if (!ip_checkentry(&e->ip)) { +- duprintf("ip check failed %p %s.\n", e, name); ++ if (!ip_checkentry(&e->ip)) + return -EINVAL; +- } + + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) +@@ -662,10 +660,6 @@ find_check_entry(struct ipt_entry *e, st + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + +- ret = check_entry(e, name); +- if (ret) +- return ret; +- + j = 0; + mtpar.net = net; + mtpar.table = name; +@@ -729,6 +723,7 @@ check_entry_size_and_hooks(struct ipt_en + unsigned int valid_hooks) + { + unsigned int h; ++ int err; + + if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || + (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { +@@ -743,6 +738,10 @@ check_entry_size_and_hooks(struct ipt_en + return -EINVAL; + } + ++ err = check_entry(e); ++ if (err) ++ return err; ++ + /* Check hooks & underflows */ + for (h = 0; h < NF_INET_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) +@@ -1503,7 +1502,7 @@ check_compat_entry_size_and_hooks(struct + } + + /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct ipt_entry *)e, name); ++ ret = check_entry((struct ipt_entry *)e); + if (ret) + return ret; + +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -575,14 +575,12 @@ static void cleanup_match(struct xt_entr + } + + static int +-check_entry(const struct ip6t_entry *e, const char *name) ++check_entry(const struct ip6t_entry *e) + { + const struct xt_entry_target *t; + +- if (!ip6_checkentry(&e->ipv6)) { +- duprintf("ip_tables: ip check failed %p %s.\n", e, name); ++ if (!ip6_checkentry(&e->ipv6)) + return -EINVAL; +- } + + if (e->target_offset + sizeof(struct xt_entry_target) > + e->next_offset) +@@ -673,10 +671,6 @@ find_check_entry(struct ip6t_entry *e, s + struct xt_mtchk_param mtpar; + struct xt_entry_match *ematch; + +- ret = check_entry(e, name); +- if (ret) +- return ret; +- + j = 0; + mtpar.net = net; + mtpar.table = name; +@@ -740,6 +734,7 @@ check_entry_size_and_hooks(struct ip6t_e + unsigned int valid_hooks) + { + unsigned int h; ++ int err; + + if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || + (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { +@@ -754,6 +749,10 @@ check_entry_size_and_hooks(struct ip6t_e + return -EINVAL; + } + ++ err = check_entry(e); ++ if (err) ++ return err; ++ + /* Check hooks & underflows */ + for (h = 0; h < NF_INET_NUMHOOKS; h++) { + if (!(valid_hooks & (1 << h))) +@@ -1515,7 +1514,7 @@ check_compat_entry_size_and_hooks(struct + } + + /* For purposes of check_entry casting the compat entry is fine */ +- ret = check_entry((struct ip6t_entry *)e, name); ++ ret = check_entry((struct ip6t_entry *)e); + if (ret) + return ret; + diff --git a/queue-3.14/series b/queue-3.14/series index 39d568b00e6..49eb2602688 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -12,9 +12,18 @@ wext-fix-32-bit-iwpriv-compatibility-issue-with-64-bit-kernel.patch fix-d_walk-non-delayed-__d_free-race.patch mips-fix-64k-page-support-for-32-bit-kernels.patch powerpc-pseries-eeh-handle-rtas-delay-requests-in-configure_bridge.patch +netfilter-x_tables-validate-e-target_offset-early.patch netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch netfilter-x_tables-fix-unconditional-helper.patch xfs-fix-up-backport-error-in-fs-xfs-xfs_inode.c.patch pipe-limit-the-per-user-amount-of-pages-allocated-in-pipes.patch netfilter-x_tables-don-t-move-to-non-existent-next-rule.patch netfilter-x_tables-validate-targets-of-jumps.patch +netfilter-x_tables-add-and-use-xt_check_entry_offsets.patch +netfilter-x_tables-kill-check_entry-helper.patch +netfilter-x_tables-assert-minimum-target-size.patch +netfilter-x_tables-add-compat-version-of-xt_check_entry_offsets.patch +netfilter-x_tables-check-standard-target-size-too.patch +netfilter-x_tables-check-for-bogus-target-offset.patch +netfilter-x_tables-validate-all-offsets-and-sizes-in-a-rule.patch +netfilter-x_tables-don-t-reject-valid-target-size-on-some-architectures.patch -- 2.47.3