[PATCH] wprintf overflow
Kevin Cernekee
kpc-uclibc at b32.net
Tue Dec 11 19:00:52 PST 2007
Hi,
I am seeing a buffer overflow in uClibc-0.9.28 on mipsel, illustrated by
the following test program:
#include <stdio.h>
#include <wchar.h>
int main(int argc, char **argv)
{
wprintf(L"This line is OK\n");
wprintf(L"This line is no problem either because the format spec
is at the end: %d\n", 1);
wprintf(L"%d: This line will segfault because the format spec is
too far from the end\n", 1);
return(0);
}
In uClibc/libc/stdio/vfprintf.c or _vfprintf.c, function
_ppfs_parsespec(), there is a loop that copies the const wchar_t format
specifier into a char buffer so that it can be parsed using the same code.
However, this loop terminates at the end of the string, rather than the
end of the format spec, causing a buffer overflow for strings in which the
format specifier begins more than 32 characters from the end of the
string.
I don't see any evidence that this has been fixed in the SVN sources, but
admittedly I have not tried building/running them either.
My workaround is attached. A better solution might be to figure out when
the format spec ends, and stop copying at that point. This would allow us
to reinstate the "char != wchar_t" check that errors out if the user puts
a high character in the format spec. Another option would be to just
store a NUL byte and quit copying if a high character is encountered,
letting the format spec parser sort out any issues. Something like:
do {
if(i == sizeof(buf))
break;
if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
!= (((wchar_t *) ppfs->fmtpos)[i-1])
) {
buf[i] = 0;
break;
}
} while (buf[i++]);
-------------- next part --------------
--- uClibc.orig/libc/stdio/vfprintf.c 2007-09-10 18:19:31.000000000 -0700
+++ uClibc/libc/stdio/vfprintf.c 2007-12-11 15:26:09.000000000 -0800
@@ -873,11 +873,27 @@
fmt = buf + 1;
i = 0;
do {
+#if 1
+ /*
+ * WORKAROUND: the original code assumes that the
+ * end of the format specifier is the same as the
+ * end of the format string.
+ *
+ * This workaround prevents the stack overflow, but
+ * we can no longer check to make sure that
+ * the format string doesn't contain characters
+ * outside the normal char range.
+ */
+ if(i == sizeof(buf))
+ break;
+ buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]);
+#else
if ((buf[i] = (char) (((wchar_t *) ppfs->fmtpos)[i-1]))
!= (((wchar_t *) ppfs->fmtpos)[i-1])
) {
return -1;
}
+#endif
} while (buf[i++]);
buf[sizeof(buf)-1] = 0;
}
More information about the uClibc
mailing list