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);

Reply via email to