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@
This commit is contained in:
parent
3b2df19edf
commit
b760398bd2
|
@ -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 cmd, void *data, struct ifnet *ifp)
|
|||
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 cmd, void *data, struct ifnet *ifp)
|
|||
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);
|
||||
|
|
Loading…
Reference in New Issue