On 03/09/14(Wed) 20:59, Alexander Bluhm wrote:
> On Wed, Sep 03, 2014 at 03:53:34PM +0200, Martin Pieuchot wrote:
> > @@ -1078,7 +1079,7 @@ in6_purgeaddr(struct ifaddr *ifa)
> > void
> > in6_unlink_ifa(struct in6_ifaddr *ia6, struct ifnet *ifp)
> > {
> > - int s = splnet();
> > + splsoftassert(IPL_SOFTNET);
> >
> > ifa_del(ifp, &ia6->ia_ifa);
> >
>
> I think there are code paths that can trigger this assertion
>
> netinet6/in6.c: in6_unlink_ifa()
> netinet6/in6.c: in6_purgeaddr()
> netinet6/nd6_rtr.c: purge_detached()
> netinet6/nd6_rtr.c: nd6_prelist_add()
> netinet6/in6.c: in6_control()
> netinet/tcp_usrreq.c: tcp_usrreq()
> kern/sys_socket.c: soo_ioctl()
>
> netinet6/in6.c: in6_unlink_ifa()
> netinet6/in6.c: in6_purgeaddr()
> netinet6/nd6_rtr.c: purge_detached()
> netinet6/nd6_rtr.c: nd6_prelist_add()
> netinet6/in6_ifattach.c: in6_ifattach_linklocal()
> netinet/ip_carp.c carp_set_enaddr()
> netinet/ip_carp.c carp_ioctl()
> ...
>
> nd6_prelist_add() does some splsoftnet() already. I think you
> should put one around purge_detached() there.
Nice catch, updated diff below.
Index: net/if_loop.c
===================================================================
RCS file: /home/ncvs/src/sys/net/if_loop.c,v
retrieving revision 1.57
diff -u -p -r1.57 if_loop.c
--- net/if_loop.c 22 Jul 2014 11:06:09 -0000 1.57
+++ net/if_loop.c 11 Sep 2014 08:45:29 -0000
@@ -288,15 +288,13 @@ loioctl(struct ifnet *ifp, u_long cmd, c
{
struct ifaddr *ifa;
struct ifreq *ifr;
- int s, error = 0;
+ int error = 0;
switch (cmd) {
case SIOCSIFADDR:
- s = splnet();
ifp->if_flags |= IFF_RUNNING;
if_up(ifp); /* send up RTM_IFINFO */
- splx(s);
ifa = (struct ifaddr *)data;
if (ifa != 0)
Index: netinet/in.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/in.c,v
retrieving revision 1.103
diff -u -p -r1.103 in.c
--- netinet/in.c 3 Sep 2014 08:59:06 -0000 1.103
+++ netinet/in.c 11 Sep 2014 08:45:29 -0000
@@ -612,7 +612,7 @@ in_ifinit(struct ifnet *ifp, struct in_i
{
u_int32_t i = sin->sin_addr.s_addr;
struct sockaddr_in oldaddr;
- int s, error = 0;
+ int error = 0;
splsoftassert(IPL_SOFTNET);
@@ -627,7 +627,6 @@ in_ifinit(struct ifnet *ifp, struct in_i
rt_ifa_delloop(&ia->ia_ifa);
ifa_del(ifp, &ia->ia_ifa);
}
- s = splnet();
oldaddr = ia->ia_addr;
ia->ia_addr = *sin;
@@ -639,10 +638,8 @@ in_ifinit(struct ifnet *ifp, struct in_i
if (ifp->if_ioctl &&
(error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
ia->ia_addr = oldaddr;
- splx(s);
goto out;
}
- splx(s);
if (ia->ia_netmask == 0) {
if (IN_CLASSA(i))
Index: netinet/ip_carp.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet/ip_carp.c,v
retrieving revision 1.234
diff -u -p -r1.234 ip_carp.c
--- netinet/ip_carp.c 8 Sep 2014 06:24:13 -0000 1.234
+++ netinet/ip_carp.c 11 Sep 2014 08:45:29 -0000
@@ -2059,10 +2059,11 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
struct ifaddr *ifa = (struct ifaddr *)addr;
struct ifreq *ifr = (struct ifreq *)addr;
struct ifnet *cdev = NULL;
- int i, error = 0;
+ int s, i, error = 0;
switch (cmd) {
case SIOCSIFADDR:
+ s = splnet();
switch (ifa->ifa_addr->sa_family) {
#ifdef INET
case AF_INET:
@@ -2087,6 +2088,7 @@ carp_ioctl(struct ifnet *ifp, u_long cmd
break;
}
break;
+ splx(s);
case SIOCSIFFLAGS:
vhe = LIST_FIRST(&sc->carp_vhosts);
Index: netinet6/in6.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/in6.c,v
retrieving revision 1.140
diff -u -p -r1.140 in6.c
--- netinet6/in6.c 26 Aug 2014 21:44:29 -0000 1.140
+++ netinet6/in6.c 11 Sep 2014 08:45:29 -0000
@@ -172,7 +172,7 @@ in6_control(struct socket *so, u_long cm
struct in6_ifaddr *ia6 = NULL;
struct in6_aliasreq *ifra = (struct in6_aliasreq *)data;
struct sockaddr_in6 *sa6;
- int privileged;
+ int s, privileged;
privileged = 0;
if ((so->so_state & SS_PRIV) != 0)
@@ -463,7 +463,6 @@ in6_control(struct socket *so, u_long cm
{
int i, error = 0;
struct nd_prefix pr0, *pr;
- int s;
/* reject read-only flags */
if ((ifra->ifra_flags & IN6_IFF_DUPLICATED) != 0 ||
@@ -561,8 +560,10 @@ in6_control(struct socket *so, u_long cm
}
case SIOCDIFADDR_IN6:
+ s = splsoftnet();
in6_purgeaddr(&ia6->ia_ifa);
dohooks(ifp->if_addrhooks, 0);
+ splx(s);
break;
default:
@@ -1078,7 +1079,7 @@ in6_purgeaddr(struct ifaddr *ifa)
void
in6_unlink_ifa(struct in6_ifaddr *ia6, struct ifnet *ifp)
{
- int s = splnet();
+ splsoftassert(IPL_SOFTNET);
ifa_del(ifp, &ia6->ia_ifa);
@@ -1107,8 +1108,6 @@ in6_unlink_ifa(struct in6_ifaddr *ia6, s
* Note that we should decrement the refcnt at least once for all *BSD.
*/
ifafree(&ia6->ia_ifa);
-
- splx(s);
}
/*
@@ -1355,9 +1354,10 @@ int
in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia6, int newhost)
{
int error = 0, plen, ifacount = 0;
- int s = splnet();
struct ifaddr *ifa;
+ splsoftassert(IPL_SOFTNET);
+
/*
* Give the interface a chance to initialize
* if this is its first address (or it is a CARP interface)
@@ -1374,10 +1374,8 @@ in6_ifinit(struct ifnet *ifp, struct in6
if ((ifacount <= 1 || ifp->if_type == IFT_CARP ||
(ifp->if_flags & IFF_POINTOPOINT)) && ifp->if_ioctl &&
(error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia6))) {
- splx(s);
return (error);
}
- splx(s);
ia6->ia_ifa.ifa_metric = ifp->if_metric;
Index: netinet6/nd6_rtr.c
===================================================================
RCS file: /home/ncvs/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.87
diff -u -p -r1.87 nd6_rtr.c
--- netinet6/nd6_rtr.c 9 Sep 2014 20:33:24 -0000 1.87
+++ netinet6/nd6_rtr.c 11 Sep 2014 08:45:29 -0000
@@ -990,6 +990,8 @@ purge_detached(struct ifnet *ifp)
struct in6_ifaddr *ia6;
struct ifaddr *ifa, *ifa_next;
+ splsoftassert(IPL_SOFTNET);
+
LIST_FOREACH_SAFE(pr, &nd_prefix, ndpr_entry, pr_next) {
/*
* This function is called when we need to make more room for
@@ -1025,8 +1027,11 @@ nd6_prelist_add(struct nd_prefix *pr, st
struct in6_ifextra *ext = pr->ndpr_ifp->if_afdata[AF_INET6];
if (ip6_maxifprefixes >= 0) {
- if (ext->nprefixes >= ip6_maxifprefixes / 2)
+ if (ext->nprefixes >= ip6_maxifprefixes / 2) {
+ s = splsoftnet();
purge_detached(pr->ndpr_ifp);
+ splx(s);
+ }
if (ext->nprefixes >= ip6_maxifprefixes)
return(ENOMEM);
}