summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTung Nguyen <tung.q.nguyen@dektech.com.au>2020-10-27 10:24:03 +0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-11-01 12:45:40 +0100
commitaf5d5b8afd1235517b2ea1590dbf145a458839f4 (patch)
tree98f4b86b4b04441e4374de5e7cf915fac1e5a82b
parent519366f64c272746dd339574e4be6eb5e29d8303 (diff)
downloadlinux-stable-af5d5b8afd1235517b2ea1590dbf145a458839f4.tar.gz
linux-stable-af5d5b8afd1235517b2ea1590dbf145a458839f4.tar.bz2
linux-stable-af5d5b8afd1235517b2ea1590dbf145a458839f4.zip
tipc: fix memory leak caused by tipc_buf_append()
[ Upstream commit ceb1eb2fb609c88363e06618b8d4bbf7815a4e03 ] Commit ed42989eab57 ("tipc: fix the skb_unshare() in tipc_buf_append()") replaced skb_unshare() with skb_copy() to not reduce the data reference counter of the original skb intentionally. This is not the correct way to handle the cloned skb because it causes memory leak in 2 following cases: 1/ Sending multicast messages via broadcast link The original skb list is cloned to the local skb list for local destination. After that, the data reference counter of each skb in the original list has the value of 2. This causes each skb not to be freed after receiving ACK: tipc_link_advance_transmq() { ... /* release skb */ __skb_unlink(skb, &l->transmq); kfree_skb(skb); <-- memory exists after being freed } 2/ Sending multicast messages via replicast link Similar to the above case, each skb cannot be freed after purging the skb list: tipc_mcast_xmit() { ... __skb_queue_purge(pkts); <-- memory exists after being freed } This commit fixes this issue by using skb_unshare() instead. Besides, to avoid use-after-free error reported by KASAN, the pointer to the fragment is set to NULL before calling skb_unshare() to make sure that the original skb is not freed after freeing the fragment 2 times in case skb_unshare() returns NULL. Fixes: ed42989eab57 ("tipc: fix the skb_unshare() in tipc_buf_append()") Acked-by: Jon Maloy <jmaloy@redhat.com> Reported-by: Thang Hoang Ngo <thang.h.ngo@dektech.com.au> Signed-off-by: Tung Nguyen <tung.q.nguyen@dektech.com.au> Reviewed-by: Xin Long <lucien.xin@gmail.com> Acked-by: Cong Wang <xiyou.wangcong@gmail.com> Link: https://lore.kernel.org/r/20201027032403.1823-1-tung.q.nguyen@dektech.com.au Signed-off-by: Jakub Kicinski <kuba@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--net/tipc/msg.c5
1 files changed, 2 insertions, 3 deletions
diff --git a/net/tipc/msg.c b/net/tipc/msg.c
index 15b24fbcbe97..0d6297f75df1 100644
--- a/net/tipc/msg.c
+++ b/net/tipc/msg.c
@@ -150,12 +150,11 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)
if (fragid == FIRST_FRAGMENT) {
if (unlikely(head))
goto err;
- if (skb_cloned(frag))
- frag = skb_copy(frag, GFP_ATOMIC);
+ *buf = NULL;
+ frag = skb_unshare(frag, GFP_ATOMIC);
if (unlikely(!frag))
goto err;
head = *headbuf = frag;
- *buf = NULL;
TIPC_SKB_CB(head)->tail = NULL;
if (skb_is_nonlinear(head)) {
skb_walk_frags(head, tail) {