From nobody@FreeBSD.org  Mon Apr  4 19:16:45 2011
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 4B229106564A
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  4 Apr 2011 19:16:45 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from red.freebsd.org (red.freebsd.org [IPv6:2001:4f8:fff6::22])
	by mx1.freebsd.org (Postfix) with ESMTP id 3B5528FC17
	for <freebsd-gnats-submit@FreeBSD.org>; Mon,  4 Apr 2011 19:16:45 +0000 (UTC)
Received: from red.freebsd.org (localhost [127.0.0.1])
	by red.freebsd.org (8.14.4/8.14.4) with ESMTP id p34JGjNY053758
	for <freebsd-gnats-submit@FreeBSD.org>; Mon, 4 Apr 2011 19:16:45 GMT
	(envelope-from nobody@red.freebsd.org)
Received: (from nobody@localhost)
	by red.freebsd.org (8.14.4/8.14.4/Submit) id p34JGiXe053757;
	Mon, 4 Apr 2011 19:16:44 GMT
	(envelope-from nobody)
Message-Id: <201104041916.p34JGiXe053757@red.freebsd.org>
Date: Mon, 4 Apr 2011 19:16:44 GMT
From: Karim Fodil-Lemelin <fodillemlinkarim@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: ipfw checks TCP options on non-contiguous header
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         156180
>Category:       kern
>Synopsis:       [ipfw] [patch] ipfw checks TCP options on non-contiguous header
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    glebius
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Apr 04 19:20:09 UTC 2011
>Closed-Date:    Fri Jul 08 12:54:27 UTC 2011
>Last-Modified:  Fri Jul  8 13:00:01 UTC 2011
>Originator:     Karim Fodil-Lemelin
>Release:        CURRENT
>Organization:
>Environment:
>Description:
When using tcpopt_match in ipfw there is no guarantee that the TCP option space matched is not bogus.

This is because the case IPPROTO_TCP does not do an m_pullup on the entire IP+TCP+TCP option header.
>How-To-Repeat:

>Fix:
The attached patch will call m_pullup on the TCP option space if it wasn't done already.

Patch attached with submission follows:

Index: netinet/ipfw/ip_fw2.c
===================================================================
--- netinet/ipfw/ip_fw2.c	(revision 219967)
+++ netinet/ipfw/ip_fw2.c	(working copy)
@@ -949,6 +949,11 @@
 
 			case IPPROTO_TCP:
 				PULLUP_TO(hlen, ulp, struct tcphdr);
+				/* kfl: check 'contiguousity' of the option space */
+				if (m->m_len < (hlen + (TCP(ulp)->th_off << 2))) {
+				  if ((m = m_pullup(m, hlen+(TCP(ulp)->th_off << 2))) == NULL)
+				    goto pullup_failed;
+				}
 				dst_port = TCP(ulp)->th_dport;
 				src_port = TCP(ulp)->th_sport;
 				/* save flags for dynamic rules */
@@ -1117,6 +1122,11 @@
 			switch (proto) {
 			case IPPROTO_TCP:
 				PULLUP_TO(hlen, ulp, struct tcphdr);
+				/* kfl: check 'contiguousity' of the option space */
+				if (m->m_len < (hlen + (TCP(ulp)->th_off << 2))) {
+				  if ((m = m_pullup(m, hlen+(TCP(ulp)->th_off << 2))) == NULL)
+				    goto pullup_failed;
+				}
 				dst_port = TCP(ulp)->th_dport;
 				src_port = TCP(ulp)->th_sport;
 				/* save flags for dynamic rules */


>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: freebsd-bugs->freebsd-ipfw 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Tue Apr 5 03:34:24 UTC 2011 
Responsible-Changed-Why:  
Over to maintainer(s). 

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

From: Gleb Smirnoff <glebius@FreeBSD.org>
To: bug-followup@FreeBSD.org
Cc: ae@FreeBSD.org
Subject: kern/156180
Date: Wed, 6 Apr 2011 01:07:29 +0400

 --5gxpn/Q6ypwruk0T
 Content-Type: text/plain; charset=koi8-r
 Content-Disposition: inline
 
   What about the following approach? See attached
 snap, not tested, patch.
 
 -- 
 Totus tuus, Glebius.
 
 --5gxpn/Q6ypwruk0T
 Content-Type: text/x-diff; charset=koi8-r
 Content-Disposition: attachment; filename="156180.diff"
 
 Index: ip_fw2.c
 ===================================================================
 --- ip_fw2.c	(revision 220373)
 +++ ip_fw2.c	(working copy)
 @@ -913,9 +913,10 @@
   * pointer might become stale after other pullups (but we never use it
   * this way).
   */
 -#define PULLUP_TO(_len, p, T)					\
 +#define PULLUP_TO(_len, p, T)	PULLUP_LEN(_len, p, sizeof(T))
 +#define PULLUP_LEN(_len, p, T)					\
  do {								\
 -	int x = (_len) + sizeof(T);				\
 +	int x = (_len) + T;					\
  	if ((m)->m_len < x) {					\
  		args->m = m = m_pullup(m, x);			\
  		if (m == NULL)					\
 @@ -1600,6 +1601,7 @@
  				break;
  
  			case O_TCPOPTS:
 +				PULLUP_LEN(hlen, ulp, (TCP(ulp)->th_off << 2));
  				match = (proto == IPPROTO_TCP && offset == 0 &&
  				    tcpopts_match(TCP(ulp), cmd));
  				break;
 @@ -2230,6 +2232,7 @@
  			}
  
  		}	/* end of inner loop, scan opcodes */
 +#undef PULLUP_LEN
  
  		if (done)
  			break;
 
 --5gxpn/Q6ypwruk0T--

From: Gleb Smirnoff <glebius@freebsd.org>
To: Karim Fodil-Lemelin <fodillemlinkarim@gmail.com>
Cc: bug-followup@freebsd.org
Subject: Re: kern/156180
Date: Wed, 6 Apr 2011 20:59:22 +0400

   Hi, Karim!
 
 On Wed, Apr 06, 2011 at 10:36:46AM -0400, Karim Fodil-Lemelin wrote:
 K> Thanks for the patch it does work in FBSD although it does not work in my
 K> setup since I have extended TCP option checking into another ipfw action and
 K> while I could add the check you've proposed for tcpop_match I would prefer a
 K> more generic approach where the m_pullup call is done for all TCP packets
 K> with options (basically in the case IPPROTO_TCP).
 K> 
 K> The rationale behind this is such that there is a guarantee that tcpop_match
 K> will work but also that any future extensions based on TCP options would
 K> also work saving the hard to debug situation that a missing call to m_pullup
 K> can create.
 
 Currently almost all TCP traffic has TCP options. And currently most,
 I suppose > 90%, installations, that use ipfw(4) do not have rules with
 'tcpoptions' keyword. So, we would add extra pullup, that is not needed
 in most cases and may have a performance impact.
 
 In case of future extensions the hard to debug situation won't happen
 if a developer analyses the function he modifies thoroughly.
 
 So, can you please confirm, that if you adding this string
 
 PULLUP_LEN(hlen, ulp, (TCP(ulp)->th_off << 2));
 
 into your new ipfw action, solves the discussed problem?
 
 -- 
 Totus tuus, Glebius.

From: Karim Fodil-Lemelin <fodillemlinkarim@gmail.com>
To: Gleb Smirnoff <glebius@FreeBSD.org>
Cc:  
Subject: Re: kern/156180
Date: Wed, 6 Apr 2011 14:07:08 -0400

 --000e0cd5d1826dc62504a043dcf6
 Content-Type: text/plain; charset=ISO-8859-1
 
 Hi Gleb,
 
 2011/4/6 Gleb Smirnoff <glebius@freebsd.org>
 
 >  Hi, Karim!
 >
 > On Wed, Apr 06, 2011 at 10:36:46AM -0400, Karim Fodil-Lemelin wrote:
 > K> Thanks for the patch it does work in FBSD although it does not work in
 > my
 > K> setup since I have extended TCP option checking into another ipfw action
 > and
 > K> while I could add the check you've proposed for tcpop_match I would
 > prefer a
 > K> more generic approach where the m_pullup call is done for all TCP
 > packets
 > K> with options (basically in the case IPPROTO_TCP).
 > K>
 > K> The rationale behind this is such that there is a guarantee that
 > tcpop_match
 > K> will work but also that any future extensions based on TCP options would
 > K> also work saving the hard to debug situation that a missing call to
 > m_pullup
 > K> can create.
 >
 > Currently almost all TCP traffic has TCP options. And currently most,
 > I suppose > 90%, installations, that use ipfw(4) do not have rules with
 > 'tcpoptions' keyword. So, we would add extra pullup, that is not needed
 > in most cases and may have a performance impact.
 >
 
 In my case even if all packets have at least a timestamp option or SACK the
 actual m_pullup was only called once every 10s of thousands packet as most
 of the time the lower layers hands out perfectly contiguous headers.
 
 What I've found is whenever a netgraph node or some other decapsulation
 mechanisms that tends to modify headers and due to its internal operations
 needs to somewhat break down the mbuf chain, the m_pullup call might be
 needed due to trailing options being in another mbuf. Most other times the
 headers are just fine and thats what made this problem hard to find in the
 first place.
 
 So I don't think there is a significant performance hit but I do see your
 point (see my point on multiple TCP microinstructions below).
 
 
 > In case of future extensions the hard to debug situation won't happen
 > if a developer analyses the function he modifies thoroughly.
 >
 
 One could assume that adding an action to ipfw should be relatively
 straightforward and the mechanics of doing sanity checks and what not was
 already handled by the top half of the function. Although I'm sure that with
 the call to PULLUP_LEN in tcpopt_match developers basing their code on it
 will not miss it ;)
 
 I can understand that since TCP option filtering isn't used much by the
 community its better to keep its specific processing isolated from IP
 although that approach has its drawback. You can imagine that if multiple
 TCP actions are chained (as microinstructions) together (and so are the
 calls to PULLUP_LEN) the call overhead becomes quickly a performance issue.
 
 
 >
 > So, can you please confirm, that if you adding this string
 >
 > PULLUP_LEN(hlen, ulp, (TCP(ulp)->th_off << 2));
 >
 > into your new ipfw action, solves the discussed problem?
 >
 
 Unfortunately I won't be able to test this exact code, as I mentionned
 earlier, since it is not applicable to our solution (btw the problem would
 show up once every 2 days or so). My PR was really just a mere pointer to an
 issue I have encountered and I perfectly understand the context of your
 solution and its applicability. You see myself in the impossibility to
 confirm with testing your proposed patch.
 
 If that can be a consolation my first fix was to add a call to m_pullup in
 every TCP action we had and it worked just fine although the final solution
 was to integrate it higher up in the function (before the microinstruction
 loop). Though, I do have to admit I prefer your macro integration to what
 I've proposed since it 'blends in' better with the previous implementation.
 
 Best regards,
 
 Karim.
 
 --000e0cd5d1826dc62504a043dcf6
 Content-Type: text/html; charset=ISO-8859-1
 Content-Transfer-Encoding: quoted-printable
 
 Hi Gleb,<br><br><div class=3D"gmail_quote">2011/4/6 Gleb Smirnoff <span dir=
 =3D"ltr">&lt;<a href=3D"mailto:glebius@freebsd.org">glebius@freebsd.org</a>=
 &gt;</span><br><blockquote class=3D"gmail_quote" style=3D"border-left: 1px =
 solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
  =A0Hi, Karim!<br>
 <br>
 On Wed, Apr 06, 2011 at 10:36:46AM -0400, Karim Fodil-Lemelin wrote:<br>
 K&gt; Thanks for the patch it does work in FBSD although it does not work i=
 n my<br>
 K&gt; setup since I have extended TCP option checking into another ipfw act=
 ion and<br>
 K&gt; while I could add the check you&#39;ve proposed for tcpop_match I wou=
 ld prefer a<br>
 K&gt; more generic approach where the m_pullup call is done for all TCP pac=
 kets<br>
 K&gt; with options (basically in the case IPPROTO_TCP).<br>
 K&gt;<br>
 K&gt; The rationale behind this is such that there is a guarantee that tcpo=
 p_match<br>
 K&gt; will work but also that any future extensions based on TCP options wo=
 uld<br>
 K&gt; also work saving the hard to debug situation that a missing call to m=
 _pullup<br>
 K&gt; can create.<br>
 <br>
 Currently almost all TCP traffic has TCP options. And currently most,<br>
 I suppose &gt; 90%, installations, that use ipfw(4) do not have rules with<=
 br>
 &#39;tcpoptions&#39; keyword. So, we would add extra pullup, that is not ne=
 eded<br>
 in most cases and may have a performance impact.<br></blockquote><div><br>I=
 n my case even if all packets have at least a timestamp option or SACK the =
 actual m_pullup was only called once every 10s of thousands packet as most =
 of the time the lower layers hands out perfectly contiguous headers.<br>
 <br>What I&#39;ve found is whenever a netgraph node or some other decapsula=
 tion mechanisms that tends to modify headers and due to its internal operat=
 ions needs to somewhat break down the mbuf chain, the m_pullup call might b=
 e needed due to trailing options being in another mbuf. Most other times th=
 e headers are just fine and thats what made this problem hard to find in th=
 e first place.<br>
 <br>So I don&#39;t think there is a significant performance hit but I do se=
 e your point (see my point on multiple TCP microinstructions below).<br><br=
 ></div><blockquote class=3D"gmail_quote" style=3D"border-left: 1px solid rg=
 b(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 
 <br>
 In case of future extensions the hard to debug situation won&#39;t happen<b=
 r>
 if a developer analyses the function he modifies thoroughly.<br></blockquot=
 e><div>=A0</div><div>One could assume that adding an action to ipfw should =
 be relatively straightforward and the mechanics of doing sanity checks and =
 what not was already handled by the top half of the function. Although I&#3=
 9;m sure that with the call to PULLUP_LEN in tcpopt_match developers basing=
  their code on it will not miss it ;)<br>
 <br>I can understand that since TCP option filtering isn&#39;t used much by=
  the community its better to keep its specific processing isolated from IP =
 although that approach has its drawback. You can imagine that if multiple T=
 CP actions are chained (as microinstructions) together (and so are the call=
 s to PULLUP_LEN) the call overhead becomes quickly a performance issue.<br>
 =A0</div><blockquote class=3D"gmail_quote" style=3D"border-left: 1px solid =
 rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
 <br>
 So, can you please confirm, that if you adding this string<br>
 <br>
 PULLUP_LEN(hlen, ulp, (TCP(ulp)-&gt;th_off &lt;&lt; 2));<br>
 <br>
 into your new ipfw action, solves the discussed problem?<br></blockquote></=
 div><br>Unfortunately I won&#39;t be able to test this exact code, as I men=
 tionned earlier, since it is not applicable to our solution (btw the proble=
 m would show up once every 2 days or so). My PR was really just a mere poin=
 ter to an issue I have encountered and I perfectly understand the context o=
 f your solution and its applicability. You see myself in the impossibility =
 to confirm with testing your proposed patch.<br>
 <br>If that can be a consolation my first fix was to add a call to m_pullup=
  in every TCP action we had and it worked just fine although the final solu=
 tion was to integrate it higher up in the function (before the microinstruc=
 tion loop). Though, I do have to admit I prefer your macro integration to w=
 hat I&#39;ve proposed since it &#39;blends in&#39; better with the previous=
  implementation.<br>
 <br>Best regards,<br><br>Karim.<br>
 
 --000e0cd5d1826dc62504a043dcf6--
State-Changed-From-To: open->patched 
State-Changed-By: glebius 
State-Changed-When: Mon Apr 18 18:22:21 UTC 2011 
State-Changed-Why:  
Fixed in head/. 


Responsible-Changed-From-To: freebsd-ipfw->glebius 
Responsible-Changed-By: glebius 
Responsible-Changed-When: Mon Apr 18 18:22:21 UTC 2011 
Responsible-Changed-Why:  
Fixed in head/. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/156180: commit references a PR
Date: Mon, 18 Apr 2011 18:22:20 +0000 (UTC)

 Author: glebius
 Date: Mon Apr 18 18:22:10 2011
 New Revision: 220796
 URL: http://svn.freebsd.org/changeset/base/220796
 
 Log:
   Pullup up to TCP header length before matching against 'tcpopts'.
   
   PR:		kern/156180
   Reviewed by:	luigi
 
 Modified:
   head/sys/netinet/ipfw/ip_fw2.c
 
 Modified: head/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- head/sys/netinet/ipfw/ip_fw2.c	Mon Apr 18 18:18:07 2011	(r220795)
 +++ head/sys/netinet/ipfw/ip_fw2.c	Mon Apr 18 18:22:10 2011	(r220796)
 @@ -913,9 +913,10 @@ ipfw_chk(struct ip_fw_args *args)
   * pointer might become stale after other pullups (but we never use it
   * this way).
   */
 -#define PULLUP_TO(_len, p, T)					\
 +#define PULLUP_TO(_len, p, T)	PULLUP_LEN(_len, p, sizeof(T))
 +#define PULLUP_LEN(_len, p, T)					\
  do {								\
 -	int x = (_len) + sizeof(T);				\
 +	int x = (_len) + T;					\
  	if ((m)->m_len < x) {					\
  		args->m = m = m_pullup(m, x);			\
  		if (m == NULL)					\
 @@ -1600,6 +1601,7 @@ do {								\
  				break;
  
  			case O_TCPOPTS:
 +				PULLUP_LEN(hlen, ulp, (TCP(ulp)->th_off << 2));
  				match = (proto == IPPROTO_TCP && offset == 0 &&
  				    tcpopts_match(TCP(ulp), cmd));
  				break;
 @@ -2233,6 +2235,7 @@ do {								\
  			}
  
  		}	/* end of inner loop, scan opcodes */
 +#undef PULLUP_LEN
  
  		if (done)
  			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: glebius 
State-Changed-When: Fri Jul 8 12:51:13 UTC 2011 
State-Changed-Why:  
Merged to stable/8. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/156180: commit references a PR
Date: Fri,  8 Jul 2011 12:54:19 +0000 (UTC)

 Author: glebius
 Date: Fri Jul  8 12:54:10 2011
 New Revision: 223868
 URL: http://svn.freebsd.org/changeset/base/223868
 
 Log:
   Merge from head/ 220796:
     Pullup up to TCP header length before matching against 'tcpopts'.
   
     PR:           kern/156180
     Reviewed by:  luigi
 
 Modified:
   stable/8/sys/netinet/ipfw/ip_fw2.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/netinet/ipfw/ip_fw2.c
 ==============================================================================
 --- stable/8/sys/netinet/ipfw/ip_fw2.c	Fri Jul  8 12:50:35 2011	(r223867)
 +++ stable/8/sys/netinet/ipfw/ip_fw2.c	Fri Jul  8 12:54:10 2011	(r223868)
 @@ -913,9 +913,10 @@ ipfw_chk(struct ip_fw_args *args)
   * pointer might become stale after other pullups (but we never use it
   * this way).
   */
 -#define PULLUP_TO(_len, p, T)					\
 +#define PULLUP_TO(_len, p, T)	PULLUP_LEN(_len, p, sizeof(T))
 +#define PULLUP_LEN(_len, p, T)					\
  do {								\
 -	int x = (_len) + sizeof(T);				\
 +	int x = (_len) + T;					\
  	if ((m)->m_len < x) {					\
  		args->m = m = m_pullup(m, x);			\
  		if (m == NULL)					\
 @@ -1600,6 +1601,7 @@ do {								\
  				break;
  
  			case O_TCPOPTS:
 +				PULLUP_LEN(hlen, ulp, (TCP(ulp)->th_off << 2));
  				match = (proto == IPPROTO_TCP && offset == 0 &&
  				    tcpopts_match(TCP(ulp), cmd));
  				break;
 @@ -2208,6 +2210,7 @@ do {								\
  			}
  
  		}	/* end of inner loop, scan opcodes */
 +#undef PULLUP_LEN
  
  		if (done)
  			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"
 
>Unformatted:
