generic: ar8216: group MIB counters and use two basic ones only by default
[oweals/openwrt.git] / target / linux / generic / backport-4.14 / 345-v4.16-netfilter-nf_flow_offload-fix-use-after-free-and-a-r.patch
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);