aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsubashab@codeaurora.org <subashab@codeaurora.org>2015-01-23 22:26:02 +0000
committerMoyster <oysterized@gmail.com>2016-11-07 13:47:01 +0100
commit470ec616976d17c5ef1975f3444be573dc5d3c43 (patch)
tree91d3df7ffc7a7b35def26a4049a4875efba59580
parent5347a622c40f09112a56c45a4644b70e3dedc7e9 (diff)
ping: Fix race in free in receive path
[ Upstream commit fc752f1f43c1c038a2c6ae58cc739ebb5953ccb0 ] An exception is seen in ICMP ping receive path where the skb destructor sock_rfree() tries to access a freed socket. This happens because ping_rcv() releases socket reference with sock_put() and this internally frees up the socket. Later icmp_rcv() will try to free the skb and as part of this, skb destructor is called and which leads to a kernel panic as the socket is freed already in ping_rcv(). -->|exception -007|sk_mem_uncharge -007|sock_rfree -008|skb_release_head_state -009|skb_release_all -009|__kfree_skb -010|kfree_skb -011|icmp_rcv -012|ip_local_deliver_finish Fix this incorrect free by cloning this skb and processing this cloned skb instead. This patch was suggested by Eric Dumazet Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> Cc: Eric Dumazet <edumazet@google.com> Signed-off-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/ipv4/ping.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/net/ipv4/ping.c b/net/ipv4/ping.c
index d99c80b5a..0f49b1071 100644
--- a/net/ipv4/ping.c
+++ b/net/ipv4/ping.c
@@ -257,7 +257,7 @@ int ping_init_sock(struct sock *sk)
int i, j, count;
kgid_t low, high;
int ret = 0;
-
+
inet_get_ping_group_range_net(net, &low, &high);
if (gid_lte(low, group) && gid_lte(group, high))
return 0;
@@ -966,12 +966,18 @@ void ping_rcv(struct sk_buff *skb)
sk = ping_lookup(net, skb, ntohs(icmph->un.echo.id));
if (sk != NULL) {
-#ifdef CONFIG_MTK_NET_LOGGING
+#ifdef CONFIG_MTK_NET_LOGGING
printk(KERN_INFO "[mtk_net][ping_debug]rcv on sk %p\n", sk);
#endif
ping_queue_rcv_skb(sk, skb_get(skb));
/*mtk_net: don't put sock here, do sock_put after free skb*/
/* sock_put(sk); */
+ struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
+
+ pr_debug("rcv on socket %p\n", sk);
+ if (skb2)
+ ping_queue_rcv_skb(sk, skb2);
+ sock_put(sk);
return;
}
pr_info("[mtk_net][ping_debug]no socket, dropping\n");