[PATCH 1/3] Fix __check_pf()/make_request() stack overflow segfault (convert to alloca_account)
Debabrata Banerjee
dbanerje@akamai.com
Fri Nov 1 01:10:00 GMT 2013
Tested calls to getaddrinfo() with 64k+ local IPv4 and IPv6 addresses.
Changelog:
2013-10-31 Debabrata Banerjee <dbanerje@akamai.com>
[BZ #16002]
* sysdeps/unix/sysv/linux/check_pf.c (make_request): Use alloca_account
for allocations and fallback to malloc
Signed-off-by: Debabrata Banerjee <dbanerje@akamai.com>
---
sysdeps/unix/sysv/linux/check_pf.c | 87 ++++++++++++++++++++++++++++----------
1 file changed, 65 insertions(+), 22 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index 34c2146..5dd7650 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -139,9 +139,12 @@ make_request (int fd, pid_t pid)
#endif
bool use_malloc = false;
char *buf;
+ size_t alloca_used = 0;
+ size_t result_size = 0;
+ struct cached_data *result = NULL;
if (__libc_use_alloca (buf_size))
- buf = alloca (buf_size);
+ buf = alloca_account (buf_size, alloca_used);
else
{
buf = malloc (buf_size);
@@ -206,6 +209,8 @@ make_request (int fd, pid_t pid)
const void *local = NULL;
const void *address = NULL;
+ struct in6addrinfo *tmp_info;
+
while (RTA_OK (rta, len))
{
switch (rta->rta_type)
@@ -239,28 +244,64 @@ make_request (int fd, pid_t pid)
}
}
- struct in6ailist *newp = alloca (sizeof (*newp));
- newp->info.flags = (((ifam->ifa_flags
- & (IFA_F_DEPRECATED
- | IFA_F_OPTIMISTIC))
- ? in6ai_deprecated : 0)
- | ((ifam->ifa_flags
- & IFA_F_HOMEADDRESS)
- ? in6ai_homeaddress : 0));
- newp->info.prefixlen = ifam->ifa_prefixlen;
- newp->info.index = ifam->ifa_index;
- if (ifam->ifa_family == AF_INET)
- {
- newp->info.addr[0] = 0;
- newp->info.addr[1] = 0;
- newp->info.addr[2] = htonl (0xffff);
- newp->info.addr[3] = *(const in_addr_t *) address;
- }
+ if (__libc_use_alloca (alloca_used + sizeof (struct in6ailist)))
+ {
+ struct in6ailist *newp = alloca_account (sizeof (*newp), alloca_used);
+ newp->next = in6ailist;
+ in6ailist = newp;
+ tmp_info = &newp->info;
+ }
else
- memcpy (newp->info.addr, address, sizeof (newp->info.addr));
- newp->next = in6ailist;
- in6ailist = newp;
- ++in6ailistlen;
+ {
+ size_t allocate_size;
+
+ if (result_size < sizeof (*result)
+ + ((in6ailistlen + 1) * sizeof (struct in6addrinfo)))
+ {
+ allocate_size = sizeof (*result)
+ + (2 * in6ailistlen * sizeof (struct in6addrinfo));
+ void *newbuf = realloc (result, allocate_size);
+ if (newbuf != NULL)
+ result = newbuf;
+ else
+ goto out_fail;
+
+ if (result_size == 0)
+ {
+ int i = 0;
+ do
+ {
+ result->in6ai[i++] = in6ailist->info;
+ in6ailist = in6ailist->next;
+ }
+ while (in6ailist != NULL);
+ }
+
+ result_size = allocate_size;
+ }
+ tmp_info = &result->in6ai[in6ailistlen];
+ }
+
+ tmp_info->flags = (((ifam->ifa_flags
+ & (IFA_F_DEPRECATED
+ | IFA_F_OPTIMISTIC))
+ ? in6ai_deprecated : 0)
+ | ((ifam->ifa_flags
+ & IFA_F_HOMEADDRESS)
+ ? in6ai_homeaddress : 0));
+ tmp_info->prefixlen = ifam->ifa_prefixlen;
+ tmp_info->index = ifam->ifa_index;
+ if (ifam->ifa_family == AF_INET)
+ {
+ tmp_info->addr[0] = 0;
+ tmp_info->addr[1] = 0;
+ tmp_info->addr[2] = htonl (0xffff);
+ tmp_info->addr[3] = *(const in_addr_t *) address;
+ }
+ else
+ memcpy (tmp_info->addr, address, sizeof (tmp_info->addr));
+
+ ++in6ailistlen;
}
else if (nlmh->nlmsg_type == NLMSG_DONE)
/* We found the end, leave the loop. */
@@ -305,6 +346,8 @@ make_request (int fd, pid_t pid)
out_fail:
if (use_malloc)
free (buf);
+ if (result)
+ free (result);
return NULL;
}
--
1.8.3.4
More information about the Libc-alpha
mailing list