summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorJason A. Donenfeld <Jason@zx2c4.com>2018-02-12 11:57:32 +0100
committerJason A. Donenfeld <Jason@zx2c4.com>2018-02-12 12:04:53 +0100
commitbc8a55ed8027ce50a2b5ffd0667fcc2882862e4d (patch)
tree16ad1ae5f49034bfff0a3d7ac2bc4367465b840a
parentqemu: more granular memleak detection (diff)
downloadwireguard-monolithic-historical-bc8a55ed8027ce50a2b5ffd0667fcc2882862e4d.tar.xz
wireguard-monolithic-historical-bc8a55ed8027ce50a2b5ffd0667fcc2882862e4d.zip
socket: free skb if there isn't an endpoint
Because the packet transmission interface in Linux, in general, has the characteristic of "consuming" skbs, our own socket_send family too must always consume skbs. This means that when a caller passes an skb to a socket_send function, he looses ownership and expects for the skb to be freed by the socket_send function, not by himself. Therefore, it's important that we actually carry out this contract under all circumstances, even when there's no endpoint available. This condition could be hit by setting up a peer with a persistent keepalive but no endpoint, or by removing an endpoint once packets were queued up to be sent already.
-rw-r--r--src/socket.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/src/socket.c b/src/socket.c
index 8eefa87..6c81cc6 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -163,6 +163,8 @@ int socket_send_skb_to_peer(struct wireguard_peer *peer, struct sk_buff *skb, u8
ret = send4(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache);
else if (peer->endpoint.addr.sa_family == AF_INET6)
ret = send6(peer->device, skb, &peer->endpoint, ds, &peer->endpoint_cache);
+ else
+ dev_kfree_skb(skb);
if (likely(!ret))
peer->tx_bytes += skb_len;
read_unlock_bh(&peer->endpoint_lock);