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