OpenWrt – Blame information for rev 2
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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); |