zos: improve memory management of ip addresses (#3640 3/3)
Fixes an issue where under certain conditions, dynamically allocated ip addresses, strings, and buffers were either leaking memory, being incorrectly freed, or not performing error checks. Also fixes an issue where the uv_interface_address_t struct was not correctly initialized to 0, so use calloc() instead of malloc(). Co-authored-by: Igor Todorovski <itodorov@ca.ibm.com>
This commit is contained in:
parent
524c5ed87d
commit
d938c104e1
104
src/unix/os390.c
104
src/unix/os390.c
@ -279,6 +279,7 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
__net_ifconf6entry_t* ifr;
|
||||
__net_ifconf6entry_t* p;
|
||||
unsigned int i;
|
||||
int count_names;
|
||||
unsigned char netmask[16] = {0};
|
||||
|
||||
*count = 0;
|
||||
@ -288,17 +289,27 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
if (0 > (sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP)))
|
||||
return UV__ERR(errno);
|
||||
|
||||
ifc.__nif6h_version = 1;
|
||||
ifc.__nif6h_buflen = maxsize;
|
||||
ifc.__nif6h_buffer = uv__calloc(1, maxsize);;
|
||||
ifc.__nif6h_buffer = uv__calloc(1, maxsize);
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
|
||||
if (ifc.__nif6h_buffer == NULL) {
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
ifc.__nif6h_version = 1;
|
||||
ifc.__nif6h_buflen = maxsize;
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFCONF6, &ifc) == -1) {
|
||||
/* This will error on a system that does not support IPv6. However, we want
|
||||
* to treat this as there being 0 interfaces so we can continue to get IPv4
|
||||
* interfaces in uv_interface_addresses(). So return 0 instead of the error.
|
||||
*/
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
*count = 0;
|
||||
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
|
||||
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
|
||||
p = ifr;
|
||||
@ -313,14 +324,22 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
++(*count);
|
||||
}
|
||||
|
||||
if ((*count) == 0) {
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc(*count * sizeof(uv_interface_address_t));
|
||||
*addresses = uv__calloc(1, *count * sizeof(uv_interface_address_t));
|
||||
if (!(*addresses)) {
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
count_names = 0;
|
||||
ifr = (__net_ifconf6entry_t*)(ifc.__nif6h_buffer);
|
||||
while ((char*)ifr < (char*)ifc.__nif6h_buffer + ifc.__nif6h_buflen) {
|
||||
p = ifr;
|
||||
@ -341,11 +360,16 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
p->__nif6e_name[i] != 0)
|
||||
++i;
|
||||
address->name = uv__malloc(i + 1);
|
||||
if (address->name == NULL)
|
||||
if (address->name == NULL) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
memcpy(address->name, p->__nif6e_name, i);
|
||||
address->name[i] = '\0';
|
||||
__e2a_s(address->name);
|
||||
count_names++;
|
||||
|
||||
address->address.address6 = *((struct sockaddr_in6*) &p->__nif6e_addr);
|
||||
|
||||
@ -360,10 +384,10 @@ static int uv__interface_addresses_v6(uv_interface_address_t** addresses,
|
||||
address->netmask.netmask6.sin6_family = AF_INET6;
|
||||
|
||||
address->is_internal = p->__nif6e_flags & _NIF6E_FLAGS_LOOPBACK ? 1 : 0;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
address++;
|
||||
}
|
||||
|
||||
uv__free(ifc.__nif6h_buffer);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
@ -377,15 +401,18 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
struct ifreq flg;
|
||||
struct ifreq* ifr;
|
||||
struct ifreq* p;
|
||||
uv_interface_address_t* addresses_v6;
|
||||
int count_v6;
|
||||
unsigned int i;
|
||||
int rc;
|
||||
int count_names;
|
||||
|
||||
*count = 0;
|
||||
*addresses = NULL;
|
||||
|
||||
/* get the ipv6 addresses first */
|
||||
uv_interface_address_t* addresses_v6;
|
||||
uv__interface_addresses_v6(&addresses_v6, &count_v6);
|
||||
if ((rc = uv__interface_addresses_v6(&addresses_v6, &count_v6)) != 0)
|
||||
return rc;
|
||||
|
||||
/* now get the ipv4 addresses */
|
||||
|
||||
@ -393,12 +420,27 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
maxsize = 16384;
|
||||
|
||||
sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
|
||||
if (0 > sockfd)
|
||||
if (0 > sockfd) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
|
||||
ifc.ifc_req = uv__calloc(1, maxsize);
|
||||
|
||||
if (ifc.ifc_req == NULL) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
|
||||
ifc.ifc_len = maxsize;
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFCONF, &ifc) == -1) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
@ -419,6 +461,9 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
@ -429,27 +474,35 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
(*count)++;
|
||||
}
|
||||
|
||||
if (*count == 0) {
|
||||
if (*count == 0 && count_v6 == 0) {
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Alloc the return interface structs */
|
||||
*addresses = uv__malloc((*count + count_v6) *
|
||||
*addresses = uv__calloc(1, (*count + count_v6) *
|
||||
sizeof(uv_interface_address_t));
|
||||
|
||||
if (!(*addresses)) {
|
||||
if (count_v6)
|
||||
uv_free_interface_addresses(addresses_v6, count_v6);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
address = *addresses;
|
||||
|
||||
/* copy over the ipv6 addresses */
|
||||
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
|
||||
address += count_v6;
|
||||
*count += count_v6;
|
||||
uv__free(addresses_v6);
|
||||
/* copy over the ipv6 addresses if any are found */
|
||||
if (count_v6) {
|
||||
memcpy(address, addresses_v6, count_v6 * sizeof(uv_interface_address_t));
|
||||
address += count_v6;
|
||||
*count += count_v6;
|
||||
/* free ipv6 addresses, but keep address names */
|
||||
uv__free(addresses_v6);
|
||||
}
|
||||
|
||||
count_names = *count;
|
||||
ifr = ifc.ifc_req;
|
||||
while ((char*)ifr < (char*)ifc.ifc_req + ifc.ifc_len) {
|
||||
p = ifr;
|
||||
@ -462,6 +515,8 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
|
||||
memcpy(flg.ifr_name, p->ifr_name, sizeof(flg.ifr_name));
|
||||
if (ioctl(sockfd, SIOCGIFFLAGS, &flg) == -1) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOSYS;
|
||||
}
|
||||
@ -478,15 +533,22 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
p->ifr_name[i] != 0)
|
||||
++i;
|
||||
address->name = uv__malloc(i + 1);
|
||||
if (address->name == NULL)
|
||||
if (address->name == NULL) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV_ENOMEM;
|
||||
}
|
||||
memcpy(address->name, p->ifr_name, i);
|
||||
address->name[i] = '\0';
|
||||
__e2a_s(address->name);
|
||||
count_names++;
|
||||
|
||||
address->address.address4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
|
||||
if (ioctl(sockfd, SIOCGIFNETMASK, p) == -1) {
|
||||
uv_free_interface_addresses(*addresses, count_names);
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return UV__ERR(errno);
|
||||
}
|
||||
@ -494,13 +556,13 @@ int uv_interface_addresses(uv_interface_address_t** addresses, int* count) {
|
||||
address->netmask.netmask4 = *((struct sockaddr_in*) &p->ifr_addr);
|
||||
address->netmask.netmask4.sin_family = AF_INET;
|
||||
address->is_internal = flg.ifr_flags & IFF_LOOPBACK ? 1 : 0;
|
||||
memset(address->phys_addr, 0, sizeof(address->phys_addr));
|
||||
address++;
|
||||
}
|
||||
|
||||
#undef ADDR_SIZE
|
||||
#undef MAX
|
||||
|
||||
uv__free(ifc.ifc_req);
|
||||
uv__close(sockfd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user