]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/3.18.60/decnet-always-not-take-dst-__refcnt-when-inserting-dst-into-hash-table.patch
3.18-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.18.60 / decnet-always-not-take-dst-__refcnt-when-inserting-dst-into-hash-table.patch
CommitLineData
5e077f5d
GKH
1From foo@baz Thu Jun 29 19:45:34 CEST 2017
2From: Wei Wang <weiwan@google.com>
3Date: Fri, 16 Jun 2017 10:46:37 -0700
4Subject: decnet: always not take dst->__refcnt when inserting dst into hash table
5
6From: Wei Wang <weiwan@google.com>
7
8
9[ Upstream commit 76371d2e3ad1f84426a30ebcd8c3b9b98f4c724f ]
10
11In the existing dn_route.c code, dn_route_output_slow() takes
12dst->__refcnt before calling dn_insert_route() while dn_route_input_slow()
13does not take dst->__refcnt before calling dn_insert_route().
14This makes the whole routing code very buggy.
15In dn_dst_check_expire(), dnrt_free() is called when rt expires. This
16makes the routes inserted by dn_route_output_slow() not able to be
17freed as the refcnt is not released.
18In dn_dst_gc(), dnrt_drop() is called to release rt which could
19potentially cause the dst->__refcnt to be dropped to -1.
20In dn_run_flush(), dst_free() is called to release all the dst. Again,
21it makes the dst inserted by dn_route_output_slow() not able to be
22released and also, it does not wait on the rcu and could potentially
23cause crash in the path where other users still refer to this dst.
24
25This patch makes sure both input and output path do not take
26dst->__refcnt before calling dn_insert_route() and also makes sure
27dnrt_free()/dst_free() is called when removing dst from the hash table.
28The only difference between those 2 calls is that dnrt_free() waits on
29the rcu while dst_free() does not.
30
31Signed-off-by: Wei Wang <weiwan@google.com>
32Acked-by: Martin KaFai Lau <kafai@fb.com>
33Signed-off-by: David S. Miller <davem@davemloft.net>
34Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
35---
36 net/decnet/dn_route.c | 14 ++++----------
37 1 file changed, 4 insertions(+), 10 deletions(-)
38
39--- a/net/decnet/dn_route.c
40+++ b/net/decnet/dn_route.c
41@@ -189,12 +189,6 @@ static inline void dnrt_free(struct dn_r
42 call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
43 }
44
45-static inline void dnrt_drop(struct dn_route *rt)
46-{
47- dst_release(&rt->dst);
48- call_rcu_bh(&rt->dst.rcu_head, dst_rcu_free);
49-}
50-
51 static void dn_dst_check_expire(unsigned long dummy)
52 {
53 int i;
54@@ -249,7 +243,7 @@ static int dn_dst_gc(struct dst_ops *ops
55 }
56 *rtp = rt->dst.dn_next;
57 rt->dst.dn_next = NULL;
58- dnrt_drop(rt);
59+ dnrt_free(rt);
60 break;
61 }
62 spin_unlock_bh(&dn_rt_hash_table[i].lock);
63@@ -351,7 +345,7 @@ static int dn_insert_route(struct dn_rou
64 dst_use(&rth->dst, now);
65 spin_unlock_bh(&dn_rt_hash_table[hash].lock);
66
67- dnrt_drop(rt);
68+ dst_free(&rt->dst);
69 *rp = rth;
70 return 0;
71 }
72@@ -381,7 +375,7 @@ static void dn_run_flush(unsigned long d
73 for(; rt; rt = next) {
74 next = rcu_dereference_raw(rt->dst.dn_next);
75 RCU_INIT_POINTER(rt->dst.dn_next, NULL);
76- dst_free((struct dst_entry *)rt);
77+ dnrt_free(rt);
78 }
79
80 nothing_to_declare:
81@@ -1195,7 +1189,7 @@ make_route:
82 if (dev_out->flags & IFF_LOOPBACK)
83 flags |= RTCF_LOCAL;
84
85- rt = dst_alloc(&dn_dst_ops, dev_out, 1, DST_OBSOLETE_NONE, DST_HOST);
86+ rt = dst_alloc(&dn_dst_ops, dev_out, 0, DST_OBSOLETE_NONE, DST_HOST);
87 if (rt == NULL)
88 goto e_nobufs;
89