From: Martin Josefsson <gandalf@wlug.westbo.se>

You are correct. It was a list_del() that caused it (at least I think
so, it's 2am right now).

1. conntrack helper adds an expectation and adds that to a list hanging
of off a connection.

2. the expected connection arrives. the expectation is still on the
list.

3. the original connection that caused the expectation terminates but
the expectation still thinks it's added to the list.

4. the expected connection terminates and list_del() is called to remove
it from the list which doesn't exist anymore. boom!

(forwarded by akpm@digeo.com)


 net/ipv4/netfilter/ip_conntrack_core.c |    9 ++++++---
 1 files changed, 6 insertions(+), 3 deletions(-)

diff -puN net/ipv4/netfilter/ip_conntrack_core.c~conntrack-use-after-free-fix net/ipv4/netfilter/ip_conntrack_core.c
--- 25/net/ipv4/netfilter/ip_conntrack_core.c~conntrack-use-after-free-fix	2003-03-22 23:25:47.000000000 -0800
+++ 25-akpm/net/ipv4/netfilter/ip_conntrack_core.c	2003-03-22 23:25:47.000000000 -0800
@@ -274,6 +274,7 @@ static void remove_expectations(struct i
 		 * the un-established ones only */
 		if (exp->sibling) {
 			DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
+			exp->expectant = NULL;
 			continue;
 		}
 
@@ -327,9 +328,11 @@ destroy_conntrack(struct nf_conntrack *n
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Delete our master expectation */
 	if (ct->master) {
-		/* can't call __unexpect_related here,
-		 * since it would screw up expect_list */
-		list_del(&ct->master->expected_list);
+		if (ct->master->expectant) {
+			/* can't call __unexpect_related here,
+			 * since it would screw up expect_list */
+			list_del(&ct->master->expected_list);
+		}
 		kfree(ct->master);
 	}
 	WRITE_UNLOCK(&ip_conntrack_lock);

_