ipc: freebsd: avoid leaking memory in kernel_get_device()
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@FreeBSD.org> Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>
This commit is contained in:
parent
ca2e89ff21
commit
dbf49a7d17
|
@ -4,6 +4,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
#include <sys/nv.h>
|
#include <sys/nv.h>
|
||||||
#include <sys/sockio.h>
|
#include <sys/sockio.h>
|
||||||
#include <dev/wg/if_wg.h>
|
#include <dev/wg/if_wg.h>
|
||||||
|
@ -118,7 +119,7 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
|
||||||
goto skip_peers;
|
goto skip_peers;
|
||||||
for (i = 0; i < peer_count; ++i) {
|
for (i = 0; i < peer_count; ++i) {
|
||||||
struct wgpeer *peer;
|
struct wgpeer *peer;
|
||||||
struct wgallowedip *aip;
|
struct wgallowedip *aip = NULL;
|
||||||
const nvlist_t *const *nvl_aips;
|
const nvlist_t *const *nvl_aips;
|
||||||
size_t aip_count, j;
|
size_t aip_count, j;
|
||||||
|
|
||||||
|
@ -169,11 +170,13 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
|
||||||
if (!aip_count || !nvl_aips)
|
if (!aip_count || !nvl_aips)
|
||||||
goto skip_allowed_ips;
|
goto skip_allowed_ips;
|
||||||
for (j = 0; j < aip_count; ++j) {
|
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));
|
aip = calloc(1, sizeof(*aip));
|
||||||
if (!aip)
|
if (!aip)
|
||||||
goto err_allowed_ips;
|
goto err_allowed_ips;
|
||||||
if (!nvlist_exists_number(nvl_aips[j], "cidr"))
|
|
||||||
continue;
|
|
||||||
number = nvlist_get_number(nvl_aips[j], "cidr");
|
number = nvlist_get_number(nvl_aips[j], "cidr");
|
||||||
if (nvlist_exists_binary(nvl_aips[j], "ipv4")) {
|
if (nvlist_exists_binary(nvl_aips[j], "ipv4")) {
|
||||||
binary = nvlist_get_binary(nvl_aips[j], "ipv4", &size);
|
binary = nvlist_get_binary(nvl_aips[j], "ipv4", &size);
|
||||||
|
@ -184,7 +187,8 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
|
||||||
aip->family = AF_INET;
|
aip->family = AF_INET;
|
||||||
aip->cidr = number;
|
aip->cidr = number;
|
||||||
memcpy(&aip->ip4, binary, sizeof(aip->ip4));
|
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);
|
binary = nvlist_get_binary(nvl_aips[j], "ipv6", &size);
|
||||||
if (!binary || number > 128) {
|
if (!binary || number > 128) {
|
||||||
ret = EINVAL;
|
ret = EINVAL;
|
||||||
|
@ -193,14 +197,14 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
|
||||||
aip->family = AF_INET6;
|
aip->family = AF_INET6;
|
||||||
aip->cidr = number;
|
aip->cidr = number;
|
||||||
memcpy(&aip->ip6, binary, sizeof(aip->ip6));
|
memcpy(&aip->ip6, binary, sizeof(aip->ip6));
|
||||||
} else
|
}
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!peer->first_allowedip)
|
if (!peer->first_allowedip)
|
||||||
peer->first_allowedip = aip;
|
peer->first_allowedip = aip;
|
||||||
else
|
else
|
||||||
peer->last_allowedip->next_allowedip = aip;
|
peer->last_allowedip->next_allowedip = aip;
|
||||||
peer->last_allowedip = aip;
|
peer->last_allowedip = aip;
|
||||||
|
aip = NULL;
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
err_allowed_ips:
|
err_allowed_ips:
|
||||||
|
@ -209,6 +213,9 @@ static int kernel_get_device(struct wgdevice **device, const char *ifname)
|
||||||
free(aip);
|
free(aip);
|
||||||
goto err_peer;
|
goto err_peer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Nothing leaked, hopefully -- ownership transferred or aip freed. */
|
||||||
|
assert(aip == NULL);
|
||||||
skip_allowed_ips:
|
skip_allowed_ips:
|
||||||
if (!dev->first_peer)
|
if (!dev->first_peer)
|
||||||
dev->first_peer = peer;
|
dev->first_peer = peer;
|
||||||
|
|
Reference in New Issue