On 30/10/15(Fri) 19:44, Matthieu Herrb wrote:
> When  running my wifi configuration script which does:
> 
>  > ifconfig $1 inet6 -autoconfprivacy autoconf
> 
> on a particular wifi network, I get a 100% reproducible panic on my
> X240 running a kernel from Oct 25 (with a preliminary version of
> kettenis inteldrm at pci patch). 
> 
> Manually copied from a picture :
> 
> uwm_fault(0xffffffff81931280, 0xb, 0, 1) -> e
> kernel: page fault trap, code=0
> Stopped at    in6_ifadd+0x229;        testb $0x2,0xb0(%rax)
> ddb{0}> trace
> in6_ifadd() at in6_ifadd+0x229
> nd6_addr_add() at nd6_addr_add+0x113
> taskq_thread() at taskq_thread+0x6c
> end trace fame: 0x0, count -3
> ddb{0}> ps
> ....
> *11784        0       0       0   7  0x14200    systq
> ...
> 
> 
> Unfortunatly I'm not going to be able to re-test it with a more current
> kernel since it was in a datacenter where access is a bit complicated
> for me.

This seems to be a horrible bug related to the complexity of the ND6 and
introduced by recent changes to run sleeping code in a task.

In in6_ifadd(), line 2020 you can see:

        /* this is always non-NULL */
        ia6 = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);

        ...


Sadly the comment is no longer true as in6_update_ifa() can return 0
without creating an address if "vltime == 0".  This can now happen
because nd6_addr_add() is executed in a task with a "nd_prefix" with
a vltime and pltime of 0, see prelist_update() line 1254:

        error = nd6_prelist_add(new, dr, &newpr)
        ...

        /*
         * XXX: from the ND point of view, we can ignore a prefix
         * with the on-link bit being zero.  However, we need a
         * prefix structure for references from autoconfigured
         * addresses.  Thus, we explicitly make sure that the prefix
         * itself expires now.
         */
        if (newpr->ndpr_raf_onlink == 0) {
                newpr->ndpr_vltime = 0;
                newpr->ndpr_pltime = 0;
                in6_init_prefix_ltimes(newpr);
        }


Diff below should work around this problem.  I don't think a proper fix
can be written without rewriting this whole code.


Index: netinet6/nd6_rtr.c
===================================================================
RCS file: /cvs/src/sys/netinet6/nd6_rtr.c,v
retrieving revision 1.133
diff -u -p -r1.133 nd6_rtr.c
--- netinet6/nd6_rtr.c  2 Nov 2015 13:54:46 -0000       1.133
+++ netinet6/nd6_rtr.c  2 Nov 2015 15:45:39 -0000
@@ -2013,11 +2013,10 @@ in6_ifadd(struct nd_prefix *pr, int priv
                return (NULL);  /* ifaddr must not have been allocated. */
        }
 
-       /* this is always non-NULL */
        ia6 = in6ifa_ifpwithaddr(ifp, &ifra.ifra_addr.sin6_addr);
 
        /* Perform DAD, if needed. */
-       if (ia6->ia6_flags & IN6_IFF_TENTATIVE)
+       if (ia != NULL && ia6->ia6_flags & IN6_IFF_TENTATIVE)
                nd6_dad_start(&ia6->ia_ifa);
 
        return (ia6);

Reply via email to