aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-10-03 23:05:27 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-10-03 23:05:27 +0000
commit70e6053b202d88a666d5242be1809caff7d816f0 (patch)
tree309bf4d1501443a20c23936ac0029e0a5bd84fae
parent35dbeecf0a15d2566dff2125da587ef458277bb9 (diff)
parent23f0befcc2aecabb5fbfd1b2159389eefc9d4018 (diff)
downloadbionic-android13-qpr2-s1-release.tar.gz
Change-Id: I3241535aca435bfcb28242f423d28d37bb0c5a18
-rw-r--r--libc/bionic/gwp_asan_wrappers.cpp41
-rw-r--r--libc/bionic/sysprop_helpers.cpp2
-rw-r--r--tests/Android.bp15
-rw-r--r--tests/gwp_asan_test.cpp206
-rw-r--r--tests/utils.cpp55
-rw-r--r--tests/utils.h2
6 files changed, 282 insertions, 39 deletions
diff --git a/libc/bionic/gwp_asan_wrappers.cpp b/libc/bionic/gwp_asan_wrappers.cpp
index 7e19b311e..fc59c8882 100644
--- a/libc/bionic/gwp_asan_wrappers.cpp
+++ b/libc/bionic/gwp_asan_wrappers.cpp
@@ -41,6 +41,7 @@
#include "gwp_asan_wrappers.h"
#include "malloc_common.h"
#include "platform/bionic/android_unsafe_frame_pointer_chase.h"
+#include "platform/bionic/macros.h"
#include "platform/bionic/malloc.h"
#include "private/bionic_arc4random.h"
#include "private/bionic_globals.h"
@@ -221,6 +222,8 @@ static const char* kMaxAllocsAppSysprop = "libc.debug.gwp_asan.max_allocs.app_de
static const char* kMaxAllocsTargetedSyspropPrefix = "libc.debug.gwp_asan.max_allocs.";
static const char* kMaxAllocsEnvVar = "GWP_ASAN_MAX_ALLOCS";
+static const char kPersistPrefix[] = "persist.";
+
void SetDefaultGwpAsanOptions(Options* options, unsigned* process_sample_rate,
const android_mallopt_gwp_asan_options_t& mallopt_options) {
options->Enabled = true;
@@ -244,26 +247,40 @@ bool GetGwpAsanOption(unsigned long long* result,
const char* basename = "";
if (mallopt_options.program_name) basename = __gnu_basename(mallopt_options.program_name);
- size_t program_specific_sysprop_size = strlen(targeted_sysprop_prefix) + strlen(basename) + 1;
- char* program_specific_sysprop_name = static_cast<char*>(alloca(program_specific_sysprop_size));
- async_safe_format_buffer(program_specific_sysprop_name, program_specific_sysprop_size, "%s%s",
- targeted_sysprop_prefix, basename);
-
- const char* sysprop_names[2] = {nullptr, nullptr};
+ constexpr size_t kSyspropMaxLen = 512;
+ char program_specific_sysprop[kSyspropMaxLen] = {};
+ char persist_program_specific_sysprop[kSyspropMaxLen] = {};
+ char persist_default_sysprop[kSyspropMaxLen] = {};
+ const char* sysprop_names[4] = {};
// Tests use a blank program name to specify that system properties should not
// be used. Tests still continue to use the environment variable though.
if (*basename != '\0') {
- sysprop_names[0] = program_specific_sysprop_name;
+ const char* default_sysprop = system_sysprop;
if (mallopt_options.desire == Action::TURN_ON_FOR_APP) {
- sysprop_names[1] = app_sysprop;
- } else {
- sysprop_names[1] = system_sysprop;
+ default_sysprop = app_sysprop;
}
+ async_safe_format_buffer(&program_specific_sysprop[0], kSyspropMaxLen, "%s%s",
+ targeted_sysprop_prefix, basename);
+ async_safe_format_buffer(&persist_program_specific_sysprop[0], kSyspropMaxLen, "%s%s",
+ kPersistPrefix, program_specific_sysprop);
+ async_safe_format_buffer(&persist_default_sysprop[0], kSyspropMaxLen, "%s%s", kPersistPrefix,
+ default_sysprop);
+
+ // In order of precedence, always take the program-specific sysprop (e.g.
+ // '[persist.]libc.debug.gwp_asan.sample_rate.cameraserver') over the
+ // generic sysprop (e.g.
+ // '[persist.]libc.debug.gwp_asan.(system_default|app_default)'). In
+ // addition, always take the non-persistent option over the persistent
+ // option.
+ sysprop_names[0] = program_specific_sysprop;
+ sysprop_names[1] = persist_program_specific_sysprop;
+ sysprop_names[2] = default_sysprop;
+ sysprop_names[3] = persist_default_sysprop;
}
char settings_buf[PROP_VALUE_MAX];
- if (!get_config_from_env_or_sysprops(env_var, sysprop_names,
- /* sys_prop_names_size */ 2, settings_buf, PROP_VALUE_MAX)) {
+ if (!get_config_from_env_or_sysprops(env_var, sysprop_names, arraysize(sysprop_names),
+ settings_buf, PROP_VALUE_MAX)) {
return false;
}
diff --git a/libc/bionic/sysprop_helpers.cpp b/libc/bionic/sysprop_helpers.cpp
index edae6cc84..10da3efc2 100644
--- a/libc/bionic/sysprop_helpers.cpp
+++ b/libc/bionic/sysprop_helpers.cpp
@@ -53,7 +53,7 @@ static bool get_property_value(const char* property_name, char* dest, size_t des
strncpy(cb_cookie->dest, value, cb_cookie->size);
},
&cb_cookie);
- if (*dest != '\0' && *dest != '0') return true;
+ if (*dest != '\0') return true;
return false;
}
diff --git a/tests/Android.bp b/tests/Android.bp
index a54ffb835..8639cfc0a 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -479,6 +479,7 @@ cc_test_library {
"uchar_test.cpp",
"unistd_nofortify_test.cpp",
"unistd_test.cpp",
+ "utils.cpp",
"utmp_test.cpp",
"wchar_test.cpp",
"wctype_test.cpp",
@@ -598,18 +599,6 @@ cc_test_library {
],
}
-cc_test_library {
- name: "libBionicGwpAsanTests",
- defaults: ["bionic_tests_defaults"],
- srcs: [
- "gwp_asan_test.cpp",
- ],
- include_dirs: [
- "bionic/libc",
- ],
- static_libs: ["libbase"],
-}
-
// -----------------------------------------------------------------------------
// Fortify tests.
// -----------------------------------------------------------------------------
@@ -774,7 +763,6 @@ cc_test_library {
"libBionicStandardTests",
"libBionicElfTlsTests",
"libBionicFramePointerTests",
- "libBionicGwpAsanTests",
"libfortify1-tests-clang",
"libfortify1-new-tests-clang",
"libfortify2-tests-clang",
@@ -876,6 +864,7 @@ cc_defaults {
"__cxa_thread_atexit_test.cpp",
"gtest_globals.cpp",
"gtest_main.cpp",
+ "gwp_asan_test.cpp",
"thread_local_test.cpp",
],
diff --git a/tests/gwp_asan_test.cpp b/tests/gwp_asan_test.cpp
index b2c7780b1..8e5132304 100644
--- a/tests/gwp_asan_test.cpp
+++ b/tests/gwp_asan_test.cpp
@@ -28,27 +28,20 @@
#include <gtest/gtest.h>
#include <stdio.h>
+#include <sys/file.h>
#include <string>
#if defined(__BIONIC__)
+#include "android-base/file.h"
#include "gwp_asan/options.h"
#include "platform/bionic/malloc.h"
+#include "sys/system_properties.h"
#include "utils.h"
-void RunGwpAsanTest(const char* test_name) {
- ExecTestHelper eh;
- eh.SetEnv({"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1", "GWP_ASAN_MAX_ALLOCS=40000",
- nullptr});
- std::string filter_arg = "--gtest_filter=";
- filter_arg += test_name;
- std::string exec(testing::internal::GetArgvs()[0]);
- eh.SetArgs({exec.c_str(), "--gtest_also_run_disabled_tests", filter_arg.c_str(), nullptr});
- eh.Run([&]() { execve(exec.c_str(), eh.GetArgs(), eh.GetEnv()); },
- /* expected_exit_status */ 0,
- // |expected_output_regex|, ensure at least one test ran:
- R"(\[ PASSED \] [1-9]+0? test)");
-}
+// basename is a mess, use gnu basename explicitly to avoid the need for string
+// mutation.
+extern "C" const char* __gnu_basename(const char* path);
// This file implements "torture testing" under GWP-ASan, where we sample every
// single allocation. The upper limit for the number of GWP-ASan allocations in
@@ -58,4 +51,191 @@ TEST(gwp_asan_integration, malloc_tests_under_torture) {
RunGwpAsanTest("malloc.*:-malloc.mallinfo*");
}
+class SyspropRestorer {
+ private:
+ std::vector<std::pair<std::string, std::string>> props_to_restore_;
+ // System properties are global for a device, so the tests that mutate the
+ // GWP-ASan system properties must be run mutually exclusive. Because
+ // bionic-unit-tests is run in an isolated gtest fashion (each test is run in
+ // its own process), we have to use flocks to synchronise between tests.
+ int flock_fd_;
+
+ public:
+ SyspropRestorer() {
+ std::string path = testing::internal::GetArgvs()[0];
+ flock_fd_ = open(path.c_str(), O_RDONLY);
+ EXPECT_NE(flock_fd_, -1) << "failed to open self for a flock";
+ EXPECT_NE(flock(flock_fd_, LOCK_EX), -1) << "failed to flock myself";
+
+ const char* basename = __gnu_basename(path.c_str());
+ std::vector<std::string> props = {
+ std::string("libc.debug.gwp_asan.sample_rate.") + basename,
+ std::string("libc.debug.gwp_asan.process_sampling.") + basename,
+ std::string("libc.debug.gwp_asan.max_allocs.") + basename,
+ "libc.debug.gwp_asan.sample_rate.system_default",
+ "libc.debug.gwp_asan.sample_rate.app_default",
+ "libc.debug.gwp_asan.process_sampling.system_default",
+ "libc.debug.gwp_asan.process_sampling.app_default",
+ "libc.debug.gwp_asan.max_allocs.system_default",
+ "libc.debug.gwp_asan.max_allocs.app_default",
+ };
+
+ size_t base_props_size = props.size();
+ for (size_t i = 0; i < base_props_size; ++i) {
+ props.push_back("persist." + props[i]);
+ }
+
+ std::string reset_log;
+
+ for (const std::string& prop : props) {
+ std::string value = GetSysprop(prop);
+ props_to_restore_.emplace_back(prop, value);
+ if (!value.empty()) {
+ __system_property_set(prop.c_str(), "");
+ }
+ }
+ }
+
+ ~SyspropRestorer() {
+ for (const auto& kv : props_to_restore_) {
+ if (kv.second != GetSysprop(kv.first)) {
+ __system_property_set(kv.first.c_str(), kv.second.c_str());
+ }
+ }
+ close(flock_fd_);
+ }
+
+ static std::string GetSysprop(const std::string& name) {
+ std::string value;
+ const prop_info* pi = __system_property_find(name.c_str());
+ if (pi == nullptr) return value;
+ __system_property_read_callback(
+ pi,
+ [](void* cookie, const char* /* name */, const char* value, uint32_t /* serial */) {
+ std::string* v = static_cast<std::string*>(cookie);
+ *v = value;
+ },
+ &value);
+ return value;
+ }
+};
+
+TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_enabled) {
+ std::string maps;
+ EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
+ EXPECT_TRUE(maps.find("GWP-ASan") != std::string::npos) << maps;
+
+ volatile int* x = new int;
+ delete x;
+ EXPECT_DEATH({ *x = 7; }, "");
+}
+
+TEST(gwp_asan_integration, DISABLED_assert_gwp_asan_disabled) {
+ std::string maps;
+ EXPECT_TRUE(android::base::ReadFileToString("/proc/self/maps", &maps));
+ EXPECT_TRUE(maps.find("GWP-ASan") == std::string::npos);
+}
+
+TEST(gwp_asan_integration, sysprops_program_specific) {
+ SyspropRestorer restorer;
+
+ std::string path = testing::internal::GetArgvs()[0];
+ const char* basename = __gnu_basename(path.c_str());
+ __system_property_set((std::string("libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
+ __system_property_set((std::string("libc.debug.gwp_asan.process_sampling.") + basename).c_str(),
+ "1");
+ __system_property_set((std::string("libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
+ "40000");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
+TEST(gwp_asan_integration, sysprops_persist_program_specific) {
+ SyspropRestorer restorer;
+
+ std::string path = testing::internal::GetArgvs()[0];
+ const char* basename = __gnu_basename(path.c_str());
+ __system_property_set(
+ (std::string("persist.libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
+ __system_property_set(
+ (std::string("persist.libc.debug.gwp_asan.process_sampling.") + basename).c_str(), "1");
+ __system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
+ "40000");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
+TEST(gwp_asan_integration, sysprops_system) {
+ SyspropRestorer restorer;
+
+ __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "1");
+ __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "1");
+ __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "40000");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
+TEST(gwp_asan_integration, sysprops_persist_system) {
+ SyspropRestorer restorer;
+
+ __system_property_set("persist.libc.debug.gwp_asan.sample_rate.system_default", "1");
+ __system_property_set("persist.libc.debug.gwp_asan.process_sampling.system_default", "1");
+ __system_property_set("persist.libc.debug.gwp_asan.max_allocs.system_default", "40000");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
+TEST(gwp_asan_integration, sysprops_non_persist_overrides_persist) {
+ SyspropRestorer restorer;
+
+ __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "1");
+ __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "1");
+ __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "40000");
+
+ __system_property_set("persist.libc.debug.gwp_asan.sample_rate.system_default", "0");
+ __system_property_set("persist.libc.debug.gwp_asan.process_sampling.system_default", "0");
+ __system_property_set("persist.libc.debug.gwp_asan.max_allocs.system_default", "0");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
+TEST(gwp_asan_integration, sysprops_program_specific_overrides_default) {
+ SyspropRestorer restorer;
+
+ std::string path = testing::internal::GetArgvs()[0];
+ const char* basename = __gnu_basename(path.c_str());
+ __system_property_set(
+ (std::string("persist.libc.debug.gwp_asan.sample_rate.") + basename).c_str(), "1");
+ __system_property_set(
+ (std::string("persist.libc.debug.gwp_asan.process_sampling.") + basename).c_str(), "1");
+ __system_property_set((std::string("persist.libc.debug.gwp_asan.max_allocs.") + basename).c_str(),
+ "40000");
+
+ __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
+ __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
+ __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
+TEST(gwp_asan_integration, sysprops_can_disable) {
+ SyspropRestorer restorer;
+
+ __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
+ __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
+ __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
+
+ RunSubtestNoEnv("gwp_asan_integration.DISABLED_assert_gwp_asan_disabled");
+}
+
+TEST(gwp_asan_integration, env_overrides_sysprop) {
+ SyspropRestorer restorer;
+
+ __system_property_set("libc.debug.gwp_asan.sample_rate.system_default", "0");
+ __system_property_set("libc.debug.gwp_asan.process_sampling.system_default", "0");
+ __system_property_set("libc.debug.gwp_asan.max_allocs.system_default", "0");
+
+ RunGwpAsanTest("gwp_asan_integration.DISABLED_assert_gwp_asan_enabled");
+}
+
#endif // defined(__BIONIC__)
diff --git a/tests/utils.cpp b/tests/utils.cpp
new file mode 100644
index 000000000..825883327
--- /dev/null
+++ b/tests/utils.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "utils.h"
+
+void RunGwpAsanTest(const char* test_name) {
+ ExecTestHelper eh;
+ eh.SetEnv({"GWP_ASAN_SAMPLE_RATE=1", "GWP_ASAN_PROCESS_SAMPLING=1", "GWP_ASAN_MAX_ALLOCS=40000",
+ nullptr});
+ std::string filter_arg = "--gtest_filter=";
+ filter_arg += test_name;
+ std::string exec(testing::internal::GetArgvs()[0]);
+ eh.SetArgs({exec.c_str(), "--gtest_also_run_disabled_tests", filter_arg.c_str(), nullptr});
+ eh.Run([&]() { execve(exec.c_str(), eh.GetArgs(), eh.GetEnv()); },
+ /* expected_exit_status */ 0,
+ // |expected_output_regex|, ensure at least one test ran:
+ R"(\[ PASSED \] [1-9][0-9]* test)");
+}
+
+void RunSubtestNoEnv(const char* test_name) {
+ ExecTestHelper eh;
+ std::string filter_arg = "--gtest_filter=";
+ filter_arg += test_name;
+ std::string exec(testing::internal::GetArgvs()[0]);
+ eh.SetArgs({exec.c_str(), "--gtest_also_run_disabled_tests", filter_arg.c_str(), nullptr});
+ eh.Run([&]() { execve(exec.c_str(), eh.GetArgs(), eh.GetEnv()); },
+ /* expected_exit_status */ 0,
+ // |expected_output_regex|, ensure at least one test ran:
+ R"(\[ PASSED \] [1-9]+0? test)");
+}
diff --git a/tests/utils.h b/tests/utils.h
index 72214c2b9..81869e36a 100644
--- a/tests/utils.h
+++ b/tests/utils.h
@@ -19,6 +19,7 @@
#include <dirent.h>
#include <dlfcn.h>
#include <fcntl.h>
+#include <gtest/gtest.h>
#include <inttypes.h>
#include <sys/mman.h>
#include <sys/prctl.h>
@@ -264,6 +265,7 @@ class ExecTestHelper {
};
void RunGwpAsanTest(const char* test_name);
+void RunSubtestNoEnv(const char* test_name);
#endif
class FdLeakChecker {