From owner-freebsd-bugs@FreeBSD.ORG Fri May 7 21:54:02 2010 Return-Path: Delivered-To: freebsd-bugs@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 352061065674 for ; Fri, 7 May 2010 21:54:02 +0000 (UTC) (envelope-from mjl@luckie.org.nz) Received: from mailfilter69.ihug.co.nz (mailfilter69.ihug.co.nz [203.109.136.69]) by mx1.freebsd.org (Postfix) with ESMTP id C38828FC0C for ; Fri, 7 May 2010 21:54:01 +0000 (UTC) X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: Am4GAFch5Et2XUI5/2dsb2JhbACRYYw6cr87hRUEjDM X-IronPort-AV: E=Sophos;i="4.52,350,1270382400"; d="scan'208";a="282814378" Received: from 118-93-66-57.dsl.dyn.ihug.co.nz (HELO spandex.luckie.org.nz) ([118.93.66.57]) by smtp.mailfilter5.ihug.co.nz with ESMTP/TLS/DHE-RSA-AES256-SHA; 08 May 2010 09:24:24 +1200 Received: from mjl by spandex.luckie.org.nz with local (Exim 4.71 (FreeBSD)) (envelope-from ) id 1OAV1z-0000T1-Hd for freebsd-bugs@FreeBSD.org; Sat, 08 May 2010 09:24:23 +1200 Date: Sat, 8 May 2010 09:24:23 +1200 From: Matthew Luckie To: freebsd-bugs@FreeBSD.org Message-ID: <20100507212423.GA1771@spandex.luckie.org.nz> References: <201004152100.o3FL0DQU071739@freefall.freebsd.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="xHFwDpU9dbj6ez1V" Content-Disposition: inline In-Reply-To: <201004152100.o3FL0DQU071739@freefall.freebsd.org> User-Agent: Mutt/1.4.2.3i Cc: Subject: Re: kern/145733: [patch] ipfw flaws with ipv6 fragments X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 07 May 2010 21:54:02 -0000 --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--