From: Greg Kroah-Hartman Date: Wed, 22 Jun 2016 05:08:06 +0000 (-0700) Subject: 3.14-stable patches X-Git-Tag: v3.14.73~22 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=168ee6abc1ee024e00ed9977ca1814ff38852288;p=thirdparty%2Fkernel%2Fstable-queue.git 3.14-stable patches added patches: netfilter-x_tables-fix-unconditional-helper.patch netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch powerpc-pseries-eeh-handle-rtas-delay-requests-in-configure_bridge.patch --- diff --git a/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch b/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch new file mode 100644 index 00000000000..dd100a59d7b --- /dev/null +++ b/queue-3.14/netfilter-x_tables-fix-unconditional-helper.patch @@ -0,0 +1,231 @@ +From 54d83fc74aa9ec72794373cb47432c5f7fb1a309 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 22 Mar 2016 18:02:52 +0100 +Subject: netfilter: x_tables: fix unconditional helper + +From: Florian Westphal + +commit 54d83fc74aa9ec72794373cb47432c5f7fb1a309 upstream. + +Ben Hawkes says: + + In the mark_source_chains function (net/ipv4/netfilter/ip_tables.c) it + is possible for a user-supplied ipt_entry structure to have a large + next_offset field. This field is not bounds checked prior to writing a + counter value at the supplied offset. + +Problem is that mark_source_chains should not have been called -- +the rule doesn't have a next entry, so its supposed to return +an absolute verdict of either ACCEPT or DROP. + +However, the function conditional() doesn't work as the name implies. +It only checks that the rule is using wildcard address matching. + +However, an unconditional rule must also not be using any matches +(no -m args). + +The underflow validator only checked the addresses, therefore +passing the 'unconditional absolute verdict' test, while +mark_source_chains also tested for presence of matches, and thus +proceeeded to the next (not-existent) rule. + +Unify this so that all the callers have same idea of 'unconditional rule'. + +Reported-by: Ben Hawkes +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/netfilter/arp_tables.c | 18 +++++++++--------- + net/ipv4/netfilter/ip_tables.c | 23 +++++++++++------------ + net/ipv6/netfilter/ip6_tables.c | 23 +++++++++++------------ + 3 files changed, 31 insertions(+), 33 deletions(-) + +--- a/net/ipv4/netfilter/arp_tables.c ++++ b/net/ipv4/netfilter/arp_tables.c +@@ -355,11 +355,12 @@ unsigned int arpt_do_table(struct sk_buf + } + + /* All zeroes == unconditional rule. */ +-static inline bool unconditional(const struct arpt_arp *arp) ++static inline bool unconditional(const struct arpt_entry *e) + { + static const struct arpt_arp uncond; + +- return memcmp(arp, &uncond, sizeof(uncond)) == 0; ++ return e->target_offset == sizeof(struct arpt_entry) && ++ memcmp(&e->arp, &uncond, sizeof(uncond)) == 0; + } + + /* Figures out from what hook each rule can be called: returns 0 if +@@ -398,11 +399,10 @@ static int mark_source_chains(const stru + |= ((1 << hook) | (1 << NF_ARP_NUMHOOKS)); + + /* Unconditional return/END. */ +- if ((e->target_offset == sizeof(struct arpt_entry) && ++ if ((unconditional(e) && + (strcmp(t->target.u.user.name, + XT_STANDARD_TARGET) == 0) && +- t->verdict < 0 && unconditional(&e->arp)) || +- visited) { ++ t->verdict < 0) || visited) { + unsigned int oldpos, size; + + if ((strcmp(t->target.u.user.name, +@@ -547,7 +547,7 @@ static bool check_underflow(const struct + const struct xt_entry_target *t; + unsigned int verdict; + +- if (!unconditional(&e->arp)) ++ if (!unconditional(e)) + 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 + newinfo->hook_entry[h] = hook_entries[h]; + if ((unsigned char *)e - base == underflows[h]) { + if (!check_underflow(e)) { +- pr_err("Underflows must be unconditional and " +- "use the STANDARD target with " +- "ACCEPT/DROP\n"); ++ pr_debug("Underflows must be unconditional and " ++ "use the STANDARD target with " ++ "ACCEPT/DROP\n"); + return -EINVAL; + } + newinfo->underflow[h] = underflows[h]; +--- a/net/ipv4/netfilter/ip_tables.c ++++ b/net/ipv4/netfilter/ip_tables.c +@@ -168,11 +168,12 @@ get_entry(const void *base, unsigned int + + /* All zeroes == unconditional rule. */ + /* Mildly perf critical (only if packet tracing is on) */ +-static inline bool unconditional(const struct ipt_ip *ip) ++static inline bool unconditional(const struct ipt_entry *e) + { + static const struct ipt_ip uncond; + +- return memcmp(ip, &uncond, sizeof(uncond)) == 0; ++ return e->target_offset == sizeof(struct ipt_entry) && ++ memcmp(&e->ip, &uncond, sizeof(uncond)) == 0; + #undef FWINV + } + +@@ -229,11 +230,10 @@ get_chainname_rulenum(const struct ipt_e + } else if (s == e) { + (*rulenum)++; + +- if (s->target_offset == sizeof(struct ipt_entry) && ++ if (unconditional(s) && + strcmp(t->target.u.kernel.target->name, + XT_STANDARD_TARGET) == 0 && +- t->verdict < 0 && +- unconditional(&s->ip)) { ++ t->verdict < 0) { + /* Tail of chains: STANDARD target (return/policy) */ + *comment = *chainname == hookname + ? comments[NF_IP_TRACE_COMMENT_POLICY] +@@ -472,11 +472,10 @@ mark_source_chains(const struct xt_table + e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); + + /* Unconditional return/END. */ +- if ((e->target_offset == sizeof(struct ipt_entry) && ++ if ((unconditional(e) && + (strcmp(t->target.u.user.name, + XT_STANDARD_TARGET) == 0) && +- t->verdict < 0 && unconditional(&e->ip)) || +- visited) { ++ t->verdict < 0) || visited) { + unsigned int oldpos, size; + + if ((strcmp(t->target.u.user.name, +@@ -709,7 +708,7 @@ static bool check_underflow(const struct + const struct xt_entry_target *t; + unsigned int verdict; + +- if (!unconditional(&e->ip)) ++ if (!unconditional(e)) + 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 + newinfo->hook_entry[h] = hook_entries[h]; + if ((unsigned char *)e - base == underflows[h]) { + if (!check_underflow(e)) { +- pr_err("Underflows must be unconditional and " +- "use the STANDARD target with " +- "ACCEPT/DROP\n"); ++ pr_debug("Underflows must be unconditional and " ++ "use the STANDARD target with " ++ "ACCEPT/DROP\n"); + return -EINVAL; + } + newinfo->underflow[h] = underflows[h]; +--- a/net/ipv6/netfilter/ip6_tables.c ++++ b/net/ipv6/netfilter/ip6_tables.c +@@ -195,11 +195,12 @@ get_entry(const void *base, unsigned int + + /* All zeroes == unconditional rule. */ + /* Mildly perf critical (only if packet tracing is on) */ +-static inline bool unconditional(const struct ip6t_ip6 *ipv6) ++static inline bool unconditional(const struct ip6t_entry *e) + { + static const struct ip6t_ip6 uncond; + +- return memcmp(ipv6, &uncond, sizeof(uncond)) == 0; ++ return e->target_offset == sizeof(struct ip6t_entry) && ++ memcmp(&e->ipv6, &uncond, sizeof(uncond)) == 0; + } + + static inline const struct xt_entry_target * +@@ -255,11 +256,10 @@ get_chainname_rulenum(const struct ip6t_ + } else if (s == e) { + (*rulenum)++; + +- if (s->target_offset == sizeof(struct ip6t_entry) && ++ if (unconditional(s) && + strcmp(t->target.u.kernel.target->name, + XT_STANDARD_TARGET) == 0 && +- t->verdict < 0 && +- unconditional(&s->ipv6)) { ++ t->verdict < 0) { + /* Tail of chains: STANDARD target (return/policy) */ + *comment = *chainname == hookname + ? comments[NF_IP6_TRACE_COMMENT_POLICY] +@@ -482,11 +482,10 @@ mark_source_chains(const struct xt_table + e->comefrom |= ((1 << hook) | (1 << NF_INET_NUMHOOKS)); + + /* Unconditional return/END. */ +- if ((e->target_offset == sizeof(struct ip6t_entry) && ++ if ((unconditional(e) && + (strcmp(t->target.u.user.name, + XT_STANDARD_TARGET) == 0) && +- t->verdict < 0 && +- unconditional(&e->ipv6)) || visited) { ++ t->verdict < 0) || visited) { + unsigned int oldpos, size; + + if ((strcmp(t->target.u.user.name, +@@ -720,7 +719,7 @@ static bool check_underflow(const struct + const struct xt_entry_target *t; + unsigned int verdict; + +- if (!unconditional(&e->ipv6)) ++ if (!unconditional(e)) + 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 + newinfo->hook_entry[h] = hook_entries[h]; + if ((unsigned char *)e - base == underflows[h]) { + if (!check_underflow(e)) { +- pr_err("Underflows must be unconditional and " +- "use the STANDARD target with " +- "ACCEPT/DROP\n"); ++ pr_debug("Underflows must be unconditional and " ++ "use the STANDARD target with " ++ "ACCEPT/DROP\n"); + return -EINVAL; + } + newinfo->underflow[h] = underflows[h]; 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 new file mode 100644 index 00000000000..1a8614ce0dc --- /dev/null +++ b/queue-3.14/netfilter-x_tables-make-sure-e-next_offset-covers-remaining-blob-size.patch @@ -0,0 +1,87 @@ +From 6e94e0cfb0887e4013b3b930fa6ab1fe6bb6ba91 Mon Sep 17 00:00:00 2001 +From: Florian Westphal +Date: Tue, 22 Mar 2016 18:02:50 +0100 +Subject: netfilter: x_tables: make sure e->next_offset covers remaining blob size + +From: Florian Westphal + +commit 6e94e0cfb0887e4013b3b930fa6ab1fe6bb6ba91 upstream. + +Otherwise this function may read data beyond the ruleset blob. + +Signed-off-by: Florian Westphal +Signed-off-by: Pablo Neira Ayuso +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/netfilter/arp_tables.c | 6 ++++-- + net/ipv4/netfilter/ip_tables.c | 6 ++++-- + net/ipv6/netfilter/ip6_tables.c | 6 ++++-- + 3 files changed, 12 insertions(+), 6 deletions(-) + +--- 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; + + if ((unsigned long)e % __alignof__(struct arpt_entry) != 0 || +- (unsigned char *)e + sizeof(struct arpt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct arpt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p\n", e); + return -EINVAL; + } +@@ -1224,7 +1225,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 || +- (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct compat_arpt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p, limit = %p\n", e, limit); + return -EINVAL; + } +--- 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; + + if ((unsigned long)e % __alignof__(struct ipt_entry) != 0 || +- (unsigned char *)e + sizeof(struct ipt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct ipt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p\n", e); + return -EINVAL; + } +@@ -1490,7 +1491,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 || +- (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct compat_ipt_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p, limit = %p\n", e, limit); + return -EINVAL; + } +--- 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; + + if ((unsigned long)e % __alignof__(struct ip6t_entry) != 0 || +- (unsigned char *)e + sizeof(struct ip6t_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct ip6t_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p\n", e); + return -EINVAL; + } +@@ -1502,7 +1503,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 || +- (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit) { ++ (unsigned char *)e + sizeof(struct compat_ip6t_entry) >= limit || ++ (unsigned char *)e + e->next_offset > limit) { + duprintf("Bad offset %p, limit = %p\n", e, limit); + return -EINVAL; + } diff --git a/queue-3.14/powerpc-pseries-eeh-handle-rtas-delay-requests-in-configure_bridge.patch b/queue-3.14/powerpc-pseries-eeh-handle-rtas-delay-requests-in-configure_bridge.patch new file mode 100644 index 00000000000..ced0ba3d68c --- /dev/null +++ b/queue-3.14/powerpc-pseries-eeh-handle-rtas-delay-requests-in-configure_bridge.patch @@ -0,0 +1,96 @@ +From 871e178e0f2c4fa788f694721a10b4758d494ce1 Mon Sep 17 00:00:00 2001 +From: Russell Currey +Date: Thu, 7 Apr 2016 16:28:26 +1000 +Subject: powerpc/pseries/eeh: Handle RTAS delay requests in configure_bridge + +From: Russell Currey + +commit 871e178e0f2c4fa788f694721a10b4758d494ce1 upstream. + +In the "ibm,configure-pe" and "ibm,configure-bridge" RTAS calls, the +spec states that values of 9900-9905 can be returned, indicating that +software should delay for 10^x (where x is the last digit, i.e. 990x) +milliseconds and attempt the call again. Currently, the kernel doesn't +know about this, and respecting it fixes some PCI failures when the +hypervisor is busy. + +The delay is capped at 0.2 seconds. + +Cc: # 3.10+ +Signed-off-by: Russell Currey +Acked-by: Gavin Shan +Signed-off-by: Michael Ellerman +Signed-off-by: Greg Kroah-Hartman + +--- + arch/powerpc/platforms/pseries/eeh_pseries.c | 51 +++++++++++++++++++-------- + 1 file changed, 36 insertions(+), 15 deletions(-) + +--- a/arch/powerpc/platforms/pseries/eeh_pseries.c ++++ b/arch/powerpc/platforms/pseries/eeh_pseries.c +@@ -615,29 +615,50 @@ static int pseries_eeh_configure_bridge( + { + int config_addr; + int ret; ++ /* Waiting 0.2s maximum before skipping configuration */ ++ int max_wait = 200; + + /* Figure out the PE address */ + config_addr = pe->config_addr; + if (pe->addr) + config_addr = pe->addr; + +- /* Use new configure-pe function, if supported */ +- if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { +- ret = rtas_call(ibm_configure_pe, 3, 1, NULL, +- config_addr, BUID_HI(pe->phb->buid), +- BUID_LO(pe->phb->buid)); +- } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { +- ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, +- config_addr, BUID_HI(pe->phb->buid), +- BUID_LO(pe->phb->buid)); +- } else { +- return -EFAULT; +- } ++ while (max_wait > 0) { ++ /* Use new configure-pe function, if supported */ ++ if (ibm_configure_pe != RTAS_UNKNOWN_SERVICE) { ++ ret = rtas_call(ibm_configure_pe, 3, 1, NULL, ++ config_addr, BUID_HI(pe->phb->buid), ++ BUID_LO(pe->phb->buid)); ++ } else if (ibm_configure_bridge != RTAS_UNKNOWN_SERVICE) { ++ ret = rtas_call(ibm_configure_bridge, 3, 1, NULL, ++ config_addr, BUID_HI(pe->phb->buid), ++ BUID_LO(pe->phb->buid)); ++ } else { ++ return -EFAULT; ++ } ++ ++ if (!ret) ++ return ret; ++ ++ /* ++ * If RTAS returns a delay value that's above 100ms, cut it ++ * down to 100ms in case firmware made a mistake. For more ++ * on how these delay values work see rtas_busy_delay_time ++ */ ++ if (ret > RTAS_EXTENDED_DELAY_MIN+2 && ++ ret <= RTAS_EXTENDED_DELAY_MAX) ++ ret = RTAS_EXTENDED_DELAY_MIN+2; + +- if (ret) +- pr_warning("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", +- __func__, pe->phb->global_number, pe->addr, ret); ++ max_wait -= rtas_busy_delay_time(ret); ++ ++ if (max_wait < 0) ++ break; ++ ++ rtas_busy_delay(ret); ++ } + ++ pr_warn("%s: Unable to configure bridge PHB#%d-PE#%x (%d)\n", ++ __func__, pe->phb->global_number, pe->addr, ret); + return ret; + } + diff --git a/queue-3.14/series b/queue-3.14/series index 358a7288caa..9e7f62beddb 100644 --- a/queue-3.14/series +++ b/queue-3.14/series @@ -11,3 +11,6 @@ ecryptfs-forbid-opening-files-without-mmap-handler.patch 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-make-sure-e-next_offset-covers-remaining-blob-size.patch +netfilter-x_tables-fix-unconditional-helper.patch