From mjl@luckie.org.nz  Thu Apr 15 20:59:36 2010
Return-Path: <mjl@luckie.org.nz>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 87BDA1065672
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 15 Apr 2010 20:59:36 +0000 (UTC)
	(envelope-from mjl@luckie.org.nz)
Received: from mailfilter4.ihug.co.nz (mailfilter4.ihug.co.nz [203.109.136.4])
	by mx1.freebsd.org (Postfix) with ESMTP id 13BE28FC12
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 15 Apr 2010 20:59:34 +0000 (UTC)
Received: from 118-92-126-17.dsl.dyn.ihug.co.nz (HELO spandex.luckie.org.nz) ([118.92.126.17])
  by cust.filter4.content.vf.net.nz with ESMTP/TLS/DHE-RSA-AES256-SHA; 16 Apr 2010 08:58:38 +1200
Received: from mjl by spandex.luckie.org.nz with local (Exim 4.71 (FreeBSD))
	(envelope-from <mjl@luckie.org.nz>)
	id 1O2W9s-000C3X-72
	for FreeBSD-gnats-submit@freebsd.org; Fri, 16 Apr 2010 08:59:32 +1200
Message-Id: <E1O2W9s-000C3X-72@spandex.luckie.org.nz>
Date: Fri, 16 Apr 2010 08:59:32 +1200
From: Matthew Luckie <mjl@luckie.org.nz>
Reply-To: Matthew Luckie <mjl@luckie.org.nz>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [patch] ipfw flaws with ipv6 fragments
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         145733
>Category:       kern
>Synopsis:       [ipfw] [patch] ipfw flaws with ipv6 fragments
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    bz
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Apr 15 21:00:13 UTC 2010
>Closed-Date:    Wed Feb 08 16:29:35 UTC 2012
>Last-Modified:  Wed Feb  8 16:30:13 UTC 2012
>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 mjl@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@%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:
Responsible-Changed-From-To: freebsd-bugs->freebsd-ipfw 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Sat Apr 17 06:18:13 UTC 2010 
Responsible-Changed-Why:  
Over to maintainer(s). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=145733 

From: Matthew Luckie <mjl@luckie.org.nz>
To: freebsd-bugs@FreeBSD.org
Cc:  
Subject: Re: kern/145733: [patch] ipfw flaws with ipv6 fragments
Date: Sat, 8 May 2010 09:24:23 +1200

 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.
 
 --- patch-ip_fw2-9.c begins here ---
 --- 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;
  
 --- patch-ip_fw2-9.c ends here ---

Responsible-Changed-From-To: freebsd-ipfw->bz 
Responsible-Changed-By: bz 
Responsible-Changed-When: Wed Mar 2 21:44:09 UTC 2011 
Responsible-Changed-Why:  
*sigh* I'll take it. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=145733 

From: Mark Linimon <linimon@lonesome.com>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: [patch] ipfw flaws with ipv6 fragments
Date: Sat, 5 Mar 2011 15:26:13 -0600

 ----- Forwarded message from sthaug@nethelp.no -----
 
 Date: Sat, 05 Mar 2011 20:48:32 +0100 (CET)
 From: sthaug@nethelp.no
 To: freebsd-bugs@freebsd.org
 Subject: Re: kern/145733: [patch] ipfw flaws with ipv6 fragments
 X-Mailer: Mew version 3.3 on Emacs 21.3 / Mule 5.0 (SAKAKI)
 
 IPFW incorrectly handles IPv6 packets with a fragment header followed
 by a last fragment only (i.e. the fragment header has fragment offset
 = 0 and M bit = 0). Such packets are allowed by RFC 2460.
 
 The problem is well described in kern/145733 from 16. April 2010, but
 nothing seems to have happened with this PR so far. 
 
 I see the effects of this problem on several name servers which handle
 IPv6 traffic. One typical example is
 
 15:49:26.408456 IP6 2001:1a68::d911:210a > 2001:8c0:2001::3:53: frag (0|50) 50017 > 53: 38139% [1au] AAAA? dns1.eunet.no. (42)
         0x0000:  6008 f572 003a 2c36 2001 1a68 0000 0000  `..r.:,6...h....
         0x0010:  0000 0000 d911 210a 2001 08c0 2001 0000  ......!.........
         0x0020:  0000 0000 0003 0053 1100 0000 a977 6460  .......S.....wd`
         0x0030:  c361 0035 0032 21f6 94fb 0010 0001 0000  .a.5.2!.........
         0x0040:  0000 0001 0464 6e73 3105 6575 6e65 7402  .....dns1.eunet.
         0x0050:  6e6f 0000 1c00 0100 0029 1000 0000 8000  no.......)......
         0x0060:  0000                                     ..
 
 which results in the following log entry:
 
 Feb  6 15:49:26 dns1 kernel: IPFW2: IPV6 - Invalid Fragment Header
 
 and then the packet is dropped, even though the packet is perfectly
 valid. The logs on my name servers are getting filled with these error
 messages...
 
 Does anybody have an idea of whether the patch in kern/145733 will be
 incorporated into ip_fw2.c any time soon?
 
 Steinar Haug, Nethelp consulting, sthaug@nethelp.no
 
 ----- End forwarded message -----

From: Matthew Luckie <mjl@luckie.org.nz>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: [ipfw] [patch] ipfw flaws with ipv6 fragments
Date: Sat, 25 Jun 2011 21:24:03 +1200

 This is a multi-part message in MIME format.
 --------------090202010404060704020902
 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
 Content-Transfer-Encoding: 7bit
 
 On world IPv6 day I was asked by bz@ to re-spin the patch supplied in 
 the PR with the second and third IPv6 fragment issues listed in the PR 
 fixed, but not the first (discarding IPv6 packets with a fragment header 
 but not fragmented).  Attached is the revised patch, against 8.2R
 
 --------------090202010404060704020902
 Content-Type: text/plain;
  name="patch-ipfw2-ip6frag"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: attachment;
  filename="patch-ipfw2-ip6frag"
 
 --- ip_fw_log.c.orig	2011-06-24 19:46:44.000000000 +1200
 +++ ip_fw_log.c	2011-06-24 20:14:55.724751000 +1200
 @@ -168,6 +168,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;
  
  	if (V_fw_verbose == 0) {
  #ifndef WITHOUT_BPF
 @@ -337,6 +338,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);
 @@ -406,13 +409,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@%d%s)",
  				    args->f_id.extra,
  				    ntohs(ip6->ip6_plen) - hlen,
 -				    ntohs(offset & IP6F_OFF_MASK) << 3,
 -				    (offset & IP6F_MORE_FRAG) ? "+" : "");
 +				    ntohs(offset) << 3,
 +				    mf ? "+" : "");
  		} else
  #endif
  		{
 --- ip_fw2.c.orig	2011-06-24 19:31:28.000000000 +1200
 +++ ip_fw2.c	2011-06-24 20:14:55.724751000 +1200
 @@ -838,16 +838,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
 @@ -940,7 +937,7 @@ do {								\
  		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);
 @@ -1005,11 +1002,9 @@ 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) {
 +				if (offset == 0 && mf == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (V_fw_deny_unknown_exthdrs)
 @@ -1650,7 +1645,7 @@ do {								\
  
  			case O_LOG:
  				ipfw_log(f, hlen, args, m,
 -					    oif, offset, tablearg, ip);
 +					    oif, offset|mf, tablearg, ip);
  				match = 1;
  				break;
  
 
 --------------090202010404060704020902--

From: "Bjoern A. Zeeb" <bz@FreeBSD.org>
To: bug-followup@FreeBSD.org, mjl@luckie.org.nz, sthaug@nethelp.no
Cc:  
Subject: Re: kern/145733: [ipfw] [patch] ipfw flaws with ipv6 fragments
Date: Sun, 14 Aug 2011 16:29:47 +0000 (UTC)

 Hi,
 
 can you validate that this patch fixes problem #1 as mentioned in
 the PR for you?
 
 You can also fetch it from
 http://people.freebsd.org/~bz/20110814-01-ipfw-frag6-single-packet-pr145733.diff
 
 
 !
 ! While not explicitly allowed by RFC 2460, in case there is no
 ! translation technology involved (and that section is suggested to
 ! be removed by Errata 2843), single packet fragments do not harm.
 !
 ! There is another errata under discussion to clarify and allow this.
 ! Meanwhile add a sysctl to allow disabling this behaviour again.
 ! We will treat single packet fragment (a fragment header added
 ! when not needed) as if there was no fragment header.
 !
 ! PR:			kern/145733
 ! MFC after:		2 weeks
 !
 Index: sys/netinet/ipfw/ip_fw2.c
 ===================================================================
 --- sys/netinet/ipfw/ip_fw2.c	(revision 224865)
 +++ sys/netinet/ipfw/ip_fw2.c	(working copy)
 @@ -107,6 +107,9 @@ static VNET_DEFINE(int, ipfw_vnet_ready) = 0;
   static VNET_DEFINE(int, fw_deny_unknown_exthdrs);
   #define	V_fw_deny_unknown_exthdrs	VNET(fw_deny_unknown_exthdrs)
 
 +static VNET_DEFINE(int, fw_permit_single_frag6) = 1;
 +#define	V_fw_permit_single_frag6	VNET(fw_permit_single_frag6)
 +
   #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
   static int default_to_accept = 1;
   #else
 @@ -182,6 +185,9 @@ SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw, CTLFLAG_
   SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
       CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0,
       "Deny packets with unknown IPv6 Extension Headers");
 +SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, permit_single_frag6,
 +    CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_permit_single_frag6), 0,
 +    "Permit single packet IPv6 fragments");
   #endif /* INET6 */
 
   SYSEND
 @@ -871,10 +877,14 @@ ipfw_chk(struct ip_fw_args *args)
   	 *	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. 
 +	 *	For IPv6 offset == 0 means there is no Fragment Header or there
 +	 *	is a single packet fragement (fragement header added without
 +	 *	needed).  We will treat a single packet fragment as if there
 +	 *	was no fragment header (or log/block depending on the
 +	 *	V_fw_permit_single_frag6 sysctl setting).
   	 *	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
 +	 *	get the correct offset because we add IP6F_MORE_FRAG to be able
 +	 *	to dectect the first of multiple fragments which would
   	 *	otherwise have offset = 0.
   	 */
   	u_short offset = 0;
 @@ -1037,10 +1047,11 @@ do {								\
   				offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
   					IP6F_OFF_MASK;
   				/* Add IP6F_MORE_FRAG for offset of first
 -				 * fragment to be != 0. */
 +				 * fragment to be != 0 if there shall be more. */
   				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
   					IP6F_MORE_FRAG;
 -				if (offset == 0) {
 +				if (V_fw_permit_single_frag6 == 0 &&
 +				    offset == 0) {
   					printf("IPFW2: IPV6 - Invalid Fragment "
   					    "Header\n");
   					if (V_fw_deny_unknown_exthdrs)

From: Matthew Luckie <mjl@luckie.org.nz>
To: "Bjoern A. Zeeb" <bz@FreeBSD.org>
Cc: bug-followup@FreeBSD.org, sthaug@nethelp.no
Subject: Re: kern/145733: [ipfw] [patch] ipfw flaws with ipv6 fragments
Date: Sat, 20 Aug 2011 08:14:49 +1200

 > can you validate that this patch fixes problem #1 as mentioned in
 > the PR for you?
 
 I can confirm this patch fixes problem #1.

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Sat, 20 Aug 2011 12:40:27 +0000 (UTC)

 Author: bz
 Date: Sat Aug 20 12:40:17 2011
 New Revision: 225030
 URL: http://svn.freebsd.org/changeset/base/225030
 
 Log:
   While not explicitly allowed by RFC 2460, in case there is no
   translation technology involved (and that section is suggested to
   be removed by Errata 2843), single packet fragments do not harm.
   
   There is another errata under discussion to clarify and allow this.
   Meanwhile add a sysctl to allow disabling this behaviour again.
   We will treat single packet fragment (a fragment header added
   when not needed) as if there was no fragment header.
   
   PR:		kern/145733
   Submitted by:	Matthew Luckie (mjl luckie.org.nz) (original version)
   Tested by:	Matthew Luckie (mjl luckie.org.nz)
   MFC after:	2 weeks
   Approved by:	re (kib)
 
 Modified:
   head/sys/netinet/ipfw/ip_fw2.c
 
 Modified: head/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- head/sys/netinet/ipfw/ip_fw2.c	Sat Aug 20 12:08:53 2011	(r225029)
 +++ head/sys/netinet/ipfw/ip_fw2.c	Sat Aug 20 12:40:17 2011	(r225030)
 @@ -107,6 +107,9 @@ static VNET_DEFINE(int, ipfw_vnet_ready)
  static VNET_DEFINE(int, fw_deny_unknown_exthdrs);
  #define	V_fw_deny_unknown_exthdrs	VNET(fw_deny_unknown_exthdrs)
  
 +static VNET_DEFINE(int, fw_permit_single_frag6) = 1;
 +#define	V_fw_permit_single_frag6	VNET(fw_permit_single_frag6)
 +
  #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
  static int default_to_accept = 1;
  #else
 @@ -182,6 +185,9 @@ SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw
  SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
      CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0,
      "Deny packets with unknown IPv6 Extension Headers");
 +SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, permit_single_frag6,
 +    CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_permit_single_frag6), 0,
 +    "Permit single packet IPv6 fragments");
  #endif /* INET6 */
  
  SYSEND
 @@ -871,10 +877,14 @@ ipfw_chk(struct ip_fw_args *args)
  	 *	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. 
 +	 *	For IPv6 offset == 0 means there is no Fragment Header or there
 +	 *	is a single packet fragement (fragement header added without
 +	 *	needed).  We will treat a single packet fragment as if there
 +	 *	was no fragment header (or log/block depending on the
 +	 *	V_fw_permit_single_frag6 sysctl setting).
  	 *	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
 +	 *	get the correct offset because we add IP6F_MORE_FRAG to be able
 +	 *	to dectect the first of multiple fragments which would
  	 *	otherwise have offset = 0.
  	 */
  	u_short offset = 0;
 @@ -1037,10 +1047,11 @@ do {								\
  				offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_OFF_MASK;
  				/* Add IP6F_MORE_FRAG for offset of first
 -				 * fragment to be != 0. */
 +				 * fragment to be != 0 if there shall be more. */
  				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_MORE_FRAG;
 -				if (offset == 0) {
 +				if (V_fw_permit_single_frag6 == 0 &&
 +				    offset == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (V_fw_deny_unknown_exthdrs)
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Sat, 20 Aug 2011 13:17:57 +0000 (UTC)

 Author: bz
 Date: Sat Aug 20 13:17:47 2011
 New Revision: 225032
 URL: http://svn.freebsd.org/changeset/base/225032
 
 Log:
   ipfw internally checks for offset == 0 to determine whether the
   packet is a/the first fragment or not.  For IPv6 we have added the
   "more fragments" flag as well to be able to determine on whether
   there will be more as we do not have the fragment header avaialble
   for logging, while for IPv4 this information can be derived directly
   from the IPv4 header.  This allowed fragmented packets to bypass
   normal rules as proper masking was not done when checking offset.
   Split variables to not need masking for IPv6 to avoid further errors.
   
   PR:		kern/145733
   Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   MFC after:	2 weeks
   Approved by:	re (kib)
 
 Modified:
   head/sys/netinet/ipfw/ip_fw2.c
 
 Modified: head/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- head/sys/netinet/ipfw/ip_fw2.c	Sat Aug 20 13:07:29 2011	(r225031)
 +++ head/sys/netinet/ipfw/ip_fw2.c	Sat Aug 20 13:17:47 2011	(r225032)
 @@ -877,17 +877,14 @@ ipfw_chk(struct ip_fw_args *args)
  	 *	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 or there
 -	 *	is a single packet fragement (fragement header added without
 -	 *	needed).  We will treat a single packet fragment as if there
 -	 *	was no fragment header (or log/block depending on the
 +	 *	For IPv6 offset|ip6f_mf == 0 means there is no Fragment Header
 +	 *	or there is a single packet fragement (fragement header added
 +	 *	without needed).  We will treat a single packet fragment as if
 +	 *	there was no fragment header (or log/block depending on the
  	 *	V_fw_permit_single_frag6 sysctl setting).
 -	 *	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 of multiple fragments which would
 -	 *	otherwise have offset = 0.
  	 */
  	u_short offset = 0;
 +	u_short ip6f_mf = 0;
  
  	/*
  	 * Local copies of addresses. They are only valid if we have
 @@ -1046,12 +1043,10 @@ 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 if there shall be more. */
 -				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
 +				ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_MORE_FRAG;
  				if (V_fw_permit_single_frag6 == 0 &&
 -				    offset == 0) {
 +				    offset == 0 && ip6f_mf == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (V_fw_deny_unknown_exthdrs)
 @@ -1687,7 +1682,7 @@ do {								\
  
  			case O_LOG:
  				ipfw_log(f, hlen, args, m,
 -					    oif, offset, tablearg, ip);
 +				    oif, offset | ip6f_mf, tablearg, ip);
  				match = 1;
  				break;
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: bz 
State-Changed-When: Sat Aug 20 13:47:26 UTC 2011 
State-Changed-Why:  
The changes are committed; I had missed the logging with 
commit #2 so it's gone in seperately last.  I'll merge the 
changes in 2 weeks. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=145733 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Sat, 20 Aug 2011 13:46:29 +0000 (UTC)

 Author: bz
 Date: Sat Aug 20 13:46:19 2011
 New Revision: 225033
 URL: http://svn.freebsd.org/changeset/base/225033
 
 Log:
   If we detect an IPv6 fragment header and it is not the first fragment,
   then terminate the loop as we will not find any further headers and
   for short fragments this could otherwise lead to a pullup error
   discarding the fragment.
   
   PR:		kern/145733
   Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   MFC after:	2 weeks
   Approved by:	re (kib)
 
 Modified:
   head/sys/netinet/ipfw/ip_fw2.c
 
 Modified: head/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- head/sys/netinet/ipfw/ip_fw2.c	Sat Aug 20 13:17:47 2011	(r225032)
 +++ head/sys/netinet/ipfw/ip_fw2.c	Sat Aug 20 13:46:19 2011	(r225033)
 @@ -978,7 +978,7 @@ do {								\
  		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);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Sat, 20 Aug 2011 13:47:22 +0000 (UTC)

 Author: bz
 Date: Sat Aug 20 13:47:08 2011
 New Revision: 225034
 URL: http://svn.freebsd.org/changeset/base/225034
 
 Log:
   After r225032 fix logging in a similar way masking the the IPv6
   more fragments flag off so that offset == 0 checks work properly.
   
   PR:		kern/145733
   Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   MFC after:	2 weeks
   X-MFC with:	r225032
   Approved by:	re (kib)
 
 Modified:
   head/sys/netinet/ipfw/ip_fw_log.c
 
 Modified: head/sys/netinet/ipfw/ip_fw_log.c
 ==============================================================================
 --- head/sys/netinet/ipfw/ip_fw_log.c	Sat Aug 20 13:46:19 2011	(r225033)
 +++ head/sys/netinet/ipfw/ip_fw_log.c	Sat Aug 20 13:47:08 2011	(r225034)
 @@ -333,10 +333,14 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  #ifdef INET6
  		struct ip6_hdr *ip6 = NULL;
  		struct icmp6_hdr *icmp6;
 +		u_short ip6f_mf;
  #endif
  		src[0] = '\0';
  		dst[0] = '\0';
  #ifdef INET6
 +		ip6f_mf = offset & IP6F_MORE_FRAG;
 +		offset &= IP6F_OFF_MASK;
 +
  		if (IS_IP6_FLOW_ID(&(args->f_id))) {
  			char ip6buf[INET6_ADDRSTRLEN];
  			snprintf(src, sizeof(src), "[%s]",
 @@ -418,8 +422,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  				    " (frag %08x:%d@%d%s)",
  				    args->f_id.extra,
  				    ntohs(ip6->ip6_plen) - hlen,
 -				    ntohs(offset & IP6F_OFF_MASK) << 3,
 -				    (offset & IP6F_MORE_FRAG) ? "+" : "");
 +				    ntohs(offset) << 3, ip6f_mf ? "+" : "");
  		} else
  #endif
  		{
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: sthaug@nethelp.no
To: bz@FreeBSD.org
Cc: bug-followup@FreeBSD.org, mjl@luckie.org.nz
Subject: Re: kern/145733: [ipfw] [patch] ipfw flaws with ipv6 fragments
Date: Tue, 27 Sep 2011 10:25:05 +0200 (CEST)

 > can you validate that this patch fixes problem #1 as mentioned in
 > the PR for you?
 
 I can (finally) confirm that this patch fixes my problem too. Thanks!
 
 Steinar Haug, Nethelp consulting, sthaug@nethelp.no

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Wed,  8 Feb 2012 15:37:49 +0000 (UTC)

 Author: bz
 Date: Wed Feb  8 15:37:34 2012
 New Revision: 231206
 URL: http://svn.freebsd.org/changeset/base/231206
 
 Log:
   MFC r225030:
   
    While not explicitly allowed by RFC 2460, in case there is no
    translation technology involved (and that section is suggested to
    be removed by Errata 2843), single packet fragments do not harm.
   
    There is another errata and further drafts under discussion to clarify
    on these kinds of packets.
    Meanwhile add a sysctl to allow disabling this behaviour again.
    We will treat single packet fragment (a fragment header added
    when not needed) as if there was no fragment header.
   
    Submitted by:	Matthew Luckie (mjl luckie.org.nz) (original version)
   PR:		kern/145733
 
 Modified:
   stable/8/sys/netinet/ipfw/ip_fw2.c
 Directory Properties:
   stable/8/sys/   (props changed)
 
 Modified: stable/8/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- stable/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb  8 15:19:49 2012	(r231205)
 +++ stable/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb  8 15:37:34 2012	(r231206)
 @@ -103,6 +103,9 @@ static VNET_DEFINE(int, ipfw_vnet_ready)
  static VNET_DEFINE(int, fw_deny_unknown_exthdrs);
  #define	V_fw_deny_unknown_exthdrs	VNET(fw_deny_unknown_exthdrs)
  
 +static VNET_DEFINE(int, fw_permit_single_frag6) = 1;
 +#define	V_fw_permit_single_frag6	VNET(fw_permit_single_frag6)
 +
  #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
  static int default_to_accept = 1;
  #else
 @@ -177,6 +180,9 @@ SYSCTL_NODE(_net_inet6_ip6, OID_AUTO, fw
  SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, deny_unknown_exthdrs,
      CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_deny_unknown_exthdrs), 0,
      "Deny packets with unknown IPv6 Extension Headers");
 +SYSCTL_VNET_INT(_net_inet6_ip6_fw, OID_AUTO, permit_single_frag6,
 +    CTLFLAG_RW | CTLFLAG_SECURE, &VNET_NAME(fw_permit_single_frag6), 0,
 +    "Permit single packet IPv6 fragments");
  #endif /* INET6 */
  
  SYSEND
 @@ -838,10 +844,14 @@ ipfw_chk(struct ip_fw_args *args)
  	 *	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. 
 +	 *	For IPv6 offset == 0 means there is no Fragment Header or there
 +	 *	is a single packet fragement (fragement header added without
 +	 *	needed).  We will treat a single packet fragment as if there
 +	 *	was no fragment header (or log/block depending on the
 +	 *	V_fw_permit_single_frag6 sysctl setting).
  	 *	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
 +	 *	get the correct offset because we add IP6F_MORE_FRAG to be able
 +	 *	to dectect the first of multiple fragments which would
  	 *	otherwise have offset = 0.
  	 */
  	u_short offset = 0;
 @@ -1004,10 +1014,11 @@ do {								\
  				offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_OFF_MASK;
  				/* Add IP6F_MORE_FRAG for offset of first
 -				 * fragment to be != 0. */
 +				 * fragment to be != 0 if there shall be more. */
  				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_MORE_FRAG;
 -				if (offset == 0) {
 +				if (V_fw_permit_single_frag6 == 0 &&
 +				    offset == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (V_fw_deny_unknown_exthdrs)
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Wed,  8 Feb 2012 15:38:50 +0000 (UTC)

 Author: bz
 Date: Wed Feb  8 15:38:36 2012
 New Revision: 231207
 URL: http://svn.freebsd.org/changeset/base/231207
 
 Log:
   MFC r225030:
   
    While not explicitly allowed by RFC 2460, in case there is no
    translation technology involved (and that section is suggested to
    be removed by Errata 2843), single packet fragments do not harm.
   
    There is another errata and further drafts under discussion to clarify
    on these kinds of packets.
    Meanwhile add a sysctl to allow disabling this behaviour again.
    We will treat single packet fragment (a fragment header added
    when not needed) as if there was no fragment header.
   
    Submitted by:	Matthew Luckie (mjl luckie.org.nz) (original version)
   PR:		kern/145733
 
 Modified:
   stable/7/sys/netinet/ip_fw2.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/netinet/ip_fw2.c
 ==============================================================================
 --- stable/7/sys/netinet/ip_fw2.c	Wed Feb  8 15:37:34 2012	(r231206)
 +++ stable/7/sys/netinet/ip_fw2.c	Wed Feb  8 15:38:36 2012	(r231207)
 @@ -110,6 +110,9 @@ static u_int32_t set_disable;
  static int fw_verbose;
  static struct callout ipfw_timeout;
  static int verbose_limit;
 +#ifdef INET6
 +static int fw_permit_single_frag6 = 1;
 +#endif
  
  #ifdef IPFIREWALL_DEFAULT_TO_ACCEPT
  static int default_to_accept = 1;
 @@ -2158,10 +2161,14 @@ ipfw_chk(struct ip_fw_args *args)
  	 *	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. 
 +	 *	For IPv6 offset == 0 means there is no Fragment Header or there
 +	 *	is a single packet fragement (fragement header added without
 +	 *	needed).  We will treat a single packet fragment as if there
 +	 *	was no fragment header (or log/block depending on the
 +	 *	fw_permit_single_frag6 sysctl setting).
  	 *	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
 +	 *	get the correct offset because we add IP6F_MORE_FRAG to be able
 +	 *	to dectect the first of multiple fragments which would
  	 *	otherwise have offset = 0.
  	 */
  	u_short offset = 0;
 @@ -2318,10 +2325,11 @@ do {									\
  				offset = ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_OFF_MASK;
  				/* Add IP6F_MORE_FRAG for offset of first
 -				 * fragment to be != 0. */
 +				 * fragment to be != 0 if there shall be more. */
  				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_MORE_FRAG;
 -				if (offset == 0) {
 +				if (fw_permit_single_frag6 == 0 &&
 +				    offset == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (fw_deny_unknown_exthdrs)
 @@ -4506,6 +4514,10 @@ ipfw_init(void)
  	    OID_AUTO, "deny_unknown_exthdrs", CTLFLAG_RW | CTLFLAG_SECURE,
  	    &fw_deny_unknown_exthdrs, 0,
  	    "Deny packets with unknown IPv6 Extension Headers");
 +	SYSCTL_ADD_INT(&ip6_fw_sysctl_ctx, SYSCTL_CHILDREN(ip6_fw_sysctl_tree),
 +	    OID_AUTO, "permit_single_frag6", CTLFLAG_RW | CTLFLAG_SECURE,
 +	    &fw_permit_single_frag6, 0,
 +	    "Permit single packet IPv6 fragments");
  #endif
  
  	layer3_chain.rules = NULL;
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Wed,  8 Feb 2012 16:03:20 +0000 (UTC)

 Author: bz
 Date: Wed Feb  8 16:03:05 2012
 New Revision: 231208
 URL: http://svn.freebsd.org/changeset/base/231208
 
 Log:
   MFC r225032,225034:
   
    ipfw internally checks for offset == 0 to determine whether the
    packet is a/the first fragment or not.  For IPv6 we have added the
    "more fragments" flag as well to be able to determine on whether
    there will be more as we do not have the fragment header avaialble
    for logging, while for IPv4 this information can be derived directly
    from the IPv4 header.  This allowed fragmented packets to bypass
    normal rules as proper masking was not done when checking offset.
    Split variables to not need masking for IPv6 to avoid further errors.
   
    After r225032 fix logging in a similar way masking the the IPv6
    more fragments flag off so that offset == 0 checks work properly.
   
    Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   PR:		kern/145733
 
 Modified:
   stable/8/sys/netinet/ipfw/ip_fw2.c
   stable/8/sys/netinet/ipfw/ip_fw_log.c
 Directory Properties:
   stable/8/sys/   (props changed)
 
 Modified: stable/8/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- stable/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb  8 15:38:36 2012	(r231207)
 +++ stable/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb  8 16:03:05 2012	(r231208)
 @@ -844,17 +844,14 @@ ipfw_chk(struct ip_fw_args *args)
  	 *	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 or there
 -	 *	is a single packet fragement (fragement header added without
 -	 *	needed).  We will treat a single packet fragment as if there
 -	 *	was no fragment header (or log/block depending on the
 +	 *	For IPv6 offset|ip6f_mf == 0 means there is no Fragment Header
 +	 *	or there is a single packet fragement (fragement header added
 +	 *	without needed).  We will treat a single packet fragment as if
 +	 *	there was no fragment header (or log/block depending on the
  	 *	V_fw_permit_single_frag6 sysctl setting).
 -	 *	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 of multiple fragments which would
 -	 *	otherwise have offset = 0.
  	 */
  	u_short offset = 0;
 +	u_short ip6f_mf = 0;
  
  	/*
  	 * Local copies of addresses. They are only valid if we have
 @@ -1013,12 +1010,10 @@ 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 if there shall be more. */
 -				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
 +				ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_MORE_FRAG;
  				if (V_fw_permit_single_frag6 == 0 &&
 -				    offset == 0) {
 +				    offset == 0 && ip6f_mf == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (V_fw_deny_unknown_exthdrs)
 @@ -1666,7 +1661,7 @@ do {								\
  
  			case O_LOG:
  				ipfw_log(f, hlen, args, m,
 -					    oif, offset, tablearg, ip);
 +				    oif, offset | ip6f_mf, tablearg, ip);
  				match = 1;
  				break;
  
 
 Modified: stable/8/sys/netinet/ipfw/ip_fw_log.c
 ==============================================================================
 --- stable/8/sys/netinet/ipfw/ip_fw_log.c	Wed Feb  8 15:38:36 2012	(r231207)
 +++ stable/8/sys/netinet/ipfw/ip_fw_log.c	Wed Feb  8 16:03:05 2012	(r231208)
 @@ -328,10 +328,14 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  #ifdef INET6
  		struct ip6_hdr *ip6 = NULL;
  		struct icmp6_hdr *icmp6;
 +		u_short ip6f_mf;
  #endif
  		src[0] = '\0';
  		dst[0] = '\0';
  #ifdef INET6
 +		ip6f_mf = offset & IP6F_MORE_FRAG;
 +		offset &= IP6F_OFF_MASK;
 +
  		if (IS_IP6_FLOW_ID(&(args->f_id))) {
  			char ip6buf[INET6_ADDRSTRLEN];
  			snprintf(src, sizeof(src), "[%s]",
 @@ -413,8 +417,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  				    " (frag %08x:%d@%d%s)",
  				    args->f_id.extra,
  				    ntohs(ip6->ip6_plen) - hlen,
 -				    ntohs(offset & IP6F_OFF_MASK) << 3,
 -				    (offset & IP6F_MORE_FRAG) ? "+" : "");
 +				    ntohs(offset) << 3, ip6f_mf ? "+" : "");
  		} else
  #endif
  		{
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Wed,  8 Feb 2012 16:07:16 +0000 (UTC)

 Author: bz
 Date: Wed Feb  8 16:07:07 2012
 New Revision: 231209
 URL: http://svn.freebsd.org/changeset/base/231209
 
 Log:
   MFC r225032,225034:
   
    ipfw internally checks for offset == 0 to determine whether the
    packet is a/the first fragment or not.  For IPv6 we have added the
    "more fragments" flag as well to be able to determine on whether
    there will be more as we do not have the fragment header avaialble
    for logging, while for IPv4 this information can be derived directly
    from the IPv4 header.  This allowed fragmented packets to bypass
    normal rules as proper masking was not done when checking offset.
    Split variables to not need masking for IPv6 to avoid further errors.
   
    After r225032 fix logging in a similar way masking the the IPv6
    more fragments flag off so that offset == 0 checks work properly.
   
    Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   PR:		kern/145733
 
 Modified:
   stable/7/sys/netinet/ip_fw2.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/netinet/ip_fw2.c
 ==============================================================================
 --- stable/7/sys/netinet/ip_fw2.c	Wed Feb  8 16:03:05 2012	(r231208)
 +++ stable/7/sys/netinet/ip_fw2.c	Wed Feb  8 16:07:07 2012	(r231209)
 @@ -897,10 +897,14 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  #ifdef INET6
  		struct ip6_hdr *ip6 = NULL;
  		struct icmp6_hdr *icmp6;
 +		u_short ip6f_mf;
  #endif
  		src[0] = '\0';
  		dst[0] = '\0';
  #ifdef INET6
 +		ip6f_mf = offset & IP6F_MORE_FRAG;
 +		offset &= IP6F_OFF_MASK;
 +
  		if (IS_IP6_FLOW_ID(&(args->f_id))) {
  			char ip6buf[INET6_ADDRSTRLEN];
  			snprintf(src, sizeof(src), "[%s]",
 @@ -982,8 +986,7 @@ ipfw_log(struct ip_fw *f, u_int hlen, st
  				    " (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, ip6f_mf ? "+" : "");
  		} else
  #endif
  		{
 @@ -2161,17 +2164,14 @@ ipfw_chk(struct ip_fw_args *args)
  	 *	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 or there
 -	 *	is a single packet fragement (fragement header added without
 -	 *	needed).  We will treat a single packet fragment as if there
 -	 *	was no fragment header (or log/block depending on the
 +	 *	For IPv6 offset|ip6f_mf == 0 means there is no Fragment Header
 +	 *	or there is a single packet fragement (fragement header added
 +	 *	without needed).  We will treat a single packet fragment as if
 +	 *	there was no fragment header (or log/block depending on the
  	 *	fw_permit_single_frag6 sysctl setting).
 -	 *	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 of multiple fragments which would
 -	 *	otherwise have offset = 0.
  	 */
  	u_short offset = 0;
 +	u_short ip6f_mf = 0;
  
  	/*
  	 * Local copies of addresses. They are only valid if we have
 @@ -2324,12 +2324,10 @@ 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 if there shall be more. */
 -				offset |= ((struct ip6_frag *)ulp)->ip6f_offlg &
 +				ip6f_mf = ((struct ip6_frag *)ulp)->ip6f_offlg &
  					IP6F_MORE_FRAG;
  				if (fw_permit_single_frag6 == 0 &&
 -				    offset == 0) {
 +				    offset == 0 && ip6f_mf == 0) {
  					printf("IPFW2: IPV6 - Invalid Fragment "
  					    "Header\n");
  					if (fw_deny_unknown_exthdrs)
 @@ -2918,7 +2916,7 @@ check_body:
  			case O_LOG:
  				if (fw_verbose)
  					ipfw_log(f, hlen, args, m,
 -					    oif, offset, tablearg, ip);
 +					    oif, offset | ip6f_mf, tablearg, ip);
  				match = 1;
  				break;
  
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: bz 
State-Changed-When: Wed Feb 8 16:28:39 UTC 2012 
State-Changed-Why:  
All MFCs done.  Thanks for the patience, patches, testing! 

http://www.freebsd.org/cgi/query-pr.cgi?pr=145733 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Wed,  8 Feb 2012 16:25:16 +0000 (UTC)

 Author: bz
 Date: Wed Feb  8 16:24:56 2012
 New Revision: 231210
 URL: http://svn.freebsd.org/changeset/base/231210
 
 Log:
   MFC r225033:
   
    If we detect an IPv6 fragment header and it is not the first fragment,
    then terminate the loop as we will not find any further headers and
    for short fragments this could otherwise lead to a pullup error
    discarding the fragment.
   
    Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   PR:		kern/145733
 
 Modified:
   stable/8/sys/netinet/ipfw/ip_fw2.c
 Directory Properties:
   stable/8/sys/   (props changed)
 
 Modified: stable/8/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- stable/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb  8 16:07:07 2012	(r231209)
 +++ stable/8/sys/netinet/ipfw/ip_fw2.c	Wed Feb  8 16:24:56 2012	(r231210)
 @@ -945,7 +945,7 @@ do {								\
  		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);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/145733: commit references a PR
Date: Wed,  8 Feb 2012 16:26:19 +0000 (UTC)

 Author: bz
 Date: Wed Feb  8 16:26:01 2012
 New Revision: 231211
 URL: http://svn.freebsd.org/changeset/base/231211
 
 Log:
   MFC r225033:
   
    If we detect an IPv6 fragment header and it is not the first fragment,
    then terminate the loop as we will not find any further headers and
    for short fragments this could otherwise lead to a pullup error
    discarding the fragment.
   
    Submitted by:	Matthew Luckie (mjl luckie.org.nz)
   PR:		kern/145733
 
 Modified:
   stable/7/sys/netinet/ip_fw2.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/netinet/ip_fw2.c
 ==============================================================================
 --- stable/7/sys/netinet/ip_fw2.c	Wed Feb  8 16:24:56 2012	(r231210)
 +++ stable/7/sys/netinet/ip_fw2.c	Wed Feb  8 16:26:01 2012	(r231211)
 @@ -2260,7 +2260,7 @@ do {									\
  		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);
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
>Unformatted:
