331f22d19a29120ee39bc1a77afe6ce96ad2af1f
[openwrt/staging/luka.git] /
1 From: Felix Fietkau <nbd@nbd.name>
2 Date: Wed, 7 Feb 2018 09:23:25 +0100
3 Subject: [PATCH] netfilter: nf_flow_offload: fix use-after-free and a resource
4 leak
5
6 flow_offload_del frees the flow, so all associated resource must be
7 freed before.
8
9 Since the ct entry in struct flow_offload_entry was allocated by
10 flow_offload_alloc, it should be freed by flow_offload_free to take care
11 of the error handling path when flow_offload_add fails.
12
13 While at it, make flow_offload_del static, since it should never be
14 called directly, only from the gc step
15
16 Signed-off-by: Felix Fietkau <nbd@nbd.name>
17 ---
18
19 --- a/include/net/netfilter/nf_flow_table.h
20 +++ b/include/net/netfilter/nf_flow_table.h
21 @@ -90,7 +90,6 @@ struct flow_offload *flow_offload_alloc(
22 void flow_offload_free(struct flow_offload *flow);
23
24 int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
25 -void flow_offload_del(struct nf_flowtable *flow_table, struct flow_offload *flow);
26 struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table,
27 struct flow_offload_tuple *tuple);
28 int nf_flow_table_iterate(struct nf_flowtable *flow_table,
29 --- a/net/netfilter/nf_flow_table.c
30 +++ b/net/netfilter/nf_flow_table.c
31 @@ -125,7 +125,9 @@ void flow_offload_free(struct flow_offlo
32 dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache);
33 dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache);
34 e = container_of(flow, struct flow_offload_entry, flow);
35 - kfree(e);
36 + nf_ct_delete(e->ct, 0, 0);
37 + nf_ct_put(e->ct);
38 + kfree_rcu(e, rcu_head);
39 }
40 EXPORT_SYMBOL_GPL(flow_offload_free);
41
42 @@ -149,11 +151,9 @@ int flow_offload_add(struct nf_flowtable
43 }
44 EXPORT_SYMBOL_GPL(flow_offload_add);
45
46 -void flow_offload_del(struct nf_flowtable *flow_table,
47 - struct flow_offload *flow)
48 +static void flow_offload_del(struct nf_flowtable *flow_table,
49 + struct flow_offload *flow)
50 {
51 - struct flow_offload_entry *e;
52 -
53 rhashtable_remove_fast(&flow_table->rhashtable,
54 &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node,
55 *flow_table->type->params);
56 @@ -161,10 +161,8 @@ void flow_offload_del(struct nf_flowtabl
57 &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node,
58 *flow_table->type->params);
59
60 - e = container_of(flow, struct flow_offload_entry, flow);
61 - kfree_rcu(e, rcu_head);
62 + flow_offload_free(flow);
63 }
64 -EXPORT_SYMBOL_GPL(flow_offload_del);
65
66 struct flow_offload_tuple_rhash *
67 flow_offload_lookup(struct nf_flowtable *flow_table,
68 @@ -175,15 +173,6 @@ flow_offload_lookup(struct nf_flowtable
69 }
70 EXPORT_SYMBOL_GPL(flow_offload_lookup);
71
72 -static void nf_flow_release_ct(const struct flow_offload *flow)
73 -{
74 - struct flow_offload_entry *e;
75 -
76 - e = container_of(flow, struct flow_offload_entry, flow);
77 - nf_ct_delete(e->ct, 0, 0);
78 - nf_ct_put(e->ct);
79 -}
80 -
81 int nf_flow_table_iterate(struct nf_flowtable *flow_table,
82 void (*iter)(struct flow_offload *flow, void *data),
83 void *data)
84 @@ -259,10 +248,8 @@ static int nf_flow_offload_gc_step(struc
85 flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
86
87 if (nf_flow_has_expired(flow) ||
88 - nf_flow_is_dying(flow)) {
89 + nf_flow_is_dying(flow))
90 flow_offload_del(flow_table, flow);
91 - nf_flow_release_ct(flow);
92 - }
93 }
94 out:
95 rhashtable_walk_stop(&hti);