NetBSD Problem Report #37037

From stix@stix.id.au  Sat Sep 29 10:10:03 2007
Return-Path: <stix@stix.id.au>
Received: from mail.netbsd.org (mail.netbsd.org [204.152.190.11])
	by narn.NetBSD.org (Postfix) with ESMTP id E938863B8C2
	for <gnats-bugs@gnats.NetBSD.org>; Sat, 29 Sep 2007 10:10:02 +0000 (UTC)
Message-Id: <20070929101000.EB8CC67F9B@stix.id.au>
Date: Sat, 29 Sep 2007 20:10:00 +1000 (EST)
From: Paul@stix.id.au, Ripke@stix.id.au
Reply-To: stix@stix.id.au
To: gnats-bugs@NetBSD.org
Subject: ipnat: Data modified on freelist
X-Send-Pr-Version: 3.95

>Number:         37037
>Category:       kern
>Synopsis:       ipnat: Data modified on freelist
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    kern-bug-people
>State:          closed
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Sep 29 10:15:00 +0000 2007
>Closed-Date:    Sun Oct 14 00:51:15 +0000 2007
>Last-Modified:  Tue Nov 13 01:30:01 +0000 2007
>Originator:     Paul Ripke
>Release:        NetBSD 4.0_RC1
>Organization:
>Environment:
System: NetBSD zion.stix.org.au 4.0_RC1 NetBSD 4.0_RC1 (ZION) #1: Fri Sep 28 09:46:22 EST 2007 stix@hex.stix.org.au:/l/netbsd/netbsd-4/obj.i386/l/netbsd/netbsd-4/src/sys/arch/i386/compile/ZION i386

CVS update as of around 2007/09/28
$NetBSD: ip_state.c,v 1.15.2.8 2007/09/27 14:01:10 xtraeme Exp $

Architecture: i386
Machine: i386
>Description:

"ipnat -l" causing:
Sep 29 19:17:03 zion sudo:     stix : TTY=ttyp2 ; PWD=/export/home/stix ; USER=root ; COMMAND=/usr/sbin/ipnat -l
Sep 29 19:17:13 zion /netbsd: Data modified on freelist: word 3 of object 0xc1df2080 size 36 previous type bar (0xc1e0f200 != 0xdeadbeef)
Sep 29 19:17:43 zion /netbsd: Data modified on freelist: word 3 of object 0xc1dbfdc0 size 36 previous type bar (0xc1f51e00 != 0xdeadbeef)

Possibly due to RDR sessions not expiring:

ksh$ sudo ipnat -l | grep RDR | wc -l
    2168
ksh$ sudo ./ipnat -s
mapped  in      77822   out     125346
added   3125    expired 944
no memory       0       bad nat 224
inuse   2181
rules   4
wilds   0
table 0xbfbfe95c list 0xc1e0f800
TCP Entries per state
     0     1     2     3     4     5     6     7     8     9    10    11
     0     0     0     0  2179     0     0     0     0     0     0     0

>How-To-Repeat:

/etc/ipnat.conf:

map pppoe0 192.168.0.0/16 -> 0/32 portmap tcp/udp 49152:65535 mssclamp 1440
map pppoe0 192.168.0.0/16 -> 0/32 mssclamp 1440
rdr ath0 0.0.0.0/0 port 80 -> 127.0.0.1 port 3128 tcp
rdr sk0  0.0.0.0/0 port 80 -> 127.0.0.1 port 3128 tcp

>Fix:
Unknown.

>Release-Note:

>Audit-Trail:
From: Michael van Elst <mlelstv@serpens.de>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/37037: ipnat: Data modified on freelist
Date: Sat, 29 Sep 2007 13:14:00 +0200

 One more data point:

 the same also occurs on a NetBSD 4.0_RC1 kernel built on Sep 1.

 -- 
                                 Michael van Elst
 Internet: mlelstv@serpens.de
                                 "A potential Snark may lurk in every tree."

From: Darren Reed <darrenr@netbsd.org>
To: gnats-bugs@netbsd.org
Cc: 
Subject: Re: kern/37037
Date: Sat, 29 Sep 2007 05:30:20 -0700

 In 4.0RC1, the code is:
 5057:                case IPFGENITER_NAT :
 5058:                        if (nextnat != NULL) {
 5059:                                if (nextnat->nat_next == NULL) {
 5060:                                        count = 1;
 5061:                                        freet = t;
 5062:                                        nat = NULL;
 5063:                                }
 5064:                                if (count == 1) {
 5065:                                      
  MUTEX_ENTER(&nextnat->nat_lock);
 5066:                                        nextnat->nat_ref++;
 5067:                                      
  MUTEX_EXIT(&nextnat->nat_lock);
 5068:                                }
 5069:                        } else {
 5070:                                bzero(&zeronat, sizeof(zeronat));
 5071:                                nextnat = &zeronat;
 5072:                                count = 1;
 5073:                        }
 5074:                        break;
 5075:                default :
 5076:                        break;
 5077:                }
 5078:                RWLOCK_EXIT(&ipf_nat);
 5079:
 5080:                if (freet != NULL) {
 5081:                        ipf_freetoken(freet);
 5082:                        freet = NULL;
 5083:                }
 ...
 5112:                case IPFGENITER_NAT :
 5113:                        if (nat != NULL)
 5114:                                fr_natderef(&nat);
 5115:                        t->ipt_data = nextnat;
 5116:                        error = COPYOUT(nextnat, dst,
 sizeof(*nextnat));
 ...

 Sofor the case when nextnat->nat_next == NULL, count gets set to 1,
 freet is assigned the value of t, that structure is freed and then on 5115
 it is deref'd again (memory use after free.)

 Darren

From: Martti Kuparinen <martti.kuparinen@iki.fi>
To: gnats-bugs@netbsd.org
Cc: juan@xtrarom.org, darrenr@netbsd.org
Subject: Re: kern/37037
Date: Sat, 29 Sep 2007 21:37:22 +0300 (EEST)

 After some help from Darren, I created this patch? Does it help?

 Darren: does it look correct? I took 4.1.27 and added our local changes
 to it (caddr_t -> void * etc.)


 Index: ip_frag.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_frag.c,v
 retrieving revision 1.7
 diff -u -r1.7 ip_frag.c
 --- ip_frag.c	16 Jun 2007 10:52:28 -0000	1.7
 +++ ip_frag.c	29 Sep 2007 18:29:12 -0000
 @@ -106,7 +106,7 @@
   __KERNEL_RCSID(0, "$NetBSD: ip_frag.c,v 1.7 2007/06/16 10:52:28 martin Exp $");
   #else
   static const char sccsid[] = "@(#)ip_frag.c	1.11 3/24/96 (C) 1993-2000 Darren Reed";
 -static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77.2.9 2007/05/27 11:13:44 darrenr Exp";
 +static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $";
   #endif
   #endif

 @@ -943,16 +943,16 @@
   	} else {
   		bzero(&zero, sizeof(zero));
   		next = &zero;
 -		token->ipt_data = (void *)-1;
 +		token->ipt_data = NULL;
   	}
   	RWLOCK_EXIT(lock);

   	if (frag != NULL) {
 -		WRITE_ENTER(lock);
 -		frag->ipfr_ref--;
 -		if (frag->ipfr_ref <= 0)
 -			fr_fragfree(frag);
 -		RWLOCK_EXIT(lock);
 +#ifdef USE_MUTEXES
 +		fr_fragderef(&frag, lock);
 +#else
 +		fr_fragderef(&frag);
 +#endif
   	}

   	error = COPYOUT(next, itp->igi_data, sizeof(*next));
 Index: ip_state.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_state.c,v
 retrieving revision 1.29
 diff -u -r1.29 ip_state.c
 --- ip_state.c	17 Sep 2007 06:56:15 -0000	1.29
 +++ ip_state.c	29 Sep 2007 18:29:15 -0000
 @@ -117,7 +117,7 @@
   __KERNEL_RCSID(0, "$NetBSD: ip_state.c,v 1.29 2007/09/17 06:56:15 martti Exp $");
   #else
   static const char sccsid[] = "@(#)ip_state.c	1.8 6/5/96 (C) 1993-2000 Darren Reed";
 -static const char rcsid[] = "@(#)Id: ip_state.c,v 2.186.2.69 2007/05/26 13:05:14 darrenr Exp";
 +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.78 2007/09/20 12:51:53 darrenr Exp $";
   #endif
   #endif

 @@ -657,8 +657,8 @@
   	int error;

   	error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
 -	if (error)
 -		return EFAULT;
 +	if (error != 0)
 +		return error;

   	isn = ips.ips_next;
   	if (isn == NULL) {
 @@ -687,9 +687,7 @@
   		bcopy((char *)isn->is_rule, (char *)&ips.ips_fr,
   		      sizeof(ips.ips_fr));
   	error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
 -	if (error)
 -		return EFAULT;
 -	return 0;
 +	return error;
   }


 @@ -1444,7 +1442,7 @@
   			is->is_state[!source] = IPF_TCPS_CLOSED;
   			fr_movequeue(&is->is_sti, is->is_sti.tqe_ifq,
   				     &ips_deletetq);
 -			MUTEX_ENTER(&is->is_lock);
 +			MUTEX_EXIT(&is->is_lock);
   			return 0;
   		}
   	}
 @@ -2308,8 +2306,6 @@
   	ipstate_t **isp;
   	u_int hvm;

 -	ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
 -
   	hvm = is->is_hv;
   	/*
   	 * Remove the hash from the old location...
 @@ -2897,8 +2893,6 @@
   int why;
   {

 -	ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
 -
   	/*
   	 * Since we want to delete this, remove it from the state table,
   	 * where it can be found & used, first.
 @@ -4072,7 +4066,7 @@
   	if (itp->igi_data == NULL)
   		return EFAULT;

 -	if (itp->igi_nitems == 0)
 +	if (itp->igi_nitems < 1)
   		return ENOSPC;

   	if (itp->igi_type != IPFGENITER_STATE)
 @@ -4094,33 +4088,29 @@
   		next = is->is_next;
   	}

 -	for (count = itp->igi_nitems; count > 0; count--) {
 +	count = itp->igi_nitems;
 +	for (;;) {
   		if (next != NULL) {
   			/*
   			 * If we find a state entry to use, bump its
   			 * reference count so that it can be used for
   			 * is_next when we come back.
   			 */
 -			MUTEX_ENTER(&next->is_lock);
 -			next->is_ref++;
 -			MUTEX_EXIT(&next->is_lock);
 -			token->ipt_data = next;
 +			if (count == 1) {
 +				MUTEX_ENTER(&next->is_lock);
 +				next->is_ref++;
 +				MUTEX_EXIT(&next->is_lock);
 +				token->ipt_data = next;
 +			}
   		} else {
   			bzero(&zero, sizeof(zero));
   			next = &zero;
 -			token->ipt_data = (void *)-1;
   			count = 1;
 +			token->ipt_data = NULL;
   		}
   		RWLOCK_EXIT(&ipf_state);

   		/*
 -		 * If we had a prior pointer to a state entry, release it.
 -		 */
 -		if (is != NULL) {
 -			fr_statederef(&is);
 -		}
 -
 -		/*
   		 * This should arguably be via fr_outobj() so that the state
   		 * structure can (if required) be massaged going out.
   		 */
 @@ -4131,9 +4121,14 @@
   			break;

   		dst += sizeof(*next);
 +		count--;
 +
   		READ_ENTER(&ipf_state);
 -		is = next;
 -		next = is->is_next;
 +		next = next->is_next;
 +	}
 +
 +	if (is != NULL) {
 +		fr_statederef(&is);
   	}

   	return error;

From: Darren Reed <darrenr@netbsd.org>
To: Martti Kuparinen <martti.kuparinen@iki.fi>
Cc: gnats-bugs@netbsd.org, juan@xtrarom.org
Subject: Re: kern/37037
Date: Sat, 29 Sep 2007 13:51:07 -0700

 Martti Kuparinen wrote:
 > After some help from Darren, I created this patch? Does it help?

 You did not include the changes to ip_nat.c in this, which are vital.

 > Darren: does it look correct? I took 4.1.27 and added our local changes
 > to it (caddr_t -> void * etc.)

 What is there looks correct.

 Darren

From: Martti Kuparinen <martti.kuparinen@iki.fi>
To: darrenr@netbsd.org
Cc: gnats-bugs@netbsd.org, juan@xtrarom.org
Subject: Re: kern/37037
Date: Sun, 30 Sep 2007 10:03:02 +0300

 Darren Reed wrote:

 > You did not include the changes to ip_nat.c in this, which are vital.

 Oh, you didn't tell me that this file is also needed (you told me only
 about ip_state.c and ip_frag.c). This new ip_nat.c needs the new
 ip_fil.h and I'm losing the track here with all these changes.

 Could you please provide a patch which contains only the required changes?

 Martti

From: Martti Kuparinen <martti.kuparinen@iki.fi>
To: Darren Reed <darrenr@netbsd.org>
Cc: gnats-bugs@netbsd.org, juan@xtrarom.org
Subject: Re: kern/37037
Date: Sun, 30 Sep 2007 10:15:28 +0300 (EEST)

 Could you please try this patch (also at http://users.piuha.net/martti/tmp/p)

 Martti



 Index: ip_fil.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_fil.h,v
 retrieving revision 1.14
 diff -u -r1.14 ip_fil.h
 --- ip_fil.h	19 Jul 2007 14:04:34 -0000	1.14
 +++ ip_fil.h	30 Sep 2007 07:10:15 -0000
 @@ -184,14 +184,14 @@
   			      HI63(a) < HI63(b)))))))
   #define	NLADD(n,x)	htonl(ntohl(n) + (x))
   #define	IP6_INC(a)	\
 -		{ i6addr_t *_i6 = (i6addr_t *)(a); \
 -		  _i6->i6[0] = NLADD(_i6->i6[0], 1); \
 -		  if (_i6->i6[0] == 0) { \
 -			_i6->i6[0] = NLADD(_i6->i6[1], 1); \
 -			if (_i6->i6[1] == 0) { \
 -				_i6->i6[0] = NLADD(_i6->i6[2], 1); \
 -				if (_i6->i6[2] == 0) { \
 -					_i6->i6[0] = NLADD(_i6->i6[3], 1); \
 +		{ u_32_t *_i6 = (u_32_t *)(a); \
 +		  _i6[3] = NLADD(_i6[3], 1); \
 +		  if (_i6[3] == 0) { \
 +			_i6[2] = NLADD(_i6[2], 1); \
 +			if (_i6[2] == 0) { \
 +				_i6[1] = NLADD(_i6[1], 1); \
 +				if (_i6[1] == 0) { \
 +					_i6[0] = NLADD(_i6[0], 1); \
   				} \
   			} \
   		  } \
 @@ -270,6 +270,7 @@
   #define	FI_WITH		0xeffe	/* Not FI_TCPUDP */
   #define	FI_V6EXTHDR	0x10000
   #define	FI_COALESCE	0x20000
 +#define	FI_NEWNAT	0x40000
   #define	FI_NOCKSUM	0x20000000	/* don't do a L4 checksum validation */
   #define	FI_DONTCACHE	0x40000000	/* don't cache the result */
   #define	FI_IGNORE	0x80000000
 @@ -329,6 +330,7 @@
   	u_short	fin_off;
   	int	fin_depth;		/* Group nesting depth */
   	int	fin_error;		/* Error code to return */
 +	int	fin_cksum;		/* -1 bad, 1 good, 0 not done */
   	void	*fin_nat;
   	void	*fin_state;
   	void	*fin_nattag;
 @@ -1203,6 +1205,8 @@
   } ipftable_t;

   #define	IPFTABLE_BUCKETS	1
 +#define	IPFTABLE_BUCKETS_NATIN	2
 +#define	IPFTABLE_BUCKETS_NATOUT	3


   /*
 @@ -1402,6 +1406,13 @@
   #  endif /* __ sgi */
   # endif /* MENTAT */

 +# if defined(__FreeBSD_version)
 +extern	int	ipf_pfil_hook __P((void));
 +extern	int	ipf_pfil_unhook __P((void));
 +extern	void	ipf_event_reg __P((void));
 +extern	void	ipf_event_dereg __P((void));
 +# endif
 +
   #endif /* #ifndef _KERNEL */

   extern	ipfmutex_t	ipl_mutex, ipf_authmx, ipf_rw, ipf_hostmap;
 Index: ip_frag.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_frag.c,v
 retrieving revision 1.7
 diff -u -r1.7 ip_frag.c
 --- ip_frag.c	16 Jun 2007 10:52:28 -0000	1.7
 +++ ip_frag.c	30 Sep 2007 07:10:15 -0000
 @@ -106,7 +106,7 @@
   __KERNEL_RCSID(0, "$NetBSD: ip_frag.c,v 1.7 2007/06/16 10:52:28 martin Exp $");
   #else
   static const char sccsid[] = "@(#)ip_frag.c	1.11 3/24/96 (C) 1993-2000 Darren Reed";
 -static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77.2.9 2007/05/27 11:13:44 darrenr Exp";
 +static const char rcsid[] = "@(#)Id: ip_frag.c,v 2.77.2.12 2007/09/20 12:51:51 darrenr Exp $";
   #endif
   #endif

 @@ -943,16 +943,16 @@
   	} else {
   		bzero(&zero, sizeof(zero));
   		next = &zero;
 -		token->ipt_data = (void *)-1;
 +		token->ipt_data = NULL;
   	}
   	RWLOCK_EXIT(lock);

   	if (frag != NULL) {
 -		WRITE_ENTER(lock);
 -		frag->ipfr_ref--;
 -		if (frag->ipfr_ref <= 0)
 -			fr_fragfree(frag);
 -		RWLOCK_EXIT(lock);
 +#ifdef USE_MUTEXES
 +		fr_fragderef(&frag, lock);
 +#else
 +		fr_fragderef(&frag);
 +#endif
   	}

   	error = COPYOUT(next, itp->igi_data, sizeof(*next));
 Index: ip_nat.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_nat.c,v
 retrieving revision 1.32
 diff -u -r1.32 ip_nat.c
 --- ip_nat.c	14 Sep 2007 11:28:45 -0000	1.32
 +++ ip_nat.c	30 Sep 2007 07:10:19 -0000
 @@ -1,4 +1,4 @@
 -/*	$NetBSD: ip_nat.c,v 1.32 2007/09/14 11:28:45 martti Exp $	*/
 +/*	$NetBSD: ip_nat.c,v 1.1.1.9 2007/06/16 10:33:21 martin Exp $	*/

   /*
    * Copyright (C) 1995-2003 by Darren Reed.
 @@ -16,12 +16,13 @@
   #include <sys/param.h>
   #include <sys/time.h>
   #include <sys/file.h>
 -#if (__NetBSD_Version__ >= 399002000) && defined(_KERNEL)
 +#if defined(_KERNEL) && defined(__NetBSD_Version__) && \
 +    (__NetBSD_Version__ >= 399002000)
   # include <sys/kauth.h>
   #endif
   #if defined(__NetBSD__) && (NetBSD >= 199905) && !defined(IPFILTER_LKM) && \
       defined(_KERNEL)
 -# if (__NetBSD_Version__ < 399001400)
 +#if defined(__NetBSD_Version__) && (__NetBSD_Version__ < 399001400)
   #  include "opt_ipfilter_log.h"
   # else
   #  include "opt_ipfilter.h"
 @@ -116,7 +117,7 @@

   #if !defined(lint)
   static const char sccsid[] = "@(#)ip_nat.c	1.11 6/5/96 (C) 1995 Darren Reed";
 -static const char rcsid[] = "@(#)Id: ip_nat.c,v 2.195.2.87 2007/05/31 10:17:17 darrenr Exp";
 +static const char rcsid[] = "@(#)$Id: ip_nat.c,v 2.195.2.100 2007/09/25 08:27:31 darrenr Exp $";
   #endif


 @@ -177,7 +178,7 @@
   natstat_t nat_stats;
   int	fr_nat_lock = 0;
   int	fr_nat_init = 0;
 -#if SOLARIS
 +#if SOLARIS && !defined(_INET_IP_STACK_H)
   extern	int		pfil_delayed_copy;
   #endif

 @@ -186,13 +187,13 @@
   static	int	nat_clearlist __P((void));
   static	void	nat_addnat __P((struct ipnat *));
   static	void	nat_addrdr __P((struct ipnat *));
 -static	void	nat_delete __P((struct nat *, int));
   static	void	nat_delrdr __P((struct ipnat *));
   static	void	nat_delnat __P((struct ipnat *));
   static	int	fr_natgetent __P((caddr_t));
   static	int	fr_natgetsz __P((caddr_t));
   static	int	fr_natputent __P((caddr_t, int));
   static	int	nat_extraflush __P((int));
 +static	int	nat_gettable __P((char *));
   static	void	nat_tabmove __P((nat_t *));
   static	int	nat_match __P((fr_info_t *, ipnat_t *));
   static	INLINE	int nat_newmap __P((fr_info_t *, nat_t *, natinfo_t *));
 @@ -652,7 +653,7 @@
   	SPL_INT(s);

   #if (BSD >= 199306) && defined(_KERNEL)
 -# if (__NetBSD_Version__ >= 399002000)
 +# if defined(__NetBSD_Version__) && (__NetBSD_Version__ >= 399002000)
   	if ((mode & FWRITE) &&
   	     kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_FIREWALL,
   				     KAUTH_REQ_NETWORK_FIREWALL_FW,
 @@ -943,6 +944,10 @@
   		error = fr_outobj(data, nat_tqb, IPFOBJ_STATETQTAB);
   		break;

 +	case SIOCGTABL :
 +		error = nat_gettable(data);
 +		break;
 +
   	default :
   		error = EINVAL;
   		break;
 @@ -1080,7 +1085,7 @@

   	n = NULL;
   	nat_stats.ns_rules++;
 -#if SOLARIS
 +#if SOLARIS && !defined(_INET_IP_STACK_H)
   	pfil_delayed_copy = 0;
   #endif
   	if (getlock) {
 @@ -1168,9 +1173,10 @@
   	if (n->in_use == 0) {
   		if (n->in_apr)
   			appr_free(n->in_apr);
 +		MUTEX_DESTROY(&n->in_lock);
   		KFREE(n);
   		nat_stats.ns_rules--;
 -#if SOLARIS
 +#if SOLARIS && !defined(_INET_IP_STACK_H)
   		if (nat_stats.ns_rules == 0)
   			pfil_delayed_copy = 1;
   #endif
 @@ -1660,11 +1666,12 @@
   /* Delete a nat entry from the various lists and table.  If NAT logging is  */
   /* enabled then generate a NAT log record for this event.                   */
   /* ------------------------------------------------------------------------ */
 -static void nat_delete(nat, logtype)
 +void nat_delete(nat, logtype)
   struct nat *nat;
   int logtype;
   {
   	struct ipnat *ipn;
 +	int removed = 0;

   	if (logtype != 0 && nat_logging != 0)
   		nat_log(nat, logtype);
 @@ -1674,6 +1681,8 @@
   	 * nat_pnext is set.
   	 */
   	if (nat->nat_pnext != NULL) {
 +		removed = 1;
 +
   		nat_stats.ns_bucketlen[0][nat->nat_hv[0]]--;
   		nat_stats.ns_bucketlen[1][nat->nat_hv[1]]--;

 @@ -1714,9 +1723,24 @@
   		nat_stats.ns_expire++;

   	MUTEX_ENTER(&nat->nat_lock);
 -	if (nat->nat_ref > 1) {
 +	/*
 +	 * NL_DESTROY should only be passed in when we've got nat_ref >= 2.
 +	 * This happens when a nat'd packet is blocked and we want to throw
 +	 * away the NAT session.
 +	 */
 +	if (logtype == NL_DESTROY) {
 +		if (nat->nat_ref > 2) {
 +			nat->nat_ref -= 2;
 +			MUTEX_EXIT(&nat->nat_lock);
 +			if (removed)
 +				nat_stats.ns_orphans++;
 +			return;
 +		}
 +	} else if (nat->nat_ref > 1) {
   		nat->nat_ref--;
   		MUTEX_EXIT(&nat->nat_lock);
 +		if (removed)
 +			nat_stats.ns_orphans++;
   		return;
   	}
   	MUTEX_EXIT(&nat->nat_lock);
 @@ -1725,6 +1749,8 @@
   	 * At this point, nat_ref is 1, doing "--" would make it 0..
   	 */
   	nat->nat_ref = 0;
 +	if (!removed)
 +		nat_stats.ns_orphans--;

   #ifdef	IPFILTER_SYNC
   	if (nat->nat_sync)
 @@ -1824,6 +1850,7 @@
   		if (n->in_use == 0) {
   			if (n->in_apr != NULL)
   				appr_free(n->in_apr);
 +			MUTEX_DESTROY(&n->in_lock);
   			KFREE(n);
   			nat_stats.ns_rules--;
   		} else {
 @@ -1832,7 +1859,7 @@
   		}
   		i++;
   	}
 -#if SOLARIS
 +#if SOLARIS && !defined(_INET_IP_STACK_H)
   	pfil_delayed_copy = 1;
   #endif
   	nat_masks = 0;
 @@ -2498,10 +2525,12 @@
   	}

   	if (nat_finalise(fin, nat, &ni, tcp, natsave, direction) == -1) {
 +		fr_nat_doflush = 1;
   		goto badnat;
   	}
   	if (flags & SI_WILDP)
   		nat_stats.ns_wilds++;
 +	fin->fin_flx |= FI_NEWNAT;
   	goto done;
   badnat:
   	nat_stats.ns_badnat++;
 @@ -3011,10 +3040,22 @@
   			}

   			if (sumd2 != 0) {
 +				ipnat_t *np;
 +
 +				np = nat->nat_ptr;
   				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
   				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
   				sumd2 = (sumd2 & 0xffff) + (sumd2 >> 16);
 -				fix_incksum(fin, &icmp->icmp_cksum, sumd2);
 +
 +				if ((odst == 0) && (dir == NAT_OUTBOUND) &&
 +				    (fin->fin_rev == 0) && (np != NULL) &&
 +				    (np->in_redir & NAT_REDIRECT)) {
 +					fix_outcksum(fin, &icmp->icmp_cksum,
 +						     sumd2);
 +				} else {
 +					fix_incksum(fin, &icmp->icmp_cksum,
 +						    sumd2);
 +				}
   			}
   		}
   	} else if (((flags & IPN_ICMPQUERY) != 0) && (dlen >= 8)) {
 @@ -4684,9 +4725,10 @@
   	if (in->in_use == 0 && (in->in_flags & IPN_DELETE)) {
   		if (in->in_apr)
   			appr_free(in->in_apr);
 +		MUTEX_DESTROY(&in->in_lock);
   		KFREE(in);
   		nat_stats.ns_rules--;
 -#if SOLARIS
 +#if SOLARIS && !defined(_INET_IP_STACK_H)
   		if (nat_stats.ns_rules == 0)
   			pfil_delayed_copy = 1;
   #endif
 @@ -5013,10 +5055,11 @@
   	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
   	nat_t *nat, *nextnat = NULL, zeronat;
   	int error = 0, count;
 -	ipftoken_t *freet;
   	char *dst;

 -	freet = NULL;
 +	count = itp->igi_nitems;
 +	if (count < 1)
 +		return ENOSPC;

   	READ_ENTER(&ipf_nat);

 @@ -5054,61 +5097,52 @@
   	}

   	dst = itp->igi_data;
 -	for (count = itp->igi_nitems; count > 0; count--) {
 +	for (;;) {
   		switch (itp->igi_type)
   		{
   		case IPFGENITER_HOSTMAP :
   			if (nexthm != NULL) {
 -				if (nexthm->hm_next == NULL) {
 -					freet = t;
 -					count = 1;
 -					hm = NULL;
 -				}
   				if (count == 1) {
   					ATOMIC_INC32(nexthm->hm_ref);
 +					t->ipt_data = nexthm;
   				}
   			} else {
   				bzero(&zerohm, sizeof(zerohm));
   				nexthm = &zerohm;
   				count = 1;
 +				t->ipt_data = NULL;
   			}
   			break;

   		case IPFGENITER_IPNAT :
   			if (nextipnat != NULL) {
 -				if (nextipnat->in_next == NULL) {
 -					freet = t;
 -					count = 1;
 -					ipn = NULL;
 -				}
   				if (count == 1) {
   					MUTEX_ENTER(&nextipnat->in_lock);
   					nextipnat->in_use++;
   					MUTEX_EXIT(&nextipnat->in_lock);
 +					t->ipt_data = nextipnat;
   				}
   			} else {
   				bzero(&zeroipn, sizeof(zeroipn));
   				nextipnat = &zeroipn;
   				count = 1;
 +				t->ipt_data = NULL;
   			}
   			break;

   		case IPFGENITER_NAT :
   			if (nextnat != NULL) {
 -				if (nextnat->nat_next == NULL) {
 -					count = 1;
 -					freet = t;
 -					nat = NULL;
 -				}
   				if (count == 1) {
   					MUTEX_ENTER(&nextnat->nat_lock);
   					nextnat->nat_ref++;
   					MUTEX_EXIT(&nextnat->nat_lock);
 +					t->ipt_data = nextnat;
   				}
   			} else {
   				bzero(&zeronat, sizeof(zeronat));
   				nextnat = &zeronat;
   				count = 1;
 +				t->ipt_data = NULL;
   			}
   			break;
   		default :
 @@ -5116,20 +5150,12 @@
   		}
   		RWLOCK_EXIT(&ipf_nat);

 -		if (freet != NULL) {
 -			ipf_freetoken(freet);
 -			freet = NULL;
 -		}
 -
 +		/*
 +		 * Copying out to user space needs to be done without the lock.
 +		 */
   		switch (itp->igi_type)
   		{
   		case IPFGENITER_HOSTMAP :
 -			if (hm != NULL) {
 -				WRITE_ENTER(&ipf_nat);
 -				fr_hostmapdel(&hm);
 -				RWLOCK_EXIT(&ipf_nat);
 -			}
 -			t->ipt_data = nexthm;
   			error = COPYOUT(nexthm, dst, sizeof(*nexthm));
   			if (error != 0)
   				error = EFAULT;
 @@ -5138,9 +5164,6 @@
   			break;

   		case IPFGENITER_IPNAT :
 -			if (ipn != NULL)
 -				fr_ipnatderef(&ipn);
 -			t->ipt_data = nextipnat;
   			error = COPYOUT(nextipnat, dst, sizeof(*nextipnat));
   			if (error != 0)
   				error = EFAULT;
 @@ -5149,9 +5172,6 @@
   			break;

   		case IPFGENITER_NAT :
 -			if (nat != NULL)
 -				fr_natderef(&nat);
 -			t->ipt_data = nextnat;
   			error = COPYOUT(nextnat, dst, sizeof(*nextnat));
   			if (error != 0)
   				error = EFAULT;
 @@ -5163,29 +5183,52 @@
   		if ((count == 1) || (error != 0))
   			break;

 +		count--;
 +
   		READ_ENTER(&ipf_nat);

 +		/*
 +		 * We need to have the lock again here to make sure that
 +		 * using _next is consistent.
 +		 */
   		switch (itp->igi_type)
   		{
   		case IPFGENITER_HOSTMAP :
 -			hm = nexthm;
 -			nexthm = hm->hm_next;
 +			nexthm = nexthm->hm_next;
   			break;
 -
   		case IPFGENITER_IPNAT :
 -			ipn = nextipnat;
 -			nextipnat = ipn->in_next;
 +			nextipnat = nextipnat->in_next;
   			break;
 -
   		case IPFGENITER_NAT :
 -			nat = nextnat;
 -			nextnat = nat->nat_next;
 -			break;
 -		default :
 +			nextnat = nextnat->nat_next;
   			break;
   		}
   	}

 +
 +	switch (itp->igi_type)
 +	{
 +	case IPFGENITER_HOSTMAP :
 +		if (hm != NULL) {
 +			WRITE_ENTER(&ipf_nat);
 +			fr_hostmapdel(&hm);
 +			RWLOCK_EXIT(&ipf_nat);
 +		}
 +		break;
 +	case IPFGENITER_IPNAT :
 +		if (ipn != NULL) {
 +			fr_ipnatderef(&ipn);
 +		}
 +		break;
 +	case IPFGENITER_NAT :
 +		if (nat != NULL) {
 +			fr_natderef(&nat);
 +		}
 +		break;
 +	default :
 +		break;
 +	}
 +
   	return error;
   }

 @@ -5394,3 +5437,44 @@
   	nat_delete(entry, NL_FLUSH);
   	return 0;
   }
 +
 +
 +/* ------------------------------------------------------------------------ */
 +/* Function:    nat_gettable                                                */
 +/* Returns:     int     - 0 = success, else error                           */
 +/* Parameters:  data(I) - pointer to ioctl data                             */
 +/*                                                                          */
 +/* This function handles ioctl requests for tables of nat information.      */
 +/* At present the only table it deals with is the hash bucket statistics.   */
 +/* ------------------------------------------------------------------------ */
 +static int nat_gettable(data)
 +char *data;
 +{
 +	ipftable_t table;
 +	int error;
 +
 +	error = fr_inobj(data, &table, IPFOBJ_GTABLE);
 +	if (error != 0)
 +		return error;
 +
 +	switch (table.ita_type)
 +	{
 +	case IPFTABLE_BUCKETS_NATIN :
 +		error = COPYOUT(nat_stats.ns_bucketlen[0], table.ita_table, 
 +				ipf_nattable_sz * sizeof(u_long));
 +		break;
 +
 +	case IPFTABLE_BUCKETS_NATOUT :
 +		error = COPYOUT(nat_stats.ns_bucketlen[1], table.ita_table, 
 +				ipf_nattable_sz * sizeof(u_long));
 +		break;
 +
 +	default :
 +		return EINVAL;
 +	}
 +
 +	if (error != 0) {
 +		error = EFAULT;
 +	}
 +	return error;
 +}
 Index: ip_nat.h
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_nat.h,v
 retrieving revision 1.12
 diff -u -r1.12 ip_nat.h
 --- ip_nat.h	14 Sep 2007 11:28:46 -0000	1.12
 +++ ip_nat.h	30 Sep 2007 07:10:19 -0000
 @@ -6,7 +6,7 @@
    * See the IPFILTER.LICENCE file for details on licencing.
    *
    * @(#)ip_nat.h	1.5 2/4/96
 - * Id: ip_nat.h,v 2.90.2.17 2007/05/11 10:19:11 darrenr Exp
 + * $Id: ip_nat.h,v 2.90.2.20 2007/09/25 08:27:32 darrenr Exp $
    */

   #ifndef	__IP_NAT_H__
 @@ -363,6 +363,7 @@
   	hostmap_t *ns_maplist;
   	u_long	*ns_bucketlen[2];
   	u_long	ns_ticks;
 +	u_int	ns_orphans;
   } natstat_t;

   typedef	struct	natlog {
 @@ -384,6 +385,7 @@
   #define	NL_NEWRDR	NAT_REDIRECT
   #define	NL_NEWBIMAP	NAT_BIMAP
   #define	NL_NEWBLOCK	NAT_MAPBLK
 +#define	NL_DESTROY	0xfffc
   #define	NL_CLONE	0xfffd
   #define	NL_FLUSH	0xfffe
   #define	NL_EXPIRE	0xffff
 @@ -447,6 +449,7 @@
   extern	nat_t	*nat_lookupredir __P((natlookup_t *));
   extern	nat_t	*nat_icmperrorlookup __P((fr_info_t *, int));
   extern	nat_t	*nat_icmperror __P((fr_info_t *, u_int *, int));
 +extern	void	nat_delete __P((struct nat *, int));
   extern	int	nat_insert __P((nat_t *, int));

   extern	int	fr_checknatout __P((fr_info_t *, u_32_t *));
 Index: ip_state.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_state.c,v
 retrieving revision 1.29
 diff -u -r1.29 ip_state.c
 --- ip_state.c	17 Sep 2007 06:56:15 -0000	1.29
 +++ ip_state.c	30 Sep 2007 07:10:21 -0000
 @@ -117,7 +117,7 @@
   __KERNEL_RCSID(0, "$NetBSD: ip_state.c,v 1.29 2007/09/17 06:56:15 martti Exp $");
   #else
   static const char sccsid[] = "@(#)ip_state.c	1.8 6/5/96 (C) 1993-2000 Darren Reed";
 -static const char rcsid[] = "@(#)Id: ip_state.c,v 2.186.2.69 2007/05/26 13:05:14 darrenr Exp";
 +static const char rcsid[] = "@(#)$Id: ip_state.c,v 2.186.2.78 2007/09/20 12:51:53 darrenr Exp $";
   #endif
   #endif

 @@ -657,8 +657,8 @@
   	int error;

   	error = fr_inobj(data, &ips, IPFOBJ_STATESAVE);
 -	if (error)
 -		return EFAULT;
 +	if (error != 0)
 +		return error;

   	isn = ips.ips_next;
   	if (isn == NULL) {
 @@ -687,9 +687,7 @@
   		bcopy((char *)isn->is_rule, (char *)&ips.ips_fr,
   		      sizeof(ips.ips_fr));
   	error = fr_outobj(data, &ips, IPFOBJ_STATESAVE);
 -	if (error)
 -		return EFAULT;
 -	return 0;
 +	return error;
   }


 @@ -1444,7 +1442,7 @@
   			is->is_state[!source] = IPF_TCPS_CLOSED;
   			fr_movequeue(&is->is_sti, is->is_sti.tqe_ifq,
   				     &ips_deletetq);
 -			MUTEX_ENTER(&is->is_lock);
 +			MUTEX_EXIT(&is->is_lock);
   			return 0;
   		}
   	}
 @@ -2308,8 +2306,6 @@
   	ipstate_t **isp;
   	u_int hvm;

 -	ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
 -
   	hvm = is->is_hv;
   	/*
   	 * Remove the hash from the old location...
 @@ -2897,8 +2893,6 @@
   int why;
   {

 -	ASSERT(rw_read_locked(&ipf_state.ipf_lk) == 0);
 -
   	/*
   	 * Since we want to delete this, remove it from the state table,
   	 * where it can be found & used, first.
 @@ -4072,7 +4066,7 @@
   	if (itp->igi_data == NULL)
   		return EFAULT;

 -	if (itp->igi_nitems == 0)
 +	if (itp->igi_nitems < 1)
   		return ENOSPC;

   	if (itp->igi_type != IPFGENITER_STATE)
 @@ -4094,33 +4088,29 @@
   		next = is->is_next;
   	}

 -	for (count = itp->igi_nitems; count > 0; count--) {
 +	count = itp->igi_nitems;
 +	for (;;) {
   		if (next != NULL) {
   			/*
   			 * If we find a state entry to use, bump its
   			 * reference count so that it can be used for
   			 * is_next when we come back.
   			 */
 -			MUTEX_ENTER(&next->is_lock);
 -			next->is_ref++;
 -			MUTEX_EXIT(&next->is_lock);
 -			token->ipt_data = next;
 +			if (count == 1) {
 +				MUTEX_ENTER(&next->is_lock);
 +				next->is_ref++;
 +				MUTEX_EXIT(&next->is_lock);
 +				token->ipt_data = next;
 +			}
   		} else {
   			bzero(&zero, sizeof(zero));
   			next = &zero;
 -			token->ipt_data = (void *)-1;
   			count = 1;
 +			token->ipt_data = NULL;
   		}
   		RWLOCK_EXIT(&ipf_state);

   		/*
 -		 * If we had a prior pointer to a state entry, release it.
 -		 */
 -		if (is != NULL) {
 -			fr_statederef(&is);
 -		}
 -
 -		/*
   		 * This should arguably be via fr_outobj() so that the state
   		 * structure can (if required) be massaged going out.
   		 */
 @@ -4131,9 +4121,14 @@
   			break;

   		dst += sizeof(*next);
 +		count--;
 +
   		READ_ENTER(&ipf_state);
 -		is = next;
 -		next = is->is_next;
 +		next = next->is_next;
 +	}
 +
 +	if (is != NULL) {
 +		fr_statederef(&is);
   	}

   	return error;

From: Martti Kuparinen <martti.kuparinen@iki.fi>
To: gnats-bugs@NetBSD.org
Cc: kern-bug-people@NetBSD.org, gnats-admin@NetBSD.org,
	netbsd-bugs@NetBSD.org, stix@stix.id.au
Subject: Re: kern/37037
Date: Sun, 30 Sep 2007 19:01:07 +0300

 >  Could you please try this patch (also at http://users.piuha.net/martti/tmp/p)

 After compiling the kernel make sure you also build and install the
 userland:

 cd /usr/src/sys
 make includes
 cd /usr/src/usr.sbin/ipf
 make clean
 make
 make install

From: Paul Ripke <stix@stix.id.au>
To: Martti Kuparinen <martti.kuparinen@iki.fi>
Cc: Juan RP <juan@xtrarom.org>,
	Michael van Elst <mlelstv@serpens.de>, pavel@netbsd.org,
	Darren Reed <darrenr@netbsd.org>,
	NetBSD gnats-bugs <gnats-bugs@NetBSD.org>
Subject: Re: kern/37037
Date: Mon, 1 Oct 2007 22:30:07 +1000

 On Mon, Oct 01, 2007 at 08:43:43AM +0300, Martti Kuparinen wrote:
 > >Does this patch break userland compatibility? if that's the case, please
 > >fix it correctly.
 > 
 > Try the new patch: http://users.piuha.net/martti/tmp/nat2.diff
 > 
 > Changes: I did not add "fin_cksum" to the fr_info_t structure...

 Tested - I needed to install a new ipnat(8) (expected?), otherwise:
 # ipnat -l
 ioctl(SIOCGNATS): Invalid argument

 No longer get "Data modified on freelist", but I'm still waiting for
 any of the RDR sessions to age out. I'll check again in the morning.

 -- 
 Paul Ripke

From: Paul Ripke <stix@stix.id.au>
To: NetBSD gnats-bugs <gnats-bugs@NetBSD.org>
Cc: 
Subject: Re: kern/37037
Date: Wed, 3 Oct 2007 09:16:55 +1000

 For the benefit of the PR:

 ----- Forwarded message from Michael van Elst <mlelstv@serpens.de> -----
 On Tue, Oct 02, 2007 at 08:32:19AM +1000, Paul Ripke wrote:
 > FYI: the RDR sessions definitely are not expiring. Does this issue
 > deserve another send-pr?

 > The verbose state appears like:
 > 
 > RDR 127.0.0.1       3128  <- -> 209.85.197.147  80    [192.168.254.5 1418]
 >         ttl 863347 use 0 sumd 0xf3ff/0xf3ff pr 6 bkt 849/267 flags 1
 >         ifp X,X bytes 1495/639 pkts 6/5 ipsumd e817
 > RDR 127.0.0.1       3128  <- -> 63.245.209.21   80    [192.168.254.5 4654]
 >         ttl 785177 use 0 sumd 0x79de/0x79de pr 6 bkt 1874/996 flags 1
 >         ifp X,X bytes 891/900 pkts 6/5 ipsumd 6df6

 According to the TTL the session expires after 5 days (two ticks per
 second). Apparently the filter doesn't handle the end of the
 TCP session.

 -- 
                                 Michael van Elst
 Internet: mlelstv@serpens.de
                                 "A potential Snark may lurk in every tree."
 ----- End forwarded message -----
 --
 Paul Ripke

From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc: stix@stix.id.au, Michael van Elst <mlelstv@serpens.de>
Subject: Re: kern/37037: ipnat: Data modified on freelist
Date: Wed, 3 Oct 2007 12:03:11 +0200

 --5vNYLRcllDrimb99
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline

 Could you try if this patch alone fixes the write after free problem
 for you too? Restore the original RC2 userland binaries/headers and just
 try a kernel build with this patch (against RC2, without Martti's patch).

 It won't touch the tcp rdr timeouts, but that should be a different PR
 (and IMHO is not fixed in IPF 4.1.27, but maybe I overlooked something).

 Martin

 --5vNYLRcllDrimb99
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename=patch

 Index: ip_nat.c
 ===================================================================
 RCS file: /cvsroot/src/sys/dist/ipf/netinet/ip_nat.c,v
 retrieving revision 1.19.2.7
 diff -c -u -p -r1.19.2.7 ip_nat.c
 --- ip_nat.c	16 Sep 2007 15:46:48 -0000	1.19.2.7
 +++ ip_nat.c	3 Oct 2007 09:57:44 -0000
 @@ -5013,10 +5013,11 @@ ipfgeniter_t *itp;
  	ipnat_t *ipn, *nextipnat = NULL, zeroipn;
  	nat_t *nat, *nextnat = NULL, zeronat;
  	int error = 0, count;
 -	ipftoken_t *freet;
  	char *dst;

 -	freet = NULL;
 +	count = itp->igi_nitems;
 +	if (count < 1)
 +		return ENOSPC;

  	READ_ENTER(&ipf_nat);

 @@ -5054,61 +5055,52 @@ ipfgeniter_t *itp;
  	}

  	dst = itp->igi_data;
 -	for (count = itp->igi_nitems; count > 0; count--) {
 +	for (;;) {
  		switch (itp->igi_type)
  		{
  		case IPFGENITER_HOSTMAP :
  			if (nexthm != NULL) {
 -				if (nexthm->hm_next == NULL) {
 -					freet = t;
 -					count = 1;
 -					hm = NULL;
 -				}
  				if (count == 1) {
  					ATOMIC_INC32(nexthm->hm_ref);
 +					t->ipt_data = nexthm;
  				}
  			} else {
  				bzero(&zerohm, sizeof(zerohm));
  				nexthm = &zerohm;
  				count = 1;
 +				t->ipt_data = NULL;
  			}
  			break;

  		case IPFGENITER_IPNAT :
  			if (nextipnat != NULL) {
 -				if (nextipnat->in_next == NULL) {
 -					freet = t;
 -					count = 1;
 -					ipn = NULL;
 -				}
  				if (count == 1) {
  					MUTEX_ENTER(&nextipnat->in_lock);
  					nextipnat->in_use++;
  					MUTEX_EXIT(&nextipnat->in_lock);
 +					t->ipt_data = nextipnat;
  				}
  			} else {
  				bzero(&zeroipn, sizeof(zeroipn));
  				nextipnat = &zeroipn;
  				count = 1;
 +				t->ipt_data = NULL;
  			}
  			break;

  		case IPFGENITER_NAT :
  			if (nextnat != NULL) {
 -				if (nextnat->nat_next == NULL) {
 -					count = 1;
 -					freet = t;
 -					nat = NULL;
 -				}
  				if (count == 1) {
  					MUTEX_ENTER(&nextnat->nat_lock);
  					nextnat->nat_ref++;
  					MUTEX_EXIT(&nextnat->nat_lock);
 +					t->ipt_data = nextnat;
  				}
  			} else {
  				bzero(&zeronat, sizeof(zeronat));
  				nextnat = &zeronat;
  				count = 1;
 +				t->ipt_data = NULL;
  			}
  			break;
  		default :
 @@ -5116,20 +5108,12 @@ ipfgeniter_t *itp;
  		}
  		RWLOCK_EXIT(&ipf_nat);

 -		if (freet != NULL) {
 -			ipf_freetoken(freet);
 -			freet = NULL;
 -		}
 -
 +		/*
 +		 * Copying out to user space needs to be done without the lock.
 +		 */
  		switch (itp->igi_type)
  		{
  		case IPFGENITER_HOSTMAP :
 -			if (hm != NULL) {
 -				WRITE_ENTER(&ipf_nat);
 -				fr_hostmapdel(&hm);
 -				RWLOCK_EXIT(&ipf_nat);
 -			}
 -			t->ipt_data = nexthm;
  			error = COPYOUT(nexthm, dst, sizeof(*nexthm));
  			if (error != 0)
  				error = EFAULT;
 @@ -5138,9 +5122,6 @@ ipfgeniter_t *itp;
  			break;

  		case IPFGENITER_IPNAT :
 -			if (ipn != NULL)
 -				fr_ipnatderef(&ipn);
 -			t->ipt_data = nextipnat;
  			error = COPYOUT(nextipnat, dst, sizeof(*nextipnat));
  			if (error != 0)
  				error = EFAULT;
 @@ -5149,9 +5130,6 @@ ipfgeniter_t *itp;
  			break;

  		case IPFGENITER_NAT :
 -			if (nat != NULL)
 -				fr_natderef(&nat);
 -			t->ipt_data = nextnat;
  			error = COPYOUT(nextnat, dst, sizeof(*nextnat));
  			if (error != 0)
  				error = EFAULT;
 @@ -5163,29 +5141,52 @@ ipfgeniter_t *itp;
  		if ((count == 1) || (error != 0))
  			break;

 +		count--;
 +
  		READ_ENTER(&ipf_nat);

 +		/*
 +		 * We need to have the lock again here to make sure that
 +		 * using _next is consistent.
 +		 */
  		switch (itp->igi_type)
  		{
  		case IPFGENITER_HOSTMAP :
 -			hm = nexthm;
 -			nexthm = hm->hm_next;
 +			nexthm = nexthm->hm_next;
  			break;
 -
  		case IPFGENITER_IPNAT :
 -			ipn = nextipnat;
 -			nextipnat = ipn->in_next;
 +			nextipnat = nextipnat->in_next;
  			break;
 -
  		case IPFGENITER_NAT :
 -			nat = nextnat;
 -			nextnat = nat->nat_next;
 -			break;
 -		default :
 +			nextnat = nextnat->nat_next;
  			break;
  		}
  	}

 +
 +	switch (itp->igi_type)
 +	{
 +	case IPFGENITER_HOSTMAP :
 +		if (hm != NULL) {
 +			WRITE_ENTER(&ipf_nat);
 +			fr_hostmapdel(&hm);
 +			RWLOCK_EXIT(&ipf_nat);
 +		}
 +		break;
 +	case IPFGENITER_IPNAT :
 +		if (ipn != NULL) {
 +			fr_ipnatderef(&ipn);
 +		}
 +		break;
 +	case IPFGENITER_NAT :
 +		if (nat != NULL) {
 +			fr_natderef(&nat);
 +		}
 +		break;
 +	default :
 +		break;
 +	}
 +
  	return error;
  }


 --5vNYLRcllDrimb99--

From: Paul Ripke <stix@stix.id.au>
To: Martin Husemann <martin@duskware.de>
Cc: gnats-bugs@NetBSD.org, Michael van Elst <mlelstv@serpens.de>
Subject: Re: kern/37037: ipnat: Data modified on freelist
Date: Thu, 4 Oct 2007 00:40:29 +1000

 That patch appears to fix the write after free issue fine. Thanks!

 Should I raise another pr for the RDR TTL issue?

 -- 
 Paul Ripke

From: Juan Romero Pardines <xtraeme@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: PR/37037 CVS commit: [netbsd-4] src/sys/dist/ipf/netinet
Date: Fri, 12 Oct 2007 16:50:39 +0000 (UTC)

 Module Name:	src
 Committed By:	xtraeme
 Date:		Fri Oct 12 16:50:38 UTC 2007

 Modified Files:
 	src/sys/dist/ipf/netinet [netbsd-4]: ip_nat.c

 Log Message:
 Pullup following revision(s) (requested by martin in ticket #916):
 	sys/dist/ipf/netinet/ip_nat.c: patch

 Fix PR kern/37037 "ipnat: Data modified on freelist", verified by
 the submitter.


 To generate a diff of this commit:
 cvs rdiff -r1.19.2.7 -r1.19.2.8 src/sys/dist/ipf/netinet/ip_nat.c

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

State-Changed-From-To: open->closed
State-Changed-By: xtraeme@netbsd.org
State-Changed-When: Sun, 14 Oct 2007 00:51:15 +0000
State-Changed-Why:
Fix was applied yesterday, thanks.


From: Pavel Cahyna <pavel@netbsd.org>
To: gnats-bugs@NetBSD.org
Cc: 
Subject: PR/37037 CVS commit: [netbsd-4] src/sys/dist/ipf/netinet
Date: Sat, 27 Oct 2007 15:58:57 +0000 (UTC)

 Module Name:	src
 Committed By:	pavel
 Date:		Sat Oct 27 15:58:57 UTC 2007

 Modified Files:
 	src/sys/dist/ipf/netinet [netbsd-4]: ip_nat.c ip_nat.h ip_state.c
 	    ip_state.h

 Log Message:
 revert pullup #880. It reportedly causes RDR sessions to not expire and
 fill up the NAT table. See PR kern/37037 and possibly kern/37174.


 To generate a diff of this commit:
 cvs rdiff -r1.19.2.8 -r1.19.2.9 src/sys/dist/ipf/netinet/ip_nat.c
 cvs rdiff -r1.7.12.4 -r1.7.12.5 src/sys/dist/ipf/netinet/ip_nat.h
 cvs rdiff -r1.15.2.8 -r1.15.2.9 src/sys/dist/ipf/netinet/ip_state.c
 cvs rdiff -r1.5.12.4 -r1.5.12.5 src/sys/dist/ipf/netinet/ip_state.h

 Please note that diffs are not public domain; they are subject to the
 copyright notices on the relevant files.

From: Paul Ripke <stix@stix.id.au>
To: gnats-bugs@NetBSD.org
Cc: Darren Reed <darrenr@netbsd.org>,
	Martti Kuparinen <martti.kuparinen@iki.fi>,
	Juan RP <juan@xtrarom.org>, Michael van Elst <mlelstv@serpens.de>,
	Pavel Cahyna <pavel@netbsd.org>
Subject: Re: PR/37037 CVS commit: [netbsd-4] src/sys/dist/ipf/netinet
Date: Tue, 13 Nov 2007 12:28:37 +1100

 Confirmed (belatedly) it works fine in my environment. RDR sessions
 expire as they should, and I haven't seen any occurrences of
 "Data modified on freelist".

 -- 
 Paul Ripke

>Unformatted:

NetBSD Home
NetBSD PR Database Search

(Contact us) $NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2007 The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.