From: Greg Kroah-Hartman Date: Tue, 18 Jul 2017 08:12:35 +0000 (+0200) Subject: 4.4-stable patches X-Git-Tag: v4.12.3~28 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0bada0f0b0025241e26706093fdc9781210ccc84;p=thirdparty%2Fkernel%2Fstable-queue.git 4.4-stable patches added patches: ipv6-avoid-unregistering-inet6_dev-for-loopback.patch net-dp83640-avoid-null-pointer-dereference.patch net-phy-micrel-configure-intterupts-after-autoneg-workaround.patch net-prevent-sign-extension-in-dev_get_stats.patch net-sched-fix-one-possible-panic-when-no-destroy-callback.patch net_sched-fix-error-recovery-at-qdisc-creation.patch tcp-reset-sk_rx_dst-in-tcp_disconnect.patch --- diff --git a/queue-4.4/ipv6-avoid-unregistering-inet6_dev-for-loopback.patch b/queue-4.4/ipv6-avoid-unregistering-inet6_dev-for-loopback.patch new file mode 100644 index 00000000000..cbee7d447ea --- /dev/null +++ b/queue-4.4/ipv6-avoid-unregistering-inet6_dev-for-loopback.patch @@ -0,0 +1,65 @@ +From 60abc0be96e00ca71bac083215ac91ad2e575096 Mon Sep 17 00:00:00 2001 +From: WANG Cong +Date: Wed, 21 Jun 2017 14:34:58 -0700 +Subject: ipv6: avoid unregistering inet6_dev for loopback + +From: WANG Cong + +commit 60abc0be96e00ca71bac083215ac91ad2e575096 upstream. + +The per netns loopback_dev->ip6_ptr is unregistered and set to +NULL when its mtu is set to smaller than IPV6_MIN_MTU, this +leads to that we could set rt->rt6i_idev NULL after a +rt6_uncached_list_flush_dev() and then crash after another +call. + +In this case we should just bring its inet6_dev down, rather +than unregistering it, at least prior to commit 176c39af29bc +("netns: fix addrconf_ifdown kernel panic") we always +override the case for loopback. + +Thanks a lot to Andrey for finding a reliable reproducer. + +Fixes: 176c39af29bc ("netns: fix addrconf_ifdown kernel panic") +Reported-by: Andrey Konovalov +Cc: Andrey Konovalov +Cc: Daniel Lezcano +Cc: David Ahern +Signed-off-by: Cong Wang +Acked-by: David Ahern +Tested-by: Andrey Konovalov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv6/addrconf.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -3143,6 +3143,7 @@ static int addrconf_notify(struct notifi + { + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct inet6_dev *idev = __in6_dev_get(dev); ++ struct net *net = dev_net(dev); + int run_pending = 0; + int err; + +@@ -3158,7 +3159,7 @@ static int addrconf_notify(struct notifi + case NETDEV_CHANGEMTU: + /* if MTU under IPV6_MIN_MTU stop IPv6 on this interface. */ + if (dev->mtu < IPV6_MIN_MTU) { +- addrconf_ifdown(dev, 1); ++ addrconf_ifdown(dev, dev != net->loopback_dev); + break; + } + +@@ -3271,7 +3272,7 @@ static int addrconf_notify(struct notifi + * IPV6_MIN_MTU stop IPv6 on this interface. + */ + if (dev->mtu < IPV6_MIN_MTU) +- addrconf_ifdown(dev, 1); ++ addrconf_ifdown(dev, dev != net->loopback_dev); + } + break; + diff --git a/queue-4.4/net-dp83640-avoid-null-pointer-dereference.patch b/queue-4.4/net-dp83640-avoid-null-pointer-dereference.patch new file mode 100644 index 00000000000..641f4024345 --- /dev/null +++ b/queue-4.4/net-dp83640-avoid-null-pointer-dereference.patch @@ -0,0 +1,43 @@ +From db9d8b29d19d2801793e4419f4c6272bf8951c62 Mon Sep 17 00:00:00 2001 +From: Richard Cochran +Date: Fri, 23 Jun 2017 17:51:31 +0200 +Subject: net: dp83640: Avoid NULL pointer dereference. + +From: Richard Cochran + +commit db9d8b29d19d2801793e4419f4c6272bf8951c62 upstream. + +The function, skb_complete_tx_timestamp(), used to allow passing in a +NULL pointer for the time stamps, but that was changed in commit +62bccb8cdb69051b95a55ab0c489e3cab261c8ef ("net-timestamp: Make the +clone operation stand-alone from phy timestamping"), and the existing +call sites, all of which are in the dp83640 driver, were fixed up. + +Even though the kernel-doc was subsequently updated in commit +7a76a021cd5a292be875fbc616daf03eab1e6996 ("net-timestamp: Update +skb_complete_tx_timestamp comment"), still a bug fix from Manfred +Rudigier came into the driver using the old semantics. Probably +Manfred derived that patch from an older kernel version. + +This fix should be applied to the stable trees as well. + +Fixes: 81e8f2e930fe ("net: dp83640: Fix tx timestamp overflow handling.") +Signed-off-by: Richard Cochran +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/phy/dp83640.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/drivers/net/phy/dp83640.c ++++ b/drivers/net/phy/dp83640.c +@@ -907,7 +907,7 @@ static void decode_txts(struct dp83640_p + if (overflow) { + pr_debug("tx timestamp queue overflow, count %d\n", overflow); + while (skb) { +- skb_complete_tx_timestamp(skb, NULL); ++ kfree_skb(skb); + skb = skb_dequeue(&dp83640->tx_queue); + } + return; diff --git a/queue-4.4/net-phy-micrel-configure-intterupts-after-autoneg-workaround.patch b/queue-4.4/net-phy-micrel-configure-intterupts-after-autoneg-workaround.patch new file mode 100644 index 00000000000..2d21502aaaf --- /dev/null +++ b/queue-4.4/net-phy-micrel-configure-intterupts-after-autoneg-workaround.patch @@ -0,0 +1,38 @@ +From b866203d872d5deeafcecd25ea429d6748b5bd56 Mon Sep 17 00:00:00 2001 +From: Zach Brown +Date: Tue, 20 Jun 2017 12:48:11 -0500 +Subject: net/phy: micrel: configure intterupts after autoneg workaround + +From: Zach Brown + +commit b866203d872d5deeafcecd25ea429d6748b5bd56 upstream. + +The commit ("net/phy: micrel: Add workaround for bad autoneg") fixes an +autoneg failure case by resetting the hardware. This turns off +intterupts. Things will work themselves out if the phy polls, as it will +figure out it's state during a poll. However if the phy uses only +intterupts, the phy will stall, since interrupts are off. This patch +fixes the issue by calling config_intr after resetting the phy. + +Fixes: d2fd719bcb0e ("net/phy: micrel: Add workaround for bad autoneg ") +Signed-off-by: Zach Brown +Reviewed-by: Andrew Lunn +Reviewed-by: Florian Fainelli +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/net/phy/micrel.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/phy/micrel.c ++++ b/drivers/net/phy/micrel.c +@@ -539,6 +539,8 @@ static int ksz9031_read_status(struct ph + if ((regval & 0xFF) == 0xFF) { + phy_init_hw(phydev); + phydev->link = 0; ++ if (phydev->drv->config_intr && phy_interrupt_is_valid(phydev)) ++ phydev->drv->config_intr(phydev); + } + + return 0; diff --git a/queue-4.4/net-prevent-sign-extension-in-dev_get_stats.patch b/queue-4.4/net-prevent-sign-extension-in-dev_get_stats.patch new file mode 100644 index 00000000000..aade8f11681 --- /dev/null +++ b/queue-4.4/net-prevent-sign-extension-in-dev_get_stats.patch @@ -0,0 +1,41 @@ +From 6f64ec74515925cced6df4571638b5a099a49aae Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 27 Jun 2017 07:02:20 -0700 +Subject: net: prevent sign extension in dev_get_stats() + +From: Eric Dumazet + +commit 6f64ec74515925cced6df4571638b5a099a49aae upstream. + +Similar to the fix provided by Dominik Heidler in commit +9b3dc0a17d73 ("l2tp: cast l2tp traffic counter to unsigned") +we need to take care of 32bit kernels in dev_get_stats(). + +When using atomic_long_read(), we add a 'long' to u64 and +might misinterpret high order bit, unless we cast to unsigned. + +Fixes: caf586e5f23ce ("net: add a core netdev->rx_dropped counter") +Fixes: 015f0688f57ca ("net: net: add a core netdev->tx_dropped counter") +Fixes: 6e7333d315a76 ("net: add rx_nohandler stat counter") +Signed-off-by: Eric Dumazet +Cc: Jarod Wilson +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/core/dev.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/net/core/dev.c ++++ b/net/core/dev.c +@@ -7052,8 +7052,8 @@ struct rtnl_link_stats64 *dev_get_stats( + } else { + netdev_stats_to_stats64(storage, &dev->stats); + } +- storage->rx_dropped += atomic_long_read(&dev->rx_dropped); +- storage->tx_dropped += atomic_long_read(&dev->tx_dropped); ++ storage->rx_dropped += (unsigned long)atomic_long_read(&dev->rx_dropped); ++ storage->tx_dropped += (unsigned long)atomic_long_read(&dev->tx_dropped); + return storage; + } + EXPORT_SYMBOL(dev_get_stats); diff --git a/queue-4.4/net-sched-fix-one-possible-panic-when-no-destroy-callback.patch b/queue-4.4/net-sched-fix-one-possible-panic-when-no-destroy-callback.patch new file mode 100644 index 00000000000..023a4f501f7 --- /dev/null +++ b/queue-4.4/net-sched-fix-one-possible-panic-when-no-destroy-callback.patch @@ -0,0 +1,44 @@ +From c1a4872ebfb83b1af7144f7b29ac8c4b344a12a8 Mon Sep 17 00:00:00 2001 +From: Gao Feng +Date: Wed, 28 Jun 2017 12:53:54 +0800 +Subject: net: sched: Fix one possible panic when no destroy callback + +From: Gao Feng + +commit c1a4872ebfb83b1af7144f7b29ac8c4b344a12a8 upstream. + +When qdisc fail to init, qdisc_create would invoke the destroy callback +to cleanup. But there is no check if the callback exists really. So it +would cause the panic if there is no real destroy callback like the qdisc +codel, fq, and so on. + +Take codel as an example following: +When a malicious user constructs one invalid netlink msg, it would cause +codel_init->codel_change->nla_parse_nested failed. +Then kernel would invoke the destroy callback directly but qdisc codel +doesn't define one. It causes one panic as a result. + +Now add one the check for destroy to avoid the possible panic. + +Fixes: 87b60cfacf9f ("net_sched: fix error recovery at qdisc creation") +Signed-off-by: Gao Feng +Acked-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sched/sch_api.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -1005,7 +1005,8 @@ qdisc_create(struct net_device *dev, str + return sch; + } + /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */ +- ops->destroy(sch); ++ if (ops->destroy) ++ ops->destroy(sch); + err_out3: + dev_put(dev); + kfree((char *) sch - sch->padded); diff --git a/queue-4.4/net_sched-fix-error-recovery-at-qdisc-creation.patch b/queue-4.4/net_sched-fix-error-recovery-at-qdisc-creation.patch new file mode 100644 index 00000000000..b70f60ace0f --- /dev/null +++ b/queue-4.4/net_sched-fix-error-recovery-at-qdisc-creation.patch @@ -0,0 +1,198 @@ +From 87b60cfacf9f17cf71933c6e33b66e68160af71d Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Fri, 10 Feb 2017 10:31:49 -0800 +Subject: net_sched: fix error recovery at qdisc creation + +From: Eric Dumazet + +commit 87b60cfacf9f17cf71933c6e33b66e68160af71d upstream. + +Dmitry reported uses after free in qdisc code [1] + +The problem here is that ops->init() can return an error. + +qdisc_create_dflt() then call ops->destroy(), +while qdisc_create() does _not_ call it. + +Four qdisc chose to call their own ops->destroy(), assuming their caller +would not. + +This patch makes sure qdisc_create() calls ops->destroy() +and fixes the four qdisc to avoid double free. + +[1] +BUG: KASAN: use-after-free in mq_destroy+0x242/0x290 net/sched/sch_mq.c:33 at addr ffff8801d415d440 +Read of size 8 by task syz-executor2/5030 +CPU: 0 PID: 5030 Comm: syz-executor2 Not tainted 4.3.5-smp-DEV #119 +Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011 + 0000000000000046 ffff8801b435b870 ffffffff81bbbed4 ffff8801db000400 + ffff8801d415d440 ffff8801d415dc40 ffff8801c4988510 ffff8801b435b898 + ffffffff816682b1 ffff8801b435b928 ffff8801d415d440 ffff8801c49880c0 +Call Trace: + [] __dump_stack lib/dump_stack.c:15 [inline] + [] dump_stack+0x6c/0x98 lib/dump_stack.c:51 + [] kasan_object_err+0x21/0x70 mm/kasan/report.c:158 + [] print_address_description mm/kasan/report.c:196 [inline] + [] kasan_report_error+0x1b4/0x4b0 mm/kasan/report.c:285 + [] kasan_report mm/kasan/report.c:305 [inline] + [] __asan_report_load8_noabort+0x43/0x50 mm/kasan/report.c:326 + [] mq_destroy+0x242/0x290 net/sched/sch_mq.c:33 + [] qdisc_destroy+0x12d/0x290 net/sched/sch_generic.c:953 + [] qdisc_create_dflt+0xf0/0x120 net/sched/sch_generic.c:848 + [] attach_default_qdiscs net/sched/sch_generic.c:1029 [inline] + [] dev_activate+0x6ad/0x880 net/sched/sch_generic.c:1064 + [] __dev_open+0x221/0x320 net/core/dev.c:1403 + [] __dev_change_flags+0x15e/0x3e0 net/core/dev.c:6858 + [] dev_change_flags+0x8e/0x140 net/core/dev.c:6926 + [] dev_ifsioc+0x446/0x890 net/core/dev_ioctl.c:260 + [] dev_ioctl+0x1ba/0xb80 net/core/dev_ioctl.c:546 + [] sock_do_ioctl+0x99/0xb0 net/socket.c:879 + [] sock_ioctl+0x2a0/0x390 net/socket.c:958 + [] vfs_ioctl fs/ioctl.c:44 [inline] + [] do_vfs_ioctl+0x8a8/0xe50 fs/ioctl.c:611 + [] SYSC_ioctl fs/ioctl.c:626 [inline] + [] SyS_ioctl+0x94/0xc0 fs/ioctl.c:617 + [] entry_SYSCALL_64_fastpath+0x12/0x17 + +Signed-off-by: Eric Dumazet +Reported-by: Dmitry Vyukov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/sched/sch_api.c | 2 ++ + net/sched/sch_hhf.c | 8 ++++++-- + net/sched/sch_mq.c | 10 +++------- + net/sched/sch_mqprio.c | 19 ++++++------------- + net/sched/sch_sfq.c | 3 ++- + 5 files changed, 19 insertions(+), 23 deletions(-) + +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -1004,6 +1004,8 @@ qdisc_create(struct net_device *dev, str + + return sch; + } ++ /* ops->init() failed, we call ->destroy() like qdisc_create_dflt() */ ++ ops->destroy(sch); + err_out3: + dev_put(dev); + kfree((char *) sch - sch->padded); +--- a/net/sched/sch_hhf.c ++++ b/net/sched/sch_hhf.c +@@ -636,7 +636,9 @@ static int hhf_init(struct Qdisc *sch, s + q->hhf_arrays[i] = hhf_zalloc(HHF_ARRAYS_LEN * + sizeof(u32)); + if (!q->hhf_arrays[i]) { +- hhf_destroy(sch); ++ /* Note: hhf_destroy() will be called ++ * by our caller. ++ */ + return -ENOMEM; + } + } +@@ -647,7 +649,9 @@ static int hhf_init(struct Qdisc *sch, s + q->hhf_valid_bits[i] = hhf_zalloc(HHF_ARRAYS_LEN / + BITS_PER_BYTE); + if (!q->hhf_valid_bits[i]) { +- hhf_destroy(sch); ++ /* Note: hhf_destroy() will be called ++ * by our caller. ++ */ + return -ENOMEM; + } + } +--- a/net/sched/sch_mq.c ++++ b/net/sched/sch_mq.c +@@ -52,7 +52,7 @@ static int mq_init(struct Qdisc *sch, st + /* pre-allocate qdiscs, attachment can't fail */ + priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), + GFP_KERNEL); +- if (priv->qdiscs == NULL) ++ if (!priv->qdiscs) + return -ENOMEM; + + for (ntx = 0; ntx < dev->num_tx_queues; ntx++) { +@@ -60,18 +60,14 @@ static int mq_init(struct Qdisc *sch, st + qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(ntx + 1))); +- if (qdisc == NULL) +- goto err; ++ if (!qdisc) ++ return -ENOMEM; + priv->qdiscs[ntx] = qdisc; + qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + } + + sch->flags |= TCQ_F_MQROOT; + return 0; +- +-err: +- mq_destroy(sch); +- return -ENOMEM; + } + + static void mq_attach(struct Qdisc *sch) +--- a/net/sched/sch_mqprio.c ++++ b/net/sched/sch_mqprio.c +@@ -117,20 +117,17 @@ static int mqprio_init(struct Qdisc *sch + /* pre-allocate qdisc, attachment can't fail */ + priv->qdiscs = kcalloc(dev->num_tx_queues, sizeof(priv->qdiscs[0]), + GFP_KERNEL); +- if (priv->qdiscs == NULL) { +- err = -ENOMEM; +- goto err; +- } ++ if (!priv->qdiscs) ++ return -ENOMEM; + + for (i = 0; i < dev->num_tx_queues; i++) { + dev_queue = netdev_get_tx_queue(dev, i); + qdisc = qdisc_create_dflt(dev_queue, default_qdisc_ops, + TC_H_MAKE(TC_H_MAJ(sch->handle), + TC_H_MIN(i + 1))); +- if (qdisc == NULL) { +- err = -ENOMEM; +- goto err; +- } ++ if (!qdisc) ++ return -ENOMEM; ++ + priv->qdiscs[i] = qdisc; + qdisc->flags |= TCQ_F_ONETXQUEUE | TCQ_F_NOPARENT; + } +@@ -143,7 +140,7 @@ static int mqprio_init(struct Qdisc *sch + priv->hw_owned = 1; + err = dev->netdev_ops->ndo_setup_tc(dev, qopt->num_tc); + if (err) +- goto err; ++ return err; + } else { + netdev_set_num_tc(dev, qopt->num_tc); + for (i = 0; i < qopt->num_tc; i++) +@@ -157,10 +154,6 @@ static int mqprio_init(struct Qdisc *sch + + sch->flags |= TCQ_F_MQROOT; + return 0; +- +-err: +- mqprio_destroy(sch); +- return err; + } + + static void mqprio_attach(struct Qdisc *sch) +--- a/net/sched/sch_sfq.c ++++ b/net/sched/sch_sfq.c +@@ -742,9 +742,10 @@ static int sfq_init(struct Qdisc *sch, s + q->ht = sfq_alloc(sizeof(q->ht[0]) * q->divisor); + q->slots = sfq_alloc(sizeof(q->slots[0]) * q->maxflows); + if (!q->ht || !q->slots) { +- sfq_destroy(sch); ++ /* Note: sfq_destroy() will be called by our caller */ + return -ENOMEM; + } ++ + for (i = 0; i < q->divisor; i++) + q->ht[i] = SFQ_EMPTY_SLOT; + diff --git a/queue-4.4/series b/queue-4.4/series index e69de29bb2d..0217eec40bb 100644 --- a/queue-4.4/series +++ b/queue-4.4/series @@ -0,0 +1,7 @@ +net_sched-fix-error-recovery-at-qdisc-creation.patch +net-sched-fix-one-possible-panic-when-no-destroy-callback.patch +net-phy-micrel-configure-intterupts-after-autoneg-workaround.patch +ipv6-avoid-unregistering-inet6_dev-for-loopback.patch +net-dp83640-avoid-null-pointer-dereference.patch +tcp-reset-sk_rx_dst-in-tcp_disconnect.patch +net-prevent-sign-extension-in-dev_get_stats.patch diff --git a/queue-4.4/tcp-reset-sk_rx_dst-in-tcp_disconnect.patch b/queue-4.4/tcp-reset-sk_rx_dst-in-tcp_disconnect.patch new file mode 100644 index 00000000000..1389d14f9f8 --- /dev/null +++ b/queue-4.4/tcp-reset-sk_rx_dst-in-tcp_disconnect.patch @@ -0,0 +1,40 @@ +From d747a7a51b00984127a88113cdbbc26f91e9d815 Mon Sep 17 00:00:00 2001 +From: WANG Cong +Date: Sat, 24 Jun 2017 23:50:30 -0700 +Subject: tcp: reset sk_rx_dst in tcp_disconnect() + +From: WANG Cong + +commit d747a7a51b00984127a88113cdbbc26f91e9d815 upstream. + +We have to reset the sk->sk_rx_dst when we disconnect a TCP +connection, because otherwise when we re-connect it this +dst reference is simply overridden in tcp_finish_connect(). + +This fixes a dst leak which leads to a loopback dev refcnt +leak. It is a long-standing bug, Kevin reported a very similar +(if not same) bug before. Thanks to Andrei for providing such +a reliable reproducer which greatly narrows down the problem. + +Fixes: 41063e9dd119 ("ipv4: Early TCP socket demux.") +Reported-by: Andrei Vagin +Reported-by: Kevin Xu +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman + +--- + net/ipv4/tcp.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -2263,6 +2263,8 @@ int tcp_disconnect(struct sock *sk, int + tcp_init_send_head(sk); + memset(&tp->rx_opt, 0, sizeof(tp->rx_opt)); + __sk_dst_reset(sk); ++ dst_release(sk->sk_rx_dst); ++ sk->sk_rx_dst = NULL; + tcp_saved_syn_free(tp); + + WARN_ON(inet->inet_num && !icsk->icsk_bind_hash);