Re: net: heap out-of-bounds in fib6_clean_node/rt6_fill_node/fib6_age/fib6_prune_clone

From: Andrey Konovalov
Date: Thu Apr 20 2017 - 11:28:54 EST


I've extracted a reproducer for another bug.

This one seems to be much closer to what Dmitry reported intially.

------------[ cut here ]------------
WARNING: CPU: 1 PID: 3892 at net/ipv6/ip6_fib.c:1472 fib6_del+0xa60/0xdc0
Modules linked in:
CPU: 1 PID: 3892 Comm: a.out Not tainted 4.11.0-rc7+ #251
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Bochs 01/01/2011
Call Trace:
__dump_stack lib/dump_stack.c:16
dump_stack+0x292/0x398 lib/dump_stack.c:52
__warn+0x19f/0x1e0 kernel/panic.c:549
warn_slowpath_null+0x2c/0x40 kernel/panic.c:584
fib6_del+0xa60/0xdc0 net/ipv6/ip6_fib.c:1472
fib6_clean_node+0x3ce/0x550 net/ipv6/ip6_fib.c:1652
fib6_walk_continue+0x577/0x760 net/ipv6/ip6_fib.c:1578
fib6_walk+0x91/0xf0 net/ipv6/ip6_fib.c:1623
fib6_clean_tree+0x266/0x3c0 net/ipv6/ip6_fib.c:1695
__fib6_clean_all+0x1f7/0x3b0 net/ipv6/ip6_fib.c:1711
fib6_clean_all+0x27/0x30 net/ipv6/ip6_fib.c:1722
rt6_ifdown+0xf7/0x910 net/ipv6/route.c:2820
addrconf_ifdown+0x1a3/0x1aa0 net/ipv6/addrconf.c:3541
addrconf_notify+0x1bb/0x2570 net/ipv6/addrconf.c:3466
notifier_call_chain+0x145/0x2f0 kernel/notifier.c:93
__raw_notifier_call_chain kernel/notifier.c:394
raw_notifier_call_chain+0x2d/0x40 kernel/notifier.c:401
call_netdevice_notifiers_info+0x51/0x90 net/core/dev.c:1647
call_netdevice_notifiers net/core/dev.c:1663
__dev_notify_flags+0x1fd/0x320 net/core/dev.c:6499
dev_change_flags+0xf5/0x140 net/core/dev.c:6530
dev_ifsioc+0x62a/0x9f0 net/core/dev_ioctl.c:254
dev_ioctl+0x249/0x1160 net/core/dev_ioctl.c:532
sock_do_ioctl+0x94/0xb0 net/socket.c:913
sock_ioctl+0x28f/0x440 net/socket.c:1004
vfs_ioctl fs/ioctl.c:45
do_vfs_ioctl+0x1bf/0x1780 fs/ioctl.c:685
SYSC_ioctl fs/ioctl.c:700
SyS_ioctl+0x8f/0xc0 fs/ioctl.c:691
entry_SYSCALL_64_fastpath+0x1f/0xc2 arch/x86/entry/entry_64.S:204
RIP: 0033:0x7f575ded4347
RSP: 002b:00007fffc94d9948 EFLAGS: 00000217 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007fffc94d9b30 RCX: 00007f575ded4347
RDX: 00007fffc94d9980 RSI: 0000000000008914 RDI: 0000000000000006
RBP: 00000000004004e0 R08: 0000000000000028 R09: 0101010101010101
R10: 0000000000000000 R11: 0000000000000217 R12: 0000000000000000
R13: 00007fffc94d9b30 R14: 0000000000000000 R15: 0000000000000000
---[ end trace 9bda4459ad907043 ]---

Attachment: .config
Description: Binary data

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

#ifndef __NR_socket
#define __NR_socket 41
#endif
#ifndef __NR_ioctl
#define __NR_ioctl 16
#endif
#ifndef __NR_mmap
#define __NR_mmap 9
#endif

#define _GNU_SOURCE

#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <linux/capability.h>
#include <linux/if.h>
#include <linux/if_tun.h>
#include <linux/kvm.h>
#include <linux/sched.h>
#include <net/if_arp.h>
#include <linux/in.h>
#include <linux/ipv6.h>
#include <linux/ipv6_route.h>

#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <pthread.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

void test() {
int s0 = socket(AF_INET6, SOCK_RAW, IPPROTO_TCP);

struct ifreq ifr0;
memset(&ifr0, 0, sizeof(ifr0));
strcpy(ifr0.ifr_name, "lo");
ifr0.ifr_flags = 0x8301;
ioctl(s0, SIOCSIFFLAGS, &ifr0);

int s1 = socket(AF_INET6, SOCK_RAW|SOCK_CLOEXEC, 0x2b);

int s2 = socket(AF_INET6, SOCK_DGRAM|SOCK_NONBLOCK, IPPROTO_IP);

struct ifreq ifr1;
memset(&ifr1, 0, sizeof(ifr1));
strcpy(ifr1.ifr_name, "ip6_vti0");
ioctl(s2, SIOCGIFINDEX, &ifr1);

struct in6_ifreq ifr2;
memset(&ifr2, 0, sizeof(ifr2));
memcpy(&ifr2.ifr6_addr, "\xfd\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\x00\x00\x00\x00\x00\xbb", 16);
ifr2.ifr6_prefixlen = 9;
ifr2.ifr6_ifindex = ifr1.ifr_ifindex;
ioctl(s1, SIOCSIFADDR, &ifr2);

int s3 = socket(AF_INET6, SOCK_STREAM|SOCK_NONBLOCK, 0x84);

struct ifreq ifr3;
memset(&ifr3, 0, sizeof(ifr3));
strcpy(ifr3.ifr_name, "lo");
ifr3.ifr_flags = 0x8000;
ioctl(s3, SIOCSIFFLAGS, &ifr3);

int s4 = socket(AF_INET6, SOCK_RAW, 0x3);

struct ifreq ifr4;
memset(&ifr4, 0, sizeof(ifr4));
strcpy(ifr4.ifr_name, "ip6_vti0");
ifr4.ifr_flags = 0x8301;
ioctl(s4, SIOCSIFFLAGS, &ifr4);

ioctl(s0, SIOCSIFFLAGS, &ifr0);
ioctl(s3, SIOCSIFFLAGS, &ifr3);
}

int main() {
test();
return 0;
}