Skip to content

Commit

Permalink
fix memory leaks
Browse files Browse the repository at this point in the history
  • Loading branch information
bradh352 committed Dec 27, 2024
1 parent 9b395f1 commit 16f8ecf
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 74 deletions.
167 changes: 98 additions & 69 deletions src/lib/ares_addrinfo2hostent.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,119 +47,152 @@
# include <limits.h>
#endif

static size_t hostent_nalias(const struct hostent *host)
{
size_t i;
for (i=0; host->h_aliases != NULL && host->h_aliases[i] != NULL; i++)
;

return i;
}

static size_t ai_nalias(const struct ares_addrinfo *ai)
{
const struct ares_addrinfo_cname *cname;
size_t i = 0;

for (cname = ai->cnames; cname != NULL; cname=cname->next) {
i++;
}

return i;
}

static size_t hostent_naddr(const struct hostent *host)
{
size_t i;
for (i=0; host->h_addr_list != NULL && host->h_addr_list[i] != NULL; i++)
;

return i;
}

static size_t ai_naddr(const struct ares_addrinfo *ai)
{
const struct ares_addrinfo_node *node;
size_t i = 0;

for (node = ai->nodes; node != NULL; node=node->ai_next) {
i++;
}

return i;
}

ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family,
struct hostent **host)
{
struct ares_addrinfo_node *next;
struct ares_addrinfo_cname *next_cname;
char **aliases = NULL;
char *addrs = NULL;
char **addrs = NULL;
size_t naliases = 0;
size_t naddrs = 0;
size_t alias = 0;
size_t i;
size_t ealiases = 0;
size_t eaddrs = 0;

if (ai == NULL || host == NULL) {
return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
}

/* Use the first node of the response as the family, since hostent can only
/* Use either the host set in the passed in hosts to be filled in, or the
* first node of the response as the family, since hostent can only
* represent one family. We assume getaddrinfo() returned a sorted list if
* the user requested AF_UNSPEC. */
if (family == AF_UNSPEC && ai->nodes) {
family = ai->nodes->ai_family;
if (family == AF_UNSPEC) {
if (*host != NULL && (*host)->h_addrtype != AF_UNSPEC) {
family = (*host)->h_addrtype;
} else if (ai->nodes != NULL) {
family = ai->nodes->ai_family;
}
}

if (family != AF_INET && family != AF_INET6) {
return ARES_EBADQUERY; /* LCOV_EXCL_LINE: DefensiveCoding */
}

*host = ares_malloc(sizeof(**host));
if (!(*host)) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
if (*host == NULL) {
*host = ares_malloc_zero(sizeof(**host));
if (!(*host)) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
}
memset(*host, 0, sizeof(**host));

next = ai->nodes;
while (next) {
if (next->ai_family == family) {
++naddrs;
}
next = next->ai_next;
(*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family;
if (family == AF_INET) {
(*host)->h_length = sizeof(struct in_addr);
} else if (family == AF_INET6) {
(*host)->h_length = sizeof(struct ares_in6_addr);
}

next_cname = ai->cnames;
while (next_cname) {
if (next_cname->alias) {
++naliases;
if ((*host)->h_name == NULL) {
if (ai->cnames) {
(*host)->h_name = ares_strdup(ai->cnames->name);
if ((*host)->h_name == NULL && ai->cnames->name) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
} else {
(*host)->h_name = ares_strdup(ai->name);
if ((*host)->h_name == NULL && ai->name) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
}
next_cname = next_cname->next;
}

aliases = ares_malloc((naliases + 1) * sizeof(char *));
naliases = ai_nalias(ai);
ealiases = hostent_nalias(*host);
aliases = ares_realloc_zero((*host)->h_aliases,
ealiases * sizeof(char *),
(naliases + ealiases + 1) * sizeof(char *));
if (!aliases) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
(*host)->h_aliases = aliases;
memset(aliases, 0, (naliases + 1) * sizeof(char *));

if (naliases) {
for (next_cname = ai->cnames; next_cname != NULL;
next_cname = next_cname->next) {
if (next_cname->alias == NULL) {
const struct ares_addrinfo_cname *cname;
i = ealiases;
for (cname = ai->cnames; cname != NULL; cname = cname->next) {
if (cname->alias == NULL) {
continue;
}
aliases[alias] = ares_strdup(next_cname->alias);
if (!aliases[alias]) {
(*host)->h_aliases[i] = ares_strdup(cname->alias);
if ((*host)->h_aliases[i] == NULL) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
alias++;
i++;
}
}


(*host)->h_addr_list = ares_malloc((naddrs + 1) * sizeof(char *));
if (!(*host)->h_addr_list) {
naddrs = ai_naddr(ai);
eaddrs = hostent_naddr(*host);
addrs = ares_realloc_zero((*host)->h_addr_list, eaddrs * sizeof(char *),
(naddrs + eaddrs + 1) * sizeof(char *));
if (addrs == NULL) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}

memset((*host)->h_addr_list, 0, (naddrs + 1) * sizeof(char *));

if (ai->cnames) {
(*host)->h_name = ares_strdup(ai->cnames->name);
if ((*host)->h_name == NULL && ai->cnames->name) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
} else {
(*host)->h_name = ares_strdup(ai->name);
if ((*host)->h_name == NULL && ai->name) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
}

(*host)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family;

if (family == AF_INET) {
(*host)->h_length = sizeof(struct in_addr);
}

if (family == AF_INET6) {
(*host)->h_length = sizeof(struct ares_in6_addr);
}
(*host)->h_addr_list = addrs;

if (naddrs) {
addrs = ares_malloc(naddrs * (size_t)(*host)->h_length);
if (!addrs) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}

i = 0;
i = eaddrs;
for (next = ai->nodes; next != NULL; next = next->ai_next) {
if (next->ai_family != family) {
continue;
}
(*host)->h_addr_list[i] = addrs + (i * (size_t)(*host)->h_length);
(*host)->h_addr_list[i] = ares_malloc_zero((size_t)(*host)->h_length);
if ((*host)->h_addr_list[i] == NULL) {
goto enomem; /* LCOV_EXCL_LINE: OutOfMemory */
}
if (family == AF_INET6) {
memcpy((*host)->h_addr_list[i],
&(CARES_INADDR_CAST(const struct sockaddr_in6 *, next->ai_addr)
Expand All @@ -172,15 +205,11 @@ ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family,
->sin_addr),
(size_t)(*host)->h_length);
}
++i;
}

if (i == 0) {
ares_free(addrs);
i++;
}
}

if (naddrs == 0 && naliases == 0) {
if (naddrs + eaddrs == 0 && naliases + ealiases == 0) {
ares_free_hostent(*host);
*host = NULL;
return ARES_ENODATA;
Expand Down
5 changes: 4 additions & 1 deletion src/lib/ares_addrinfo_localhost.c
Original file line number Diff line number Diff line change
Expand Up @@ -224,8 +224,11 @@ ares_status_t ares_addrinfo_localhost(const char *name, unsigned short port,
return ARES_EBADFAMILY; /* LCOV_EXCL_LINE: DefensiveCoding */
}

if (ai->name != NULL) {
ares_free(ai->name);
}
ai->name = ares_strdup(name);
if (!ai->name) {
if (ai->name == NULL) {
status = ARES_ENOMEM;
goto done; /* LCOV_EXCL_LINE: OutOfMemory */
}
Expand Down
7 changes: 4 additions & 3 deletions src/lib/ares_free_hostent.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,10 @@ void ares_free_hostent(struct hostent *host)
}
ares_free(host->h_aliases);
if (host->h_addr_list) {
ares_free(
host->h_addr_list[0]); /* no matter if there is one or many entries,
there is only one malloc for all of them */
size_t i;
for (i=0; host->h_addr_list[i] != NULL; i++) {
ares_free(host->h_addr_list[i]);
}
ares_free(host->h_addr_list);
}
ares_free(host);
Expand Down
2 changes: 1 addition & 1 deletion src/lib/ares_gethostbyaddr.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ static void next_lookup(struct addr_query *aquery)
{
const char *p;
ares_status_t status;
struct hostent *host;
struct hostent *host = NULL;
char *name;

for (p = aquery->remaining_lookups; *p; p++) {
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ares_gethostbyname.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,8 @@ static ares_status_t ares_gethostbyname_file_int(ares_channel_t *channel,
return ARES_ENOTFOUND;
}

*host = NULL;

/* Per RFC 7686, reject queries for ".onion" domain names with NXDOMAIN. */
if (ares_is_onion_domain(name)) {
return ARES_ENOTFOUND;
Expand Down
1 change: 1 addition & 0 deletions src/lib/ares_hosts_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -860,6 +860,7 @@ ares_status_t ares_hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry,
}

if (name != NULL) {
ares_free(ai->name);
ai->name = ares_strdup(name);
if (ai->name == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ares_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,10 @@ ares_status_t ares_parse_ptr_reply_dnsrec(const ares_dns_record_t *dnsrec,
const void *addr, int addrlen,
int family, struct hostent **host);

/* host address must be valid or NULL as will create or append */
ares_status_t ares_addrinfo2hostent(const struct ares_addrinfo *ai, int family,
struct hostent **host);

ares_status_t ares_addrinfo2addrttl(const struct ares_addrinfo *ai, int family,
size_t req_naddrttls,
struct ares_addrttl *addrttls,
Expand Down
1 change: 1 addition & 0 deletions src/lib/legacy/ares_parse_a_reply.c
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ int ares_parse_a_reply(const unsigned char *abuf, int alen,
}

if (host != NULL) {
*host = NULL;
status = ares_addrinfo2hostent(&ai, AF_INET, host);
if (status != ARES_SUCCESS && status != ARES_ENODATA) {
goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */
Expand Down
1 change: 1 addition & 0 deletions src/lib/legacy/ares_parse_aaaa_reply.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ int ares_parse_aaaa_reply(const unsigned char *abuf, int alen,
}

if (host != NULL) {
*host = NULL;
status = ares_addrinfo2hostent(&ai, AF_INET6, host);
if (status != ARES_SUCCESS && status != ARES_ENODATA) {
goto fail; /* LCOV_EXCL_LINE: DefensiveCoding */
Expand Down

0 comments on commit 16f8ecf

Please sign in to comment.