From: Greg Kroah-Hartman Date: Mon, 18 Sep 2017 06:53:12 +0000 (+0200) Subject: drop queue-3.18/ipv6-add-rcu-grace-period-before-freeing-fib6_node.patch X-Git-Tag: v4.9.51~18 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=933a6db148d83168f94674900f5e3247f62a8664;p=thirdparty%2Fkernel%2Fstable-queue.git drop queue-3.18/ipv6-add-rcu-grace-period-before-freeing-fib6_node.patch --- diff --git a/queue-3.18/ipv6-add-rcu-grace-period-before-freeing-fib6_node.patch b/queue-3.18/ipv6-add-rcu-grace-period-before-freeing-fib6_node.patch deleted file mode 100644 index 72025984acc..00000000000 --- a/queue-3.18/ipv6-add-rcu-grace-period-before-freeing-fib6_node.patch +++ /dev/null @@ -1,172 +0,0 @@ -From foo@baz Fri Sep 15 17:17:53 PDT 2017 -From: Wei Wang -Date: Mon, 21 Aug 2017 09:47:10 -0700 -Subject: ipv6: add rcu grace period before freeing fib6_node - -From: Wei Wang - - -[ Upstream commit c5cff8561d2d0006e972bd114afd51f082fee77c ] - -We currently keep rt->rt6i_node pointing to the fib6_node for the route. -And some functions make use of this pointer to dereference the fib6_node -from rt structure, e.g. rt6_check(). However, as there is neither -refcount nor rcu taken when dereferencing rt->rt6i_node, it could -potentially cause crashes as rt->rt6i_node could be set to NULL by other -CPUs when doing a route deletion. -This patch introduces an rcu grace period before freeing fib6_node and -makes sure the functions that dereference it takes rcu_read_lock(). - -Note: there is no "Fixes" tag because this bug was there in a very -early stage. - -Signed-off-by: Wei Wang -Acked-by: Eric Dumazet -Acked-by: Martin KaFai Lau -Signed-off-by: David S. Miller -Signed-off-by: Greg Kroah-Hartman ---- - include/net/ip6_fib.h | 30 +++++++++++++++++++++++++++++- - net/ipv6/ip6_fib.c | 20 ++++++++++++++++---- - net/ipv6/route.c | 14 +++++++++++--- - 3 files changed, 56 insertions(+), 8 deletions(-) - -diff --git a/include/net/ip6_fib.h b/include/net/ip6_fib.h -index a74e2aa40ef4..c17180118897 100644 ---- a/include/net/ip6_fib.h -+++ b/include/net/ip6_fib.h -@@ -68,6 +68,7 @@ struct fib6_node { - __u16 fn_flags; - int fn_sernum; - struct rt6_info *rr_ptr; -+ struct rcu_head rcu; - }; - - #ifndef CONFIG_IPV6_SUBTREES -@@ -165,13 +166,40 @@ static inline void rt6_update_expires(struct rt6_info *rt0, int timeout) - rt0->rt6i_flags |= RTF_EXPIRES; - } - -+/* Function to safely get fn->sernum for passed in rt -+ * and store result in passed in cookie. -+ * Return true if we can get cookie safely -+ * Return false if not -+ */ -+static inline bool rt6_get_cookie_safe(const struct rt6_info *rt, -+ u32 *cookie) -+{ -+ struct fib6_node *fn; -+ bool status = false; -+ -+ rcu_read_lock(); -+ fn = rcu_dereference(rt->rt6i_node); -+ -+ if (fn) { -+ *cookie = fn->fn_sernum; -+ status = true; -+ } -+ -+ rcu_read_unlock(); -+ return status; -+} -+ - static inline u32 rt6_get_cookie(const struct rt6_info *rt) - { -+ u32 cookie = 0; -+ - if (rt->rt6i_flags & RTF_PCPU || - (unlikely(rt->dst.flags & DST_NOCACHE) && rt->dst.from)) - rt = (struct rt6_info *)(rt->dst.from); - -- return rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; -+ rt6_get_cookie_safe(rt, &cookie); -+ -+ return cookie; - } - - static inline void ip6_rt_put(struct rt6_info *rt) -diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c -index ff389591a340..ed832b3d9b70 100644 ---- a/net/ipv6/ip6_fib.c -+++ b/net/ipv6/ip6_fib.c -@@ -148,11 +148,23 @@ static struct fib6_node *node_alloc(void) - return fn; - } - --static void node_free(struct fib6_node *fn) -+static void node_free_immediate(struct fib6_node *fn) -+{ -+ kmem_cache_free(fib6_node_kmem, fn); -+} -+ -+static void node_free_rcu(struct rcu_head *head) - { -+ struct fib6_node *fn = container_of(head, struct fib6_node, rcu); -+ - kmem_cache_free(fib6_node_kmem, fn); - } - -+static void node_free(struct fib6_node *fn) -+{ -+ call_rcu(&fn->rcu, node_free_rcu); -+} -+ - static void rt6_rcu_free(struct rt6_info *rt) - { - call_rcu(&rt->dst.rcu_head, dst_rcu_free); -@@ -589,9 +601,9 @@ static struct fib6_node *fib6_add_1(struct fib6_node *root, - - if (!in || !ln) { - if (in) -- node_free(in); -+ node_free_immediate(in); - if (ln) -- node_free(ln); -+ node_free_immediate(ln); - return ERR_PTR(-ENOMEM); - } - -@@ -1020,7 +1032,7 @@ int fib6_add(struct fib6_node *root, struct rt6_info *rt, - root, and then (in failure) stale node - in main tree. - */ -- node_free(sfn); -+ node_free_immediate(sfn); - err = PTR_ERR(sn); - goto failure; - } -diff --git a/net/ipv6/route.c b/net/ipv6/route.c -index 5764a84465f8..632987ffc07d 100644 ---- a/net/ipv6/route.c -+++ b/net/ipv6/route.c -@@ -1267,7 +1267,9 @@ static void rt6_dst_from_metrics_check(struct rt6_info *rt) - - static struct dst_entry *rt6_check(struct rt6_info *rt, u32 cookie) - { -- if (!rt->rt6i_node || (rt->rt6i_node->fn_sernum != cookie)) -+ u32 rt_cookie; -+ -+ if (!rt6_get_cookie_safe(rt, &rt_cookie) || rt_cookie != cookie) - return NULL; - - if (rt6_check_expired(rt)) -@@ -1335,8 +1337,14 @@ static void ip6_link_failure(struct sk_buff *skb) - if (rt->rt6i_flags & RTF_CACHE) { - dst_hold(&rt->dst); - ip6_del_rt(rt); -- } else if (rt->rt6i_node && (rt->rt6i_flags & RTF_DEFAULT)) { -- rt->rt6i_node->fn_sernum = -1; -+ } else { -+ struct fib6_node *fn; -+ -+ rcu_read_lock(); -+ fn = rcu_dereference(rt->rt6i_node); -+ if (fn && (rt->rt6i_flags & RTF_DEFAULT)) -+ fn->fn_sernum = -1; -+ rcu_read_unlock(); - } - } - } --- -2.13.5 - diff --git a/queue-3.18/series b/queue-3.18/series index 4c237f5aac9..d61ef922489 100644 --- a/queue-3.18/series +++ b/queue-3.18/series @@ -5,4 +5,3 @@ tcp-initialize-rcv_mss-to-tcp_min_mss-instead-of-0.patch ipv6-fix-memory-leak-with-multiple-tables-during-netns-destruction.patch ipv6-fix-typo-in-fib6_net_exit.patch f2fs-check-hot_data-for-roll-forward-recovery.patch -ipv6-add-rcu-grace-period-before-freeing-fib6_node.patch