Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 9 Mar 2012 16:59:32 -0800
From:      prabhakar lakhera <prabhakar.lakhera@gmail.com>
To:        freebsd-net@freebsd.org
Subject:   Race condition in IPv6 DAD detection code?
Message-ID:  <CALg%2BrhV8OMw5qHydbajYNAFkkSCfChH2Hk_eAr3DrW%2BdhOVkuw@mail.gmail.com>

next in thread | raw e-mail | index | archive | help
Hi,

I had sent a mail sometime back regarding some queries/concern regarding v6
DAD detection code.
Here's what my concern is, drawing tables for the whole sequence in hopes
of getting some replies:

  *CPU1*

 *CPU2*

In nd6_dad_na_input...



  struct dadq *dp;



        if (ifa =3D=3D NULL)

                panic("ifa =3D=3D NULL in nd6_dad_na_input");



        dp =3D nd6_dad_find(ifa);

        if (dp)







nd6_dad_timer.. last attempt and NA counter not yet incremented by the
thread on CPU1, therefore address considered to be not duplicated.

if (dp->dad_ns_ocount < dp->dad_count) {

=85..

        } else {

                /*

                 * We have transmitted sufficient number of DAD packets.

                 * See what we've got.

                 */

                int duplicate;



                duplicate =3D 0;



                if (dp->dad_na_icount) {

                        /*

                         * the check is in nd6_dad_na_input(),

                         * but just in case

                         */

                        duplicate++;

                }



                if (dp->dad_ns_icount) {

                        /* We've seen NS, means DAD has failed. */

                        duplicate++;

                }



                if (duplicate) {   =DF----- Duplicate 0 here

                        /* (*dp) will be freed in nd6_dad_duplicated() */

                        dp =3D NULL;

                        nd6_dad_duplicated(ifa);

                } else {



In nd6_dad_na_input...



        dp->dad_na_icount++;



        /* remove the address. */

        nd6_dad_duplicated(ifa);



Inside nd6_dad_duplicated=85



nd6_dad_duplicated(struct ifaddr *ifa)

{

        struct in6_ifaddr *ia =3D (struct in6_ifaddr *)ifa;

        struct ifnet *ifp;

        struct dadq *dp;

        char ip6buf[INET6_ADDRSTRLEN];



        dp =3D nd6_dad_find(ifa);

        if (dp =3D=3D NULL) {

                log(LOG_ERR, "nd6_dad_duplicated: DAD structure not
found\n");

                return;

        }



       =85. --=E0 dp is not NULL as has not yet been removed from queue.









Nd6_dad_timer executing else=85.



/*

                         * We are done with DAD.  No NA came, no NS came.

                         * No duplicate address found.

                         */

                        ia->ia6_flags &=3D ~IN6_IFF_TENTATIVE;



                        nd6log((LOG_DEBUG,

                            "%s: DAD complete for %s - no duplicates
found\n",

                            if_name(ifa->ifa_ifp),

                            ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr)));



                        TAILQ_REMOVE(&V_dadq, (struct dadq *)dp, dad_list);

                        free(dp, M_IP6NDP);

                        dp =3D NULL;

                        ifa_free(ifa);

                }

In nd6_dad_duplicated(struct ifaddr *ifa) =85

*Working on freed pointer???

*

*        log(LOG_ERR, "%s: DAD detected duplicate IPv6 address %s: "*

*            "NS in/out=3D%d/%d, NA in=3D%d\n",*

*            if_name(ifa->ifa_ifp), ip6_sprintf(ip6buf,
&ia->ia_addr.sin6_addr),*

*            dp->dad_ns_icount, dp->dad_ns_ocount, dp->dad_na_icount);*





On Wed, Mar 7, 2012 at 5:51 PM, prabhakar lakhera <
prabhakar.lakhera@gmail.com> wrote:

> Hi,
>
> I was puzzled to look at DAD detection code in FreeBSD. We check for
> counters for any received NA/NS for DAD in nd6_dad_timer:
>
>   if (dp->dad_na_icount) {
>  1326                         /*
>  1327                          * the check is in nd6_dad_na_input(),
>  1328                          * but just in case
>  1329                          */
>  1330                         duplicate++;
>  1331                 }
>  1332
>  1333                 if (dp->dad_ns_icount) {
>  1334                         /* We've seen NS, means DAD has failed. */
>  1335                         duplicate++;
>  1336                 }
>  1337
>  1338                 if (duplicate) {
>  1339                         /* (*dp) will be freed in
> nd6_dad_duplicated() */
>  1340                         dp =3D NULL;
>  1341                         nd6_dad_duplicated(ifa);
>
> the function later calls nd6_dad_duplicated to perform the remaining work
> if the address is detected duplicate.
>
> nd6_dad_duplicated also gets called from nd6_dad_na_input
> and  nd6_dad_ns_input, both the functions are the only places which
> increment the input NA/NS counters respectively.
>
>  1505 static void
>  1506 nd6_dad_na_input(struct ifaddr *ifa)
>  1507 {
>  1508         struct dadq *dp;
>  1509
>  1510         if (ifa =3D=3D NULL)
>  1511                 panic("ifa =3D=3D NULL in nd6_dad_na_input");
>  1512
>  1513         dp =3D nd6_dad_find(ifa);
>  1514         if (dp)
>  1515                 dp->dad_na_icount++;
>  1516
>  1517         /* remove the address. */
>  1518         nd6_dad_duplicated(ifa);
>  1519 }
>
> nd6_dad_duplicated stops the timer among other things.
>
> Why nd6_dad_timer need check on these counters if we stop the timer on DA=
D
> failure anyways?
> Ok.. may be just an optimization which just "hopes" that the counters hav=
e
> been updated but the nd6_dad_*_input has not yet called nd6_dad_duplicate=
d.
>
> Can the this timer and na packet processing ever run in parallel, I don;t
> see dp being protected by any locks, nor does it seem that it's been
> reference counted.
> Any explanation will be highly appreciated.
>
> Best,
>
> Prabhakar
>
>
>
>
>
>



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CALg%2BrhV8OMw5qHydbajYNAFkkSCfChH2Hk_eAr3DrW%2BdhOVkuw>