From b5bf9a135808b579f659d73e6048dd86bc6db903 Mon Sep 17 00:00:00 2001 From: "jln@chromium.org" Date: Tue, 15 Jan 2013 20:16:33 +0000 Subject: TCMalloc: restrict maximum size of memory allocations For security purposes, we restrict the maximum size of memory allocations under what can be indexed by an int. BUG=169327 NOTRY=true Review URL: https://chromiumcodereview.appspot.com/11857007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@176961 0039d316-1c4b-4281-b951-d872f2087c98 --- base/base.gyp | 1 + base/security_unittest.cc | 103 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+) create mode 100644 base/security_unittest.cc (limited to 'base') diff --git a/base/base.gyp b/base/base.gyp index 08cf7f4..f650f56 100644 --- a/base/base.gyp +++ b/base/base.gyp @@ -527,6 +527,7 @@ 'rand_util_unittest.cc', 'scoped_native_library_unittest.cc', 'scoped_observer.h', + 'security_unittest.cc', 'sequence_checker_unittest.cc', 'sequence_checker_impl_unittest.cc', 'sha1_unittest.cc', diff --git a/base/security_unittest.cc b/base/security_unittest.cc new file mode 100644 index 0000000..11e871b --- /dev/null +++ b/base/security_unittest.cc @@ -0,0 +1,103 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include +#include +#include + +#include +#include + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "testing/gtest/include/gtest/gtest.h" + +using std::nothrow; + +namespace { + +// 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 +// - ADDRESS_SANITIZER because it has its own memory allocator +// - IOS does not seem to honor nothrow in new properly +// - OS_MACOSX does not use tcmalloc +#if !defined(NO_TCMALLOC) && !defined(ADDRESS_SANITIZER) && \ + !defined(OS_IOS) && !defined(OS_MACOSX) + #define ALLOC_TEST(function) function +#else + #define ALLOC_TEST(function) DISABLED_##function +#endif + +// TODO(jln): switch to std::numeric_limits::max() when we switch to +// C++11. +const size_t kTooBigAllocSize = INT_MAX; + +// Detect runtime TCMalloc bypasses. +bool IsTcMallocBypassed() { +#if defined(OS_LINUX) || defined(OS_CHROMEOS) + // This should detect a TCMalloc bypass from Valgrind. + char* g_slice = getenv("G_SLICE"); + if (g_slice && !strcmp(g_slice, "always-malloc")) + return true; +#endif + return false; +} + +// Fake test that allow to know the state of TCMalloc by looking at bots. +TEST(SecurityTest, ALLOC_TEST(IsTCMallocDynamicallyBypassed)) { + printf("Malloc is dynamically bypassed: %s\n", + IsTcMallocBypassed() ? "yes." : "no."); +} + +TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsMalloc)) { + if (!IsTcMallocBypassed()) { + scoped_ptr + ptr(static_cast(malloc(kTooBigAllocSize))); + ASSERT_TRUE(ptr == NULL); + } +} + +TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsCalloc)) { + if (!IsTcMallocBypassed()) { + scoped_ptr + ptr(static_cast(calloc(kTooBigAllocSize, 1))); + ASSERT_TRUE(ptr == NULL); + } +} + +TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsRealloc)) { + if (!IsTcMallocBypassed()) { + char* orig_ptr = static_cast(malloc(1)); + ASSERT_TRUE(orig_ptr != NULL); + scoped_ptr + ptr(static_cast(realloc(orig_ptr, kTooBigAllocSize))); + ASSERT_TRUE(ptr == NULL); + // If realloc() did not succeed, we need to free orig_ptr. + free(orig_ptr); + } +} + +typedef struct { + char large_array[kTooBigAllocSize]; +} VeryLargeStruct; + +TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNew)) { + if (!IsTcMallocBypassed()) { + scoped_ptr ptr(new (nothrow) VeryLargeStruct); + ASSERT_TRUE(ptr == NULL); + } +} + +TEST(SecurityTest, ALLOC_TEST(MemoryAllocationRestrictionsNewArray)) { + if (!IsTcMallocBypassed()) { + scoped_array ptr(new (nothrow) char[kTooBigAllocSize]); + ASSERT_TRUE(ptr == NULL); + } +} + +} // namespace -- cgit v1.1