net: hang in unregister_netdevice: waiting for lo to become free

From: Dmitry Vyukov
Date: Tue Jan 30 2018 - 07:10:22 EST


Hello,

The following program creates a hang in unregister_netdevice.
cleanup_net work hangs there forever periodically printing
"unregister_netdevice: waiting for lo to become free. Usage count = 3"
and creation of any new network namespaces hangs forever.

[ 101.320142] unregister_netdevice: waiting for lo to become free.
Usage count = 3
[ 103.368144] unregister_netdevice: waiting for lo to become free.
Usage count = 3
[ 105.416149] unregister_netdevice: waiting for lo to become free.
Usage count = 3

[ 951.239250] Workqueue: netns cleanup_net
[ 951.240312] Call Trace:
[ 951.247450] schedule+0xe8/0x420
[ 951.256257] schedule_timeout+0x4cb/0x14b0
[ 951.277475] msleep+0x66/0x90
[ 951.278071] netdev_wait_allrefs+0x13a/0x410
[ 951.290040] netdev_run_todo+0x4a5/0xb40
[ 951.302415] rtnl_unlock+0xe/0x10
[ 951.302919] default_device_exit_batch+0x4bf/0x5d0
[ 951.313823] ops_exit_list.isra.6+0x100/0x150
[ 951.315009] cleanup_net+0x5db/0xbb0
[ 951.327867] process_one_work+0x9d5/0x1480
[ 951.343357] worker_thread+0x1cc/0x1410
[ 951.354108] kthread+0x304/0x3c0

I've currently reproduced it on 4.15, but I think I saw something
similar for a long time, so most likely this is not a new bug. I've
also attached my .config.

// autogenerated by syzkaller (http://github.com/google/syzkaller)
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <sched.h>
#include <memory.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

int main()
{
int sock;
struct sockaddr_in6 addr;

unshare(CLONE_NEWNET);
system("ip -6 addr add fe80::00:0a/120 dev gretap0");
system("ip link set dev ip6gre0 up");
sock = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_IP);
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_port = htobe16(0x4e20);
bind(sock, &addr, sizeof(addr));
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
inet_pton(AF_INET6, "fe80::bb", &addr.sin6_addr);
addr.sin6_scope_id = if_nametoindex("gretap0");
fcntl(sock, F_SETFL, O_NONBLOCK);
connect(sock, &addr, sizeof(addr));
return 0;
}

Attachment: .config
Description: Binary data