1 /*
2 * Copyright (C) 2021 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29 #include <gtest/gtest.h>
30 #include <stdio.h>
31 #include <sys/file.h>
32 #include <string>
33
34 #if defined(__BIONIC__)
35
36 #include "android-base/file.h"
37 #include "android-base/silent_death_test.h"
38 #include "android-base/test_utils.h"
39 #include "gwp_asan/options.h"
40 #include "platform/bionic/malloc.h"
41 #include "sys/system_properties.h"
42 #include "utils.h"
43
44 using gwp_asan_integration_DeathTest = SilentDeathTest;
45
46 // basename is a mess, use gnu basename explicitly to avoid the need for string
47 // mutation.
48 extern "C" const char* __gnu_basename(const char* path);
49
50 // GWP-ASan tests can run much slower, especially when combined with HWASan.
51 // Triple the deadline to avoid flakes (b/238585984).
GetInitialArgs(const char *** args,size_t * num_args)52 extern "C" bool GetInitialArgs(const char*** args, size_t* num_args) {
53 static const char* initial_args[] = {"--deadline_threshold_ms=270000"};
54 *args = initial_args;
55 *num_args = 1;
56 return true;
57 }
58
59 // This file implements "torture testing" under GWP-ASan, where we sample every
60 // single allocation. The upper limit for the number of GWP-ASan allocations in
61 // the torture mode is is generally 40,000, so that svelte devices don't
62 // explode, as this uses ~163MiB RAM (4KiB per live allocation).
TEST(gwp_asan_integration,malloc_tests_under_torture)63 TEST(gwp_asan_integration, malloc_tests_under_torture) {
64 // Do not override HWASan with GWP ASan.
65 SKIP_WITH_HWASAN;
66
67 RunGwpAsanTest("malloc.*:-malloc.mallinfo*");
68 }
69
70 class SyspropRestorer {
71 private:
72 std::vector<std::pair<std::string, std::string>> props_to_restore_;
73 // System properties are global for a device, so the tests that mutate the
74 // GWP-ASan system properties must be run mutually exclusive. Because
75 // bionic-unit-tests is run in an isolated gtest fashion (each test is run in
76 // its own process), we have to use flocks to synchronise between tests.
77 int flock_fd_;
78
79 public:
SyspropRestorer()80 SyspropRestorer() {
81 std::string path = testing::internal::GetArgvs()[0];
82 flock_fd_ = open(path.c_str(), O_RDONLY);
83 EXPECT_NE(flock_fd_, -1) << "failed to open self for a flock";
84 EXPECT_NE(flock(flock_fd_, LOCK_EX), -1) << "failed to flock myself";
85
86 const char* basename = __gnu_basename(path.c_str());
87 std::vector<std::string> props = {
88 std::string("libc.debug.gwp_asan.sample_rate.") + basename,
89 std::string("libc.debug.gwp_asan.process_sampling.") + basename,
90 std::string("libc.debug.gwp_asan.max_allocs.") + basename,
91 "libc.debug.gwp_asan.sample_rate.system_default",
92 "libc.debug.gwp_asan.sample_rate.app_default",
93 "libc.debug.gwp_asan.process_sampling.system_default",
94 "libc.debug.gwp_asan.process_sampling.app_default",
95 "libc.debug.gwp_asan.max_allocs.system_default",
96 "libc.debug.gwp_asan.max_allocs.app_default",
97 };
98
99 size_t base_props_size = props.size();
100 for (size_t i = 0; i < base_props_size; ++i) {
101 props.push_back("persist." + props[i]);
102 }
103
104 std::string reset_log;
105
106 for (const std::string& prop : props) {
107 std::string value = GetSysprop(prop);
108 props_to_restore_.emplace_back(prop, value);
109 if (!value.empty()) {
110 __system_property_set(prop.c_str(), "");
111 }
112 }
113 }
114
~SyspropRestorer()115 ~SyspropRestorer() {
116 for (const auto& kv : props_to_restore_) {
117 if (kv.second != GetSysprop(kv.first)) {
118 __system_property_set(kv.first.c_str(), kv.second.c_str());
119 }
120 }
121 close(flock_fd_);
122 }
123
GetSysprop(const std::string & name)124 static std::string GetSysprop(const std::string& name) {
125 std::string value;
126 const prop_info* pi = __system_property_find(name.c_str());
127 if (pi == nullptr) return value;
128 __system_property_read_callback(
129 pi,
130 [](void* cookie, const char* /* name */, const char* value, uint32_t /* serial */) {
131 std::string* v = static_cast<std::string*>(cookie);
132 *v = value;
133 },
134 &value);
135 return value;
136 }
137 };
138
TEST_F(gwp_asan_integration_DeathTest,DISABLED_assert_gwp_asan_enabled)139 TEST_F(gwp_asan_integration_DeathTest, DISABLED_assert_gwp_asan_enabled) {
140 std::string maps;
141 EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
142 EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
143
144 volatile int* x = new int;
145 delete x;
146 EXPECT_DEATH({ *x = 7; }, "");
147 }
148
149 // A weaker version of the above tests, only checking that GWP-ASan is enabled
150 // for any pointer, not *our* pointer. This allows us to test the system_default
151 // sysprops without potentially OOM-ing other random processes:
152 // b/273904016#comment5
TEST(gwp_asan_integration,DISABLED_assert_gwp_asan_enabled_weaker)153 TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_enabled_weaker) {
154 std::string maps;
155 EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
156 EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
157 }
158
TEST(gwp_asan_integration,DISABLED_assert_gwp_asan_disabled)159 TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_disabled) {
160 std::string maps;
161 EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
162 EXPECT_TRUE(maps.find("GWP-ASan") == std::string::npos);
163 }
164
TEST(gwp_asan_integration,sysprops_program_specific)165 TEST(gwp_asan_integration, sysprops_program_specific) {
166 // Do not override HWASan with GWP ASan.
167 SKIP_WITH_HWASAN;
168
169 SyspropRestorer restorer;
170
171 std::string path = testing::internal::GetArgvs()[0];
172 const char* basename = __gnu_basename(path.c_str());
173 __system_property_set((std::string("libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
174 __system_property_set((std::string("libc.debug.gwp_asan.process_sampling.") + basename).c_str(),
175 "1");
176 __system_property_set((std::string("libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
177 "40000");
178
179 RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
180 }
181
TEST(gwp_asan_integration,sysprops_persist_program_specific)182 TEST(gwp_asan_integration, sysprops_persist_program_specific) {
183 // Do not override HWASan with GWP ASan.
184 SKIP_WITH_HWASAN;
185
186 SyspropRestorer restorer;
187
188 std::string path = testing::internal::GetArgvs()[0];
189 const char* basename = __gnu_basename(path.c_str());
190 __system_property_set(
191 (std::string("persist.libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
192 __system_property_set(
193 (std::string("persist.libc.debug.gwp_asan.process_sampling.") + basename).c_str(), "1");
194 __system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
195 "40000");
196
197 RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
198 }
199
TEST(gwp_asan_integration,sysprops_non_persist_overrides_persist)200 TEST(gwp_asan_integration, sysprops_non_persist_overrides_persist) {
201 // Do not override HWASan with GWP ASan.
202 SKIP_WITH_HWASAN;
203
204 SyspropRestorer restorer;
205
206 __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "1");
207 __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "1");
208 // Note, any processes launched elsewhere on the system right now will have
209 // GWP-ASan enabled. Make sure that we only use a single slot, otherwise we
210 // could end up causing said badly-timed processes to use up to 163MiB extra
211 // penalty that 40,000 allocs would cause. See b/273904016#comment5 for more
212 // context.
213 __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "1");
214
215 __system_property_set("persist.libc.debug.gwp_asan.sample_rate.system_default", "0");
216 __system_property_set("persist.libc.debug.gwp_asan.process_sampling.system_default", "0");
217 __system_property_set("persist.libc.debug.gwp_asan.max_allocs.system_default", "0");
218
219 RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled_weaker");
220 }
221
TEST(gwp_asan_integration,sysprops_program_specific_overrides_default)222 TEST(gwp_asan_integration, sysprops_program_specific_overrides_default) {
223 // Do not override HWASan with GWP ASan.
224 SKIP_WITH_HWASAN;
225
226 SyspropRestorer restorer;
227
228 std::string path = testing::internal::GetArgvs()[0];
229 const char* basename = __gnu_basename(path.c_str());
230 __system_property_set(
231 (std::string("persist.libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
232 __system_property_set(
233 (std::string("persist.libc.debug.gwp_asan.process_sampling.") + basename).c_str(), "1");
234 __system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
235 "40000");
236
237 __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
238 __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
239 __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
240
241 RunSubtestNoEnv("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
242 }
243
TEST(gwp_asan_integration,sysprops_can_disable)244 TEST(gwp_asan_integration, sysprops_can_disable) {
245 // Do not override HWASan with GWP ASan.
246 SKIP_WITH_HWASAN;
247
248 SyspropRestorer restorer;
249
250 __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
251 __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
252 __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
253
254 RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_disabled");
255 }
256
TEST(gwp_asan_integration,env_overrides_sysprop)257 TEST(gwp_asan_integration, env_overrides_sysprop) {
258 // Do not override HWASan with GWP ASan.
259 SKIP_WITH_HWASAN;
260
261 SyspropRestorer restorer;
262
263 __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
264 __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
265 __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
266
267 RunGwpAsanTest("gwp_asan_integration_DeathTest.DISABLED_assert_gwp_asan_enabled");
268 }
269
270 #endif // defined(__BIONIC__)
271