[PATCH 1/2] ipc: freebsd: avoid leaking memory in kernel_get_device()

kevans at FreeBSD.org kevans at FreeBSD.org
Thu Nov 3 18:38:20 UTC 2022


From: Kyle Evans <kevans at FreeBSD.org>

Primarily, front-load validation of an allowed-ip entry to before we
allocate `aip`, so that we don't need to free() it if we end up skipping
this entry.  Assert that `aip` is NULL after we exit the loop, as we
should have transfered ownership to the `peer` or freed it in all paths
through the allowed-ip loop.

FreeBSD-Coverity:	1500405
Signed-off-by: Kyle Evans <kevans at FreeBSD.org>
---
 src/ipc-freebsd.h | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/ipc-freebsd.h b/src/ipc-freebsd.h
index b5be15b..78064e9 100644
--- a/src/ipc-freebsd.h
+++ b/src/ipc-freebsd.h
@@ -8,6 +8,8 @@
 #include <sys/sockio.h>
 #include <dev/wg/if_wg.h>
 
+#include <assert.h>
+
 #define IPC_SUPPORTS_KERNEL_INTERFACE
 
 static int get_dgram_socket(void)
@@ -118,7 +120,7 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
 		goto skip_peers;
 	for (i = 0; i < peer_count; ++i) {
 		struct wgpeer *peer;
-		struct wgallowedip *aip;
+		struct wgallowedip *aip = NULL;
 		const nvlist_t *const *nvl_aips;
 		size_t aip_count, j;
 
@@ -169,11 +171,13 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
 		if (!aip_count || !nvl_aips)
 			goto skip_allowed_ips;
 		for (j = 0; j < aip_count; ++j) {
+			if (!nvlist_exists_number(nvl_aips[j], "cidr"))
+				continue;
+			if (!nvlist_exists_binary(nvl_aips[j], "ipv4") && !nvlist_exists_binary(nvl_aips[j], "ipv6"))
+				continue;
 			aip = calloc(1, sizeof(*aip));
 			if (!aip)
 				goto err_allowed_ips;
-			if (!nvlist_exists_number(nvl_aips[j], "cidr"))
-				continue;
 			number = nvlist_get_number(nvl_aips[j], "cidr");
 			if (nvlist_exists_binary(nvl_aips[j], "ipv4")) {
 				binary = nvlist_get_binary(nvl_aips[j], "ipv4", &size);
@@ -184,7 +188,8 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
 				aip->family = AF_INET;
 				aip->cidr = number;
 				memcpy(&aip->ip4, binary, sizeof(aip->ip4));
-			} else if (nvlist_exists_binary(nvl_aips[j], "ipv6")) {
+			} else {
+				assert(nvlist_exists_binary(nvl_aips[j], "ipv6"));
 				binary = nvlist_get_binary(nvl_aips[j], "ipv6", &size);
 				if (!binary || number > 128) {
 					ret = EINVAL;
@@ -193,14 +198,14 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
 				aip->family = AF_INET6;
 				aip->cidr = number;
 				memcpy(&aip->ip6, binary, sizeof(aip->ip6));
-			} else
-				continue;
+			}
 
 			if (!peer->first_allowedip)
 				peer->first_allowedip = aip;
 			else
 				peer->last_allowedip->next_allowedip = aip;
 			peer->last_allowedip = aip;
+			aip = NULL;
 			continue;
 
 		err_allowed_ips:
@@ -209,6 +214,12 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
 			free(aip);
 			goto err_peer;
 		}
+
+		/*
+		 * Nothing leaked, hopefully -- ownership transferred or aip
+		 * freed.
+		 */
+		assert(aip == NULL);
 	skip_allowed_ips:
 		if (!dev->first_peer)
 			dev->first_peer = peer;
-- 
2.36.1



More information about the WireGuard mailing list