On Sun, Sep 04, 2016 at 05:43:20PM +0200, Martin Pieuchot wrote:
> Thanks to awolk@ hacking on USB wireless we found a lot of new races in
> the network stack.
>
> Passing and ``ifp'' pointer to a task is *not* safe. If the task
> sleeps, then another thread my start executing if_detach() freeing the
> memory associated to ``ifp''. And task do sleep, that's why we use
> them in the first place.
>
> So we should always pass and ifp index like I did with the
> if_input_process() task. Diff attached fix awolk@'s first panic.
>
> ok?
>
OK claudio@
> Index: net/if.c
> ===================================================================
> RCS file: /cvs/src/sys/net/if.c,v
> retrieving revision 1.441
> diff -u -p -r1.441 if.c
> --- net/if.c 4 Sep 2016 10:32:01 -0000 1.441
> +++ net/if.c 4 Sep 2016 11:03:37 -0000
> @@ -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,19 @@ 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);
> @@ -1482,11 +1485,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
> @@ -1494,6 +1502,8 @@ if_linkstate(void *xifp)
> #endif
> dohooks(ifp->if_linkstatehooks, 0);
> splx(s);
> +
> + if_put(ifp);
> }
>
> /*
> @@ -1525,15 +1535,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);
> }
>
> /*
--
:wq Claudio