Subject: Re: kernel >= 4.0: crashes when using traceroute6 with isatap

From: Vlad Yasevich <[email-masked]>
Date: Tue, 12 May 2015 16:46:31 -0400

On 05/12/2015 04:36 PM, Eric Dumazet wrote:
> On Tue, 2015-05-12 at 16:18 -0400, Vlad Yasevich wrote:
>> On 05/06/2015 06:11 PM, Wolfgang Walter wrote:
>>> Am Mittwoch, 6. Mai 2015, 11:15:18 schrieben Sie:
>>>> (Cc'ing netdev.)
>>>>
>>>> On Sat, May 2, 2015 at 5:29 AM, Wolfgang Walter <[email-masked]> wrote:
>>>>> Am Samstag, 2. Mai 2015, 02:16:36 schrieb Wolfgang Walter:
>>>>>> Hello,
>>>>>>
>>>>>> kernel 4.0 (and 4.0.1) crashes immediately when I use traceroute6 with an
>>>>>> isatap-tunnel.
>>>>>
>>>>> I did some further tests. To trigger the crash you need
>>>>>
>>>>> * isatap-tunnel (probably any sit-tunnel will do it)
>>>>> * raw-socket
>>>>> * udp
>>>>>
>>>>> Using icmpv6 or tcp i.e. does not trigger it.
>>>>
>>>> Do you have a script to reproduce it?
>>>>
>>>>
>>>> Thanks for the bug report!
>>>
>>> You need a isatap-server with say ipv4-address $X
>>>
>>> Then, on host with 4.0, start isatapd: isatapd --mtu 1280 $X
>>>
>>> then do
>>>
>>> 	traceroute6 www.google.de
>>>
>>> Regards,
>>>
>>
>> Hi Walter
>>
>> Could you try this patch.  Looks like raw passes transhdrlen
>> of 0 on the first packet and that makes IPv4 behave correctly,
>> but not IPv6.
>>
>>
>> diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
>> index 7fde1f2..fd9c079 100644
>> --- a/net/ipv6/ip6_output.c
>> +++ b/net/ipv6/ip6_output.c
>> @@ -1278,7 +1278,7 @@ emsgsize:
>>  	/* If this is the first and only packet and device
>>  	 * supports checksum offloading, let's use it.
>>  	 */
>> -	if (!skb && sk->sk_protocol == IPPROTO_UDP &&
>> +	if (transhdrlen && sk->sk_protocol == IPPROTO_UDP &&
>>  	    length + fragheaderlen < mtu &&
>>  	    rt->dst.dev->features & NETIF_F_V6_CSUM &&
>>  	    !exthdrlen)
> 
> And make sure the checksum is correct ;)
> 
> Vlad, can you tell where skb->cum_start and skb->csum_offset are set ?
> 
> 

For udp, udp6_hwcsum_outgoing(), but with the above patch, the check above will return
false, and we'll fallback to using CHECKSUM_NONE.

Before, the !skb was true since there there was no skb on the queue.  Now, that
we are checking transhdr and raw passing in 0, the check will be false.  This
is what's making IPv4 work correctly in this case.

-vlad