From nobody@FreeBSD.org  Mon Apr 28 22:48:22 2014
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115])
	(using TLSv1 with cipher ADH-AES256-SHA (256/256 bits))
	(No client certificate requested)
	by hub.freebsd.org (Postfix) with ESMTPS id 117AFB62
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 28 Apr 2014 22:48:22 +0000 (UTC)
Received: from cgiserv.freebsd.org (cgiserv.freebsd.org [IPv6:2001:1900:2254:206a::50:4])
	(using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits))
	(Client did not present a certificate)
	by mx1.freebsd.org (Postfix) with ESMTPS id E52711B08
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 28 Apr 2014 22:48:21 +0000 (UTC)
Received: from cgiserv.freebsd.org ([127.0.1.6])
	by cgiserv.freebsd.org (8.14.8/8.14.8) with ESMTP id s3SMmLnm008800
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 28 Apr 2014 22:48:21 GMT
	(envelope-from nobody@cgiserv.freebsd.org)
Received: (from nobody@localhost)
	by cgiserv.freebsd.org (8.14.8/8.14.8/Submit) id s3SMmLiT008795;
	Mon, 28 Apr 2014 22:48:21 GMT
	(envelope-from nobody)
Message-Id: <201404282248.s3SMmLiT008795@cgiserv.freebsd.org>
Date: Mon, 28 Apr 2014 22:48:21 GMT
From: Alan Somers <asomers@freebsd.org>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Panic when removing an IP address from an interface, if the same address exists on another interface
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         189089
>Category:       kern
>Synopsis:       Panic when removing an IP address from an interface, if the same address exists on another interface
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    asomers
>State:          patched
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Apr 28 22:50:00 UTC 2014
>Closed-Date:    
>Last-Modified:  Tue Apr 29 15:07:30 UTC 2014
>Originator:     Alan Somers
>Release:        11.0 CURRENT
>Organization:
Spectra Logic
>Environment:
FreeBSD b 11.0-CURRENT FreeBSD 11.0-CURRENT #9 r264904M: Fri Apr 25 14:46:45 PDT 2014     neel@b:/usr/obj/neel/usr/freebsd/head2/sys/GENERIC  amd64
>Description:
If you assign the same IP address to multiple interfaces simultaneously, then remove it from one of them, the system will panic with this message:

panic: rtalloc1_fib: bad fibnum

The panic was introduced by revision 264887, which changed the fibnum parameter in the call to rtalloc1_fib() in ifa_switch_loopback_route() from RT_DEFAULT_FIB to RT_ALL_FIBS.  Prior to 264887 the call would always succeed, but it could corrupt the network stack if the route in question was not located in the default fib.  That wasn't a big deal though, since prior to 264887 it was very difficult create that route in a nondefault fib.


>How-To-Repeat:
# # Set net.fibs=1 and net.add_addr_allfibs=1
# ifconfig tap0 create
# ifconfig tap1 create
# ifconfig tap0 192.0.0.2/24 up
# ifconfig tap1 192.0.0.2/32 up
# netstat -rn -f inet
Routing tables

Internet:
Destination        Gateway            Flags    Netif Expire
default            10.1.0.1           UGS       em0
10.1.0.0/20        link#1             U         em0
10.1.3.220         link#1             UHS       lo0
127.0.0.1          link#2             UH        lo0
192.0.0.0/24       link#3             U        tap0
192.0.0.2          link#3             UHS       lo0
192.0.0.2/32       link#4             U        tap1
# ifconfig tap1 -alias 192.0.0.2 # This line will panic!

>Fix:
The solution is to use the interface fib instead of either the default fib or ALL_FIBS.  This will give equivalent behavior as the pre-264887 status quo for the majority of users.

Patch attached with submission follows:

Index: sys/netinet/in.c
===================================================================
--- sys/netinet/in.c	(revision 265061)
+++ sys/netinet/in.c	(working copy)
@@ -696,11 +696,9 @@
 {
 	struct in_ifaddr *ia;
 	struct in_addr prefix, mask, p, m;
-	int error = 0, fibnum;
+	int error = 0;
 	struct sockaddr_in prefix0, mask0;
 
-	fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib;
-
 	/*
 	 * Remove the loopback route to the interface address.
 	 */
@@ -712,6 +710,8 @@
 		eia = in_localip_more(target);
 
 		if (eia != NULL) {
+			int fibnum = target->ia_ifp->if_fib;
+
 			error = ifa_switch_loopback_route((struct ifaddr *)eia,
 			    (struct sockaddr *)&target->ia_addr, fibnum);
 			ifa_free(&eia->ia_ifa);
@@ -736,6 +736,10 @@
 	}
 
 	if ((target->ia_flags & IFA_ROUTE) == 0) {
+		int fibnum;
+		
+		fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS :
+			target->ia_ifp->if_fib;
 		rt_addrmsg(RTM_DELETE, &target->ia_ifa, fibnum);
 		return (0);
 	}
Index: tests/sys/netinet/fibs_test.sh
===================================================================
--- tests/sys/netinet/fibs_test.sh	(revision 265061)
+++ tests/sys/netinet/fibs_test.sh	(working copy)
@@ -213,6 +213,45 @@
 }
 
 
+# Regression test for a panic introduced in change 264887
+# Create two tap interfaces and assign them both the same IP address but with
+# different netmasks, and both on the default FIB.  Then remove one's IP
+# address.  Hopefully the machine won't panic.
+atf_test_case same_ip_multiple_ifaces_fib0 cleanup
+same_ip_multiple_ifaces_fib0_head()
+{
+	atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface."
+	atf_set "require.user" "root"
+	atf_set "require.config" "fibs"
+}
+same_ip_multiple_ifaces_fib0_body()
+{
+	ADDR="192.0.2.2"
+	MASK0="24"
+	MASK1="32"
+
+	# Unlike most of the tests in this file, this is applicable regardless
+	# of net.add_addr_allfibs
+
+	# Setup the interfaces, then remove one alias.  It should not panic.
+	setup_tap 0 ${ADDR} ${MASK0}
+	TAP0=${TAP}
+	setup_tap 0 ${ADDR} ${MASK1}
+	TAP1=${TAP}
+	ifconfig ${TAP1} -alias ${ADDR}
+
+	# Do it again, in the opposite order.  It should not panic.
+	setup_tap 0 ${ADDR} ${MASK0}
+	TAP0=${TAP}
+	setup_tap 0 ${ADDR} ${MASK1}
+	TAP1=${TAP}
+	ifconfig ${TAP0} -alias ${ADDR}
+}
+same_ip_multiple_ifaces_fib0_cleanup()
+{
+	cleanup_tap
+}
+
 # Regression test for kern/187550
 atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
 subnet_route_with_multiple_fibs_on_same_subnet_head()
@@ -309,6 +348,7 @@
 	atf_add_test_case arpresolve_checks_interface_fib
 	atf_add_test_case loopback_and_network_routes_on_nondefault_fib
 	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
+	atf_add_test_case same_ip_multiple_ifaces_fib0
 	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
 	atf_add_test_case udp_dontroute
 }


>Release-Note:
>Audit-Trail:

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/189089: commit references a PR
Date: Tue, 29 Apr 2014 14:46:48 +0000 (UTC)

 Author: asomers
 Date: Tue Apr 29 14:46:45 2014
 New Revision: 265092
 URL: http://svnweb.freebsd.org/changeset/base/265092
 
 Log:
   Fix a panic when removing an IP address from an interface, if the same address
   exists on another interface.  The panic was introduced by change 264887, which
   changed the fibnum parameter in the call to rtalloc1_fib() in
   ifa_switch_loopback_route() from RT_DEFAULT_FIB to RT_ALL_FIBS.  The solution
   is to use the interface fib in that call.  For the majority of users, that will
   be equivalent to the legacy behavior.
   
   PR:		kern/189089
   Reported by:	neel
   Reviewed by:	neel
   MFC after:	3 weeks
   X-MFC with:	264887
   Sponsored by:	Spectra Logic
 
 Modified:
   head/sys/netinet/in.c
   head/tests/sys/netinet/fibs_test.sh
 
 Modified: head/sys/netinet/in.c
 ==============================================================================
 --- head/sys/netinet/in.c	Tue Apr 29 12:52:36 2014	(r265091)
 +++ head/sys/netinet/in.c	Tue Apr 29 14:46:45 2014	(r265092)
 @@ -696,11 +696,9 @@ in_scrubprefix(struct in_ifaddr *target,
  {
  	struct in_ifaddr *ia;
  	struct in_addr prefix, mask, p, m;
 -	int error = 0, fibnum;
 +	int error = 0;
  	struct sockaddr_in prefix0, mask0;
  
 -	fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS : target->ia_ifp->if_fib;
 -
  	/*
  	 * Remove the loopback route to the interface address.
  	 */
 @@ -712,6 +710,8 @@ in_scrubprefix(struct in_ifaddr *target,
  		eia = in_localip_more(target);
  
  		if (eia != NULL) {
 +			int fibnum = target->ia_ifp->if_fib;
 +
  			error = ifa_switch_loopback_route((struct ifaddr *)eia,
  			    (struct sockaddr *)&target->ia_addr, fibnum);
  			ifa_free(&eia->ia_ifa);
 @@ -736,6 +736,10 @@ in_scrubprefix(struct in_ifaddr *target,
  	}
  
  	if ((target->ia_flags & IFA_ROUTE) == 0) {
 +		int fibnum;
 +		
 +		fibnum = rt_add_addr_allfibs ? RT_ALL_FIBS :
 +			target->ia_ifp->if_fib;
  		rt_addrmsg(RTM_DELETE, &target->ia_ifa, fibnum);
  		return (0);
  	}
 
 Modified: head/tests/sys/netinet/fibs_test.sh
 ==============================================================================
 --- head/tests/sys/netinet/fibs_test.sh	Tue Apr 29 12:52:36 2014	(r265091)
 +++ head/tests/sys/netinet/fibs_test.sh	Tue Apr 29 14:46:45 2014	(r265092)
 @@ -213,6 +213,45 @@ default_route_with_multiple_fibs_on_same
  }
  
  
 +# Regression test for PR kern/189089
 +# Create two tap interfaces and assign them both the same IP address but with
 +# different netmasks, and both on the default FIB.  Then remove one's IP
 +# address.  Hopefully the machine won't panic.
 +atf_test_case same_ip_multiple_ifaces_fib0 cleanup
 +same_ip_multiple_ifaces_fib0_head()
 +{
 +	atf_set "descr" "Can remove an IP alias from an interface when the same IP is also assigned to another interface."
 +	atf_set "require.user" "root"
 +	atf_set "require.config" "fibs"
 +}
 +same_ip_multiple_ifaces_fib0_body()
 +{
 +	ADDR="192.0.2.2"
 +	MASK0="24"
 +	MASK1="32"
 +
 +	# Unlike most of the tests in this file, this is applicable regardless
 +	# of net.add_addr_allfibs
 +
 +	# Setup the interfaces, then remove one alias.  It should not panic.
 +	setup_tap 0 ${ADDR} ${MASK0}
 +	TAP0=${TAP}
 +	setup_tap 0 ${ADDR} ${MASK1}
 +	TAP1=${TAP}
 +	ifconfig ${TAP1} -alias ${ADDR}
 +
 +	# Do it again, in the opposite order.  It should not panic.
 +	setup_tap 0 ${ADDR} ${MASK0}
 +	TAP0=${TAP}
 +	setup_tap 0 ${ADDR} ${MASK1}
 +	TAP1=${TAP}
 +	ifconfig ${TAP0} -alias ${ADDR}
 +}
 +same_ip_multiple_ifaces_fib0_cleanup()
 +{
 +	cleanup_tap
 +}
 +
  # Regression test for kern/187550
  atf_test_case subnet_route_with_multiple_fibs_on_same_subnet cleanup
  subnet_route_with_multiple_fibs_on_same_subnet_head()
 @@ -309,6 +348,7 @@ atf_init_test_cases()
  	atf_add_test_case arpresolve_checks_interface_fib
  	atf_add_test_case loopback_and_network_routes_on_nondefault_fib
  	atf_add_test_case default_route_with_multiple_fibs_on_same_subnet
 +	atf_add_test_case same_ip_multiple_ifaces_fib0
  	atf_add_test_case subnet_route_with_multiple_fibs_on_same_subnet
  	atf_add_test_case udp_dontroute
  }
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: asomers 
State-Changed-When: Tue Apr 29 15:07:26 UTC 2014 
State-Changed-Why:  
Patched by change 265092 


Responsible-Changed-From-To: freebsd-bugs->asomers 
Responsible-Changed-By: asomers 
Responsible-Changed-When: Tue Apr 29 15:07:26 UTC 2014 
Responsible-Changed-Why:  
Patched by change 265092 

http://www.freebsd.org/cgi/query-pr.cgi?pr=189089 
>Unformatted:
