diff options
author | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-09-04 17:14:59 +0000 |
---|---|---|
committer | Martin Pieuchot <mpi@cvs.openbsd.org> | 2016-09-04 17:14:59 +0000 |
commit | 294cf4fe6029e9945075dbb88e7d78165754555b (patch) | |
tree | 45f5c65be6085276297b3a3f70e69f5bc7197464 | |
parent | f5b8ac9e8c62d0faaed2bfab3e3ccf84b223097e (diff) |
Prevent a race between a thread detaching an interface and the watchdog
or linkstate task sleeping.
Pass an index to the task and use if_get(9) if the ifp is still alive.
Found the hardway by awolk@.
ok claudio@, bluhm@, mikeb@
-rw-r--r-- | sys/net/if.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/sys/net/if.c b/sys/net/if.c index c06ee3f40c6..19ec65c60eb 100644 --- a/sys/net/if.c +++ b/sys/net/if.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if.c,v 1.443 2016/09/04 15:46:39 reyk Exp $ */ +/* $OpenBSD: if.c,v 1.444 2016/09/04 17:14:58 mpi Exp $ */ /* $NetBSD: if.c,v 1.35 1996/05/07 05:26:04 thorpej Exp $ */ /* @@ -400,6 +400,8 @@ if_map_dtor(void *null, void *m) void if_attachsetup(struct ifnet *ifp) { + unsigned long ifidx; + TAILQ_INIT(&ifp->if_groups); if_addgroup(ifp, IFG_ALL); @@ -409,18 +411,18 @@ if_attachsetup(struct ifnet *ifp) pfi_attach_ifnet(ifp); #endif - task_set(ifp->if_watchdogtask, if_watchdog_task, ifp); timeout_set(ifp->if_slowtimo, if_slowtimo, ifp); if_slowtimo(ifp); - task_set(ifp->if_linkstatetask, if_linkstate, ifp); - if_idxmap_insert(ifp); KASSERT(if_get(0) == NULL); + ifidx = ifp->if_index; + mq_init(&ifp->if_inputqueue, 8192, IPL_NET); - task_set(ifp->if_inputtask, if_input_process, - (void *)(unsigned long)ifp->if_index); + task_set(ifp->if_inputtask, if_input_process, (void *)ifidx); + task_set(ifp->if_watchdogtask, if_watchdog_task, (void *)ifidx); + task_set(ifp->if_linkstatetask, if_linkstate, (void *)ifidx); /* Announce the interface. */ rt_ifannouncemsg(ifp, IFAN_ARRIVAL); @@ -1486,11 +1488,16 @@ if_up(struct ifnet *ifp) * a link-state transition. */ void -if_linkstate(void *xifp) +if_linkstate(void *xifidx) { - struct ifnet *ifp = xifp; + unsigned int ifidx = (unsigned long)xifidx; + struct ifnet *ifp; int s; + ifp = if_get(ifidx); + if (ifp == NULL) + return; + s = splsoftnet(); rt_ifmsg(ifp); #ifndef SMALL_KERNEL @@ -1498,6 +1505,8 @@ if_linkstate(void *xifp) #endif dohooks(ifp->if_linkstatehooks, 0); splx(s); + + if_put(ifp); } /* @@ -1529,15 +1538,22 @@ if_slowtimo(void *arg) } void -if_watchdog_task(void *arg) +if_watchdog_task(void *xifidx) { - struct ifnet *ifp = arg; + unsigned int ifidx = (unsigned long)xifidx; + struct ifnet *ifp; int s; + ifp = if_get(ifidx); + if (ifp == NULL) + return; + s = splnet(); if (ifp->if_watchdog) (*ifp->if_watchdog)(ifp); splx(s); + + if_put(ifp); } /* |