From: Greg Kroah-Hartman Date: Thu, 11 May 2017 10:58:25 +0000 (+0200) Subject: 3.18-stable patches X-Git-Tag: v4.4.68~20 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4d102e585a9280aa9abd9d77ff363b748c967347;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: ipv4-ipv6-ensure-raw-socket-message-is-big-enough-to-hold-an-ip-header.patch ipv6-initialize-route-null-entry-in-addrconf_init.patch ipv6-reorder-ip6_route_dev_notifier-after-ipv6_dev_notf.patch tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch tcp-fix-wraparound-issue-in-tcp_lp.patch --- diff --git a/queue-3.18/ipv4-ipv6-ensure-raw-socket-message-is-big-enough-to-hold-an-ip-header.patch b/queue-3.18/ipv4-ipv6-ensure-raw-socket-message-is-big-enough-to-hold-an-ip-header.patch new file mode 100644 index 00000000000..0bf11912b69 --- /dev/null +++ b/queue-3.18/ipv4-ipv6-ensure-raw-socket-message-is-big-enough-to-hold-an-ip-header.patch @@ -0,0 +1,112 @@ +From foo@baz Thu May 11 12:52:00 CEST 2017 +From: Alexander Potapenko +Date: Wed, 3 May 2017 17:06:58 +0200 +Subject: ipv4, ipv6: ensure raw socket message is big enough to hold an IP header + +From: Alexander Potapenko + + +[ Upstream commit 86f4c90a1c5c1493f07f2d12c1079f5bf01936f2 ] + +raw_send_hdrinc() and rawv6_send_hdrinc() expect that the buffer copied +from the userspace contains the IPv4/IPv6 header, so if too few bytes are +copied, parts of the header may remain uninitialized. + +This bug has been detected with KMSAN. + +For the record, the KMSAN report: + +================================================================== +BUG: KMSAN: use of unitialized memory in nf_ct_frag6_gather+0xf5a/0x44a0 +inter: 0 +CPU: 0 PID: 1036 Comm: probe Not tainted 4.11.0-rc5+ #2455 +Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011 +Call Trace: + __dump_stack lib/dump_stack.c:16 + dump_stack+0x143/0x1b0 lib/dump_stack.c:52 + kmsan_report+0x16b/0x1e0 mm/kmsan/kmsan.c:1078 + __kmsan_warning_32+0x5c/0xa0 mm/kmsan/kmsan_instr.c:510 + nf_ct_frag6_gather+0xf5a/0x44a0 net/ipv6/netfilter/nf_conntrack_reasm.c:577 + ipv6_defrag+0x1d9/0x280 net/ipv6/netfilter/nf_defrag_ipv6_hooks.c:68 + nf_hook_entry_hookfn ./include/linux/netfilter.h:102 + nf_hook_slow+0x13f/0x3c0 net/netfilter/core.c:310 + nf_hook ./include/linux/netfilter.h:212 + NF_HOOK ./include/linux/netfilter.h:255 + rawv6_send_hdrinc net/ipv6/raw.c:673 + rawv6_sendmsg+0x2fcb/0x41a0 net/ipv6/raw.c:919 + inet_sendmsg+0x3f8/0x6d0 net/ipv4/af_inet.c:762 + sock_sendmsg_nosec net/socket.c:633 + sock_sendmsg net/socket.c:643 + SYSC_sendto+0x6a5/0x7c0 net/socket.c:1696 + SyS_sendto+0xbc/0xe0 net/socket.c:1664 + do_syscall_64+0x72/0xa0 arch/x86/entry/common.c:285 + entry_SYSCALL64_slow_path+0x25/0x25 arch/x86/entry/entry_64.S:246 +RIP: 0033:0x436e03 +RSP: 002b:00007ffce48baf38 EFLAGS: 00000246 ORIG_RAX: 000000000000002c +RAX: ffffffffffffffda RBX: 00000000004002b0 RCX: 0000000000436e03 +RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000003 +RBP: 00007ffce48baf90 R08: 00007ffce48baf50 R09: 000000000000001c +R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 +R13: 0000000000401790 R14: 0000000000401820 R15: 0000000000000000 +origin: 00000000d9400053 + save_stack_trace+0x16/0x20 arch/x86/kernel/stacktrace.c:59 + kmsan_save_stack_with_flags mm/kmsan/kmsan.c:362 + kmsan_internal_poison_shadow+0xb1/0x1a0 mm/kmsan/kmsan.c:257 + kmsan_poison_shadow+0x6d/0xc0 mm/kmsan/kmsan.c:270 + slab_alloc_node mm/slub.c:2735 + __kmalloc_node_track_caller+0x1f4/0x390 mm/slub.c:4341 + __kmalloc_reserve net/core/skbuff.c:138 + __alloc_skb+0x2cd/0x740 net/core/skbuff.c:231 + alloc_skb ./include/linux/skbuff.h:933 + alloc_skb_with_frags+0x209/0xbc0 net/core/skbuff.c:4678 + sock_alloc_send_pskb+0x9ff/0xe00 net/core/sock.c:1903 + sock_alloc_send_skb+0xe4/0x100 net/core/sock.c:1920 + rawv6_send_hdrinc net/ipv6/raw.c:638 + rawv6_sendmsg+0x2918/0x41a0 net/ipv6/raw.c:919 + inet_sendmsg+0x3f8/0x6d0 net/ipv4/af_inet.c:762 + sock_sendmsg_nosec net/socket.c:633 + sock_sendmsg net/socket.c:643 + SYSC_sendto+0x6a5/0x7c0 net/socket.c:1696 + SyS_sendto+0xbc/0xe0 net/socket.c:1664 + do_syscall_64+0x72/0xa0 arch/x86/entry/common.c:285 + return_from_SYSCALL_64+0x0/0x6a arch/x86/entry/entry_64.S:246 +================================================================== + +, triggered by the following syscalls: + socket(PF_INET6, SOCK_RAW, IPPROTO_RAW) = 3 + sendto(3, NULL, 0, 0, {sa_family=AF_INET6, sin6_port=htons(0), inet_pton(AF_INET6, "ff00::", &sin6_addr), sin6_flowinfo=0, sin6_scope_id=0}, 28) = -1 EPERM + +A similar report is triggered in net/ipv4/raw.c if we use a PF_INET socket +instead of a PF_INET6 one. + +Signed-off-by: Alexander Potapenko +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/raw.c | 3 +++ + net/ipv6/raw.c | 2 ++ + 2 files changed, 5 insertions(+) + +--- a/net/ipv4/raw.c ++++ b/net/ipv4/raw.c +@@ -345,6 +345,9 @@ static int raw_send_hdrinc(struct sock * + rt->dst.dev->mtu); + return -EMSGSIZE; + } ++ if (length < sizeof(struct iphdr)) ++ return -EINVAL; ++ + if (flags&MSG_PROBE) + goto out; + +--- a/net/ipv6/raw.c ++++ b/net/ipv6/raw.c +@@ -624,6 +624,8 @@ static int rawv6_send_hdrinc(struct sock + ipv6_local_error(sk, EMSGSIZE, fl6, rt->dst.dev->mtu); + return -EMSGSIZE; + } ++ if (length < sizeof(struct ipv6hdr)) ++ return -EINVAL; + if (flags&MSG_PROBE) + goto out; + diff --git a/queue-3.18/ipv6-initialize-route-null-entry-in-addrconf_init.patch b/queue-3.18/ipv6-initialize-route-null-entry-in-addrconf_init.patch new file mode 100644 index 00000000000..f017567f7a0 --- /dev/null +++ b/queue-3.18/ipv6-initialize-route-null-entry-in-addrconf_init.patch @@ -0,0 +1,97 @@ +From foo@baz Thu May 11 12:52:00 CEST 2017 +From: WANG Cong +Date: Wed, 3 May 2017 22:07:31 -0700 +Subject: ipv6: initialize route null entry in addrconf_init() + +From: WANG Cong + + +[ Upstream commit 2f460933f58eee3393aba64f0f6d14acb08d1724 ] + +Andrey reported a crash on init_net.ipv6.ip6_null_entry->rt6i_idev +since it is always NULL. + +This is clearly wrong, we have code to initialize it to loopback_dev, +unfortunately the order is still not correct. + +loopback_dev is registered very early during boot, we lose a chance +to re-initialize it in notifier. addrconf_init() is called after +ip6_route_init(), which means we have no chance to correct it. + +Fix it by moving this initialization explicitly after +ipv6_add_dev(init_net.loopback_dev) in addrconf_init(). + +Reported-by: Andrey Konovalov +Signed-off-by: Cong Wang +Tested-by: Andrey Konovalov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ip6_route.h | 1 + + net/ipv6/addrconf.c | 2 ++ + net/ipv6/route.c | 26 +++++++++++++++----------- + 3 files changed, 18 insertions(+), 11 deletions(-) + +--- a/include/net/ip6_route.h ++++ b/include/net/ip6_route.h +@@ -69,6 +69,7 @@ struct dst_entry *ip6_route_output(struc + struct dst_entry *ip6_route_lookup(struct net *net, struct flowi6 *fl6, + int flags); + ++void ip6_route_init_special_entries(void); + int ip6_route_init(void); + void ip6_route_cleanup(void); + +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -5441,6 +5441,8 @@ int __init addrconf_init(void) + goto errlo; + } + ++ ip6_route_init_special_entries(); ++ + for (i = 0; i < IN6_ADDR_HSIZE; i++) + INIT_HLIST_HEAD(&inet6_addr_lst[i]); + +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -3133,6 +3133,21 @@ static struct notifier_block ip6_route_d + .priority = 0, + }; + ++void __init ip6_route_init_special_entries(void) ++{ ++ /* Registering of the loopback is done before this portion of code, ++ * the loopback reference in rt6_info will not be taken, do it ++ * manually for init_net */ ++ init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ #ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; ++ init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); ++ #endif ++} ++ + int __init ip6_route_init(void) + { + int ret; +@@ -3158,17 +3173,6 @@ int __init ip6_route_init(void) + + ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops_template.kmem_cachep; + +- /* Registering of the loopback is done before this portion of code, +- * the loopback reference in rt6_info will not be taken, do it +- * manually for init_net */ +- init_net.ipv6.ip6_null_entry->dst.dev = init_net.loopback_dev; +- init_net.ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); +- #ifdef CONFIG_IPV6_MULTIPLE_TABLES +- init_net.ipv6.ip6_prohibit_entry->dst.dev = init_net.loopback_dev; +- init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); +- init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev; +- init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev); +- #endif + ret = fib6_init(); + if (ret) + goto out_register_subsys; diff --git a/queue-3.18/ipv6-reorder-ip6_route_dev_notifier-after-ipv6_dev_notf.patch b/queue-3.18/ipv6-reorder-ip6_route_dev_notifier-after-ipv6_dev_notf.patch new file mode 100644 index 00000000000..7d073f8744f --- /dev/null +++ b/queue-3.18/ipv6-reorder-ip6_route_dev_notifier-after-ipv6_dev_notf.patch @@ -0,0 +1,101 @@ +From foo@baz Thu May 11 12:52:00 CEST 2017 +From: WANG Cong +Date: Mon, 8 May 2017 10:12:13 -0700 +Subject: ipv6: reorder ip6_route_dev_notifier after ipv6_dev_notf + +From: WANG Cong + + +[ Upstream commit 242d3a49a2a1a71d8eb9f953db1bcaa9d698ce00 ] + +For each netns (except init_net), we initialize its null entry +in 3 places: + +1) The template itself, as we use kmemdup() +2) Code around dst_init_metrics() in ip6_route_net_init() +3) ip6_route_dev_notify(), which is supposed to initialize it after + loopback registers + +Unfortunately the last one still happens in a wrong order because +we expect to initialize net->ipv6.ip6_null_entry->rt6i_idev to +net->loopback_dev's idev, thus we have to do that after we add +idev to loopback. However, this notifier has priority == 0 same as +ipv6_dev_notf, and ipv6_dev_notf is registered after +ip6_route_dev_notifier so it is called actually after +ip6_route_dev_notifier. This is similar to commit 2f460933f58e +("ipv6: initialize route null entry in addrconf_init()") which +fixes init_net. + +Fix it by picking a smaller priority for ip6_route_dev_notifier. +Also, we have to release the refcnt accordingly when unregistering +loopback_dev because device exit functions are called before subsys +exit functions. + +Acked-by: David Ahern +Tested-by: David Ahern +Signed-off-by: Cong Wang +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + include/net/addrconf.h | 2 ++ + net/ipv6/addrconf.c | 1 + + net/ipv6/route.c | 13 +++++++++++-- + 3 files changed, 14 insertions(+), 2 deletions(-) + +--- a/include/net/addrconf.h ++++ b/include/net/addrconf.h +@@ -19,6 +19,8 @@ + #define ADDRCONF_TIMER_FUZZ (HZ / 4) + #define ADDRCONF_TIMER_FUZZ_MAX (HZ) + ++#define ADDRCONF_NOTIFY_PRIORITY 0 ++ + #include + #include + +--- a/net/ipv6/addrconf.c ++++ b/net/ipv6/addrconf.c +@@ -2984,6 +2984,7 @@ static int addrconf_notify(struct notifi + */ + static struct notifier_block ipv6_dev_notf = { + .notifier_call = addrconf_notify, ++ .priority = ADDRCONF_NOTIFY_PRIORITY, + }; + + static void addrconf_type_change(struct net_device *dev, unsigned long event) +--- a/net/ipv6/route.c ++++ b/net/ipv6/route.c +@@ -2815,7 +2815,10 @@ static int ip6_route_dev_notify(struct n + struct net_device *dev = netdev_notifier_info_to_dev(ptr); + struct net *net = dev_net(dev); + +- if (event == NETDEV_REGISTER && (dev->flags & IFF_LOOPBACK)) { ++ if (!(dev->flags & IFF_LOOPBACK)) ++ return NOTIFY_OK; ++ ++ if (event == NETDEV_REGISTER) { + net->ipv6.ip6_null_entry->dst.dev = dev; + net->ipv6.ip6_null_entry->rt6i_idev = in6_dev_get(dev); + #ifdef CONFIG_IPV6_MULTIPLE_TABLES +@@ -2824,6 +2827,12 @@ static int ip6_route_dev_notify(struct n + net->ipv6.ip6_blk_hole_entry->dst.dev = dev; + net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev); + #endif ++ } else if (event == NETDEV_UNREGISTER) { ++ in6_dev_put(net->ipv6.ip6_null_entry->rt6i_idev); ++#ifdef CONFIG_IPV6_MULTIPLE_TABLES ++ in6_dev_put(net->ipv6.ip6_prohibit_entry->rt6i_idev); ++ in6_dev_put(net->ipv6.ip6_blk_hole_entry->rt6i_idev); ++#endif + } + + return NOTIFY_OK; +@@ -3130,7 +3139,7 @@ static struct pernet_operations ip6_rout + + static struct notifier_block ip6_route_dev_notifier = { + .notifier_call = ip6_route_dev_notify, +- .priority = 0, ++ .priority = ADDRCONF_NOTIFY_PRIORITY - 10, + }; + + void __init ip6_route_init_special_entries(void) diff --git a/queue-3.18/series b/queue-3.18/series index a585b56640c..cbcd72ef20a 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -30,3 +30,8 @@ scsi-scsi_dh_emc-return-success-in-clariion_std_inquiry.patch brcmfmac-ensure-pointer-correctly-set-if-skb-data-location-changes.patch brcmfmac-make-skb-header-writable-before-use.patch staging-emxx_udc-remove-incorrect-__init-annotations.patch +tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch +ipv4-ipv6-ensure-raw-socket-message-is-big-enough-to-hold-an-ip-header.patch +ipv6-initialize-route-null-entry-in-addrconf_init.patch +ipv6-reorder-ip6_route_dev_notifier-after-ipv6_dev_notf.patch +tcp-fix-wraparound-issue-in-tcp_lp.patch diff --git a/queue-3.18/tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch b/queue-3.18/tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch new file mode 100644 index 00000000000..31a7543a22b --- /dev/null +++ b/queue-3.18/tcp-do-not-underestimate-skb-truesize-in-tcp_trim_head.patch @@ -0,0 +1,86 @@ +From foo@baz Thu May 11 12:52:00 CEST 2017 +From: Eric Dumazet +Date: Wed, 26 Apr 2017 17:15:40 -0700 +Subject: tcp: do not underestimate skb->truesize in tcp_trim_head() + +From: Eric Dumazet + + +[ Upstream commit 7162fb242cb8322beb558828fd26b33c3e9fc805 ] + +Andrey found a way to trigger the WARN_ON_ONCE(delta < len) in +skb_try_coalesce() using syzkaller and a filter attached to a TCP +socket over loopback interface. + +I believe one issue with looped skbs is that tcp_trim_head() can end up +producing skb with under estimated truesize. + +It hardly matters for normal conditions, since packets sent over +loopback are never truncated. + +Bytes trimmed from skb->head should not change skb truesize, since +skb->head is not reallocated. + +Signed-off-by: Eric Dumazet +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_output.c | 19 ++++++++++++------- + 1 file changed, 12 insertions(+), 7 deletions(-) + +--- a/net/ipv4/tcp_output.c ++++ b/net/ipv4/tcp_output.c +@@ -1212,7 +1212,7 @@ int tcp_fragment(struct sock *sk, struct + * eventually). The difference is that pulled data not copied, but + * immediately discarded. + */ +-static void __pskb_trim_head(struct sk_buff *skb, int len) ++static int __pskb_trim_head(struct sk_buff *skb, int len) + { + struct skb_shared_info *shinfo; + int i, k, eat; +@@ -1222,7 +1222,7 @@ static void __pskb_trim_head(struct sk_b + __skb_pull(skb, eat); + len -= eat; + if (!len) +- return; ++ return 0; + } + eat = len; + k = 0; +@@ -1248,23 +1248,28 @@ static void __pskb_trim_head(struct sk_b + skb_reset_tail_pointer(skb); + skb->data_len -= len; + skb->len = skb->data_len; ++ return len; + } + + /* Remove acked data from a packet in the transmit queue. */ + int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) + { ++ u32 delta_truesize; ++ + if (skb_unclone(skb, GFP_ATOMIC)) + return -ENOMEM; + +- __pskb_trim_head(skb, len); ++ delta_truesize = __pskb_trim_head(skb, len); + + TCP_SKB_CB(skb)->seq += len; + skb->ip_summed = CHECKSUM_PARTIAL; + +- skb->truesize -= len; +- sk->sk_wmem_queued -= len; +- sk_mem_uncharge(sk, len); +- sock_set_flag(sk, SOCK_QUEUE_SHRUNK); ++ if (delta_truesize) { ++ skb->truesize -= delta_truesize; ++ sk->sk_wmem_queued -= delta_truesize; ++ sk_mem_uncharge(sk, delta_truesize); ++ sock_set_flag(sk, SOCK_QUEUE_SHRUNK); ++ } + + /* Any change of skb->len requires recalculation of tso factor. */ + if (tcp_skb_pcount(skb) > 1) diff --git a/queue-3.18/tcp-fix-wraparound-issue-in-tcp_lp.patch b/queue-3.18/tcp-fix-wraparound-issue-in-tcp_lp.patch new file mode 100644 index 00000000000..c7cd0e51a38 --- /dev/null +++ b/queue-3.18/tcp-fix-wraparound-issue-in-tcp_lp.patch @@ -0,0 +1,41 @@ +From foo@baz Thu May 11 12:38:23 CEST 2017 +From: Eric Dumazet +Date: Mon, 1 May 2017 15:29:48 -0700 +Subject: tcp: fix wraparound issue in tcp_lp + +From: Eric Dumazet + + +[ Upstream commit a9f11f963a546fea9144f6a6d1a307e814a387e7 ] + +Be careful when comparing tcp_time_stamp to some u32 quantity, +otherwise result can be surprising. + +Fixes: 7c106d7e782b ("[TCP]: TCP Low Priority congestion control") +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_lp.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +--- a/net/ipv4/tcp_lp.c ++++ b/net/ipv4/tcp_lp.c +@@ -264,13 +264,15 @@ static void tcp_lp_pkts_acked(struct soc + { + struct tcp_sock *tp = tcp_sk(sk); + struct lp *lp = inet_csk_ca(sk); ++ u32 delta; + + if (rtt_us > 0) + tcp_lp_rtt_sample(sk, rtt_us); + + /* calc inference */ +- if (tcp_time_stamp > tp->rx_opt.rcv_tsecr) +- lp->inference = 3 * (tcp_time_stamp - tp->rx_opt.rcv_tsecr); ++ delta = tcp_time_stamp - tp->rx_opt.rcv_tsecr; ++ if ((s32)delta > 0) ++ lp->inference = 3 * delta; + + /* test if within inference */ + if (lp->last_drop && (tcp_time_stamp - lp->last_drop < lp->inference))