You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
144 lines
5.1 KiB
144 lines
5.1 KiB
commit af37a8a3496327a6e5617a2c76f17aa1e8db835e |
|
Author: Siddhesh Poyarekar <siddhesh@redhat.com> |
|
Date: Mon Jan 27 11:32:44 2014 +0530 |
|
|
|
Avoid undefined behaviour in netgroupcache |
|
|
|
Using a buffer after it has been reallocated is undefined behaviour, |
|
so get offsets of the triplets in the old buffer before reallocating |
|
it. |
|
|
|
commit 5d41dadf31bc8a2f9c34c40d52a442d3794e405c |
|
Author: Siddhesh Poyarekar <siddhesh@redhat.com> |
|
Date: Fri Jan 24 13:51:15 2014 +0530 |
|
|
|
Adjust pointers to triplets in netgroup query data (BZ #16474) |
|
|
|
The _nss_*_getnetgrent_r query populates the netgroup results in the |
|
allocated buffer and then sets the result triplet to point to strings |
|
in the buffer. This is a problem when the buffer is reallocated since |
|
the pointers to the triplet strings are no longer valid. The pointers |
|
need to be adjusted so that they now point to strings in the |
|
reallocated buffer. |
|
|
|
commit 980cb5180e1b71224a57ca52b995c959b7148c09 |
|
Author: Siddhesh Poyarekar <siddhesh@redhat.com> |
|
Date: Thu Jan 16 10:20:22 2014 +0530 |
|
|
|
Don't use alloca in addgetnetgrentX (BZ #16453) |
|
|
|
addgetnetgrentX has a buffer which is grown as per the needs of the |
|
requested size either by using alloca or by falling back to malloc if |
|
the size is larger than 1K. There are two problems with the alloca |
|
bits: firstly, it doesn't really extend the buffer since it does not |
|
use the return value of the extend_alloca macro, which is the location |
|
of the reallocated buffer. Due to this the buffer does not actually |
|
extend itself and hence a subsequent write may overwrite stuff on the |
|
stack. |
|
|
|
The second problem is more subtle - the buffer growth on the stack is |
|
discontinuous due to block scope local variables. Combine that with |
|
the fact that unlike realloc, extend_alloca does not copy over old |
|
content and you have a situation where the buffer just has garbage in |
|
the space where it should have had data. |
|
|
|
This could have been fixed by adding code to copy over old data |
|
whenever we call extend_alloca, but it seems unnecessarily |
|
complicated. This code is not exactly a performance hotspot (it's |
|
called when there is a cache miss, so factors like network lookup or |
|
file reads will dominate over memory allocation/reallocation), so this |
|
premature optimization is unnecessary. |
|
|
|
Thanks Brad Hubbard <bhubbard@redhat.com> for his help with debugging |
|
the problem. |
|
|
|
diff -pruN glibc-2.17-c758a686/nscd/netgroupcache.c glibc-2.17-c758a686/nscd/netgroupcache.c |
|
--- glibc-2.17-c758a686/nscd/netgroupcache.c 2014-04-09 12:13:58.618582111 +0530 |
|
+++ glibc-2.17-c758a686/nscd/netgroupcache.c 2014-04-09 12:07:21.486598665 +0530 |
|
@@ -93,7 +93,6 @@ addgetnetgrentX (struct database_dyn *db |
|
size_t buffilled = sizeof (*dataset); |
|
char *buffer = NULL; |
|
size_t nentries = 0; |
|
- bool use_malloc = false; |
|
size_t group_len = strlen (key) + 1; |
|
union |
|
{ |
|
@@ -138,7 +137,7 @@ addgetnetgrentX (struct database_dyn *db |
|
} |
|
|
|
memset (&data, '\0', sizeof (data)); |
|
- buffer = alloca (buflen); |
|
+ buffer = xmalloc (buflen); |
|
first_needed.elem.next = &first_needed.elem; |
|
memcpy (first_needed.elem.name, key, group_len); |
|
data.needed_groups = &first_needed.elem; |
|
@@ -218,21 +217,24 @@ addgetnetgrentX (struct database_dyn *db |
|
|
|
if (buflen - req->key_len - bufused < needed) |
|
{ |
|
- size_t newsize = MAX (2 * buflen, |
|
- buflen + 2 * needed); |
|
- if (use_malloc || newsize > 1024 * 1024) |
|
- { |
|
- buflen = newsize; |
|
- char *newbuf = xrealloc (use_malloc |
|
- ? buffer |
|
- : NULL, |
|
- buflen); |
|
- |
|
- buffer = newbuf; |
|
- use_malloc = true; |
|
- } |
|
- else |
|
- extend_alloca (buffer, buflen, newsize); |
|
+ buflen += MAX (buflen, 2 * needed); |
|
+ /* Save offset in the old buffer. We don't |
|
+ bother with the NULL check here since |
|
+ we'll do that later anyway. */ |
|
+ size_t nhostdiff = nhost - buffer; |
|
+ size_t nuserdiff = nuser - buffer; |
|
+ size_t ndomaindiff = ndomain - buffer; |
|
+ |
|
+ char *newbuf = xrealloc (buffer, buflen); |
|
+ /* Fix up the triplet pointers into the new |
|
+ buffer. */ |
|
+ nhost = (nhost ? newbuf + nhostdiff |
|
+ : NULL); |
|
+ nuser = (nuser ? newbuf + nuserdiff |
|
+ : NULL); |
|
+ ndomain = (ndomain ? newbuf + ndomaindiff |
|
+ : NULL); |
|
+ buffer = newbuf; |
|
} |
|
|
|
nhost = memcpy (buffer + bufused, |
|
@@ -299,18 +301,8 @@ addgetnetgrentX (struct database_dyn *db |
|
} |
|
else if (status == NSS_STATUS_UNAVAIL && e == ERANGE) |
|
{ |
|
- size_t newsize = 2 * buflen; |
|
- if (use_malloc || newsize > 1024 * 1024) |
|
- { |
|
- buflen = newsize; |
|
- char *newbuf = xrealloc (use_malloc |
|
- ? buffer : NULL, buflen); |
|
- |
|
- buffer = newbuf; |
|
- use_malloc = true; |
|
- } |
|
- else |
|
- extend_alloca (buffer, buflen, newsize); |
|
+ buflen *= 2; |
|
+ buffer = xrealloc (buffer, buflen); |
|
} |
|
} |
|
|
|
@@ -446,8 +438,7 @@ addgetnetgrentX (struct database_dyn *db |
|
} |
|
|
|
out: |
|
- if (use_malloc) |
|
- free (buffer); |
|
+ free (buffer); |
|
|
|
*resultp = dataset;
|
|
|