summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorasomers <asomers@FreeBSD.org>2014-04-29 14:46:45 +0000
committerasomers <asomers@FreeBSD.org>2014-04-29 14:46:45 +0000
commit130691029ea0ff4f544eb8cac0561dca14040b3d (patch)
tree2b18993d059a435b96ac7815e263a377b9e6f393
parentb1337c7d4cc6ee167ff7de43b69332e6371e44b6 (diff)
downloadFreeBSD-src-130691029ea0ff4f544eb8cac0561dca14040b3d.zip
FreeBSD-src-130691029ea0ff4f544eb8cac0561dca14040b3d.tar.gz
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
-rw-r--r--sys/netinet/in.c10
-rwxr-xr-xtests/sys/netinet/fibs_test.sh40
2 files changed, 47 insertions, 3 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 1cb4f09..336c9e5 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -696,11 +696,9 @@ in_scrubprefix(struct in_ifaddr *target, u_int flags)
{
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, u_int flags)
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, u_int flags)
}
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);
}
diff --git a/tests/sys/netinet/fibs_test.sh b/tests/sys/netinet/fibs_test.sh
index dc51b54..f25b90d 100755
--- a/tests/sys/netinet/fibs_test.sh
+++ b/tests/sys/netinet/fibs_test.sh
@@ -213,6 +213,45 @@ default_route_with_multiple_fibs_on_same_subnet_cleanup()
}
+# 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
}
OpenPOWER on IntegriCloud