diff options
author | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-15 06:10:40 +0000 |
---|---|---|
committer | jln@chromium.org <jln@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-15 06:10:40 +0000 |
commit | d6a6cea6231e77f0c92c0528e772c8e5586eb3ff (patch) | |
tree | 75df1fa929f40fe591db7bee12f08c313e0571e6 /base/security_unittest.cc | |
parent | a9a3b59f21d0ae4d1ae10b364adebb5d0649953d (diff) | |
download | chromium_src-d6a6cea6231e77f0c92c0528e772c8e5586eb3ff.zip chromium_src-d6a6cea6231e77f0c92c0528e772c8e5586eb3ff.tar.gz chromium_src-d6a6cea6231e77f0c92c0528e772c8e5586eb3ff.tar.bz2 |
Base: account for calloc aborting in security unittests
On Linux, when not using tcmalloc, we still have a small wrapper
that aborts when allocation functions OOM.
In that configuration, we now We consider it a successful detection
of an overflow condition if the process aborts.
BUG=175500
Review URL: https://chromiumcodereview.appspot.com/12220107
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182628 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/security_unittest.cc')
-rw-r--r-- | base/security_unittest.cc | 79 |
1 files changed, 47 insertions, 32 deletions
diff --git a/base/security_unittest.cc b/base/security_unittest.cc index 59a3ddd..1454003 100644 --- a/base/security_unittest.cc +++ b/base/security_unittest.cc @@ -37,20 +37,15 @@ Type HideValueFromCompiler(volatile Type value) { return value; } -// Check that we can not allocate a memory range that cannot be indexed -// via an int. This is used to mitigate vulnerabilities in libraries that use -// int instead of size_t. -// See crbug.com/169327. - -// - NO_TCMALLOC because we only patched tcmalloc +// - NO_TCMALLOC (should be defined if we compile with linux_use_tcmalloc=0) // - ADDRESS_SANITIZER because it has its own memory allocator -// - IOS does not seem to honor nothrow in new properly +// - IOS does not use tcmalloc // - OS_MACOSX does not use tcmalloc #if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \ !defined(OS_IOS) && !defined(OS_MACOSX) - #define ALLOC_TEST(function) function + #define TCMALLOC_TEST(function) function #else - #define ALLOC_TEST(function) DISABLED_##function + #define TCMALLOC_TEST(function) DISABLED_##function #endif // TODO(jln): switch to std::numeric_limits<int>::max() when we switch to @@ -68,13 +63,28 @@ bool IsTcMallocBypassed() { return false; } +bool CallocDiesOnOOM() { +// The wrapper function in base/process_util_linux.cc that is used when we +// compile without TCMalloc will just die on OOM instead of returning NULL. +#if defined(OS_LINUX) && defined(NO_TCMALLOC) + return true; +#else + return false; +#endif +} + // Fake test that allow to know the state of TCMalloc by looking at bots. -TEST(SecurityTest, ALLOC_TEST(IsTCMallocDynamicallyBypassed)) { +TEST(SecurityTest, TCMALLOC_TEST(IsTCMallocDynamicallyBypassed)) { printf("Malloc is dynamically bypassed: %s\n", IsTcMallocBypassed() ? "yes." : "no."); } -TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { +// The MemoryAllocationRestrictions* tests test that we can not allocate a +// memory range that cannot be indexed via an int. This is used to mitigate +// vulnerabilities in libraries that use int instead of size_t. See +// crbug.com/169327. + +TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { if (!IsTcMallocBypassed()) { scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>( HideValueFromCompiler(malloc(kTooBigAllocSize)))); @@ -82,7 +92,7 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { } } -TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { +TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { if (!IsTcMallocBypassed()) { scoped_ptr<char, base::FreeDeleter> ptr(static_cast<char*>( HideValueFromCompiler(calloc(kTooBigAllocSize, 1)))); @@ -90,7 +100,7 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { } } -TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsRealloc)) { +TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsRealloc)) { if (!IsTcMallocBypassed()) { char* orig_ptr = static_cast<char*>(malloc(1)); ASSERT_TRUE(orig_ptr); @@ -106,7 +116,7 @@ typedef struct { char large_array[kTooBigAllocSize]; } VeryLargeStruct; -TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNew)) { +TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNew)) { if (!IsTcMallocBypassed()) { scoped_ptr<VeryLargeStruct> ptr( HideValueFromCompiler(new (nothrow) VeryLargeStruct)); @@ -114,7 +124,7 @@ TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNew)) { } } -TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { +TEST(SecurityTest, TCMALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { if (!IsTcMallocBypassed()) { scoped_ptr<char[]> ptr( HideValueFromCompiler(new (nothrow) char[kTooBigAllocSize])); @@ -184,27 +194,32 @@ TEST(SecurityTest, DISABLE_ON_IOS_AND_WIN(NewOverflow)) { } #endif +// Call calloc(), eventually free the memory and return whether or not +// calloc() did succeed. +bool CallocReturnsNull(size_t nmemb, size_t size) { + scoped_ptr<char, base::FreeDeleter> array_pointer( + static_cast<char*>(calloc(nmemb, size))); + // 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. + return HideValueFromCompiler(array_pointer.get()) == NULL; +} + // Test if calloc() can overflow. Disable on ASAN for now since the -// overflow seems present there. +// overflow seems present there (crbug.com/175554). 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); + if (!CallocDiesOnOOM()) { + EXPECT_TRUE(CallocReturnsNull(kArraySize, kArraySize2)); + EXPECT_TRUE(CallocReturnsNull(kArraySize2, kArraySize)); + } else { + // It's also ok for calloc to just terminate the process. +#if defined(GTEST_HAS_DEATH_TEST) + EXPECT_DEATH(CallocReturnsNull(kArraySize, kArraySize2), ""); + EXPECT_DEATH(CallocReturnsNull(kArraySize2, kArraySize), ""); +#endif // GTEST_HAS_DEATH_TEST } } @@ -230,7 +245,7 @@ bool ArePointersToSameArea(void* ptr1, void* ptr2, size_t size) { } // Check if TCMalloc uses an underlying random memory allocator. -TEST(SecurityTest, ALLOC_TEST(RandomMemoryAllocations)) { +TEST(SecurityTest, TCMALLOC_TEST(RandomMemoryAllocations)) { if (IsTcMallocBypassed()) return; size_t kPageSize = 4096; // We support x86_64 only. |