>Number: 145733 >Category: kern >Synopsis: [patch] ipfw flaws with ipv6 fragments >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Apr 15 21:00:13 UTC 2010 >Closed-Date: >Last-Modified: >Originator: Matthew Luckie >Release: FreeBSD 8.0-RELEASE-p1 i386 >Organization: >Environment: System: FreeBSD spandex.luckie.org.nz 8.0-RELEASE-p1 FreeBSD 8.0-RELEASE-p1 #1: Fri Dec 4 08:21:29 NZDT 2009 m...@spandex.luckie.org.nz:/usr/obj/usr/src/sys/spandex i386
>Description: IPFW has two flaws in its handling of IPv6 packets that arrive in fragments. First, it will deny an IPv6 packet that arrives with a fragmentation header which has an offset of zero, but no further fragments. This type of packet is explicitly allowed in RFC 2460: In response to an IPv6 packet that is sent to an IPv4 destination (i.e., a packet that undergoes translation from IPv6 to IPv4), the originating IPv6 node may receive an ICMP Packet Too Big message reporting a Next-Hop MTU less than 1280. In that case, the IPv6 node is not required to reduce the size of subsequent packets to less than 1280, but must include a Fragment header in those packets so that the IPv6-to-IPv4 translating router can obtain a suitable Identification value to use in resulting IPv4 fragments. Note that this means the payload may have to be reduced to 1232 octets (1280 minus 40 for the IPv6 header and 8 for the Fragment header), and smaller still if additional extension headers are used. The second flaw is that the code allows IPv6 packets that arrive in fragments to avoid transport-layer rules. For example, consider this ruleset: 00001 deny tcp from 2607:f0b0:0:6:209:87:239:67 80 to 2404:138:4002:4000:205:1cff:fe11:beff dst-port 37822 65534 allow ip from any to any 65535 deny ip from any to any Rule 1 will not be applied to the fragment with offset zero because the MF bit is intentionally included in the offset variable used in ipfw_chk, so the check to see if the transport header is found in fragment zero will fail. Instead, the rule will be skipped over, and the next rule which in this example is an allow will accept the fragment. Where an administrator might have expected the traffic to be blocked it will instead be allowed through the firewall. >How-To-Repeat: As above. I can provide code to reproduce this problem out of band. >Fix: Apply this patch. --- patch-ip_fw2-8.c begins here --- --- ip_fw2.c.orig 2010-04-16 08:38:52.000000000 +1200 +++ ip_fw2.c 2010-04-16 08:42:03.000000000 +1200 @@ -804,6 +804,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, st 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 @@ ipfw_log(struct ip_fw *f, u_int hlen, st 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 @@ ipfw_log(struct ip_fw *f, u_int hlen, st #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%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 @@ ipfw_chk(struct ip_fw_args *args) /* * 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 @@ -2345,17 +2345,8 @@ do { \ 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 @@ check_body: 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; --- patch-ip_fw2-8.c ends here --- >Release-Note: >Audit-Trail: >Unformatted: _______________________________________________ freebsd-bugs@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-bugs To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"