Re: Infinite loop in ip6_fragment

2015-10-13 Thread Hannes Frederic Sowa
Hello,

On Mon, Oct 12, 2015, at 11:26, Dmitry Vyukov wrote:
>  [] ip6_fragment+0x37e/0x9d0 net/ipv6/ip6_output.c:805
>  [] ip6_finish_output+0xcd/0xe0
>  net/ipv6/ip6_output.c:130
>  [< inline >] NF_HOOK_COND include/linux/netfilter.h:236
>  [] ip6_output+0x3f/0xe0 net/ipv6/ip6_output.c:146
>  [< inline >] dst_output_sk include/net/dst.h:459
>  [] ip6_local_out_sk+0x28/0x30
>  net/ipv6/output_core.c:167
>  [] ip6_local_out+0x10/0x20 net/ipv6/output_core.c:175
>  [] ip6_send_skb+0x18/0x60 net/ipv6/ip6_output.c:1683
>  [] ip6_push_pending_frames+0x34/0x40
> net/ipv6/ip6_output.c:1703
>  [< inline >] rawv6_push_pending_frames net/ipv6/raw.c:607
>  [] rawv6_sendmsg+0x871/0xb30 net/ipv6/raw.c:901
>  [] inet_sendmsg+0x62/0xa0 net/ipv4/af_inet.c:737
>  [< inline >] sock_sendmsg_nosec net/socket.c:610
>  [] sock_sendmsg+0x33/0x40 net/socket.c:620
>  [] sock_write_iter+0x73/0xd0 net/socket.c:819
>  [< inline >] do_iter_readv_writev fs/read_write.c:664
>  [] do_readv_writev+0x1bd/0x270 fs/read_write.c:808
>  [] vfs_writev+0x34/0x40 fs/read_write.c:847
>  [< inline >] SYSC_writev fs/read_write.c:880
>  [] SyS_writev+0x45/0xc0 fs/read_write.c:872
>  [] entry_SYSCALL_64_fastpath+0x12/0x6a
> arch/x86/entry/entry_64.S:185
> 
> ip6_fragment computes mtu value as 4, which is then rounded down to 8
> and becomes 0. This causes infinite send loop by 0 bytes. Initial mtu
> value is 1500, but here is becomes 4:
> 
> mtu -= hlen + sizeof(struct frag_hdr);
> 
> sizeof(struct frag_hdr) = 8, hlen = 1488.

Yeah, absolutely logic and difficult to fix.

Because of the unknown socket(..., ..., protocol = 0x) you enabled
hdrincl. The writev included non-fragmentable padding and options (yeah
by being just zeros). hlen is the non-fragmentable header length of the
packet and thus reduced the length of the actual payload near to or
equal to zero.

I think we just have to abort sending those packets and send errors back
to user space.

Thanks for the report!

Bye,
Hannes
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html


Infinite loop in ip6_fragment

2015-10-12 Thread Dmitry Vyukov
Hello,

The following program causes infinite loop in ip6_fragment function:

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include 
#include 
#include 

int main()
{
long r0 = syscall(SYS_socket, 0xaul, 0x3ul, 0x53cul);
long r1 = syscall(SYS_mmap, 0x2000ul, 0x1000ul, 0x3ul,
0x32ul, 0xul, 0x0ul);
*(uint64_t*)0x2fc0 = 0xa;
*(uint64_t*)0x2fc8 = 0x;
*(uint64_t*)0x2fd0 = 0x0;
*(uint64_t*)0x2fd8 = 0xa5;
*(uint64_t*)0x2fe0 = 0x1;
*(uint64_t*)0x2fe8 = 0x9;
*(uint64_t*)0x2ff0 = 0x8;
*(uint64_t*)0x2ff8 = 0x4cd;
long r10 = syscall(SYS_connect, r0, 0x2fc0ul, 0x40ul);
long r11 = syscall(SYS_mmap, 0x20001000ul, 0x1000ul, 0x3ul,
0x32ul, 0xul, 0x0ul);
long r12 = syscall(SYS_mmap, 0x20002000ul, 0x1000ul, 0x3ul,
0x32ul, 0xul, 0x0ul);
long r13 = syscall(SYS_mmap, 0x20003000ul, 0x1000ul, 0x3ul,
0x32ul, 0xul, 0x0ul);
*(uint64_t*)0x200010b3 = 0x200012e6;
*(uint64_t*)0x200010bb = 0xf;
*(uint64_t*)0x200010c3 = 0x20002000;
*(uint64_t*)0x200010cb = 0x1000;
long r20 = syscall(SYS_writev, r0, 0x200010b3ul, 0x2ul);
return 0;
}

On commit dd36d7393d6310b0c1adefb22fba79c3cf8a577c
(git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git)

INFO: rcu_sched self-detected stall on CPU
0: (20822 ticks this GP) idle=94b/141/0
softirq=2353/2355 fqs=6717
 (t=21000 jiffies g=1103 c=1102 q=171)
Task dump for CPU 0:
a.out   R  running task13472  2613   2610 0x0008
 81e40900 88083fc03bb0 810788b3 
 81e40900 88083fc03bc8 8107ab84 0001
 88083fc03bf8 8109fc35 88083fc15e00 81e40900
Call Trace:
   [] sched_show_task+0xc3/0x120 kernel/sched/core.c:4874
 [] dump_cpu_task+0x34/0x40 kernel/sched/core.c:8563
 [] rcu_dump_cpu_stacks+0x85/0xc0 kernel/rcu/tree.c:1199
 [< inline >] print_cpu_stall kernel/rcu/tree.c:1306
 [< inline >] check_cpu_stall kernel/rcu/tree.c:1370
 [< inline >] __rcu_pending kernel/rcu/tree.c:3601
 [< inline >] rcu_pending kernel/rcu/tree.c:3665
 [] rcu_check_callbacks+0x45c/0x740 kernel/rcu/tree.c:2764
 [] update_process_times+0x34/0x60 kernel/time/timer.c:1397
 [] tick_sched_handle.isra.15+0x31/0x40
kernel/time/tick-sched.c:151
 [] tick_sched_timer+0x3b/0x70 kernel/time/tick-sched.c:1070
 [< inline >] __run_hrtimer kernel/time/hrtimer.c:1229
 [] __hrtimer_run_queues+0xda/0x1f0 kernel/time/hrtimer.c:1293
 [] hrtimer_interrupt+0xa3/0x190 kernel/time/hrtimer.c:1327
 [] local_apic_timer_interrupt+0x30/0x60
arch/x86/kernel/apic/apic.c:901
 [] smp_apic_timer_interrupt+0x38/0x50
arch/x86/kernel/apic/apic.c:925
 [] apic_timer_interrupt+0x7f/0x90
arch/x86/entry/entry_64.S:683
 [< inline >] napi_poll net/core/dev.c:4755
 [] net_rx_action+0x134/0x300 net/core/dev.c:4820
 [] __do_softirq+0xc7/0x240 kernel/softirq.c:273
 [] do_softirq_own_stack+0x1c/0x30
arch/x86/entry/entry_64.S:871
   [] do_softirq+0x2c/0x40 kernel/softirq.c:317
 [] __local_bh_enable_ip+0x73/0x80 kernel/softirq.c:170
 [< inline >] local_bh_enable include/linux/bottom_half.h:31
 [< inline >] rcu_read_unlock_bh include/linux/rcupdate.h:954
 [] ip6_finish_output2+0x16c/0x480 net/ipv6/ip6_output.c:114
 [] ip6_fragment+0x37e/0x9d0 net/ipv6/ip6_output.c:805
 [] ip6_finish_output+0xcd/0xe0 net/ipv6/ip6_output.c:130
 [< inline >] NF_HOOK_COND include/linux/netfilter.h:236
 [] ip6_output+0x3f/0xe0 net/ipv6/ip6_output.c:146
 [< inline >] dst_output_sk include/net/dst.h:459
 [] ip6_local_out_sk+0x28/0x30 net/ipv6/output_core.c:167
 [] ip6_local_out+0x10/0x20 net/ipv6/output_core.c:175
 [] ip6_send_skb+0x18/0x60 net/ipv6/ip6_output.c:1683
 [] ip6_push_pending_frames+0x34/0x40
net/ipv6/ip6_output.c:1703
 [< inline >] rawv6_push_pending_frames net/ipv6/raw.c:607
 [] rawv6_sendmsg+0x871/0xb30 net/ipv6/raw.c:901
 [] inet_sendmsg+0x62/0xa0 net/ipv4/af_inet.c:737
 [< inline >] sock_sendmsg_nosec net/socket.c:610
 [] sock_sendmsg+0x33/0x40 net/socket.c:620
 [] sock_write_iter+0x73/0xd0 net/socket.c:819
 [< inline >] do_iter_readv_writev fs/read_write.c:664
 [] do_readv_writev+0x1bd/0x270 fs/read_write.c:808
 [] vfs_writev+0x34/0x40 fs/read_write.c:847
 [< inline >] SYSC_writev fs/read_write.c:880
 [] SyS_writev+0x45/0xc0 fs/read_write.c:872
 [] entry_SYSCALL_64_fastpath+0x12/0x6a
arch/x86/entry/entry_64.S:185

ip6_fragment computes mtu value as 4, which is then rounded down to 8
and becomes 0. This causes infinite send loop by 0 bytes. Initial mtu
value is 1500, but here is becomes 4:

mtu -= hlen + sizeof(struct frag_hdr);

sizeof(struct frag_hdr) = 8