Don't allow OS::SNPrint or OS::VSNPrint to return negative values.

If we encounter conditions that would have caused vsnprintf to return
a negative value, then something pretty wild is going on.  We choose
to terminate the vm when this occurs.

This fixes security bug 1745.
Review URL: https://chromiumcodereview.appspot.com//10696165

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@9558 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
turnidge@google.com 2012-07-11 17:54:24 +00:00
parent 1ae72fbd8b
commit 9cbae35238
6 changed files with 43 additions and 12 deletions

View file

@ -5,6 +5,9 @@
# When a spawned isolate throws an uncaught exception, we terminate the vm.
cc/RunLoop_ExceptionChild: Fail
# This test is expected to crash on all platforms.
cc/SNPrint_BadArgs: Crash
[ $arch == x64 ]
cc/IsolateInterrupt: Skip

View file

@ -62,16 +62,21 @@ class OS {
static void PrintErr(const char* format, ...);
static void VFPrint(FILE* stream, const char* format, va_list args);
// Print formatted output info a buffer.
//
// Does not write more than size characters (including the trailing '\0').
// Returns the number of characters (excluding the trailing '\0') that would
// been written if the buffer had been big enough.
// If the return value is greater or equal than the given size then the output
// has been truncated.
// The buffer will always be terminated by a '\0', unless the buffer is of
// size 0.
// The buffer might be NULL if the size is 0.
// This specification conforms to C99 standard which is implemented by
// glibc 2.1+.
//
// Returns the number of characters (excluding the trailing '\0')
// that would been written if the buffer had been big enough. If
// the return value is greater or equal than the given size then the
// output has been truncated. The return value is never negative.
//
// The buffer will always be terminated by a '\0', unless the buffer
// is of size 0. The buffer might be NULL if the size is 0.
//
// This specification conforms to C99 standard which is implemented
// by glibc 2.1+ with one exception: the C99 standard allows a
// negative return value. We will terminate the vm rather than let
// that occur.
static int SNPrint(char* str, size_t size, const char* format, ...);
static int VSNPrint(char* str, size_t size,
const char* format,

View file

@ -153,7 +153,11 @@ int OS::SNPrint(char* str, size_t size, const char* format, ...) {
int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
return vsnprintf(str, size, format, args);
int retval = vsnprintf(str, size, format, args);
if (retval < 0) {
FATAL1("Fatal error in OS::VSNPrint with format '%s'", format);
}
return retval;
}

View file

@ -128,7 +128,11 @@ int OS::SNPrint(char* str, size_t size, const char* format, ...) {
int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
return vsnprintf(str, size, format, args);
int retval = vsnprintf(str, size, format, args);
if (retval < 0) {
FATAL1("Fatal error in OS::VSNPrint with format '%s'", format);
}
return retval;
}

View file

@ -38,6 +38,14 @@ UNIT_TEST_CASE(SNPrint) {
}
// This test is expected to crash when it runs.
UNIT_TEST_CASE(SNPrint_BadArgs) {
int width = kMaxInt32;
int num = 7;
OS::SNPrint(NULL, 0, "%*d%*d", width, num, width, num);
}
UNIT_TEST_CASE(OsFuncs) {
EXPECT(Utils::IsPowerOfTwo(OS::ActivationFrameAlignment()));
EXPECT(Utils::IsPowerOfTwo(OS::PreferredCodeAlignment()));

View file

@ -155,7 +155,11 @@ int OS::SNPrint(char* str, size_t size, const char* format, ...) {
int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
if (str == NULL || size == 0) {
return _vscprintf(format, args);
int retval = _vscprintf(format, args);
if (retval < 0) {
FATAL1("Fatal error in OS::VSNPrint with format '%s'", format);
}
return retval;
}
va_list args_copy;
va_copy(args_copy, args);
@ -168,6 +172,9 @@ int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
va_list args_retry;
va_copy(args_retry, args);
written = _vscprintf(format, args_retry);
if (written < 0) {
FATAL1("Fatal error in OS::VSNPrint with format '%s'", format);
}
va_end(args_retry);
}
// Make sure to zero-terminate the string if the output was