1 From stable-bounces@linux.kernel.org Wed May 16 09:58:34 2007
2 Message-ID: <464B37AB.5040802@trash.net>
3 Date: Wed, 16 May 2007 18:56:11 +0200
4 From: Patrick McHardy <kaber@trash.net>
6 Cc: Netfilter Development Mailinglist <netfilter-devel@lists.netfilter.org>, "David S. Miller" <davem@davemloft.net>
7 Subject: NETFILTER: {ip,nf}_conntrack: fix use-after-free in helper destroy callback invocation
9 When the helper module is removed for a master connection that has a
10 fulfilled expectation, but has already timed out and got removed from
11 the hash tables, nf_conntrack_helper_unregister can't find the master
12 connection to unset the helper, causing a use-after-free when the
13 expected connection is destroyed and releases the last reference to
16 The helper destroy callback was introduced for the PPtP helper to clean
17 up expectations and expected connections when the master connection
18 times out, but doing this from destroy_conntrack only works for
19 unfulfilled expectations since expected connections hold a reference
20 to the master, preventing its destruction. Move the destroy callback to
21 the timeout function, which fixes both problems.
23 Reported/tested by Gabor Burjan <buga@buvoshetes.hu>.
25 Signed-off-by: Patrick McHardy <kaber@trash.net>
26 Signed-off-by: Chris Wright <chrisw@sous-sol.org>
28 commit 441f15ce23ef5c4d149b7e7985f63c1ddd334c45
29 tree 8783e067803def0fc2773ef3515190143ac47320
30 parent 8d8b10482fffcb72b15515231bb942e2ad6395c9
31 author Patrick McHardy <kaber@trash.net> Wed, 16 May 2007 18:52:36 +0200
32 committer Patrick McHardy <kaber@trash.net> Wed, 16 May 2007 18:52:36 +0200
34 net/ipv4/netfilter/ip_conntrack_core.c | 10 +++++-----
35 net/netfilter/nf_conntrack_core.c | 8 ++++----
36 2 files changed, 9 insertions(+), 9 deletions(-)
38 --- linux-2.6.21.1.orig/net/ipv4/netfilter/ip_conntrack_core.c
39 +++ linux-2.6.21.1/net/ipv4/netfilter/ip_conntrack_core.c
40 @@ -302,7 +302,6 @@ destroy_conntrack(struct nf_conntrack *n
42 struct ip_conntrack *ct = (struct ip_conntrack *)nfct;
43 struct ip_conntrack_protocol *proto;
44 - struct ip_conntrack_helper *helper;
45 typeof(ip_conntrack_destroyed) destroyed;
47 DEBUGP("destroy_conntrack(%p)\n", ct);
48 @@ -312,10 +311,6 @@ destroy_conntrack(struct nf_conntrack *n
49 ip_conntrack_event(IPCT_DESTROY, ct);
50 set_bit(IPS_DYING_BIT, &ct->status);
52 - helper = ct->helper;
53 - if (helper && helper->destroy)
54 - helper->destroy(ct);
56 /* To make sure we don't get any weird locking issues here:
57 * destroy_conntrack() MUST NOT be called with a write lock
58 * to ip_conntrack_lock!!! -HW */
59 @@ -356,6 +351,11 @@ destroy_conntrack(struct nf_conntrack *n
60 static void death_by_timeout(unsigned long ul_conntrack)
62 struct ip_conntrack *ct = (void *)ul_conntrack;
63 + struct ip_conntrack_helper *helper;
65 + helper = ct->helper;
66 + if (helper && helper->destroy)
67 + helper->destroy(ct);
69 write_lock_bh(&ip_conntrack_lock);
70 /* Inside lock so preempt is disabled on module removal path.
71 --- linux-2.6.21.1.orig/net/netfilter/nf_conntrack_core.c
72 +++ linux-2.6.21.1/net/netfilter/nf_conntrack_core.c
73 @@ -315,7 +315,6 @@ static void
74 destroy_conntrack(struct nf_conntrack *nfct)
76 struct nf_conn *ct = (struct nf_conn *)nfct;
77 - struct nf_conn_help *help = nfct_help(ct);
78 struct nf_conntrack_l3proto *l3proto;
79 struct nf_conntrack_l4proto *l4proto;
80 typeof(nf_conntrack_destroyed) destroyed;
81 @@ -327,9 +326,6 @@ destroy_conntrack(struct nf_conntrack *n
82 nf_conntrack_event(IPCT_DESTROY, ct);
83 set_bit(IPS_DYING_BIT, &ct->status);
85 - if (help && help->helper && help->helper->destroy)
86 - help->helper->destroy(ct);
88 /* To make sure we don't get any weird locking issues here:
89 * destroy_conntrack() MUST NOT be called with a write lock
90 * to nf_conntrack_lock!!! -HW */
91 @@ -375,6 +371,10 @@ destroy_conntrack(struct nf_conntrack *n
92 static void death_by_timeout(unsigned long ul_conntrack)
94 struct nf_conn *ct = (void *)ul_conntrack;
95 + struct nf_conn_help *help = nfct_help(ct);
97 + if (help && help->helper && help->helper->destroy)
98 + help->helper->destroy(ct);
100 write_lock_bh(&nf_conntrack_lock);
101 /* Inside lock so preempt is disabled on module removal path.