Module Name: src Committed By: ozaki-r Date: Thu May 25 02:43:43 UTC 2017
Modified Files: src/sys/netinet: in.c Log Message: Fix that a fresh in_ifaddr is unexpectedly freed before activating it An in_ifaddr object is initialized with refcnt=0 and the refcnt is incremented when being enqueued to the lists. However before enqueuing it, in_ifinit can hold and refelease a reference to it, i.e., call ifaref and ifafree, resulting in that the object is freed in ifafree because its refcnt is decremented to 0. It can be reproduced by doing: ifconfig tun0 create ifconfig tun1 create ifconfig tun0 10.1 10.2 ifconfig tun1 10.2 10.1 ifconfig # Cause a kernel panic (may depend on environmemts) We need to initialize a created in_ifaddr object with refcnt=1 to make the object survive over in_ifinit. The issue is found by ryo@ To generate a diff of this commit: cvs rdiff -u -r1.201 -r1.202 src/sys/netinet/in.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/netinet/in.c diff -u src/sys/netinet/in.c:1.201 src/sys/netinet/in.c:1.202 --- src/sys/netinet/in.c:1.201 Fri May 12 17:53:53 2017 +++ src/sys/netinet/in.c Thu May 25 02:43:43 2017 @@ -1,4 +1,4 @@ -/* $NetBSD: in.c,v 1.201 2017/05/12 17:53:53 ryo Exp $ */ +/* $NetBSD: in.c,v 1.202 2017/05/25 02:43:43 ozaki-r Exp $ */ /* * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. @@ -91,7 +91,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.201 2017/05/12 17:53:53 ryo Exp $"); +__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.202 2017/05/25 02:43:43 ozaki-r Exp $"); #include "arp.h" @@ -495,6 +495,11 @@ in_control0(struct socket *so, u_long cm IN_ADDRHASH_ENTRY_INIT(ia); IN_ADDRLIST_ENTRY_INIT(ia); ifa_psref_init(&ia->ia_ifa); + /* + * We need a reference to make ia survive over in_ifinit + * that does ifaref and ifafree. + */ + ifaref(&ia->ia_ifa); newifaddr = 1; } @@ -681,6 +686,8 @@ in_control0(struct socket *so, u_long cm TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list); IN_ADDRLIST_WRITER_INSERT_TAIL(ia); in_addrhash_insert_locked(ia); + /* Release a reference that is held just after creation. */ + ifafree(&ia->ia_ifa); mutex_exit(&in_ifaddr_lock); } else if (need_reinsert) { in_addrhash_insert(ia);