diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-25 22:47:12 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-01-25 22:47:12 +0000 |
commit | 9dd40c83ae92697e834c726b4eb0754ac04217a0 (patch) | |
tree | 4e0f8074ab965b0bf2e8cb78f36b4765aa1b0b8c /base/security_unittest.cc | |
parent | 6ef0c391fe92b35b42f291a61f7c4608bc80c023 (diff) | |
download | chromium_src-9dd40c83ae92697e834c726b4eb0754ac04217a0.zip chromium_src-9dd40c83ae92697e834c726b4eb0754ac04217a0.tar.gz chromium_src-9dd40c83ae92697e834c726b4eb0754ac04217a0.tar.bz2 |
Base: add a security test to check for new[] or calloc()
overflowing
BUG=172149
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/12033064
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@178928 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/security_unittest.cc')
-rw-r--r-- | base/security_unittest.cc | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/base/security_unittest.cc b/base/security_unittest.cc index 5db18fd..483d2a8 100644 --- a/base/security_unittest.cc +++ b/base/security_unittest.cc @@ -14,6 +14,7 @@ #include "testing/gtest/include/gtest/gtest.h" using std::nothrow; +using std::numeric_limits; namespace { @@ -100,4 +101,94 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { } } +// The tests bellow check for overflows in new[] and calloc(). + +#if defined(OS_IOS) + #define DISABLE_ON_IOS(function) DISABLED_##function +#else + #define DISABLE_ON_IOS(function) function +#endif + +#if defined(ADDRESS_SANITIZER) + #define DISABLE_ON_ASAN(function) DISABLED_##function +#else + #define DISABLE_ON_ASAN(function) function +#endif + +// There are platforms where these tests are known to fail. We would like to +// be able to easily check the status on the bots, but marking tests as +// FAILS_ is too clunky. +void OverflowTestsSoftExpectTrue(bool overflow_detected) { + if (!overflow_detected) { +#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) + // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't + // fail the test, but report. + printf("Platform has overflow: %s\n", + !overflow_detected ? "yes." : "no."); +#else + // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT + // aren't). + EXPECT_TRUE(overflow_detected); +#endif + } +} + +// This function acts as a compiler optimization barrier. We use it to +// prevent the compiler from making an expression a compile-time constant. +// We also use it so that the compiler doesn't discard certain return values +// as something we don't need (see the comment with calloc below). +template <typename Type> +Type HideValueFromCompiler(volatile Type value) { + return value; +} + +// Test array[TooBig][X] and array[X][TooBig] allocations for int overflows. +// IOS doesn't honor nothrow, so disable the test there. +TEST(SecurityTest, DISABLE_ON_IOS(NewOverflow)) { + const size_t kArraySize = 4096; + // We want something "dynamic" here, so that the compiler doesn't + // immediately reject crazy arrays. + const size_t kDynamicArraySize = HideValueFromCompiler(kArraySize); + // numeric_limits are still not constexpr until we switch to C++11, so we + // use an ugly cast. + const size_t kMaxSizeT = ~static_cast<size_t>(0); + ASSERT_EQ(numeric_limits<size_t>::max(), kMaxSizeT); + const size_t kArraySize2 = kMaxSizeT / kArraySize + 10; + const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2); + { + scoped_ptr<char[][kArraySize]> array_pointer(new (nothrow) + char[kDynamicArraySize2][kArraySize]); + OverflowTestsSoftExpectTrue(array_pointer == NULL); + } + { + scoped_ptr<char[][kArraySize2]> array_pointer(new (nothrow) + char[kDynamicArraySize][kArraySize2]); + OverflowTestsSoftExpectTrue(array_pointer == NULL); + } +} + +// Test if calloc() can overflow. Disable on ASAN for now since the +// overflow seems present there. +TEST(SecurityTest, DISABLE_ON_ASAN(CallocOverflow)) { + const size_t kArraySize = 4096; + const size_t kMaxSizeT = numeric_limits<size_t>::max(); + const size_t kArraySize2 = kMaxSizeT / kArraySize + 10; + { + scoped_ptr<char> array_pointer( + static_cast<char*>(calloc(kArraySize, kArraySize2))); + // We need the call to HideValueFromCompiler(): we have seen LLVM + // optimize away the call to calloc() entirely and assume + // the pointer to not be NULL. + EXPECT_TRUE(HideValueFromCompiler(array_pointer.get()) == NULL); + } + { + scoped_ptr<char> array_pointer( + static_cast<char*>(calloc(kArraySize2, kArraySize))); + // We need the call to HideValueFromCompiler(): we have seen LLVM + // optimize away the call to calloc() entirely and assume + // the pointer to not be NULL. + EXPECT_TRUE(HideValueFromCompiler(array_pointer.get()) == NULL); + } +} + } // namespace |