From: Greg Kroah-Hartman Date: Fri, 2 Jun 2017 06:01:40 +0000 (+0900) Subject: 3.18-stable patches X-Git-Tag: v3.18.56~28 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=71f72bfc816d958199b3ae2564093b628274e13b;p=thirdparty%2Fkernel%2Fstable-queue.git 3.18-stable patches added patches: dccp-tcp-do-not-inherit-mc_list-from-parent.patch ipv6-check-ip6_find_1stfragopt-return-value-properly.patch ipv6-fix-out-of-bound-writes-in-__ip6_append_data.patch ipv6-prevent-overrun-when-parsing-v6-header-options.patch qmi_wwan-add-another-lenovo-em74xx-device-id.patch s390-qeth-avoid-null-pointer-dereference-on-osn.patch s390-qeth-handle-sysfs-error-during-initialization.patch s390-qeth-unbreak-osm-and-osn-support.patch sctp-do-not-inherit-ipv6_-mc-ac-fl-_list-from-parent.patch sctp-fix-icmp-processing-if-skb-is-non-linear.patch sctp-fix-src-address-selection-if-using-secondary-addresses-for-ipv6.patch tcp-avoid-fastopen-api-to-be-used-on-af_unspec.patch tcp-avoid-fragmenting-peculiar-skbs-in-sack.patch tcp-eliminate-negative-reordering-in-tcp_clean_rtx_queue.patch --- diff --git a/queue-3.18/dccp-tcp-do-not-inherit-mc_list-from-parent.patch b/queue-3.18/dccp-tcp-do-not-inherit-mc_list-from-parent.patch new file mode 100644 index 00000000000..66973d6c998 --- /dev/null +++ b/queue-3.18/dccp-tcp-do-not-inherit-mc_list-from-parent.patch @@ -0,0 +1,42 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Eric Dumazet +Date: Tue, 9 May 2017 06:29:19 -0700 +Subject: dccp/tcp: do not inherit mc_list from parent + +From: Eric Dumazet + + +[ Upstream commit 657831ffc38e30092a2d5f03d385d710eb88b09a ] + +syzkaller found a way to trigger double frees from ip_mc_drop_socket() + +It turns out that leave a copy of parent mc_list at accept() time, +which is very bad. + +Very similar to commit 8b485ce69876 ("tcp: do not inherit +fastopen_req from parent") + +Initial report from Pray3r, completed by Andrey one. +Thanks a lot to them ! + +Signed-off-by: Eric Dumazet +Reported-by: Pray3r +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/inet_connection_sock.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/net/ipv4/inet_connection_sock.c ++++ b/net/ipv4/inet_connection_sock.c +@@ -677,6 +677,8 @@ struct sock *inet_csk_clone_lock(const s + inet_sk(newsk)->inet_sport = htons(inet_rsk(req)->ir_num); + newsk->sk_write_space = sk_stream_write_space; + ++ inet_sk(newsk)->mc_list = NULL; ++ + newsk->sk_mark = inet_rsk(req)->ir_mark; + + newicsk->icsk_retransmits = 0; diff --git a/queue-3.18/ipv6-check-ip6_find_1stfragopt-return-value-properly.patch b/queue-3.18/ipv6-check-ip6_find_1stfragopt-return-value-properly.patch new file mode 100644 index 00000000000..788de6cdaa9 --- /dev/null +++ b/queue-3.18/ipv6-check-ip6_find_1stfragopt-return-value-properly.patch @@ -0,0 +1,89 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: "David S. Miller" +Date: Wed, 17 May 2017 22:54:11 -0400 +Subject: ipv6: Check ip6_find_1stfragopt() return value properly. + +From: "David S. Miller" + + +[ Upstream commit 7dd7eb9513bd02184d45f000ab69d78cb1fa1531 ] + +Do not use unsigned variables to see if it returns a negative +error or not. + +Fixes: 2423496af35d ("ipv6: Prevent overrun when parsing v6 header options") +Reported-by: Julia Lawall +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_offload.c | 9 ++++----- + net/ipv6/ip6_output.c | 7 +++---- + net/ipv6/udp_offload.c | 8 +++++--- + 3 files changed, 12 insertions(+), 12 deletions(-) + +--- a/net/ipv6/ip6_offload.c ++++ b/net/ipv6/ip6_offload.c +@@ -62,7 +62,6 @@ static struct sk_buff *ipv6_gso_segment( + const struct net_offload *ops; + int proto; + struct frag_hdr *fptr; +- unsigned int unfrag_ip6hlen; + u8 *prevhdr; + int offset = 0; + bool encap, udpfrag; +@@ -121,10 +120,10 @@ static struct sk_buff *ipv6_gso_segment( + skb->network_header = (u8 *)ipv6h - skb->head; + + if (udpfrag) { +- unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); +- if (unfrag_ip6hlen < 0) +- return ERR_PTR(unfrag_ip6hlen); +- fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen); ++ int err = ip6_find_1stfragopt(skb, &prevhdr); ++ if (err < 0) ++ return ERR_PTR(err); ++ fptr = (struct frag_hdr *)((u8 *)ipv6h + err); + fptr->frag_off = htons(offset); + if (skb->next != NULL) + fptr->frag_off |= htons(IP6_MF); +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -569,11 +569,10 @@ int ip6_fragment(struct sk_buff *skb, in + u8 *prevhdr, nexthdr = 0; + struct net *net = dev_net(skb_dst(skb)->dev); + +- hlen = ip6_find_1stfragopt(skb, &prevhdr); +- if (hlen < 0) { +- err = hlen; ++ err = ip6_find_1stfragopt(skb, &prevhdr); ++ if (err < 0) + goto fail; +- } ++ hlen = err; + nexthdr = *prevhdr; + + mtu = ip6_skb_dst_mtu(skb); +--- a/net/ipv6/udp_offload.c ++++ b/net/ipv6/udp_offload.c +@@ -29,6 +29,7 @@ static struct sk_buff *udp6_ufo_fragment + u8 frag_hdr_sz = sizeof(struct frag_hdr); + __wsum csum; + int tnl_hlen; ++ int err; + + mss = skb_shinfo(skb)->gso_size; + if (unlikely(skb->len <= mss)) +@@ -93,9 +94,10 @@ static struct sk_buff *udp6_ufo_fragment + /* Find the unfragmentable header and shift it left by frag_hdr_sz + * bytes to insert fragment header. + */ +- unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); +- if (unfrag_ip6hlen < 0) +- return ERR_PTR(unfrag_ip6hlen); ++ err = ip6_find_1stfragopt(skb, &prevhdr); ++ if (err < 0) ++ return ERR_PTR(err); ++ unfrag_ip6hlen = err; + nexthdr = *prevhdr; + *prevhdr = NEXTHDR_FRAGMENT; + unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) + diff --git a/queue-3.18/ipv6-fix-out-of-bound-writes-in-__ip6_append_data.patch b/queue-3.18/ipv6-fix-out-of-bound-writes-in-__ip6_append_data.patch new file mode 100644 index 00000000000..f4f35d4ee8d --- /dev/null +++ b/queue-3.18/ipv6-fix-out-of-bound-writes-in-__ip6_append_data.patch @@ -0,0 +1,67 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Eric Dumazet +Date: Fri, 19 May 2017 14:17:48 -0700 +Subject: ipv6: fix out of bound writes in __ip6_append_data() + +From: Eric Dumazet + + +[ Upstream commit 232cd35d0804cc241eb887bb8d4d9b3b9881c64a ] + +Andrey Konovalov and idaifish@gmail.com reported crashes caused by +one skb shared_info being overwritten from __ip6_append_data() + +Andrey program lead to following state : + +copy -4200 datalen 2000 fraglen 2040 +maxfraglen 2040 alloclen 2048 transhdrlen 0 offset 0 fraggap 6200 + +The skb_copy_and_csum_bits(skb_prev, maxfraglen, data + transhdrlen, +fraggap, 0); is overwriting skb->head and skb_shared_info + +Since we apparently detect this rare condition too late, move the +code earlier to even avoid allocating skb and risking crashes. + +Once again, many thanks to Andrey and syzkaller team. + +Signed-off-by: Eric Dumazet +Reported-by: Andrey Konovalov +Tested-by: Andrey Konovalov +Reported-by: +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_output.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -1376,6 +1376,11 @@ alloc_new_skb: + */ + alloclen += sizeof(struct frag_hdr); + ++ copy = datalen - transhdrlen - fraggap; ++ if (copy < 0) { ++ err = -EINVAL; ++ goto error; ++ } + if (transhdrlen) { + skb = sock_alloc_send_skb(sk, + alloclen + hh_len, +@@ -1425,13 +1430,9 @@ alloc_new_skb: + data += fraggap; + pskb_trim_unique(skb_prev, maxfraglen); + } +- copy = datalen - transhdrlen - fraggap; +- +- if (copy < 0) { +- err = -EINVAL; +- kfree_skb(skb); +- goto error; +- } else if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, fraggap, skb) < 0) { ++ if (copy > 0 && ++ getfrag(from, data + transhdrlen, offset, ++ copy, fraggap, skb) < 0) { + err = -EFAULT; + kfree_skb(skb); + goto error; diff --git a/queue-3.18/ipv6-prevent-overrun-when-parsing-v6-header-options.patch b/queue-3.18/ipv6-prevent-overrun-when-parsing-v6-header-options.patch new file mode 100644 index 00000000000..e22d53e4d51 --- /dev/null +++ b/queue-3.18/ipv6-prevent-overrun-when-parsing-v6-header-options.patch @@ -0,0 +1,226 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Craig Gallek +Date: Tue, 16 May 2017 14:36:23 -0400 +Subject: ipv6: Prevent overrun when parsing v6 header options + +From: Craig Gallek + + +[ Upstream commit 2423496af35d94a87156b063ea5cedffc10a70a1 ] + +The KASAN warning repoted below was discovered with a syzkaller +program. The reproducer is basically: + int s = socket(AF_INET6, SOCK_RAW, NEXTHDR_HOP); + send(s, &one_byte_of_data, 1, MSG_MORE); + send(s, &more_than_mtu_bytes_data, 2000, 0); + +The socket() call sets the nexthdr field of the v6 header to +NEXTHDR_HOP, the first send call primes the payload with a non zero +byte of data, and the second send call triggers the fragmentation path. + +The fragmentation code tries to parse the header options in order +to figure out where to insert the fragment option. Since nexthdr points +to an invalid option, the calculation of the size of the network header +can made to be much larger than the linear section of the skb and data +is read outside of it. + +This fix makes ip6_find_1stfrag return an error if it detects +running out-of-bounds. + +[ 42.361487] ================================================================== +[ 42.364412] BUG: KASAN: slab-out-of-bounds in ip6_fragment+0x11c8/0x3730 +[ 42.365471] Read of size 840 at addr ffff88000969e798 by task ip6_fragment-oo/3789 +[ 42.366469] +[ 42.366696] CPU: 1 PID: 3789 Comm: ip6_fragment-oo Not tainted 4.11.0+ #41 +[ 42.367628] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.10.1-1ubuntu1 04/01/2014 +[ 42.368824] Call Trace: +[ 42.369183] dump_stack+0xb3/0x10b +[ 42.369664] print_address_description+0x73/0x290 +[ 42.370325] kasan_report+0x252/0x370 +[ 42.370839] ? ip6_fragment+0x11c8/0x3730 +[ 42.371396] check_memory_region+0x13c/0x1a0 +[ 42.371978] memcpy+0x23/0x50 +[ 42.372395] ip6_fragment+0x11c8/0x3730 +[ 42.372920] ? nf_ct_expect_unregister_notifier+0x110/0x110 +[ 42.373681] ? ip6_copy_metadata+0x7f0/0x7f0 +[ 42.374263] ? ip6_forward+0x2e30/0x2e30 +[ 42.374803] ip6_finish_output+0x584/0x990 +[ 42.375350] ip6_output+0x1b7/0x690 +[ 42.375836] ? ip6_finish_output+0x990/0x990 +[ 42.376411] ? ip6_fragment+0x3730/0x3730 +[ 42.376968] ip6_local_out+0x95/0x160 +[ 42.377471] ip6_send_skb+0xa1/0x330 +[ 42.377969] ip6_push_pending_frames+0xb3/0xe0 +[ 42.378589] rawv6_sendmsg+0x2051/0x2db0 +[ 42.379129] ? rawv6_bind+0x8b0/0x8b0 +[ 42.379633] ? _copy_from_user+0x84/0xe0 +[ 42.380193] ? debug_check_no_locks_freed+0x290/0x290 +[ 42.380878] ? ___sys_sendmsg+0x162/0x930 +[ 42.381427] ? rcu_read_lock_sched_held+0xa3/0x120 +[ 42.382074] ? sock_has_perm+0x1f6/0x290 +[ 42.382614] ? ___sys_sendmsg+0x167/0x930 +[ 42.383173] ? lock_downgrade+0x660/0x660 +[ 42.383727] inet_sendmsg+0x123/0x500 +[ 42.384226] ? inet_sendmsg+0x123/0x500 +[ 42.384748] ? inet_recvmsg+0x540/0x540 +[ 42.385263] sock_sendmsg+0xca/0x110 +[ 42.385758] SYSC_sendto+0x217/0x380 +[ 42.386249] ? SYSC_connect+0x310/0x310 +[ 42.386783] ? __might_fault+0x110/0x1d0 +[ 42.387324] ? lock_downgrade+0x660/0x660 +[ 42.387880] ? __fget_light+0xa1/0x1f0 +[ 42.388403] ? __fdget+0x18/0x20 +[ 42.388851] ? sock_common_setsockopt+0x95/0xd0 +[ 42.389472] ? SyS_setsockopt+0x17f/0x260 +[ 42.390021] ? entry_SYSCALL_64_fastpath+0x5/0xbe +[ 42.390650] SyS_sendto+0x40/0x50 +[ 42.391103] entry_SYSCALL_64_fastpath+0x1f/0xbe +[ 42.391731] RIP: 0033:0x7fbbb711e383 +[ 42.392217] RSP: 002b:00007ffff4d34f28 EFLAGS: 00000246 ORIG_RAX: 000000000000002c +[ 42.393235] RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007fbbb711e383 +[ 42.394195] RDX: 0000000000001000 RSI: 00007ffff4d34f60 RDI: 0000000000000003 +[ 42.395145] RBP: 0000000000000046 R08: 00007ffff4d34f40 R09: 0000000000000018 +[ 42.396056] R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000400aad +[ 42.396598] R13: 0000000000000066 R14: 00007ffff4d34ee0 R15: 00007fbbb717af00 +[ 42.397257] +[ 42.397411] Allocated by task 3789: +[ 42.397702] save_stack_trace+0x16/0x20 +[ 42.398005] save_stack+0x46/0xd0 +[ 42.398267] kasan_kmalloc+0xad/0xe0 +[ 42.398548] kasan_slab_alloc+0x12/0x20 +[ 42.398848] __kmalloc_node_track_caller+0xcb/0x380 +[ 42.399224] __kmalloc_reserve.isra.32+0x41/0xe0 +[ 42.399654] __alloc_skb+0xf8/0x580 +[ 42.400003] sock_wmalloc+0xab/0xf0 +[ 42.400346] __ip6_append_data.isra.41+0x2472/0x33d0 +[ 42.400813] ip6_append_data+0x1a8/0x2f0 +[ 42.401122] rawv6_sendmsg+0x11ee/0x2db0 +[ 42.401505] inet_sendmsg+0x123/0x500 +[ 42.401860] sock_sendmsg+0xca/0x110 +[ 42.402209] ___sys_sendmsg+0x7cb/0x930 +[ 42.402582] __sys_sendmsg+0xd9/0x190 +[ 42.402941] SyS_sendmsg+0x2d/0x50 +[ 42.403273] entry_SYSCALL_64_fastpath+0x1f/0xbe +[ 42.403718] +[ 42.403871] Freed by task 1794: +[ 42.404146] save_stack_trace+0x16/0x20 +[ 42.404515] save_stack+0x46/0xd0 +[ 42.404827] kasan_slab_free+0x72/0xc0 +[ 42.405167] kfree+0xe8/0x2b0 +[ 42.405462] skb_free_head+0x74/0xb0 +[ 42.405806] skb_release_data+0x30e/0x3a0 +[ 42.406198] skb_release_all+0x4a/0x60 +[ 42.406563] consume_skb+0x113/0x2e0 +[ 42.406910] skb_free_datagram+0x1a/0xe0 +[ 42.407288] netlink_recvmsg+0x60d/0xe40 +[ 42.407667] sock_recvmsg+0xd7/0x110 +[ 42.408022] ___sys_recvmsg+0x25c/0x580 +[ 42.408395] __sys_recvmsg+0xd6/0x190 +[ 42.408753] SyS_recvmsg+0x2d/0x50 +[ 42.409086] entry_SYSCALL_64_fastpath+0x1f/0xbe +[ 42.409513] +[ 42.409665] The buggy address belongs to the object at ffff88000969e780 +[ 42.409665] which belongs to the cache kmalloc-512 of size 512 +[ 42.410846] The buggy address is located 24 bytes inside of +[ 42.410846] 512-byte region [ffff88000969e780, ffff88000969e980) +[ 42.411941] The buggy address belongs to the page: +[ 42.412405] page:ffffea000025a780 count:1 mapcount:0 mapping: (null) index:0x0 compound_mapcount: 0 +[ 42.413298] flags: 0x100000000008100(slab|head) +[ 42.413729] raw: 0100000000008100 0000000000000000 0000000000000000 00000001800c000c +[ 42.414387] raw: ffffea00002a9500 0000000900000007 ffff88000c401280 0000000000000000 +[ 42.415074] page dumped because: kasan: bad access detected +[ 42.415604] +[ 42.415757] Memory state around the buggy address: +[ 42.416222] ffff88000969e880: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42.416904] ffff88000969e900: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +[ 42.417591] >ffff88000969e980: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc +[ 42.418273] ^ +[ 42.418588] ffff88000969ea00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 42.419273] ffff88000969ea80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb +[ 42.419882] ================================================================== + +Reported-by: Andrey Konovalov +Signed-off-by: Craig Gallek +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv6/ip6_offload.c | 2 ++ + net/ipv6/ip6_output.c | 4 ++++ + net/ipv6/output_core.c | 14 ++++++++------ + net/ipv6/udp_offload.c | 2 ++ + 4 files changed, 16 insertions(+), 6 deletions(-) + +--- a/net/ipv6/ip6_offload.c ++++ b/net/ipv6/ip6_offload.c +@@ -122,6 +122,8 @@ static struct sk_buff *ipv6_gso_segment( + + if (udpfrag) { + unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); ++ if (unfrag_ip6hlen < 0) ++ return ERR_PTR(unfrag_ip6hlen); + fptr = (struct frag_hdr *)((u8 *)ipv6h + unfrag_ip6hlen); + fptr->frag_off = htons(offset); + if (skb->next != NULL) +--- a/net/ipv6/ip6_output.c ++++ b/net/ipv6/ip6_output.c +@@ -570,6 +570,10 @@ int ip6_fragment(struct sk_buff *skb, in + struct net *net = dev_net(skb_dst(skb)->dev); + + hlen = ip6_find_1stfragopt(skb, &prevhdr); ++ if (hlen < 0) { ++ err = hlen; ++ goto fail; ++ } + nexthdr = *prevhdr; + + mtu = ip6_skb_dst_mtu(skb); +--- a/net/ipv6/output_core.c ++++ b/net/ipv6/output_core.c +@@ -45,14 +45,13 @@ EXPORT_SYMBOL_GPL(ipv6_proxy_select_iden + int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) + { + u16 offset = sizeof(struct ipv6hdr); +- struct ipv6_opt_hdr *exthdr = +- (struct ipv6_opt_hdr *)(ipv6_hdr(skb) + 1); + unsigned int packet_len = skb_tail_pointer(skb) - + skb_network_header(skb); + int found_rhdr = 0; + *nexthdr = &ipv6_hdr(skb)->nexthdr; + +- while (offset + 1 <= packet_len) { ++ while (offset <= packet_len) { ++ struct ipv6_opt_hdr *exthdr; + + switch (**nexthdr) { + +@@ -73,13 +72,16 @@ int ip6_find_1stfragopt(struct sk_buff * + return offset; + } + +- offset += ipv6_optlen(exthdr); +- *nexthdr = &exthdr->nexthdr; ++ if (offset + sizeof(struct ipv6_opt_hdr) > packet_len) ++ return -EINVAL; ++ + exthdr = (struct ipv6_opt_hdr *)(skb_network_header(skb) + + offset); ++ offset += ipv6_optlen(exthdr); ++ *nexthdr = &exthdr->nexthdr; + } + +- return offset; ++ return -EINVAL; + } + EXPORT_SYMBOL(ip6_find_1stfragopt); + +--- a/net/ipv6/udp_offload.c ++++ b/net/ipv6/udp_offload.c +@@ -94,6 +94,8 @@ static struct sk_buff *udp6_ufo_fragment + * bytes to insert fragment header. + */ + unfrag_ip6hlen = ip6_find_1stfragopt(skb, &prevhdr); ++ if (unfrag_ip6hlen < 0) ++ return ERR_PTR(unfrag_ip6hlen); + nexthdr = *prevhdr; + *prevhdr = NEXTHDR_FRAGMENT; + unfrag_len = (skb_network_header(skb) - skb_mac_header(skb)) + diff --git a/queue-3.18/qmi_wwan-add-another-lenovo-em74xx-device-id.patch b/queue-3.18/qmi_wwan-add-another-lenovo-em74xx-device-id.patch new file mode 100644 index 00000000000..a66c6d1d417 --- /dev/null +++ b/queue-3.18/qmi_wwan-add-another-lenovo-em74xx-device-id.patch @@ -0,0 +1,33 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Bjørn Mork +Date: Wed, 17 May 2017 16:31:41 +0200 +Subject: qmi_wwan: add another Lenovo EM74xx device ID + +From: Bjørn Mork + + +[ Upstream commit 486181bcb3248e2f1977f4e69387a898234a4e1e ] + +In their infinite wisdom, and never ending quest for end user frustration, +Lenovo has decided to use a new USB device ID for the wwan modules in +their 2017 laptops. The actual hardware is still the Sierra Wireless +EM7455 or EM7430, depending on region. + +Signed-off-by: Bjørn Mork +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/usb/qmi_wwan.c | 2 ++ + 1 file changed, 2 insertions(+) + +--- a/drivers/net/usb/qmi_wwan.c ++++ b/drivers/net/usb/qmi_wwan.c +@@ -771,6 +771,8 @@ static const struct usb_device_id produc + {QMI_FIXED_INTF(0x1199, 0x9071, 10)}, /* Sierra Wireless MC74xx */ + {QMI_FIXED_INTF(0x1199, 0x9079, 8)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1199, 0x9079, 10)}, /* Sierra Wireless EM74xx */ ++ {QMI_FIXED_INTF(0x1199, 0x907b, 8)}, /* Sierra Wireless EM74xx */ ++ {QMI_FIXED_INTF(0x1199, 0x907b, 10)}, /* Sierra Wireless EM74xx */ + {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ + {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ + {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ diff --git a/queue-3.18/s390-qeth-avoid-null-pointer-dereference-on-osn.patch b/queue-3.18/s390-qeth-avoid-null-pointer-dereference-on-osn.patch new file mode 100644 index 00000000000..4ad2557f804 --- /dev/null +++ b/queue-3.18/s390-qeth-avoid-null-pointer-dereference-on-osn.patch @@ -0,0 +1,46 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Julian Wiedmann +Date: Wed, 10 May 2017 19:07:53 +0200 +Subject: s390/qeth: avoid null pointer dereference on OSN + +From: Julian Wiedmann + + +[ Upstream commit 25e2c341e7818a394da9abc403716278ee646014 ] + +Access card->dev only after checking whether's its valid. + +Signed-off-by: Julian Wiedmann +Reviewed-by: Ursula Braun +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/net/qeth_l2_main.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +--- a/drivers/s390/net/qeth_l2_main.c ++++ b/drivers/s390/net/qeth_l2_main.c +@@ -970,7 +970,6 @@ static int qeth_l2_setup_netdev(struct q + case QETH_CARD_TYPE_OSN: + card->dev = alloc_netdev(0, "osn%d", NET_NAME_UNKNOWN, + ether_setup); +- card->dev->flags |= IFF_NOARP; + break; + default: + card->dev = alloc_etherdev(0); +@@ -983,9 +982,12 @@ static int qeth_l2_setup_netdev(struct q + card->dev->watchdog_timeo = QETH_TX_TIMEOUT; + card->dev->mtu = card->info.initial_mtu; + card->dev->netdev_ops = &qeth_l2_netdev_ops; +- card->dev->ethtool_ops = +- (card->info.type != QETH_CARD_TYPE_OSN) ? +- &qeth_l2_ethtool_ops : &qeth_l2_osn_ops; ++ if (card->info.type == QETH_CARD_TYPE_OSN) { ++ card->dev->ethtool_ops = &qeth_l2_osn_ops; ++ card->dev->flags |= IFF_NOARP; ++ } else { ++ card->dev->ethtool_ops = &qeth_l2_ethtool_ops; ++ } + card->dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; + card->info.broadcast_capable = 1; + qeth_l2_request_initial_mac(card); diff --git a/queue-3.18/s390-qeth-handle-sysfs-error-during-initialization.patch b/queue-3.18/s390-qeth-handle-sysfs-error-during-initialization.patch new file mode 100644 index 00000000000..1bee14a829a --- /dev/null +++ b/queue-3.18/s390-qeth-handle-sysfs-error-during-initialization.patch @@ -0,0 +1,82 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Ursula Braun +Date: Wed, 10 May 2017 19:07:51 +0200 +Subject: s390/qeth: handle sysfs error during initialization + +From: Ursula Braun + + +[ Upstream commit 9111e7880ccf419548c7b0887df020b08eadb075 ] + +When setting up the device from within the layer discipline's +probe routine, creating the layer-specific sysfs attributes can fail. +Report this error back to the caller, and handle it by +releasing the layer discipline. + +Signed-off-by: Ursula Braun +[jwi: updated commit msg, moved an OSN change to a subsequent patch] +Signed-off-by: Julian Wiedmann +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/net/qeth_core_main.c | 4 +++- + drivers/s390/net/qeth_core_sys.c | 2 ++ + drivers/s390/net/qeth_l2_main.c | 5 ++++- + drivers/s390/net/qeth_l3_main.c | 5 ++++- + 4 files changed, 13 insertions(+), 3 deletions(-) + +--- a/drivers/s390/net/qeth_core_main.c ++++ b/drivers/s390/net/qeth_core_main.c +@@ -5505,8 +5505,10 @@ static int qeth_core_set_online(struct c + if (rc) + goto err; + rc = card->discipline->setup(card->gdev); +- if (rc) ++ if (rc) { ++ qeth_core_free_discipline(card); + goto err; ++ } + } + rc = card->discipline->set_online(gdev); + err: +--- a/drivers/s390/net/qeth_core_sys.c ++++ b/drivers/s390/net/qeth_core_sys.c +@@ -459,6 +459,8 @@ static ssize_t qeth_dev_layer2_store(str + goto out; + + rc = card->discipline->setup(card->gdev); ++ if (rc) ++ qeth_core_free_discipline(card); + out: + mutex_unlock(&card->discipline_mutex); + return rc ? rc : count; +--- a/drivers/s390/net/qeth_l2_main.c ++++ b/drivers/s390/net/qeth_l2_main.c +@@ -890,8 +890,11 @@ static int qeth_l2_stop(struct net_devic + static int qeth_l2_probe_device(struct ccwgroup_device *gdev) + { + struct qeth_card *card = dev_get_drvdata(&gdev->dev); ++ int rc; + +- qeth_l2_create_device_attributes(&gdev->dev); ++ rc = qeth_l2_create_device_attributes(&gdev->dev); ++ if (rc) ++ return rc; + INIT_LIST_HEAD(&card->vid_list); + INIT_LIST_HEAD(&card->mc_list); + card->options.layer2 = 1; +--- a/drivers/s390/net/qeth_l3_main.c ++++ b/drivers/s390/net/qeth_l3_main.c +@@ -3317,8 +3317,11 @@ static int qeth_l3_setup_netdev(struct q + static int qeth_l3_probe_device(struct ccwgroup_device *gdev) + { + struct qeth_card *card = dev_get_drvdata(&gdev->dev); ++ int rc; + +- qeth_l3_create_device_attributes(&gdev->dev); ++ rc = qeth_l3_create_device_attributes(&gdev->dev); ++ if (rc) ++ return rc; + card->options.layer2 = 0; + card->info.hwtrap = 0; + return 0; diff --git a/queue-3.18/s390-qeth-unbreak-osm-and-osn-support.patch b/queue-3.18/s390-qeth-unbreak-osm-and-osn-support.patch new file mode 100644 index 00000000000..680f0b2837c --- /dev/null +++ b/queue-3.18/s390-qeth-unbreak-osm-and-osn-support.patch @@ -0,0 +1,263 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Julian Wiedmann +Date: Wed, 10 May 2017 19:07:52 +0200 +Subject: s390/qeth: unbreak OSM and OSN support + +From: Julian Wiedmann + + +[ Upstream commit 2d2ebb3ed0c6acfb014f98e427298673a5d07b82 ] + +commit b4d72c08b358 ("qeth: bridgeport support - basic control") +broke the support for OSM and OSN devices as follows: + +As OSM and OSN are L2 only, qeth_core_probe_device() does an early +setup by loading the l2 discipline and calling qeth_l2_probe_device(). +In this context, adding the l2-specific bridgeport sysfs attributes +via qeth_l2_create_device_attributes() hits a BUG_ON in fs/sysfs/group.c, +since the basic sysfs infrastructure for the device hasn't been +established yet. + +Note that OSN actually has its own unique sysfs attributes +(qeth_osn_devtype), so the additional attributes shouldn't be created +at all. +For OSM, add a new qeth_l2_devtype that contains all the common +and l2-specific sysfs attributes. +When qeth_core_probe_device() does early setup for OSM or OSN, assign +the corresponding devtype so that the ccwgroup probe code creates the +full set of sysfs attributes. +This allows us to skip qeth_l2_create_device_attributes() in case +of an early setup. + +Any device that can't do early setup will initially have only the +generic sysfs attributes, and when it's probed later +qeth_l2_probe_device() adds the l2-specific attributes. + +If an early-setup device is removed (by calling ccwgroup_ungroup()), +device_unregister() will - using the devtype - delete the +l2-specific attributes before qeth_l2_remove_device() is called. +So make sure to not remove them twice. + +What complicates the issue is that qeth_l2_probe_device() and +qeth_l2_remove_device() is also called on a device when its +layer2 attribute changes (ie. its layer mode is switched). +For early-setup devices this wouldn't work properly - we wouldn't +remove the l2-specific attributes when switching to L3. +But switching the layer mode doesn't actually make any sense; +we already decided that the device can only operate in L2! +So just refuse to switch the layer mode on such devices. Note that +OSN doesn't have a layer2 attribute, so we only need to special-case +OSM. + +Based on an initial patch by Ursula Braun. + +Fixes: b4d72c08b358 ("qeth: bridgeport support - basic control") +Signed-off-by: Julian Wiedmann +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + drivers/s390/net/qeth_core.h | 4 ++++ + drivers/s390/net/qeth_core_main.c | 17 +++++++++-------- + drivers/s390/net/qeth_core_sys.c | 22 ++++++++++++++-------- + drivers/s390/net/qeth_l2.h | 2 ++ + drivers/s390/net/qeth_l2_main.c | 17 +++++++++++++---- + drivers/s390/net/qeth_l2_sys.c | 8 ++++++++ + drivers/s390/net/qeth_l3_main.c | 1 + + 7 files changed, 51 insertions(+), 20 deletions(-) + +--- a/drivers/s390/net/qeth_core.h ++++ b/drivers/s390/net/qeth_core.h +@@ -722,6 +722,7 @@ enum qeth_discipline_id { + }; + + struct qeth_discipline { ++ const struct device_type *devtype; + void (*start_poll)(struct ccw_device *, int, unsigned long); + qdio_handler_t *input_handler; + qdio_handler_t *output_handler; +@@ -887,6 +888,9 @@ extern struct qeth_discipline qeth_l2_di + extern struct qeth_discipline qeth_l3_discipline; + extern const struct attribute_group *qeth_generic_attr_groups[]; + extern const struct attribute_group *qeth_osn_attr_groups[]; ++extern const struct attribute_group qeth_device_attr_group; ++extern const struct attribute_group qeth_device_blkt_group; ++extern const struct device_type qeth_generic_devtype; + extern struct workqueue_struct *qeth_wq; + + int qeth_card_hw_is_reachable(struct qeth_card *); +--- a/drivers/s390/net/qeth_core_main.c ++++ b/drivers/s390/net/qeth_core_main.c +@@ -5304,10 +5304,12 @@ void qeth_core_free_discipline(struct qe + card->discipline = NULL; + } + +-static const struct device_type qeth_generic_devtype = { ++const struct device_type qeth_generic_devtype = { + .name = "qeth_generic", + .groups = qeth_generic_attr_groups, + }; ++EXPORT_SYMBOL_GPL(qeth_generic_devtype); ++ + static const struct device_type qeth_osn_devtype = { + .name = "qeth_osn", + .groups = qeth_osn_attr_groups, +@@ -5433,23 +5435,22 @@ static int qeth_core_probe_device(struct + goto err_card; + } + +- if (card->info.type == QETH_CARD_TYPE_OSN) +- gdev->dev.type = &qeth_osn_devtype; +- else +- gdev->dev.type = &qeth_generic_devtype; +- + switch (card->info.type) { + case QETH_CARD_TYPE_OSN: + case QETH_CARD_TYPE_OSM: + rc = qeth_core_load_discipline(card, QETH_DISCIPLINE_LAYER2); + if (rc) + goto err_card; ++ ++ gdev->dev.type = (card->info.type != QETH_CARD_TYPE_OSN) ++ ? card->discipline->devtype ++ : &qeth_osn_devtype; + rc = card->discipline->setup(card->gdev); + if (rc) + goto err_disc; +- case QETH_CARD_TYPE_OSD: +- case QETH_CARD_TYPE_OSX: ++ break; + default: ++ gdev->dev.type = &qeth_generic_devtype; + break; + } + +--- a/drivers/s390/net/qeth_core_sys.c ++++ b/drivers/s390/net/qeth_core_sys.c +@@ -446,12 +446,16 @@ static ssize_t qeth_dev_layer2_store(str + + if (card->options.layer2 == newdis) + goto out; +- else { +- card->info.mac_bits = 0; +- if (card->discipline) { +- card->discipline->remove(card->gdev); +- qeth_core_free_discipline(card); +- } ++ if (card->info.type == QETH_CARD_TYPE_OSM) { ++ /* fixed layer, can't switch */ ++ rc = -EOPNOTSUPP; ++ goto out; ++ } ++ ++ card->info.mac_bits = 0; ++ if (card->discipline) { ++ card->discipline->remove(card->gdev); ++ qeth_core_free_discipline(card); + } + + rc = qeth_core_load_discipline(card, newdis); +@@ -745,10 +749,11 @@ static struct attribute *qeth_blkt_devic + &dev_attr_inter_jumbo.attr, + NULL, + }; +-static struct attribute_group qeth_device_blkt_group = { ++const struct attribute_group qeth_device_blkt_group = { + .name = "blkt", + .attrs = qeth_blkt_device_attrs, + }; ++EXPORT_SYMBOL_GPL(qeth_device_blkt_group); + + static struct attribute *qeth_device_attrs[] = { + &dev_attr_state.attr, +@@ -768,9 +773,10 @@ static struct attribute *qeth_device_att + &dev_attr_switch_attrs.attr, + NULL, + }; +-static struct attribute_group qeth_device_attr_group = { ++const struct attribute_group qeth_device_attr_group = { + .attrs = qeth_device_attrs, + }; ++EXPORT_SYMBOL_GPL(qeth_device_attr_group); + + const struct attribute_group *qeth_generic_attr_groups[] = { + &qeth_device_attr_group, +--- a/drivers/s390/net/qeth_l2.h ++++ b/drivers/s390/net/qeth_l2.h +@@ -8,6 +8,8 @@ + + #include "qeth_core.h" + ++extern const struct attribute_group *qeth_l2_attr_groups[]; ++ + int qeth_l2_create_device_attributes(struct device *); + void qeth_l2_remove_device_attributes(struct device *); + void qeth_l2_setup_bridgeport_attrs(struct qeth_card *card); +--- a/drivers/s390/net/qeth_l2_main.c ++++ b/drivers/s390/net/qeth_l2_main.c +@@ -887,14 +887,21 @@ static int qeth_l2_stop(struct net_devic + return 0; + } + ++static const struct device_type qeth_l2_devtype = { ++ .name = "qeth_layer2", ++ .groups = qeth_l2_attr_groups, ++}; ++ + static int qeth_l2_probe_device(struct ccwgroup_device *gdev) + { + struct qeth_card *card = dev_get_drvdata(&gdev->dev); + int rc; + +- rc = qeth_l2_create_device_attributes(&gdev->dev); +- if (rc) +- return rc; ++ if (gdev->dev.type == &qeth_generic_devtype) { ++ rc = qeth_l2_create_device_attributes(&gdev->dev); ++ if (rc) ++ return rc; ++ } + INIT_LIST_HEAD(&card->vid_list); + INIT_LIST_HEAD(&card->mc_list); + card->options.layer2 = 1; +@@ -906,7 +913,8 @@ static void qeth_l2_remove_device(struct + { + struct qeth_card *card = dev_get_drvdata(&cgdev->dev); + +- qeth_l2_remove_device_attributes(&cgdev->dev); ++ if (cgdev->dev.type == &qeth_generic_devtype) ++ qeth_l2_remove_device_attributes(&cgdev->dev); + qeth_set_allowed_threads(card, 0, 1); + wait_event(card->wait_q, qeth_threads_running(card, 0xffffffff) == 0); + +@@ -1276,6 +1284,7 @@ static int qeth_l2_control_event(struct + } + + struct qeth_discipline qeth_l2_discipline = { ++ .devtype = &qeth_l2_devtype, + .start_poll = qeth_qdio_start_poll, + .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, + .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, +--- a/drivers/s390/net/qeth_l2_sys.c ++++ b/drivers/s390/net/qeth_l2_sys.c +@@ -216,3 +216,11 @@ void qeth_l2_setup_bridgeport_attrs(stru + } else + qeth_bridgeport_an_set(card, 0); + } ++ ++const struct attribute_group *qeth_l2_attr_groups[] = { ++ &qeth_device_attr_group, ++ &qeth_device_blkt_group, ++ /* l2 specific, see l2_{create,remove}_device_attributes(): */ ++ &qeth_l2_bridgeport_attr_group, ++ NULL, ++}; +--- a/drivers/s390/net/qeth_l3_main.c ++++ b/drivers/s390/net/qeth_l3_main.c +@@ -3612,6 +3612,7 @@ static int qeth_l3_control_event(struct + } + + struct qeth_discipline qeth_l3_discipline = { ++ .devtype = &qeth_generic_devtype, + .start_poll = qeth_qdio_start_poll, + .input_handler = (qdio_handler_t *) qeth_qdio_input_handler, + .output_handler = (qdio_handler_t *) qeth_qdio_output_handler, diff --git a/queue-3.18/sctp-do-not-inherit-ipv6_-mc-ac-fl-_list-from-parent.patch b/queue-3.18/sctp-do-not-inherit-ipv6_-mc-ac-fl-_list-from-parent.patch new file mode 100644 index 00000000000..5d61102b821 --- /dev/null +++ b/queue-3.18/sctp-do-not-inherit-ipv6_-mc-ac-fl-_list-from-parent.patch @@ -0,0 +1,34 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Eric Dumazet +Date: Wed, 17 May 2017 07:16:40 -0700 +Subject: sctp: do not inherit ipv6_{mc|ac|fl}_list from parent + +From: Eric Dumazet + + +[ Upstream commit fdcee2cbb8438702ea1b328fb6e0ac5e9a40c7f8 ] + +SCTP needs fixes similar to 83eaddab4378 ("ipv6/dccp: do not inherit +ipv6_mc_list from parent"), otherwise bad things can happen. + +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/sctp/ipv6.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -673,6 +673,9 @@ static struct sock *sctp_v6_create_accep + newnp = inet6_sk(newsk); + + memcpy(newnp, np, sizeof(struct ipv6_pinfo)); ++ newnp->ipv6_mc_list = NULL; ++ newnp->ipv6_ac_list = NULL; ++ newnp->ipv6_fl_list = NULL; + + rcu_read_lock(); + opt = rcu_dereference(np->opt); diff --git a/queue-3.18/sctp-fix-icmp-processing-if-skb-is-non-linear.patch b/queue-3.18/sctp-fix-icmp-processing-if-skb-is-non-linear.patch new file mode 100644 index 00000000000..c3c578c5079 --- /dev/null +++ b/queue-3.18/sctp-fix-icmp-processing-if-skb-is-non-linear.patch @@ -0,0 +1,72 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Davide Caratti +Date: Thu, 25 May 2017 19:14:56 +0200 +Subject: sctp: fix ICMP processing if skb is non-linear + +From: Davide Caratti + + +[ Upstream commit 804ec7ebe8ea003999ca8d1bfc499edc6a9e07df ] + +sometimes ICMP replies to INIT chunks are ignored by the client, even if +the encapsulated SCTP headers match an open socket. This happens when the +ICMP packet is carried by a paged skb: use skb_header_pointer() to read +packet contents beyond the SCTP header, so that chunk header and initiate +tag are validated correctly. + +v2: +- don't use skb_header_pointer() to read the transport header, since + icmp_socket_deliver() already puts these 8 bytes in the linear area. +- change commit message to make specific reference to INIT chunks. + +Signed-off-by: Davide Caratti +Acked-by: Marcelo Ricardo Leitner +Acked-by: Vlad Yasevich +Reviewed-by: Xin Long +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/input.c | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +--- a/net/sctp/input.c ++++ b/net/sctp/input.c +@@ -472,15 +472,14 @@ struct sock *sctp_err_lookup(struct net + struct sctp_association **app, + struct sctp_transport **tpp) + { ++ struct sctp_init_chunk *chunkhdr, _chunkhdr; + union sctp_addr saddr; + union sctp_addr daddr; + struct sctp_af *af; + struct sock *sk = NULL; + struct sctp_association *asoc; + struct sctp_transport *transport = NULL; +- struct sctp_init_chunk *chunkhdr; + __u32 vtag = ntohl(sctphdr->vtag); +- int len = skb->len - ((void *)sctphdr - (void *)skb->data); + + *app = NULL; *tpp = NULL; + +@@ -515,13 +514,16 @@ struct sock *sctp_err_lookup(struct net + * discard the packet. + */ + if (vtag == 0) { +- chunkhdr = (void *)sctphdr + sizeof(struct sctphdr); +- if (len < sizeof(struct sctphdr) + sizeof(sctp_chunkhdr_t) +- + sizeof(__be32) || ++ /* chunk header + first 4 octects of init header */ ++ chunkhdr = skb_header_pointer(skb, skb_transport_offset(skb) + ++ sizeof(struct sctphdr), ++ sizeof(struct sctp_chunkhdr) + ++ sizeof(__be32), &_chunkhdr); ++ if (!chunkhdr || + chunkhdr->chunk_hdr.type != SCTP_CID_INIT || +- ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) { ++ ntohl(chunkhdr->init_hdr.init_tag) != asoc->c.my_vtag) + goto out; +- } ++ + } else if (vtag != asoc->c.peer_vtag) { + goto out; + } diff --git a/queue-3.18/sctp-fix-src-address-selection-if-using-secondary-addresses-for-ipv6.patch b/queue-3.18/sctp-fix-src-address-selection-if-using-secondary-addresses-for-ipv6.patch new file mode 100644 index 00000000000..35e5c69c6cb --- /dev/null +++ b/queue-3.18/sctp-fix-src-address-selection-if-using-secondary-addresses-for-ipv6.patch @@ -0,0 +1,119 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Xin Long +Date: Fri, 12 May 2017 14:39:52 +0800 +Subject: sctp: fix src address selection if using secondary addresses for ipv6 + +From: Xin Long + + +[ Upstream commit dbc2b5e9a09e9a6664679a667ff81cff6e5f2641 ] + +Commit 0ca50d12fe46 ("sctp: fix src address selection if using secondary +addresses") has fixed a src address selection issue when using secondary +addresses for ipv4. + +Now sctp ipv6 also has the similar issue. When using a secondary address, +sctp_v6_get_dst tries to choose the saddr which has the most same bits +with the daddr by sctp_v6_addr_match_len. It may make some cases not work +as expected. + +hostA: + [1] fd21:356b:459a:cf10::11 (eth1) + [2] fd21:356b:459a:cf20::11 (eth2) + +hostB: + [a] fd21:356b:459a:cf30::2 (eth1) + [b] fd21:356b:459a:cf40::2 (eth2) + +route from hostA to hostB: + fd21:356b:459a:cf30::/64 dev eth1 metric 1024 mtu 1500 + +The expected path should be: + fd21:356b:459a:cf10::11 <-> fd21:356b:459a:cf30::2 +But addr[2] matches addr[a] more bits than addr[1] does, according to +sctp_v6_addr_match_len. It causes the path to be: + fd21:356b:459a:cf20::11 <-> fd21:356b:459a:cf30::2 + +This patch is to fix it with the same way as Marcelo's fix for sctp ipv4. +As no ip_dev_find for ipv6, this patch is to use ipv6_chk_addr to check +if the saddr is in a dev instead. + +Note that for backwards compatibility, it will still do the addr_match_len +check here when no optimal is found. + +Reported-by: Patrick Talbert +Signed-off-by: Xin Long +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/sctp/ipv6.c | 46 +++++++++++++++++++++++++++++----------------- + 1 file changed, 29 insertions(+), 17 deletions(-) + +--- a/net/sctp/ipv6.c ++++ b/net/sctp/ipv6.c +@@ -239,12 +239,10 @@ static void sctp_v6_get_dst(struct sctp_ + struct sctp_bind_addr *bp; + struct ipv6_pinfo *np = inet6_sk(sk); + struct sctp_sockaddr_entry *laddr; +- union sctp_addr *baddr = NULL; + union sctp_addr *daddr = &t->ipaddr; + union sctp_addr dst_saddr; + struct in6_addr *final_p, final; + __u8 matchlen = 0; +- __u8 bmatchlen; + sctp_scope_t scope; + + memset(fl6, 0, sizeof(struct flowi6)); +@@ -311,23 +309,37 @@ static void sctp_v6_get_dst(struct sctp_ + */ + rcu_read_lock(); + list_for_each_entry_rcu(laddr, &bp->address_list, list) { +- if (!laddr->valid) ++ struct dst_entry *bdst; ++ __u8 bmatchlen; ++ ++ if (!laddr->valid || ++ laddr->state != SCTP_ADDR_SRC || ++ laddr->a.sa.sa_family != AF_INET6 || ++ scope > sctp_scope(&laddr->a)) + continue; +- if ((laddr->state == SCTP_ADDR_SRC) && +- (laddr->a.sa.sa_family == AF_INET6) && +- (scope <= sctp_scope(&laddr->a))) { +- bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); +- if (!baddr || (matchlen < bmatchlen)) { +- baddr = &laddr->a; +- matchlen = bmatchlen; +- } +- } +- } +- if (baddr) { +- fl6->saddr = baddr->v6.sin6_addr; +- fl6->fl6_sport = baddr->v6.sin6_port; ++ ++ fl6->saddr = laddr->a.v6.sin6_addr; ++ fl6->fl6_sport = laddr->a.v6.sin6_port; + final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final); +- dst = ip6_dst_lookup_flow(sk, fl6, final_p); ++ bdst = ip6_dst_lookup_flow(sk, fl6, final_p); ++ ++ if (!IS_ERR(bdst) && ++ ipv6_chk_addr(dev_net(bdst->dev), ++ &laddr->a.v6.sin6_addr, bdst->dev, 1)) { ++ if (!IS_ERR_OR_NULL(dst)) ++ dst_release(dst); ++ dst = bdst; ++ break; ++ } ++ ++ bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a); ++ if (matchlen > bmatchlen) ++ continue; ++ ++ if (!IS_ERR_OR_NULL(dst)) ++ dst_release(dst); ++ dst = bdst; ++ matchlen = bmatchlen; + } + rcu_read_unlock(); + diff --git a/queue-3.18/series b/queue-3.18/series index 859878b1edf..8c399be96ea 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -1,2 +1,16 @@ revert-stackprotector-increase-the-per-task-stack-canary-s-random-range-from-32-bits-to-64-bits-on-64-bit-platforms.patch netem-fix-skb_orphan_partial.patch +dccp-tcp-do-not-inherit-mc_list-from-parent.patch +s390-qeth-handle-sysfs-error-during-initialization.patch +s390-qeth-unbreak-osm-and-osn-support.patch +s390-qeth-avoid-null-pointer-dereference-on-osn.patch +tcp-avoid-fragmenting-peculiar-skbs-in-sack.patch +sctp-fix-src-address-selection-if-using-secondary-addresses-for-ipv6.patch +sctp-do-not-inherit-ipv6_-mc-ac-fl-_list-from-parent.patch +tcp-eliminate-negative-reordering-in-tcp_clean_rtx_queue.patch +ipv6-prevent-overrun-when-parsing-v6-header-options.patch +ipv6-check-ip6_find_1stfragopt-return-value-properly.patch +qmi_wwan-add-another-lenovo-em74xx-device-id.patch +ipv6-fix-out-of-bound-writes-in-__ip6_append_data.patch +tcp-avoid-fastopen-api-to-be-used-on-af_unspec.patch +sctp-fix-icmp-processing-if-skb-is-non-linear.patch diff --git a/queue-3.18/tcp-avoid-fastopen-api-to-be-used-on-af_unspec.patch b/queue-3.18/tcp-avoid-fastopen-api-to-be-used-on-af_unspec.patch new file mode 100644 index 00000000000..5c032de3c65 --- /dev/null +++ b/queue-3.18/tcp-avoid-fastopen-api-to-be-used-on-af_unspec.patch @@ -0,0 +1,88 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Wei Wang +Date: Wed, 24 May 2017 09:59:31 -0700 +Subject: tcp: avoid fastopen API to be used on AF_UNSPEC + +From: Wei Wang + + +[ Upstream commit ba615f675281d76fd19aa03558777f81fb6b6084 ] + +Fastopen API should be used to perform fastopen operations on the TCP +socket. It does not make sense to use fastopen API to perform disconnect +by calling it with AF_UNSPEC. The fastopen data path is also prone to +race conditions and bugs when using with AF_UNSPEC. + +One issue reported and analyzed by Vegard Nossum is as follows: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +Thread A: Thread B: +------------------------------------------------------------------------ +sendto() + - tcp_sendmsg() + - sk_stream_memory_free() = 0 + - goto wait_for_sndbuf + - sk_stream_wait_memory() + - sk_wait_event() // sleep + | sendto(flags=MSG_FASTOPEN, dest_addr=AF_UNSPEC) + | - tcp_sendmsg() + | - tcp_sendmsg_fastopen() + | - __inet_stream_connect() + | - tcp_disconnect() //because of AF_UNSPEC + | - tcp_transmit_skb()// send RST + | - return 0; // no reconnect! + | - sk_stream_wait_connect() + | - sock_error() + | - xchg(&sk->sk_err, 0) + | - return -ECONNRESET + - ... // wake up, see sk->sk_err == 0 + - skb_entail() on TCP_CLOSE socket + +If the connection is reopened then we will send a brand new SYN packet +after thread A has already queued a buffer. At this point I think the +socket internal state (sequence numbers etc.) becomes messed up. + +When the new connection is closed, the FIN-ACK is rejected because the +sequence number is outside the window. The other side tries to +retransmit, +but __tcp_retransmit_skb() calls tcp_trim_head() on an empty skb which +corrupts the skb data length and hits a BUG() in copy_and_csum_bits(). ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +Hence, this patch adds a check for AF_UNSPEC in the fastopen data path +and return EOPNOTSUPP to user if such case happens. + +Fixes: cf60af03ca4e7 ("tcp: Fast Open client - sendmsg(MSG_FASTOPEN)") +Reported-by: Vegard Nossum +Signed-off-by: Wei Wang +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +--- a/net/ipv4/tcp.c ++++ b/net/ipv4/tcp.c +@@ -1066,9 +1066,12 @@ static int tcp_sendmsg_fastopen(struct s + int *copied, size_t size) + { + struct tcp_sock *tp = tcp_sk(sk); ++ struct sockaddr *uaddr = msg->msg_name; + int err, flags; + +- if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE)) ++ if (!(sysctl_tcp_fastopen & TFO_CLIENT_ENABLE) || ++ (uaddr && msg->msg_namelen >= sizeof(uaddr->sa_family) && ++ uaddr->sa_family == AF_UNSPEC)) + return -EOPNOTSUPP; + if (tp->fastopen_req != NULL) + return -EALREADY; /* Another Fast Open is in progress */ +@@ -1081,7 +1084,7 @@ static int tcp_sendmsg_fastopen(struct s + tp->fastopen_req->size = size; + + flags = (msg->msg_flags & MSG_DONTWAIT) ? O_NONBLOCK : 0; +- err = __inet_stream_connect(sk->sk_socket, msg->msg_name, ++ err = __inet_stream_connect(sk->sk_socket, uaddr, + msg->msg_namelen, flags); + *copied = tp->fastopen_req->copied; + tcp_free_fastopen_req(tp); diff --git a/queue-3.18/tcp-avoid-fragmenting-peculiar-skbs-in-sack.patch b/queue-3.18/tcp-avoid-fragmenting-peculiar-skbs-in-sack.patch new file mode 100644 index 00000000000..5eadeba6ece --- /dev/null +++ b/queue-3.18/tcp-avoid-fragmenting-peculiar-skbs-in-sack.patch @@ -0,0 +1,55 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Yuchung Cheng +Date: Wed, 10 May 2017 17:01:27 -0700 +Subject: tcp: avoid fragmenting peculiar skbs in SACK + +From: Yuchung Cheng + + +[ Upstream commit b451e5d24ba6687c6f0e7319c727a709a1846c06 ] + +This patch fixes a bug in splitting an SKB during SACK +processing. Specifically if an skb contains multiple +packets and is only partially sacked in the higher sequences, +tcp_match_sack_to_skb() splits the skb and marks the second fragment +as SACKed. + +The current code further attempts rounding up the first fragment +to MSS boundaries. But it misses a boundary condition when the +rounded-up fragment size (pkt_len) is exactly skb size. Spliting +such an skb is pointless and causses a kernel warning and aborts +the SACK processing. This patch universally checks such over-split +before calling tcp_fragment to prevent these unnecessary warnings. + +Fixes: adb92db857ee ("tcp: Make SACK code to split only at mss boundaries") +Signed-off-by: Yuchung Cheng +Signed-off-by: Eric Dumazet +Signed-off-by: Soheil Hassas Yeganeh +Acked-by: Neal Cardwell +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_input.c | 9 +++++---- + 1 file changed, 5 insertions(+), 4 deletions(-) + +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -1171,13 +1171,14 @@ static int tcp_match_skb_to_sack(struct + */ + if (pkt_len > mss) { + unsigned int new_len = (pkt_len / mss) * mss; +- if (!in_sack && new_len < pkt_len) { ++ if (!in_sack && new_len < pkt_len) + new_len += mss; +- if (new_len >= skb->len) +- return 0; +- } + pkt_len = new_len; + } ++ ++ if (pkt_len >= skb->len && !in_sack) ++ return 0; ++ + err = tcp_fragment(sk, skb, pkt_len, mss, GFP_ATOMIC); + if (err < 0) + return err; diff --git a/queue-3.18/tcp-eliminate-negative-reordering-in-tcp_clean_rtx_queue.patch b/queue-3.18/tcp-eliminate-negative-reordering-in-tcp_clean_rtx_queue.patch new file mode 100644 index 00000000000..3d2a248821e --- /dev/null +++ b/queue-3.18/tcp-eliminate-negative-reordering-in-tcp_clean_rtx_queue.patch @@ -0,0 +1,44 @@ +From foo@baz Fri Jun 2 12:04:25 JST 2017 +From: Soheil Hassas Yeganeh +Date: Mon, 15 May 2017 17:05:47 -0400 +Subject: tcp: eliminate negative reordering in tcp_clean_rtx_queue + +From: Soheil Hassas Yeganeh + + +[ Upstream commit bafbb9c73241760023d8981191ddd30bb1c6dbac ] + +tcp_ack() can call tcp_fragment() which may dededuct the +value tp->fackets_out when MSS changes. When prior_fackets +is larger than tp->fackets_out, tcp_clean_rtx_queue() can +invoke tcp_update_reordering() with negative values. This +results in absurd tp->reodering values higher than +sysctl_tcp_max_reordering. + +Note that tcp_update_reordering indeeds sets tp->reordering +to min(sysctl_tcp_max_reordering, metric), but because +the comparison is signed, a negative metric always wins. + +Fixes: c7caf8d3ed7a ("[TCP]: Fix reord detection due to snd_una covered holes") +Reported-by: Rebecca Isaacs +Signed-off-by: Soheil Hassas Yeganeh +Signed-off-by: Neal Cardwell +Signed-off-by: Yuchung Cheng +Signed-off-by: Eric Dumazet +Signed-off-by: David S. Miller +Signed-off-by: Greg Kroah-Hartman +--- + net/ipv4/tcp_input.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +--- a/net/ipv4/tcp_input.c ++++ b/net/ipv4/tcp_input.c +@@ -3173,7 +3173,7 @@ static int tcp_clean_rtx_queue(struct so + int delta; + + /* Non-retransmitted hole got filled? That's reordering */ +- if (reord < prior_fackets) ++ if (reord < prior_fackets && reord <= tp->fackets_out) + tcp_update_reordering(sk, tp->fackets_out - reord, 0); + + delta = tcp_is_fack(tp) ? pkts_acked :