From: Martin Josefsson 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); _