[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Bug-gnulib] fnmatch fixes to avoid alloca overflow, address arithmetic
From: |
Paul Eggert |
Subject: |
[Bug-gnulib] fnmatch fixes to avoid alloca overflow, address arithmetic overflow |
Date: |
15 Oct 2003 23:55:33 -0700 |
User-agent: |
Gnus/5.09 (Gnus v5.9.0) Emacs/21.3 |
I installed the following patch to fix address arithmetic overflow
bugs in gnulib's copy of fnmatch. This stuff should be migrated back
into libc at some point, of course.
2003-10-15 Paul Eggert <address@hidden>
* fnmatch.c (SIZE_MAX): Define if standard headers don't.
(fnmatch): Do not alloca more than 2000 wide characters;
instead, use malloc for large buffers.
Check for address arithmetic overflow, and return -1
with errno set to ENOMEM in that case.
* fnmatch_loop.c (ALLOCA_LIMIT): New macro.
(NEW_PATTERN): Do not alloca more than 8000 bytes;
instead, return -1. Check for address arithmetic overflow.
Index: lib/fnmatch.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/fnmatch.c,v
retrieving revision 1.24
diff -p -u -r1.24 fnmatch.c
--- lib/fnmatch.c 9 Sep 2003 06:48:57 -0000 1.24
+++ lib/fnmatch.c 16 Oct 2003 06:46:27 -0000
@@ -80,6 +80,10 @@ char *alloca ();
extern int fnmatch (const char *pattern, const char *string, int flags);
#endif
+#ifndef SIZE_MAX
+# define SIZE_MAX ((size_t) -1)
+#endif
+
/* We often have to test for FNM_FILE_NAME and FNM_PERIOD being both set. */
#define NO_LEADING_PERIOD(flags) \
((flags & (FNM_FILE_NAME | FNM_PERIOD)) == (FNM_FILE_NAME | FNM_PERIOD))
@@ -318,40 +322,70 @@ int
fnmatch (const char *pattern, const char *string, int flags)
{
# if HANDLE_MULTIBYTE
+# define ALLOCA_LIMIT 2000
if (__builtin_expect (MB_CUR_MAX, 1) != 1)
{
mbstate_t ps;
- size_t n;
+ size_t patsize;
+ size_t strsize;
+ size_t totsize;
wchar_t *wpattern;
wchar_t *wstring;
+ int res;
- /* Convert the strings into wide characters. */
+ /* Calculate the size needed to convert the strings to
+ wide characters. */
memset (&ps, '\0', sizeof (ps));
- n = mbsrtowcs (NULL, &pattern, 0, &ps);
- if (__builtin_expect (n, 0) == (size_t) -1)
+ patsize = mbsrtowcs (NULL, &pattern, 0, &ps) + 1;
+ if (__builtin_expect (patsize == 0, 0))
/* Something wrong.
XXX Do we have to set `errno' to something which mbsrtows hasn't
already done? */
return -1;
- wpattern = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
- assert (mbsinit (&ps));
- (void) mbsrtowcs (wpattern, &pattern, n + 1, &ps);
-
assert (mbsinit (&ps));
- n = mbsrtowcs (NULL, &string, 0, &ps);
- if (__builtin_expect (n, 0) == (size_t) -1)
+ strsize = mbsrtowcs (NULL, &string, 0, &ps) + 1;
+ if (__builtin_expect (strsize == 0, 0))
/* Something wrong.
XXX Do we have to set `errno' to something which mbsrtows hasn't
already done? */
return -1;
- wstring = (wchar_t *) alloca ((n + 1) * sizeof (wchar_t));
assert (mbsinit (&ps));
- (void) mbsrtowcs (wstring, &string, n + 1, &ps);
+ totsize = patsize + strsize;
+ if (__builtin_expect (! (patsize <= totsize
+ && totsize <= SIZE_MAX / sizeof (wchar_t)),
+ 0))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* Allocate room for the wide characters. */
+ if (__builtin_expect (totsize < ALLOCA_LIMIT, 1))
+ wpattern = (wchar_t *) alloca (totsize * sizeof (wchar_t));
+ else
+ {
+ wpattern = malloc (totsize * sizeof (wchar_t));
+ if (__builtin_expect (! wpattern, 0))
+ {
+ errno = ENOMEM;
+ return -1;
+ }
+ }
+ wstring = wpattern + patsize;
+
+ /* Convert the strings into wide characters. */
+ mbsrtowcs (wpattern, &pattern, patsize, &ps);
+ assert (mbsinit (&ps));
+ mbsrtowcs (wstring, &string, strsize, &ps);
+
+ res = internal_fnwmatch (wpattern, wstring, wstring + strsize - 1,
+ flags & FNM_PERIOD, flags);
- return internal_fnwmatch (wpattern, wstring, wstring + n,
- flags & FNM_PERIOD, flags);
+ if (__builtin_expect (! (totsize < ALLOCA_LIMIT), 0))
+ free (wpattern);
+ return res;
}
-# endif /* mbstate_t and mbsrtowcs or _LIBC. */
+# endif /* HANDLE_MULTIBYTE */
return internal_fnmatch (pattern, string, string + strlen (string),
flags & FNM_PERIOD, flags);
Index: lib/fnmatch_loop.c
===================================================================
RCS file: /cvsroot/gnulib/gnulib/lib/fnmatch_loop.c,v
retrieving revision 1.4
diff -p -u -r1.4 fnmatch_loop.c
--- lib/fnmatch_loop.c 9 Sep 2003 06:48:57 -0000 1.4
+++ lib/fnmatch_loop.c 16 Oct 2003 06:46:27 -0000
@@ -1042,16 +1042,23 @@ EXT (INT opt, const CHAR *pattern, const
if (level-- == 0)
{
/* This means we found the end of the pattern. */
+#define ALLOCA_LIMIT 8000
#define NEW_PATTERN \
struct patternlist *newp; \
size_t plen; \
+ size_t plensize; \
+ size_t newpsize; \
\
plen = (opt == L('?') || opt == L('@') \
? pattern_len \
: p - startp + 1); \
- newp = (struct patternlist *) \
- alloca (offsetof (struct patternlist, str) \
- + (plen * sizeof (CHAR))); \
+ plensize = plen * sizeof (CHAR); \
+ newpsize = offsetof (struct patternlist, str) + plensize; \
+ if ((size_t) -1 / sizeof (CHAR) < plen \
+ || newpsize < offsetof (struct patternlist, str) \
+ || ALLOCA_LIMIT <= newpsize) \
+ return -1; \
+ newp = (struct patternlist *) alloca (newpsize); \
*((CHAR *) MEMPCPY (newp->str, startp, p - startp)) = L('\0'); \
newp->next = NULL; \
*lastp = newp; \
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Bug-gnulib] fnmatch fixes to avoid alloca overflow, address arithmetic overflow,
Paul Eggert <=