NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/51356: Repeating ifconfig <ip>/ifconfig <ip> delete under network load causes a panic
>Number: 51356
>Category: kern
>Synopsis: Repeating ifconfig <ip>/ifconfig <ip> delete under network load causes a panic
>Confidential: no
>Severity: critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Mon Jul 25 04:55:00 +0000 2016
>Originator: Ryota Ozaki
>Release: -current, netbsd-7 (and maybe netbsd-6)
>Organization:
>Environment:
NetBSD kvm 7.99.34 NetBSD 7.99.34 (KVM) #215: Mon Jul 25 12:42:10 JST 2016 ozaki-r@rangeley:(hidden) amd64
NetBSD netbsd7 7.0.0_PATCH NetBSD 7.0.0_PATCH (GENERIC.201512132100Z) amd64
>Description:
Adding and deleting an IP address is executed without softnet_lock, but that's unsafe
and causes a panic on rtcache or rtentry manipulations. We have to hold softnet_lock
during such operations.
>How-To-Repeat:
Setup a machine with IP forwarding enabled:
sysctl -w net.inet.ip.forwarding=1
ifconfig wm0 10.0.1.1/24
ifconfig wm1 10.0.2.1/24
Sending massive UDP packets over the machine and run the following script on the machine:
while true; do ifconfig wm0 10.0.1.1/24 >/dev/null 2>&1; ifconfig wm0 10.0.1.1/24 delete >/dev/null 2>&1; done &
while true; do ifconfig wm1 10.0.2.1/24 >/dev/null 2>&1; ifconfig wm1 10.0.2.1/24 delete >/dev/null 2>&1; done &
And wait several minutes.
>Fix:
Hold softnet_lock in in_control (and in6_control). We also need to tweak callout_halt for DAD.
diff --git a/sys/netinet/if_arp.c b/sys/netinet/if_arp.c
index 3ae4e4d..e347315 100644
--- a/sys/netinet/if_arp.c
+++ b/sys/netinet/if_arp.c
@@ -1502,7 +1502,7 @@ static void
arp_dad_stoptimer(struct dadq *dp)
{
- callout_halt(&dp->dad_timer_ch, NULL);
+ callout_halt(&dp->dad_timer_ch, softnet_lock);
}
static void
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index 7619d6b..90354f8 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -360,8 +360,8 @@ in_len2mask(struct in_addr *mask, u_int len)
* Ifp is 0 if not an interface-specific ioctl.
*/
/* ARGSUSED */
-int
-in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
+static int
+in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
{
struct ifreq *ifr = (struct ifreq *)data;
struct in_ifaddr *ia = NULL;
@@ -667,6 +667,18 @@ in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
return error;
}
+int
+in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
+{
+ int error;
+
+ mutex_enter(softnet_lock);
+ error = in_control0(so, cmd, data, ifp);
+ mutex_exit(softnet_lock);
+
+ return error;
+}
+
/* Add ownaddr as loopback rtentry. */
static void
in_ifaddlocal(struct ifaddr *ifa)
diff --git a/sys/netinet6/in6.c b/sys/netinet6/in6.c
index ead9154..54e5823 100644
--- a/sys/netinet6/in6.c
+++ b/sys/netinet6/in6.c
@@ -751,7 +751,9 @@ in6_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp)
}
s = splnet();
+ mutex_enter(softnet_lock);
error = in6_control1(so , cmd, data, ifp);
+ mutex_exit(softnet_lock);
splx(s);
return error;
}
diff --git a/sys/netinet6/nd6_nbr.c b/sys/netinet6/nd6_nbr.c
index a3ee9b9..6066460 100644
--- a/sys/netinet6/nd6_nbr.c
+++ b/sys/netinet6/nd6_nbr.c
@@ -1074,7 +1074,7 @@ static void
nd6_dad_stoptimer(struct dadq *dp)
{
- callout_halt(&dp->dad_timer_ch, NULL);
+ callout_halt(&dp->dad_timer_ch, softnet_lock);
}
/*
Home |
Main Index |
Thread Index |
Old Index