kern/144560: mld sends packets to wrong destination with a bad checksum

Petr Lampa lampa at fit.vutbr.cz
Mon Mar 8 19:00:20 UTC 2010


>Number:         144560
>Category:       kern
>Synopsis:       mld sends packets to wrong destination with a bad checksum
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Mar 08 19:00:15 UTC 2010
>Closed-Date:
>Last-Modified:
>Originator:     Petr Lampa
>Release:        FreeBSD 8.0-STABLE
>Organization:
FIT BUT
>Environment:
reeBSD xxx 8.0-STABLE FreeBSD 8.0-STABLE #1: Wed Jan  6 15:53:10 CET 2010     xxx:/usr/src/sys/i386/compile/XXXX
>Description:
This is a packet dump of MLDv1 listener report send to group ff05::1:3 (all dhcp-servers):

15:41:09.388798 IP6 fe80::230:48ff:fe30:8646 > ff05:1::1:3: HBH ICMP6, multica
st listener reportmax resp delay: 0 addr: ff05::1:3, length 24
0x0000:  3333 0001 0003 0030 4830 8646 86dd 6000  33.....0H0.F..`.
0x0010:  0000 0020 0001 fe80 0000 0000 0000 0230  ...............0
0x0020:  48ff fe30 8646 ff05 0001 0000 0000 0000  H..0.F..........
0x0030:  0000 0001 0003 3a00 0100 0502 0000 8300  ......:.........
0x0040:  b071 0000 0000 ff05 0000 0000 0000 0000  .q..............
0x0050:  0000 0001 0003                           ......

First, the destination address of packet is wrong (notice that multicast group at the packet end is ok), second, the checksum is also wrong (it should be b070 instead b071, router complains about this). 

The reason is incorrect scope embedding in mld_dispatch_packet():

#if 0
        (void)in6_setscope(&ip6->ip6_dst, ifp, NULL);   /* XXX LOR */
#else
        /*
         * XXX XXX Break some KPI rules to prevent an LOR which would
         * occur if we called in6_setscope() at transmission.
         * See comments at top of file.
         */
        MLD_EMBEDSCOPE(&ip6->ip6_dst, ifp->if_index);
#endif

The macro MLD_EMBEDSCOPE contains this:!!!

#define MLD_EMBEDSCOPE(pin6, zoneid) \
        (pin6)->s6_addr16[1] = htons((zoneid) & 0xFFFF)

That's simply wrong, it should do at least this:

#define MLD_EMBEDSCOPE(pin6, zoneid) \
if (IN6_IS_SCOPE_LINKLOCAL(pin6) || IN6_IS_ADDR_MC_INTFACELOCAL(pin6)) \
        (pin6)->s6_addr16[1] = htons((zoneid) & 0xFFFF)

The reason of wrong checksum is that checksum was calculated previously in mld_v1_transmit_report() with the correct destination address, so it's 1 less in my case (interface scope was 1). 

>How-To-Repeat:
Join any non-local IPv6 multicast group.
>Fix:
If ifp->if_index is really the correct value for scope, the following patch should be sufficient:

*** /usr/src/sys/netinet6/mld6.c.orig   2010-03-08 19:06:13.000000000 +0100
--- /usr/src/sys/netinet6/mld6.c        2010-03-08 19:07:40.000000000 +0100
***************
*** 196,201 ****
--- 196,202 ----
  MALLOC_DEFINE(M_MLD, "mld", "mld state");

  #define       MLD_EMBEDSCOPE(pin6, zoneid) \
+ if (IN6_IS_SCOPE_LINKLOCAL(pin6) || IN6_IS_ADDR_MC_INTFACELOCAL(pin6)) \
        (pin6)->s6_addr16[1] = htons((zoneid) & 0xFFFF)

  /*


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list