Infinite loop in ip6_fragment

From: Dmitry Vyukov
Date: Mon Oct 12 2015 - 05:26:35 EST


Hello,

The following program causes infinite loop in ip6_fragment function:

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#include <syscall.h>
#include <string.h>
#include <stdint.h>

int main()
{
long r0 = syscall(SYS_socket, 0xaul, 0x3ul, 0x53cul);
long r1 = syscall(SYS_mmap, 0x20000000ul, 0x1000ul, 0x3ul,
0x32ul, 0xfffffffffffffffful, 0x0ul);
*(uint64_t*)0x20000fc0 = 0xa;
*(uint64_t*)0x20000fc8 = 0xffffffffffffffff;
*(uint64_t*)0x20000fd0 = 0x0;
*(uint64_t*)0x20000fd8 = 0xa5;
*(uint64_t*)0x20000fe0 = 0x1;
*(uint64_t*)0x20000fe8 = 0x9;
*(uint64_t*)0x20000ff0 = 0x8;
*(uint64_t*)0x20000ff8 = 0x4cd;
long r10 = syscall(SYS_connect, r0, 0x20000fc0ul, 0x40ul);
long r11 = syscall(SYS_mmap, 0x20001000ul, 0x1000ul, 0x3ul,
0x32ul, 0xfffffffffffffffful, 0x0ul);
long r12 = syscall(SYS_mmap, 0x20002000ul, 0x1000ul, 0x3ul,
0x32ul, 0xfffffffffffffffful, 0x0ul);
long r13 = syscall(SYS_mmap, 0x20003000ul, 0x1000ul, 0x3ul,
0x32ul, 0xfffffffffffffffful, 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/140000000000001/0
softirq=2353/2355 fqs=6717
(t=21000 jiffies g=1103 c=1102 q=171)
Task dump for CPU 0:
a.out R running task 13472 2613 2610 0x00000008
ffffffff81e40900 ffff88083fc03bb0 ffffffff810788b3 0000000000000000
ffffffff81e40900 ffff88083fc03bc8 ffffffff8107ab84 0000000000000001
ffff88083fc03bf8 ffffffff8109fc35 ffff88083fc15e00 ffffffff81e40900
Call Trace:
<IRQ> [<ffffffff810788b3>] sched_show_task+0xc3/0x120 kernel/sched/core.c:4874
[<ffffffff8107ab84>] dump_cpu_task+0x34/0x40 kernel/sched/core.c:8563
[<ffffffff8109fc35>] 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
[<ffffffff810a2f9c>] rcu_check_callbacks+0x45c/0x740 kernel/rcu/tree.c:2764
[<ffffffff810a7a84>] update_process_times+0x34/0x60 kernel/time/timer.c:1397
[<ffffffff810b5481>] tick_sched_handle.isra.15+0x31/0x40
kernel/time/tick-sched.c:151
[<ffffffff810b5a3b>] tick_sched_timer+0x3b/0x70 kernel/time/tick-sched.c:1070
[< inline >] __run_hrtimer kernel/time/hrtimer.c:1229
[<ffffffff810a851a>] __hrtimer_run_queues+0xda/0x1f0 kernel/time/hrtimer.c:1293
[<ffffffff810a88f3>] hrtimer_interrupt+0xa3/0x190 kernel/time/hrtimer.c:1327
[<ffffffff810373a0>] local_apic_timer_interrupt+0x30/0x60
arch/x86/kernel/apic/apic.c:901
[<ffffffff81037cc8>] smp_apic_timer_interrupt+0x38/0x50
arch/x86/kernel/apic/apic.c:925
[<ffffffff8185a7cf>] apic_timer_interrupt+0x7f/0x90
arch/x86/entry/entry_64.S:683
[< inline >] napi_poll net/core/dev.c:4755
[<ffffffff81695784>] net_rx_action+0x134/0x300 net/core/dev.c:4820
[<ffffffff81056117>] __do_softirq+0xc7/0x240 kernel/softirq.c:273
[<ffffffff8185b6dc>] do_softirq_own_stack+0x1c/0x30
arch/x86/entry/entry_64.S:871
<EOI> [<ffffffff810562fc>] do_softirq+0x2c/0x40 kernel/softirq.c:317
[<ffffffff81056383>] __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
[<ffffffff8174f71c>] ip6_finish_output2+0x16c/0x480 net/ipv6/ip6_output.c:114
[<ffffffff8175164e>] ip6_fragment+0x37e/0x9d0 net/ipv6/ip6_output.c:805
[<ffffffff81751d6d>] ip6_finish_output+0xcd/0xe0 net/ipv6/ip6_output.c:130
[< inline >] NF_HOOK_COND include/linux/netfilter.h:236
[<ffffffff81751dbf>] ip6_output+0x3f/0xe0 net/ipv6/ip6_output.c:146
[< inline >] dst_output_sk include/net/dst.h:459
[<ffffffff8178ae68>] ip6_local_out_sk+0x28/0x30 net/ipv6/output_core.c:167
[<ffffffff8178ae80>] ip6_local_out+0x10/0x20 net/ipv6/output_core.c:175
[<ffffffff81752358>] ip6_send_skb+0x18/0x60 net/ipv6/ip6_output.c:1683
[<ffffffff817523d4>] ip6_push_pending_frames+0x34/0x40
net/ipv6/ip6_output.c:1703
[< inline >] rawv6_push_pending_frames net/ipv6/raw.c:607
[<ffffffff8176ccc1>] rawv6_sendmsg+0x871/0xb30 net/ipv6/raw.c:901
[<ffffffff81717d32>] inet_sendmsg+0x62/0xa0 net/ipv4/af_inet.c:737
[< inline >] sock_sendmsg_nosec net/socket.c:610
[<ffffffff8167b4c3>] sock_sendmsg+0x33/0x40 net/socket.c:620
[<ffffffff8167b543>] sock_write_iter+0x73/0xd0 net/socket.c:819
[< inline >] do_iter_readv_writev fs/read_write.c:664
[<ffffffff81165d7d>] do_readv_writev+0x1bd/0x270 fs/read_write.c:808
[<ffffffff81165ea4>] vfs_writev+0x34/0x40 fs/read_write.c:847
[< inline >] SYSC_writev fs/read_write.c:880
[<ffffffff81166b05>] SyS_writev+0x45/0xc0 fs/read_write.c:872
[<ffffffff81859a97>] 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.

I use plain defconfig/kvmconfig.

Found with syzkaller fuzzer.
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/