Thu May 25 02:43:43 2017 UTC ()
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@


(ozaki-r)
diff -r1.201 -r1.202 src/sys/netinet/in.c

cvs diff -r1.201 -r1.202 src/sys/netinet/in.c (expand / switch to unified diff)

--- src/sys/netinet/in.c 2017/05/12 17:53:53 1.201
+++ src/sys/netinet/in.c 2017/05/25 02:43:43 1.202
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: in.c,v 1.201 2017/05/12 17:53:53 ryo Exp $ */ 1/* $NetBSD: in.c,v 1.202 2017/05/25 02:43:43 ozaki-r Exp $ */
2 2
3/* 3/*
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
5 * All rights reserved. 5 * All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
10 * 1. Redistributions of source code must retain the above copyright 10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer. 11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
@@ -81,27 +81,27 @@ @@ -81,27 +81,27 @@
81 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 81 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 82 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 83 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 84 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 85 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 86 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 87 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
88 * SUCH DAMAGE. 88 * SUCH DAMAGE.
89 * 89 *
90 * @(#)in.c 8.4 (Berkeley) 1/9/95 90 * @(#)in.c 8.4 (Berkeley) 1/9/95
91 */ 91 */
92 92
93#include <sys/cdefs.h> 93#include <sys/cdefs.h>
94__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.201 2017/05/12 17:53:53 ryo Exp $"); 94__KERNEL_RCSID(0, "$NetBSD: in.c,v 1.202 2017/05/25 02:43:43 ozaki-r Exp $");
95 95
96#include "arp.h" 96#include "arp.h"
97 97
98#ifdef _KERNEL_OPT 98#ifdef _KERNEL_OPT
99#include "opt_inet.h" 99#include "opt_inet.h"
100#include "opt_inet_conf.h" 100#include "opt_inet_conf.h"
101#include "opt_mrouting.h" 101#include "opt_mrouting.h"
102#include "opt_net_mpsafe.h" 102#include "opt_net_mpsafe.h"
103#endif 103#endif
104 104
105#include <sys/param.h> 105#include <sys/param.h>
106#include <sys/ioctl.h> 106#include <sys/ioctl.h>
107#include <sys/errno.h> 107#include <sys/errno.h>
@@ -485,26 +485,31 @@ in_control0(struct socket *so, u_long cm @@ -485,26 +485,31 @@ in_control0(struct socket *so, u_long cm
485#endif /* IPSELSRC */ 485#endif /* IPSELSRC */
486 ia->ia_sockmask.sin_len = 8; 486 ia->ia_sockmask.sin_len = 8;
487 ia->ia_sockmask.sin_family = AF_INET; 487 ia->ia_sockmask.sin_family = AF_INET;
488 if (ifp->if_flags & IFF_BROADCAST) { 488 if (ifp->if_flags & IFF_BROADCAST) {
489 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 489 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
490 ia->ia_broadaddr.sin_family = AF_INET; 490 ia->ia_broadaddr.sin_family = AF_INET;
491 } 491 }
492 ia->ia_ifp = ifp; 492 ia->ia_ifp = ifp;
493 ia->ia_idsalt = cprng_fast32() % 65535; 493 ia->ia_idsalt = cprng_fast32() % 65535;
494 LIST_INIT(&ia->ia_multiaddrs); 494 LIST_INIT(&ia->ia_multiaddrs);
495 IN_ADDRHASH_ENTRY_INIT(ia); 495 IN_ADDRHASH_ENTRY_INIT(ia);
496 IN_ADDRLIST_ENTRY_INIT(ia); 496 IN_ADDRLIST_ENTRY_INIT(ia);
497 ifa_psref_init(&ia->ia_ifa); 497 ifa_psref_init(&ia->ia_ifa);
 498 /*
 499 * We need a reference to make ia survive over in_ifinit
 500 * that does ifaref and ifafree.
 501 */
 502 ifaref(&ia->ia_ifa);
498 503
499 newifaddr = 1; 504 newifaddr = 1;
500 } 505 }
501 break; 506 break;
502 507
503 case SIOCSIFBRDADDR: 508 case SIOCSIFBRDADDR:
504 if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE, 509 if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE,
505 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, 510 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd,
506 NULL) != 0) { 511 NULL) != 0) {
507 error = EPERM; 512 error = EPERM;
508 goto out; 513 goto out;
509 } 514 }
510 /* FALLTHROUGH */ 515 /* FALLTHROUGH */
@@ -671,26 +676,28 @@ in_control0(struct socket *so, u_long cm @@ -671,26 +676,28 @@ in_control0(struct socket *so, u_long cm
671 676
672 /* 677 /*
673 * XXX insert regardless of error to make in_purgeaddr below work. 678 * XXX insert regardless of error to make in_purgeaddr below work.
674 * Need to improve. 679 * Need to improve.
675 */ 680 */
676 if (newifaddr) { 681 if (newifaddr) {
677 ifaref(&ia->ia_ifa); 682 ifaref(&ia->ia_ifa);
678 ifa_insert(ifp, &ia->ia_ifa); 683 ifa_insert(ifp, &ia->ia_ifa);
679 684
680 mutex_enter(&in_ifaddr_lock); 685 mutex_enter(&in_ifaddr_lock);
681 TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list); 686 TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list);
682 IN_ADDRLIST_WRITER_INSERT_TAIL(ia); 687 IN_ADDRLIST_WRITER_INSERT_TAIL(ia);
683 in_addrhash_insert_locked(ia); 688 in_addrhash_insert_locked(ia);
 689 /* Release a reference that is held just after creation. */
 690 ifafree(&ia->ia_ifa);
684 mutex_exit(&in_ifaddr_lock); 691 mutex_exit(&in_ifaddr_lock);
685 } else if (need_reinsert) { 692 } else if (need_reinsert) {
686 in_addrhash_insert(ia); 693 in_addrhash_insert(ia);
687 } 694 }
688 695
689 if (error == 0) { 696 if (error == 0) {
690 if (run_hook) 697 if (run_hook)
691 pfil_run_addrhooks(if_pfil, cmd, &ia->ia_ifa); 698 pfil_run_addrhooks(if_pfil, cmd, &ia->ia_ifa);
692 } else if (newifaddr) { 699 } else if (newifaddr) {
693 KASSERT(ia != NULL); 700 KASSERT(ia != NULL);
694 in_purgeaddr(&ia->ia_ifa); 701 in_purgeaddr(&ia->ia_ifa);
695 ia = NULL; 702 ia = NULL;
696 } 703 }