This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH 1/2] Fix __check_pf()/make_request() stack overflow segfault (convert to alloca_account)
- From: Debabrata Banerjee <dbanerje at akamai dot com>
- To: libc-alpha at sourceware dot org, Carlos O'Donell <carlos at redhat dot com>
- Cc: Debabrata Banerjee <dbanerje at akamai dot com>
- Date: Fri, 4 Oct 2013 16:29:02 -0400
- Subject: [PATCH 1/2] Fix __check_pf()/make_request() stack overflow segfault (convert to alloca_account)
- Authentication-results: sourceware.org; auth=none
- References: <524E4504 dot 6050603 at redhat dot com>
Tested calls to getaddrinfo() with 64k+ local IPv4 and IPv6 addresses.
Changelog:
2013-10-04 Debabrata Banerjee <dbanerje@akamai.com>
* sysdeps/unix/sysv/linux/check_pf.c (make_request): use alloca_account
for allocations and fallback to malloc, preventing potential segfaults
Signed-off-by: Debabrata Banerjee <dbanerje@akamai.com>
---
sysdeps/unix/sysv/linux/check_pf.c | 95 ++++++++++++++++++++++++++++++++++----
1 file changed, 85 insertions(+), 10 deletions(-)
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index 34c2146..76bf516 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);
@@ -239,7 +242,10 @@ make_request (int fd, pid_t pid)
}
}
- struct in6ailist *newp = alloca (sizeof (*newp));
+ if (__libc_use_alloca (alloca_used + sizeof (struct in6ailist)))
+ {
+ struct in6ailist *newp =
+ alloca_account (sizeof (*newp), alloca_used);
newp->info.flags = (((ifam->ifa_flags
& (IFA_F_DEPRECATED
| IFA_F_OPTIMISTIC))
@@ -262,6 +268,58 @@ make_request (int fd, pid_t pid)
in6ailist = newp;
++in6ailistlen;
}
+ else
+ {
+ 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;
+ }
+
+ result->in6ai[in6ailistlen].flags = (((ifam->ifa_flags
+ & (IFA_F_DEPRECATED
+ | IFA_F_OPTIMISTIC))
+ ? in6ai_deprecated : 0)
+ | ((ifam->ifa_flags
+ & IFA_F_HOMEADDRESS)
+ ? in6ai_homeaddress : 0));
+ result->in6ai[in6ailistlen].prefixlen = ifam->ifa_prefixlen;
+ result->in6ai[in6ailistlen].index = ifam->ifa_index;
+ if (ifam->ifa_family == AF_INET)
+ {
+ result->in6ai[in6ailistlen].addr[0] = 0;
+ result->in6ai[in6ailistlen].addr[1] = 0;
+ result->in6ai[in6ailistlen].addr[2] = htonl (0xffff);
+ result->in6ai[in6ailistlen].addr[3] = *(const in_addr_t *) address;
+ }
+ else
+ memcpy (result->in6ai[in6ailistlen].addr, address,
+ sizeof (result->in6ai[in6ailistlen].addr));
+
+ ++in6ailistlen;
+ }
+ }
else if (nlmh->nlmsg_type == NLMSG_DONE)
/* We found the end, leave the loop. */
done = true;
@@ -269,20 +327,15 @@ make_request (int fd, pid_t pid)
}
while (! done);
- struct cached_data *result;
- if (seen_ipv6 && in6ailist != NULL)
+ if (seen_ipv6)
+ {
+ if (result == NULL && in6ailist != NULL)
{
result = malloc (sizeof (*result)
+ in6ailistlen * sizeof (struct in6addrinfo));
if (result == NULL)
goto out_fail;
- result->timestamp = get_nl_timestamp ();
- result->usecnt = 2;
- result->seen_ipv4 = seen_ipv4;
- result->seen_ipv6 = true;
- result->in6ailen = in6ailistlen;
-
do
{
result->in6ai[--in6ailistlen] = in6ailist->info;
@@ -290,9 +343,29 @@ make_request (int fd, pid_t pid)
}
while (in6ailist != NULL);
}
+
+#ifdef IS_IN_nscd
+ result->timestamp = nl_timestamp;
+ result->usecnt = 2;
+#elif defined(USE_NSCD)
+ result->timestamp = __nscd_get_nl_timestamp ();
+ result->usecnt = 2;
+#else
+ result->usecnt = 1;
+#endif
+ result->seen_ipv4 = seen_ipv4;
+ result->seen_ipv6 = true;
+ result->in6ailen = in6ailistlen;
+ }
else
{
+ if (result)
+ free (result);
+#if defined(IS_IN_nscd) || defined(USE_NSCD)
atomic_add (&noai6ai_cached.usecnt, 2);
+#else
+ atomic_add (&noai6ai_cached.usecnt, 1);
+#endif
noai6ai_cached.seen_ipv4 = seen_ipv4;
noai6ai_cached.seen_ipv6 = seen_ipv6;
result = &noai6ai_cached;
@@ -305,6 +378,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