This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH v2 1/3] Fix __check_pf()/make_request() stack overflow segfault (convert to malloc)
- From: OndÅej BÃlka <neleai at seznam dot cz>
- To: Debabrata Banerjee <dbanerje at akamai dot com>
- Cc: libc-alpha at sourceware dot org, Carlos O'Donell <carlos at redhat dot com>
- Date: Thu, 16 Jan 2014 23:53:41 +0100
- Subject: [PATCH v2 1/3] Fix __check_pf()/make_request() stack overflow segfault (convert to malloc)
- Authentication-results: sourceware.org; auth=none
- References: <524E4504 dot 6050603 at redhat dot com> <1383268213-14349-1-git-send-email-dbanerje at akamai dot com>
On Thu, Oct 31, 2013 at 09:10:11PM -0400, Debabrata Banerjee wrote:
> Tested calls to getaddrinfo() with 64k+ local IPv4 and IPv6 addresses.
>
> Changelog:
>
> 2013-10-31 Debabrata Banerjee <dbanerje@akamai.com>
>
As that patch was quite large and there is not much time if we want this
in 2.19 we should use a simpler patch. I wrote new patch that uses
malloc instead.
[BZ #16002]
* sysdeps/unix/sysv/linux/check_pf.c (make_request): Use malloc for
allocations.
diff --git a/sysdeps/unix/sysv/linux/check_pf.c b/sysdeps/unix/sysv/linux/check_pf.c
index dd333b4..e9510cb 100644
--- a/sysdeps/unix/sysv/linux/check_pf.c
+++ b/sysdeps/unix/sysv/linux/check_pf.c
@@ -102,6 +102,11 @@ cache_valid_p (void)
return false;
}
+struct freeable_data
+{
+ struct freeable_data *next;
+ char data[];
+};
static struct cached_data *
make_request (int fd, pid_t pid)
@@ -116,6 +121,7 @@ make_request (int fd, pid_t pid)
char pad[3];
} req;
struct sockaddr_nl nladdr;
+ struct cached_data *result;
req.nlh.nlmsg_len = sizeof (req);
req.nlh.nlmsg_type = RTM_GETADDR;
@@ -137,19 +143,16 @@ make_request (int fd, pid_t pid)
#else
const size_t buf_size = __getpagesize ();
#endif
- bool use_malloc = false;
char *buf;
- if (__libc_use_alloca (buf_size))
- buf = alloca (buf_size);
- else
- {
- buf = malloc (buf_size);
- if (buf != NULL)
- use_malloc = true;
- else
- goto out_fail;
- }
+ /* A linked list of allocations that we need to free at exit from function. */
+
+ struct freeable_data *freeable_data_root = NULL;
+ struct freeable_data *freeable_data_next = NULL;
+
+ buf = malloc (buf_size);
+ if (buf == NULL)
+ goto out_fail;
struct iovec iov = { buf, buf_size };
@@ -239,7 +242,13 @@ make_request (int fd, pid_t pid)
}
}
- struct in6ailist *newp = alloca (sizeof (*newp));
+ freeable_data_next = malloc (sizeof (struct freeable_data)
+ + sizeof (struct in6ailist));
+
+ freeable_data_next->next = freeable_data_root;
+ freeable_data_root = freeable_data_next;
+ struct in6ailist *newp = (struct in6ailist *) freeable_data_next->data;
+
newp->info.flags = (((ifam->ifa_flags
& (IFA_F_DEPRECATED
| IFA_F_OPTIMISTIC))
@@ -269,7 +278,6 @@ make_request (int fd, pid_t pid)
}
while (! done);
- struct cached_data *result;
if (seen_ipv6 && in6ailist != NULL)
{
result = malloc (sizeof (*result)
@@ -298,14 +306,21 @@ make_request (int fd, pid_t pid)
result = &noai6ai_cached;
}
- if (use_malloc)
- free (buf);
- return result;
+fail_cnt:
+
+ while (freeable_data_root)
+ {
+ freeable_data_next = freeable_data_root->next;
+ free (freeable_data_root);
+ freeable_data_root = freeable_data_next;
+ }
+
+ free (buf);
+ return result;
out_fail:
- if (use_malloc)
- free (buf);
- return NULL;
+ result = NULL;
+ goto fail_cnt;
}