Subject: Re: crashes in ipfilter on i386
To: None <tech-net@netbsd.org>
From: Greg Troxel <gdt@ir.bbn.com>
List: tech-net
Date: 09/10/2007 18:05:55
I am running netbsd-4 on i386, with every month of so rebuild/updates.
At some point around June (hazy), I started having occasional crashes,
and it pointed to fil.c in icmp6 code.  This was near where a sparc was
having alignment crashes.

I have now removed the IP6_NEQ statement, and my machine stayed up for
31 days, far longer than it recently had.  So I believe there is
something not right here, but I really don't know what.



  From: mlelstv@serpens.de (Michael van Elst)
  Subject:  Re: crashes in ipfilter on i386
  To: tech-net@netbsd.org
  Date: Tue, 24 Jul 2007 20:00:04 +0000 (UTC)

  Are you sure that you use this code?

  >                       if (frpr_pullup(fin, ICMP6ERR_MINPKTLEN) == -1)
  >                               return;
  [...]
  >			icmp6 = fin->fin_dp;
  >			ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
  >			if (IP6_NEQ(&fin->fin_fi.fi_dst,
  >				    &ip6->ip6_src))
  >				fin->fin_flx |= FI_BAD;

  I am asking, because there was a bug exactly in this place
  (a stale version of the icmp6 pointer was used) and the crash
  was exactly where you have shown it in your previous mail.

  However, this is fixed in the code snippet above.

  The frpr_pullup ensures that enough data is in the buffer for the
  IP6_NEQ operation and the icmp6 (and thus ip6) pointers are recomputed
  in case the buffer was moved.

I am sure that I was running the code with the frpr_pullup.


Here's the diff in my source tree, producing a kernel that doesn't
crash.  Note there is a lot of s/INLINE// noise because I found it hard
to follow the asm code, but the real change is dropping the IP6_NEQ
test.  Obviously my change causes a functionality regression - it was
intended to isolate the bug, not proposed as a fix.

I still suspect failure to pull up enough bytes, but I can't point to
the wrong line of code.

Any clues?


Index: sys/dist/ipf/netinet/fil.c
===================================================================
RCS file: /cvsroot/src/sys/dist/ipf/netinet/fil.c,v
retrieving revision 1.28.2.7
diff -u -p -r1.28.2.7 fil.c
--- sys/dist/ipf/netinet/fil.c	21 Jul 2007 12:56:45 -0000	1.28.2.7
+++ sys/dist/ipf/netinet/fil.c	10 Sep 2007 21:58:58 -0000
@@ -242,9 +242,9 @@ static	INLINE void	frpr_esp __P((fr_info
 static	INLINE void	frpr_gre __P((fr_info_t *));
 static	INLINE void	frpr_udp __P((fr_info_t *));
 static	INLINE void	frpr_tcp __P((fr_info_t *));
-static	INLINE void	frpr_icmp __P((fr_info_t *));
+static	 void	frpr_icmp __P((fr_info_t *));
 static	INLINE void	frpr_ipv4hdr __P((fr_info_t *));
-static	INLINE int	frpr_pullup __P((fr_info_t *, int));
+static int	frpr_pullup __P((fr_info_t *, int));
 static	INLINE void	frpr_short __P((fr_info_t *, int));
 static	INLINE int	frpr_tcpcommon __P((fr_info_t *));
 static	INLINE int	frpr_udpcommon __P((fr_info_t *));
@@ -357,7 +357,7 @@ static	INLINE void	frpr_esp6 __P((fr_inf
 static	INLINE void	frpr_gre6 __P((fr_info_t *));
 static	INLINE void	frpr_udp6 __P((fr_info_t *));
 static	INLINE void	frpr_tcp6 __P((fr_info_t *));
-static	INLINE void	frpr_icmp6 __P((fr_info_t *));
+static void	frpr_icmp6 __P((fr_info_t *));
 static	INLINE int	frpr_ipv6hdr __P((fr_info_t *));
 static	INLINE void	frpr_short6 __P((fr_info_t *, int));
 static	INLINE int	frpr_hopopts6 __P((fr_info_t *));
@@ -727,7 +727,7 @@ fr_info_t *fin;
 /* This routine is mainly concerned with determining the minimum valid size */
 /* for an ICMPv6 packet.                                                    */
 /* ------------------------------------------------------------------------ */
-static INLINE void frpr_icmp6(fin)
+static void frpr_icmp6(fin)
 fr_info_t *fin;
 {
 	int minicmpsz = sizeof(struct icmp6_hdr);
@@ -770,9 +770,11 @@ fr_info_t *fin;
 			 */
 			icmp6 = fin->fin_dp;
 			ip6 = (ip6_t *)((char *)icmp6 + ICMPERR_ICMPHLEN);
+#if 0
 			if (IP6_NEQ(&fin->fin_fi.fi_dst,
 				    &ip6->ip6_src))
 				fin->fin_flx |= FI_BAD;
+#endif
 
 			minicmpsz = ICMP6ERR_IPICMPHLEN - sizeof(ip6_t);
 			break;
@@ -916,7 +918,7 @@ fr_info_t *fin;
 /* to fr_pullup to ensure there is the required amount of data,             */
 /* consecutively in the packet buffer.                                      */
 /* ------------------------------------------------------------------------ */
-static INLINE int frpr_pullup(fin, plen)
+static int frpr_pullup(fin, plen)
 fr_info_t *fin;
 int plen;
 {
[<