1 // Copyright 2013 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <fcntl.h>
6 #include <stddef.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/stat.h>
11 #include <sys/types.h>
12
13 #include <algorithm>
14 #include <limits>
15 #include <memory>
16
17 #include "base/files/file_util.h"
18 #include "base/memory/free_deleter.h"
19 #include "base/sanitizer_buildflags.h"
20 #include "build/build_config.h"
21 #include "partition_alloc/partition_alloc_buildflags.h"
22 #include "testing/gtest/include/gtest/gtest.h"
23
24 #if BUILDFLAG(IS_POSIX)
25 #include <sys/mman.h>
26 #include <unistd.h>
27 #endif
28
29 using std::nothrow;
30 using std::numeric_limits;
31
32 namespace {
33
34 // This function acts as a compiler optimization barrier. We use it to
35 // prevent the compiler from making an expression a compile-time constant.
36 // We also use it so that the compiler doesn't discard certain return values
37 // as something we don't need (see the comment with calloc below).
38 template <typename Type>
HideValueFromCompiler(Type value)39 NOINLINE Type HideValueFromCompiler(Type value) {
40 #if defined(__GNUC__)
41 // In a GCC compatible compiler (GCC or Clang), make this compiler barrier
42 // more robust.
43 __asm__ volatile ("" : "+r" (value));
44 #endif // __GNUC__
45 return value;
46 }
47
48 // There are platforms where these tests are known to fail. We would like to
49 // be able to easily check the status on the bots, but marking tests as
50 // FAILS_ is too clunky.
OverflowTestsSoftExpectTrue(bool overflow_detected)51 void OverflowTestsSoftExpectTrue(bool overflow_detected) {
52 if (!overflow_detected) {
53 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_ANDROID) || \
54 BUILDFLAG(IS_APPLE)
55 // Sadly, on Linux, Android, and OSX we don't have a good story yet. Don't
56 // fail the test, but report.
57 printf("Platform has overflow: %s\n",
58 !overflow_detected ? "yes." : "no.");
59 #else
60 // Otherwise, fail the test. (Note: EXPECT are ok in subfunctions, ASSERT
61 // aren't).
62 EXPECT_TRUE(overflow_detected);
63 #endif
64 }
65 }
66
67 #if BUILDFLAG(IS_APPLE) || defined(ADDRESS_SANITIZER) || \
68 defined(THREAD_SANITIZER) || defined(MEMORY_SANITIZER) || \
69 BUILDFLAG(IS_HWASAN) || BUILDFLAG(USE_PARTITION_ALLOC_AS_MALLOC)
70 #define MAYBE_NewOverflow DISABLED_NewOverflow
71 #else
72 #define MAYBE_NewOverflow NewOverflow
73 #endif
74 // Test that array[TooBig][X] and array[X][TooBig] allocations fail and not
75 // succeed with the wrong size allocation in case of size_t overflow. This
76 // test is disabled on environments that operator new (nothrow) crashes in
77 // case of size_t overflow.
78 //
79 // - iOS doesn't honor nothrow.
80 // - XSan aborts when operator new returns nullptr.
81 // - PartitionAlloc crashes by design when size_t overflows.
82 //
83 // TODO(https://crbug.com/927179): Fix the test on Mac.
TEST(SecurityTest,MAYBE_NewOverflow)84 TEST(SecurityTest, MAYBE_NewOverflow) {
85 const size_t kArraySize = 4096;
86 // We want something "dynamic" here, so that the compiler doesn't
87 // immediately reject crazy arrays.
88 [[maybe_unused]] const size_t kDynamicArraySize =
89 HideValueFromCompiler(kArraySize);
90 const size_t kMaxSizeT = std::numeric_limits<size_t>::max();
91 const size_t kArraySize2 = kMaxSizeT / kArraySize + 10;
92 const size_t kDynamicArraySize2 = HideValueFromCompiler(kArraySize2);
93 {
94 std::unique_ptr<char[][kArraySize]> array_pointer(
95 new (nothrow) char[kDynamicArraySize2][kArraySize]);
96 // Prevent clang from optimizing away the whole test.
97 char* volatile p = reinterpret_cast<char*>(array_pointer.get());
98 OverflowTestsSoftExpectTrue(!p);
99 }
100 #if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS)
101 // On Windows, the compiler prevents static array sizes of more than
102 // 0x7fffffff (error C2148).
103 #else
104 {
105 std::unique_ptr<char[][kArraySize2]> array_pointer(
106 new (nothrow) char[kDynamicArraySize][kArraySize2]);
107 // Prevent clang from optimizing away the whole test.
108 char* volatile p = reinterpret_cast<char*>(array_pointer.get());
109 OverflowTestsSoftExpectTrue(!p);
110 }
111 #endif // BUILDFLAG(IS_WIN) && defined(ARCH_CPU_64_BITS)
112 }
113
114 } // namespace
115