Date: Sat, 8 May 2010 09:24:23 +1200 From: Matthew Luckie <mjl@luckie.org.nz> To: freebsd-bugs@FreeBSD.org Subject: Re: kern/145733: [patch] ipfw flaws with ipv6 fragments Message-ID: <20100507212423.GA1771@spandex.luckie.org.nz> In-Reply-To: <201004152100.o3FL0DQU071739@freefall.freebsd.org> References: <E1O2W9s-000C3X-72@spandex.luckie.org.nz> <201004152100.o3FL0DQU071739@freefall.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
--xHFwDpU9dbj6ez1V Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Attached is a revised patch fixing a third flaw. ipfw will reject very small IPv6 fragments when it tries to pullup the transport header. This relaxes the code to be consistent with the IPv4 path where it only tries to pull up the transport header on fragments with offset zero. --xHFwDpU9dbj6ez1V Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename=patch-ipfw-fraghdr --- ip_fw2.c.orig 2010-05-08 08:38:40.000000000 +1200 +++ ip_fw2.c 2010-05-08 09:10:28.000000000 +1200 @@ -804,6 +804,7 @@ char *action; int limit_reached = 0; char action2[40], proto[128], fragment[32]; + u_short mf = 0; fragment[0] = '\0'; proto[0] = '\0'; @@ -952,6 +953,8 @@ snprintf(dst, sizeof(dst), "[%s]", ip6_sprintf(ip6buf, &args->f_id.dst_ip6)); + mf = offset & IP6F_MORE_FRAG; + offset &= IP6F_OFF_MASK; ip6 = (struct ip6_hdr *)ip; tcp = (struct tcphdr *)(((char *)ip) + hlen); udp = (struct udphdr *)(((char *)ip) + hlen); @@ -1021,13 +1024,13 @@ #ifdef INET6 if (IS_IP6_FLOW_ID(&(args->f_id))) { - if (offset & (IP6F_OFF_MASK | IP6F_MORE_FRAG)) + if (offset || mf) snprintf(SNPARGS(fragment, 0), " (frag %08x:%d@%d%s)", args->f_id.frag_id6, ntohs(ip6->ip6_plen) - hlen, - ntohs(offset & IP6F_OFF_MASK) << 3, - (offset & IP6F_MORE_FRAG) ? "+" : ""); + ntohs(offset) << 3, + mf ? "+" : ""); } else #endif { @@ -2184,16 +2187,13 @@ /* * offset The offset of a fragment. offset != 0 means that - * we have a fragment at this offset of an IPv4 packet. - * offset == 0 means that (if this is an IPv4 packet) - * this is the first or only fragment. - * For IPv6 offset == 0 means there is no Fragment Header. - * If offset != 0 for IPv6 always use correct mask to - * get the correct offset because we add IP6F_MORE_FRAG - * to be able to dectect the first fragment which would - * otherwise have offset = 0. + * we have a fragment at this offset. + * offset == 0 means that this is the first or only fragment. + * + * mf The MF bit masked out of IPv6 packets. */ u_short offset = 0; + u_short mf = 0; /* * Local copies of addresses. They are only valid if we have @@ -2281,7 +2281,7 @@ proto = ip6->ip6_nxt; /* Search extension headers to find upper layer protocols */ - while (ulp == NULL) { + while (ulp == NULL && offset == 0) { switch (proto) { case IPPROTO_ICMPV6: PULLUP_TO(hlen, ulp, struct icmp6_hdr); @@ -2345,17 +2345,8 @@ proto = ((struct ip6_frag *)ulp)->ip6f_nxt; offset = ((struct ip6_frag *)ulp)->ip6f_offlg & IP6F_OFF_MASK; - /* Add IP6F_MORE_FRAG for offset of first - * fragment to be != 0. */ - offset |= ((struct ip6_frag *)ulp)->ip6f_offlg & + mf = ((struct ip6_frag *)ulp)->ip6f_offlg & IP6F_MORE_FRAG; - if (offset == 0) { - printf("IPFW2: IPV6 - Invalid Fragment " - "Header\n"); - if (V_fw_deny_unknown_exthdrs) - return (IP_FW_DENY); - break; - } args->f_id.frag_id6 = ntohl(((struct ip6_frag *)ulp)->ip6f_ident); ulp = NULL; @@ -2941,7 +2932,7 @@ case O_LOG: if (V_fw_verbose) ipfw_log(f, hlen, args, m, - oif, offset, tablearg, ip); + oif, offset|mf, tablearg, ip); match = 1; break; --xHFwDpU9dbj6ez1V--
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20100507212423.GA1771>