1
0
mirror of https://github.com/libuv/libuv synced 2025-03-28 21:13:16 +00:00

unix: handle out of memory in iface name copy

Allocate storage upfront, that way we can never run out of memory
halfway through processing the interface list.

Fixes: https://github.com/libuv/libuv/issues/4723
This commit is contained in:
Ben Noordhuis 2025-02-27 22:39:38 +01:00
parent 436c04048e
commit 5f6af62ee8
5 changed files with 61 additions and 54 deletions

View File

@ -1120,6 +1120,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifreq *ifr, *p, flg;
struct in6_ifreq if6;
struct sockaddr_dl* sa_addr;
size_t namelen;
char* name;
ifc.ifc_req = NULL;
sock6fd = -1;
@ -1156,6 +1158,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#define ADDR_SIZE(p) MAX((p).sa_len, sizeof(p))
/* Count all up and running ipv4/ipv6 addresses */
namelen = 0;
ifr = ifc.ifc_req;
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
p = ifr;
@ -1175,6 +1178,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
if (!(flg.ifr_flags & IFF_UP && flg.ifr_flags & IFF_RUNNING))
continue;
namelen += strlen(ent->ifa_name) + 1;
(*count)++;
}
@ -1182,8 +1186,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
goto cleanup;
/* Alloc the return interface structs */
*addresses = uv__calloc(*count, sizeof(**addresses));
if (!(*addresses)) {
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
if (*addresses == NULL) {
r = UV_ENOMEM;
goto cleanup;
}
@ -1210,7 +1214,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
/* All conditions above must match count loop */
address->name = uv__strdup(p->ifr_name);
namelen = strlen(p->ifr_name) + 1;
address->name = memcpy(name, p->ifr_name, namelen);
name += namelen;
if (inet6)
address->address.address6 = *((struct sockaddr_in6*) &p->ifr_addr);
@ -1282,13 +1288,7 @@ cleanup:
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; ++i) {
uv__free(addresses[i].name);
}
int count) {
uv__free(addresses);
}

View File

@ -65,13 +65,13 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return 0;
}
/* TODO(bnoordhuis) share with linux.c */
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
struct ifaddrs* addrs;
struct ifaddrs* ent;
uv_interface_address_t* address;
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
int i;
#endif
size_t namelen;
char* name;
*count = 0;
*addresses = NULL;
@ -80,9 +80,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return UV__ERR(errno);
/* Count the number of interfaces */
namelen = 0;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
namelen += strlen(ent->ifa_name) + 1;
(*count)++;
}
@ -92,20 +94,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
/* Make sure the memory is initiallized to zero using calloc() */
*addresses = uv__calloc(*count, sizeof(**addresses));
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
if (*addresses == NULL) {
freeifaddrs(addrs);
return UV_ENOMEM;
}
name = (char*) &(*addresses)[*count];
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
namelen = strlen(ent->ifa_name) + 1;
address->name = memcpy(name, ent->ifa_name, namelen);
name += namelen;
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
@ -129,6 +133,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#if !(defined(__CYGWIN__) || defined(__MSYS__)) && !defined(__GNU__)
/* Fill in physical addresses for each interface */
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
int i;
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFPHYS))
continue;
@ -151,13 +157,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
/* TODO(bnoordhuis) share with linux.c */
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(addresses[i].name);
}
uv__free(addresses);
}

View File

@ -403,6 +403,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return UV_ENOSYS;
/* The first loop to get the size of the array to be allocated */
namelen = 0;
for (cur = ifap; cur; cur = cur->ifa_next) {
if (!(cur->ifa_addr->sa_family == AF_INET6 ||
cur->ifa_addr->sa_family == AF_INET))
@ -411,6 +412,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
continue;
namelen += strlen(cur->ifa_name) + 1;
(*count)++;
}
@ -420,11 +422,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
/* Alloc the return interface structs */
*addresses = uv__calloc(*count, sizeof(**addresses));
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
if (*addresses == NULL) {
Qp2freeifaddrs(ifap);
return UV_ENOMEM;
}
name = (char*) &(*addresses)[*count];
address = *addresses;
/* The second loop to fill in the array */
@ -436,7 +440,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
if (!(cur->ifa_flags & IFF_UP && cur->ifa_flags & IFF_RUNNING))
continue;
address->name = uv__strdup(cur->ifa_name);
namelen = strlen(cur->ifa_name) + 1;
address->name = memcpy(name, cur->ifa_name, namelen);
name += namelen;
inet6 = (cur->ifa_addr->sa_family == AF_INET6);
@ -497,13 +503,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
void uv_free_interface_addresses(uv_interface_address_t* addresses, int count) {
int i;
for (i = 0; i < count; ++i) {
uv__free(addresses[i].name);
}
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
uv__free(addresses);
}

View File

@ -1954,11 +1954,15 @@ static int uv__ifaddr_exclude(struct ifaddrs *ent, int exclude_type) {
return !exclude_type;
}
/* TODO(bnoordhuis) share with bsd-ifaddrs.c */
int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
struct ifaddrs *addrs, *ent;
uv_interface_address_t* address;
struct sockaddr_ll* sll;
struct ifaddrs* addrs;
struct ifaddrs* ent;
size_t namelen;
char* name;
int i;
struct sockaddr_ll *sll;
*count = 0;
*addresses = NULL;
@ -1967,10 +1971,12 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return UV__ERR(errno);
/* Count the number of interfaces */
namelen = 0;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
namelen += strlen(ent->ifa_name) + 1;
(*count)++;
}
@ -1980,19 +1986,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
/* Make sure the memory is initiallized to zero using calloc() */
*addresses = uv__calloc(*count, sizeof(**addresses));
if (!(*addresses)) {
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
if (*addresses == NULL) {
freeifaddrs(addrs);
return UV_ENOMEM;
}
name = (char*) &(*addresses)[*count];
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent, UV__EXCLUDE_IFADDR))
continue;
address->name = uv__strdup(ent->ifa_name);
namelen = strlen(ent->ifa_name) + 1;
address->name = memcpy(name, ent->ifa_name, namelen);
name += namelen;
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
@ -2036,14 +2045,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
}
/* TODO(bnoordhuis) share with bsd-ifaddrs.c */
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(addresses[i].name);
}
int count) {
uv__free(addresses);
}

View File

@ -826,6 +826,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
uv_interface_address_t* address;
struct ifaddrs* addrs;
struct ifaddrs* ent;
size_t namelen;
char* name;
*count = 0;
*addresses = NULL;
@ -834,9 +836,11 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return UV__ERR(errno);
/* Count the number of interfaces */
namelen = 0;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent))
continue;
namelen += strlen(ent->ifa_name) + 1;
(*count)++;
}
@ -845,19 +849,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
return 0;
}
*addresses = uv__malloc(*count * sizeof(**addresses));
if (!(*addresses)) {
*addresses = uv__calloc(1, *count * sizeof(**addresses) + namelen);
if (*addresses == NULL) {
freeifaddrs(addrs);
return UV_ENOMEM;
}
name = (char*) &(*addresses)[*count];
address = *addresses;
for (ent = addrs; ent != NULL; ent = ent->ifa_next) {
if (uv__ifaddr_exclude(ent))
continue;
address->name = uv__strdup(ent->ifa_name);
namelen = strlen(ent->ifa_name) + 1;
address->name = memcpy(name, ent->ifa_name, namelen);
name += namelen;
if (ent->ifa_addr->sa_family == AF_INET6) {
address->address.address6 = *((struct sockaddr_in6*) ent->ifa_addr);
@ -885,13 +892,7 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
#endif /* SUNOS_NO_IFADDRS */
void uv_free_interface_addresses(uv_interface_address_t* addresses,
int count) {
int i;
for (i = 0; i < count; i++) {
uv__free(addresses[i].name);
}
int count) {
uv__free(addresses);
}