diff options
Diffstat (limited to 'target/linux/generic/backport-4.19/345-v4.16-netfilter-nf_flow_offload-fix-use-after-free-and-a-r.patch')
-rw-r--r-- | target/linux/generic/backport-4.19/345-v4.16-netfilter-nf_flow_offload-fix-use-after-free-and-a-r.patch | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/target/linux/generic/backport-4.19/345-v4.16-netfilter-nf_flow_offload-fix-use-after-free-and-a-r.patch b/target/linux/generic/backport-4.19/345-v4.16-netfilter-nf_flow_offload-fix-use-after-free-and-a-r.patch new file mode 100644 index 0000000000..331f22d19a --- /dev/null +++ b/target/linux/generic/backport-4.19/345-v4.16-netfilter-nf_flow_offload-fix-use-after-free-and-a-r.patch @@ -0,0 +1,95 @@ +From: Felix Fietkau <nbd@nbd.name> +Date: Wed, 7 Feb 2018 09:23:25 +0100 +Subject: [PATCH] netfilter: nf_flow_offload: fix use-after-free and a resource + leak + +flow_offload_del frees the flow, so all associated resource must be +freed before. + +Since the ct entry in struct flow_offload_entry was allocated by +flow_offload_alloc, it should be freed by flow_offload_free to take care +of the error handling path when flow_offload_add fails. + +While at it, make flow_offload_del static, since it should never be +called directly, only from the gc step + +Signed-off-by: Felix Fietkau <nbd@nbd.name> +--- + +--- a/include/net/netfilter/nf_flow_table.h ++++ b/include/net/netfilter/nf_flow_table.h +@@ -90,7 +90,6 @@ struct flow_offload *flow_offload_alloc( + void flow_offload_free(struct flow_offload *flow); + + int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow); +-void flow_offload_del(struct nf_flowtable *flow_table, struct flow_offload *flow); + struct flow_offload_tuple_rhash *flow_offload_lookup(struct nf_flowtable *flow_table, + struct flow_offload_tuple *tuple); + int nf_flow_table_iterate(struct nf_flowtable *flow_table, +--- a/net/netfilter/nf_flow_table.c ++++ b/net/netfilter/nf_flow_table.c +@@ -125,7 +125,9 @@ void flow_offload_free(struct flow_offlo + dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache); + dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache); + e = container_of(flow, struct flow_offload_entry, flow); +- kfree(e); ++ nf_ct_delete(e->ct, 0, 0); ++ nf_ct_put(e->ct); ++ kfree_rcu(e, rcu_head); + } + EXPORT_SYMBOL_GPL(flow_offload_free); + +@@ -149,11 +151,9 @@ int flow_offload_add(struct nf_flowtable + } + EXPORT_SYMBOL_GPL(flow_offload_add); + +-void flow_offload_del(struct nf_flowtable *flow_table, +- struct flow_offload *flow) ++static void flow_offload_del(struct nf_flowtable *flow_table, ++ struct flow_offload *flow) + { +- struct flow_offload_entry *e; +- + rhashtable_remove_fast(&flow_table->rhashtable, + &flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].node, + *flow_table->type->params); +@@ -161,10 +161,8 @@ void flow_offload_del(struct nf_flowtabl + &flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].node, + *flow_table->type->params); + +- e = container_of(flow, struct flow_offload_entry, flow); +- kfree_rcu(e, rcu_head); ++ flow_offload_free(flow); + } +-EXPORT_SYMBOL_GPL(flow_offload_del); + + struct flow_offload_tuple_rhash * + flow_offload_lookup(struct nf_flowtable *flow_table, +@@ -175,15 +173,6 @@ flow_offload_lookup(struct nf_flowtable + } + EXPORT_SYMBOL_GPL(flow_offload_lookup); + +-static void nf_flow_release_ct(const struct flow_offload *flow) +-{ +- struct flow_offload_entry *e; +- +- e = container_of(flow, struct flow_offload_entry, flow); +- nf_ct_delete(e->ct, 0, 0); +- nf_ct_put(e->ct); +-} +- + int nf_flow_table_iterate(struct nf_flowtable *flow_table, + void (*iter)(struct flow_offload *flow, void *data), + void *data) +@@ -259,10 +248,8 @@ static int nf_flow_offload_gc_step(struc + flow = container_of(tuplehash, struct flow_offload, tuplehash[0]); + + if (nf_flow_has_expired(flow) || +- nf_flow_is_dying(flow)) { ++ nf_flow_is_dying(flow)) + flow_offload_del(flow_table, flow); +- nf_flow_release_ct(flow); +- } + } + out: + rhashtable_walk_stop(&hti); |