Merge "Introduce hwasan mode for linker" am: 4967017c86
Original change: https://android-review.googlesource.com/c/platform/bionic/+/2526420 Change-Id: If0aeb413880443294504c10cfb7ac3c7e0ca5b6e Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
commit
c6c98f0053
13 changed files with 363 additions and 52 deletions
|
@ -41,6 +41,11 @@ apex {
|
|||
"libc_malloc_debug",
|
||||
"libc_malloc_hooks",
|
||||
],
|
||||
arch: {
|
||||
arm64: {
|
||||
native_shared_libs: ["libc_hwasan", "libclang_rt.hwasan"],
|
||||
},
|
||||
},
|
||||
binaries: [
|
||||
"linkerconfig",
|
||||
],
|
||||
|
|
|
@ -1674,13 +1674,12 @@ filegroup {
|
|||
// ========================================================
|
||||
// libc.a + libc.so
|
||||
// ========================================================
|
||||
cc_library {
|
||||
cc_defaults {
|
||||
defaults: [
|
||||
"libc_defaults",
|
||||
"libc_native_allocator_defaults",
|
||||
],
|
||||
name: "libc",
|
||||
static_ndk_lib: true,
|
||||
name: "libc_library_defaults",
|
||||
product_variables: {
|
||||
platform_sdk_version: {
|
||||
asflags: ["-DPLATFORM_SDK_VERSION=%d"],
|
||||
|
@ -1807,20 +1806,7 @@ cc_library {
|
|||
},
|
||||
},
|
||||
|
||||
stubs: {
|
||||
symbol_file: "libc.map.txt",
|
||||
versions: [
|
||||
"29",
|
||||
"R",
|
||||
"current",
|
||||
],
|
||||
},
|
||||
llndk: {
|
||||
symbol_file: "libc.map.txt",
|
||||
export_headers_as_system: true,
|
||||
export_preprocessed_headers: ["include"],
|
||||
export_llndk_headers: ["libc_llndk_headers"],
|
||||
},
|
||||
|
||||
apex_available: [
|
||||
"//apex_available:platform",
|
||||
"com.android.runtime",
|
||||
|
@ -1835,6 +1821,55 @@ cc_library {
|
|||
},
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libc",
|
||||
defaults: [
|
||||
"libc_library_defaults",
|
||||
],
|
||||
stubs: {
|
||||
symbol_file: "libc.map.txt",
|
||||
versions: [
|
||||
"29",
|
||||
"R",
|
||||
"current",
|
||||
],
|
||||
},
|
||||
static_ndk_lib: true,
|
||||
llndk: {
|
||||
symbol_file: "libc.map.txt",
|
||||
export_headers_as_system: true,
|
||||
export_preprocessed_headers: ["include"],
|
||||
export_llndk_headers: ["libc_llndk_headers"],
|
||||
},
|
||||
}
|
||||
|
||||
cc_library {
|
||||
name: "libc_hwasan",
|
||||
defaults: [
|
||||
"libc_library_defaults",
|
||||
],
|
||||
sanitize: {
|
||||
hwaddress: true,
|
||||
},
|
||||
enabled: false,
|
||||
arch: {
|
||||
arm64: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
stem: "libc",
|
||||
relative_install_path: "hwasan",
|
||||
// We don't really need the stubs, but this needs to stay to trigger the
|
||||
// symlink logic in soong.
|
||||
stubs: {
|
||||
symbol_file: "libc.map.txt",
|
||||
},
|
||||
native_bridge_supported: false,
|
||||
// It is never correct to depend on this directly. This is only
|
||||
// needed for the runtime apex, and in base_system.mk.
|
||||
visibility: ["//bionic/apex"],
|
||||
}
|
||||
|
||||
genrule {
|
||||
name: "libc.arm.map",
|
||||
out: ["libc.arm.map.txt"],
|
||||
|
|
|
@ -289,6 +289,7 @@ static bool __is_unsafe_environment_variable(const char* name) {
|
|||
"LD_DEBUG",
|
||||
"LD_DEBUG_OUTPUT",
|
||||
"LD_DYNAMIC_WEAK",
|
||||
"LD_HWASAN",
|
||||
"LD_LIBRARY_PATH",
|
||||
"LD_ORIGIN_PATH",
|
||||
"LD_PRELOAD",
|
||||
|
|
|
@ -374,6 +374,11 @@ cc_binary {
|
|||
],
|
||||
|
||||
symlinks: ["linker_asan"],
|
||||
arch: {
|
||||
arm64: {
|
||||
symlinks: ["linker_hwasan"],
|
||||
},
|
||||
},
|
||||
multilib: {
|
||||
lib64: {
|
||||
suffix: "64",
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/auxv.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/vfs.h>
|
||||
|
@ -133,6 +134,36 @@ static const char* const kAsanDefaultLdPaths[] = {
|
|||
nullptr
|
||||
};
|
||||
|
||||
#if defined(__aarch64__)
|
||||
static const char* const kHwasanSystemLibDir = "/system/lib64/hwasan";
|
||||
static const char* const kHwasanOdmLibDir = "/odm/lib64/hwasan";
|
||||
static const char* const kHwasanVendorLibDir = "/vendor/lib64/hwasan";
|
||||
|
||||
// HWASan is only supported on aarch64.
|
||||
static const char* const kHwsanDefaultLdPaths[] = {
|
||||
kHwasanSystemLibDir,
|
||||
kSystemLibDir,
|
||||
kHwasanOdmLibDir,
|
||||
kOdmLibDir,
|
||||
kHwasanVendorLibDir,
|
||||
kVendorLibDir,
|
||||
nullptr
|
||||
};
|
||||
|
||||
// Is HWASAN enabled?
|
||||
static bool g_is_hwasan = false;
|
||||
#else
|
||||
static const char* const kHwsanDefaultLdPaths[] = {
|
||||
kSystemLibDir,
|
||||
kOdmLibDir,
|
||||
kVendorLibDir,
|
||||
nullptr
|
||||
};
|
||||
|
||||
// Never any HWASan. Help the compiler remove the code we don't need.
|
||||
constexpr bool g_is_hwasan = false;
|
||||
#endif
|
||||
|
||||
// Is ASAN enabled?
|
||||
static bool g_is_asan = false;
|
||||
|
||||
|
@ -2134,26 +2165,46 @@ void* do_dlopen(const char* name, int flags,
|
|||
}
|
||||
// End Workaround for dlopen(/system/lib/<soname>) when .so is in /apex.
|
||||
|
||||
std::string asan_name_holder;
|
||||
std::string translated_name_holder;
|
||||
|
||||
assert(!g_is_hwasan || !g_is_asan);
|
||||
const char* translated_name = name;
|
||||
if (g_is_asan && translated_name != nullptr && translated_name[0] == '/') {
|
||||
char original_path[PATH_MAX];
|
||||
if (realpath(name, original_path) != nullptr) {
|
||||
asan_name_holder = std::string(kAsanLibDirPrefix) + original_path;
|
||||
if (file_exists(asan_name_holder.c_str())) {
|
||||
translated_name_holder = std::string(kAsanLibDirPrefix) + original_path;
|
||||
if (file_exists(translated_name_holder.c_str())) {
|
||||
soinfo* si = nullptr;
|
||||
if (find_loaded_library_by_realpath(ns, original_path, true, &si)) {
|
||||
PRINT("linker_asan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name,
|
||||
asan_name_holder.c_str());
|
||||
translated_name_holder.c_str());
|
||||
} else {
|
||||
PRINT("linker_asan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
|
||||
translated_name = asan_name_holder.c_str();
|
||||
translated_name = translated_name_holder.c_str();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (g_is_hwasan && translated_name != nullptr && translated_name[0] == '/') {
|
||||
char original_path[PATH_MAX];
|
||||
if (realpath(name, original_path) != nullptr) {
|
||||
// Keep this the same as CreateHwasanPath in system/linkerconfig/modules/namespace.cc.
|
||||
std::string path(original_path);
|
||||
auto slash = path.rfind('/');
|
||||
if (slash != std::string::npos || slash != path.size() - 1) {
|
||||
translated_name_holder = path.substr(0, slash) + "/hwasan" + path.substr(slash);
|
||||
}
|
||||
if (!translated_name_holder.empty() && file_exists(translated_name_holder.c_str())) {
|
||||
soinfo* si = nullptr;
|
||||
if (find_loaded_library_by_realpath(ns, original_path, true, &si)) {
|
||||
PRINT("linker_hwasan dlopen NOT translating \"%s\" -> \"%s\": library already loaded", name,
|
||||
translated_name_holder.c_str());
|
||||
} else {
|
||||
PRINT("linker_hwasan dlopen translating \"%s\" -> \"%s\"", name, translated_name);
|
||||
translated_name = translated_name_holder.c_str();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProtectedDataGuard guard;
|
||||
soinfo* si = find_library(ns, translated_name, flags, extinfo, caller);
|
||||
loading_trace.End();
|
||||
|
@ -3335,9 +3386,10 @@ bool soinfo::protect_relro() {
|
|||
return true;
|
||||
}
|
||||
|
||||
static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan) {
|
||||
static std::vector<android_namespace_t*> init_default_namespace_no_config(bool is_asan, bool is_hwasan) {
|
||||
g_default_namespace.set_isolated(false);
|
||||
auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : kDefaultLdPaths;
|
||||
auto default_ld_paths = is_asan ? kAsanDefaultLdPaths : (
|
||||
is_hwasan ? kHwsanDefaultLdPaths : kDefaultLdPaths);
|
||||
|
||||
char real_path[PATH_MAX];
|
||||
std::vector<std::string> ld_default_paths;
|
||||
|
@ -3441,6 +3493,7 @@ static std::string get_ld_config_file_path(const char* executable_path) {
|
|||
return kLdConfigFilePath;
|
||||
}
|
||||
|
||||
|
||||
std::vector<android_namespace_t*> init_default_namespaces(const char* executable_path) {
|
||||
g_default_namespace.set_name("(default)");
|
||||
|
||||
|
@ -3454,6 +3507,16 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable
|
|||
(strcmp(bname, "linker_asan") == 0 ||
|
||||
strcmp(bname, "linker_asan64") == 0);
|
||||
|
||||
#if defined(__aarch64__)
|
||||
// HWASan is only supported on AArch64.
|
||||
// The AT_SECURE restriction is because this is a debug feature that does
|
||||
// not need to work on secure binaries, it doesn't hurt to disallow the
|
||||
// environment variable for them, as it impacts the program execution.
|
||||
char* hwasan_env = getenv("LD_HWASAN");
|
||||
g_is_hwasan = (bname != nullptr &&
|
||||
strcmp(bname, "linker_hwasan64") == 0) ||
|
||||
(hwasan_env != nullptr && !getauxval(AT_SECURE) && strcmp(hwasan_env, "1") == 0);
|
||||
#endif
|
||||
const Config* config = nullptr;
|
||||
|
||||
{
|
||||
|
@ -3461,7 +3524,7 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable
|
|||
INFO("[ Reading linker config \"%s\" ]", ld_config_file_path.c_str());
|
||||
ScopedTrace trace(("linker config " + ld_config_file_path).c_str());
|
||||
std::string error_msg;
|
||||
if (!Config::read_binary_config(ld_config_file_path.c_str(), executable_path, g_is_asan,
|
||||
if (!Config::read_binary_config(ld_config_file_path.c_str(), executable_path, g_is_asan, g_is_hwasan,
|
||||
&config, &error_msg)) {
|
||||
if (!error_msg.empty()) {
|
||||
DL_WARN("Warning: couldn't read '%s' for '%s' (using default configuration instead): %s",
|
||||
|
@ -3472,7 +3535,7 @@ std::vector<android_namespace_t*> init_default_namespaces(const char* executable
|
|||
}
|
||||
|
||||
if (config == nullptr) {
|
||||
return init_default_namespace_no_config(g_is_asan);
|
||||
return init_default_namespace_no_config(g_is_asan, g_is_hwasan);
|
||||
}
|
||||
|
||||
const auto& namespace_configs = config->namespace_configs();
|
||||
|
|
|
@ -463,6 +463,7 @@ class Properties {
|
|||
bool Config::read_binary_config(const char* ld_config_file_path,
|
||||
const char* binary_realpath,
|
||||
bool is_asan,
|
||||
bool is_hwasan,
|
||||
const Config** config,
|
||||
std::string* error_msg) {
|
||||
g_config.clear();
|
||||
|
@ -579,6 +580,8 @@ bool Config::read_binary_config(const char* ld_config_file_path,
|
|||
// these are affected by is_asan flag
|
||||
if (is_asan) {
|
||||
property_name_prefix += ".asan";
|
||||
} else if (is_hwasan) {
|
||||
property_name_prefix += ".hwasan";
|
||||
}
|
||||
|
||||
// search paths are resolved (canonicalized). This is required mainly for
|
||||
|
|
|
@ -166,6 +166,7 @@ class Config {
|
|||
static bool read_binary_config(const char* ld_config_file_path,
|
||||
const char* binary_realpath,
|
||||
bool is_asan,
|
||||
bool is_hwasan,
|
||||
const Config** config,
|
||||
std::string* error_msg);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include <android-base/file.h>
|
||||
#include <android-base/scopeguard.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <vector>
|
||||
|
||||
#if defined(__LP64__)
|
||||
#define ARCH_SUFFIX "64"
|
||||
|
@ -64,6 +65,10 @@ static const char* config_str =
|
|||
"namespace.default.asan.search.paths = /data\n"
|
||||
"namespace.default.asan.search.paths += /vendor/${LIB}\n"
|
||||
"namespace.default.asan.permitted.paths = /data:/vendor\n"
|
||||
"namespace.default.hwasan.search.paths = /vendor/${LIB}/hwasan\n"
|
||||
"namespace.default.hwasan.search.paths += /vendor/${LIB}\n"
|
||||
"namespace.default.hwasan.permitted.paths = /vendor/${LIB}/hwasan\n"
|
||||
"namespace.default.hwasan.permitted.paths += /vendor/${LIB}\n"
|
||||
"namespace.default.links = system\n"
|
||||
"namespace.default.links += vndk\n"
|
||||
// irregular whitespaces are added intentionally for testing purpose
|
||||
|
@ -77,11 +82,17 @@ static const char* config_str =
|
|||
"namespace.system.permitted.paths = /system/${LIB}\n"
|
||||
"namespace.system.asan.search.paths = /data:/system/${LIB}\n"
|
||||
"namespace.system.asan.permitted.paths = /data:/system\n"
|
||||
"namespace.system.hwasan.search.paths = /system/${LIB}/hwasan\n"
|
||||
"namespace.system.hwasan.search.paths += /system/${LIB}\n"
|
||||
"namespace.system.hwasan.permitted.paths = /system/${LIB}/hwasan\n"
|
||||
"namespace.system.hwasan.permitted.paths += /system/${LIB}\n"
|
||||
"namespace.vndk.isolated = tr\n"
|
||||
"namespace.vndk.isolated += ue\n" // should be ignored and return as 'false'.
|
||||
"namespace.vndk.search.paths = /system/${LIB}/vndk\n"
|
||||
"namespace.vndk.asan.search.paths = /data\n"
|
||||
"namespace.vndk.asan.search.paths += /system/${LIB}/vndk\n"
|
||||
"namespace.vndk.hwasan.search.paths = /system/${LIB}/vndk/hwasan\n"
|
||||
"namespace.vndk.hwasan.search.paths += /system/${LIB}/vndk\n"
|
||||
"namespace.vndk.links = default\n"
|
||||
"namespace.vndk.link.default.allow_all_shared_libs = true\n"
|
||||
"namespace.vndk.link.vndk_in_system.allow_all_shared_libs = true\n"
|
||||
|
@ -107,26 +118,50 @@ static std::vector<std::string> resolve_paths(std::vector<std::string> paths) {
|
|||
return resolved_paths;
|
||||
}
|
||||
|
||||
static void run_linker_config_smoke_test(bool is_asan) {
|
||||
const std::vector<std::string> kExpectedDefaultSearchPath =
|
||||
resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor/lib" ARCH_SUFFIX }) :
|
||||
std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX }));
|
||||
enum class SmokeTestType {
|
||||
None,
|
||||
Asan,
|
||||
Hwasan,
|
||||
};
|
||||
|
||||
const std::vector<std::string> kExpectedDefaultPermittedPath =
|
||||
resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/vendor" }) :
|
||||
std::vector<std::string>({ "/vendor/lib" ARCH_SUFFIX }));
|
||||
static void run_linker_config_smoke_test(SmokeTestType type) {
|
||||
std::vector<std::string> expected_default_search_path;
|
||||
std::vector<std::string> expected_default_permitted_path;
|
||||
std::vector<std::string> expected_system_search_path;
|
||||
std::vector<std::string> expected_system_permitted_path;
|
||||
std::vector<std::string> expected_vndk_search_path;
|
||||
|
||||
const std::vector<std::string> kExpectedSystemSearchPath =
|
||||
resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX }) :
|
||||
std::vector<std::string>({ "/system/lib" ARCH_SUFFIX }));
|
||||
switch (type) {
|
||||
case SmokeTestType::None:
|
||||
expected_default_search_path = { "/vendor/lib" ARCH_SUFFIX };
|
||||
expected_default_permitted_path = { "/vendor/lib" ARCH_SUFFIX };
|
||||
expected_system_search_path = { "/system/lib" ARCH_SUFFIX };
|
||||
expected_system_permitted_path = { "/system/lib" ARCH_SUFFIX };
|
||||
expected_vndk_search_path = { "/system/lib" ARCH_SUFFIX "/vndk" };
|
||||
break;
|
||||
case SmokeTestType::Asan:
|
||||
expected_default_search_path = { "/data", "/vendor/lib" ARCH_SUFFIX };
|
||||
expected_default_permitted_path = { "/data", "/vendor" };
|
||||
expected_system_search_path = { "/data", "/system/lib" ARCH_SUFFIX };
|
||||
expected_system_permitted_path = { "/data", "/system" };
|
||||
expected_vndk_search_path = { "/data", "/system/lib" ARCH_SUFFIX "/vndk" };
|
||||
break;
|
||||
case SmokeTestType::Hwasan:
|
||||
expected_default_search_path = { "/vendor/lib" ARCH_SUFFIX "/hwasan", "/vendor/lib" ARCH_SUFFIX };
|
||||
expected_default_permitted_path = { "/vendor/lib" ARCH_SUFFIX "/hwasan", "/vendor/lib" ARCH_SUFFIX };
|
||||
expected_system_search_path = { "/system/lib" ARCH_SUFFIX "/hwasan" , "/system/lib" ARCH_SUFFIX };
|
||||
expected_system_permitted_path = { "/system/lib" ARCH_SUFFIX "/hwasan", "/system/lib" ARCH_SUFFIX };
|
||||
expected_vndk_search_path = { "/system/lib" ARCH_SUFFIX "/vndk/hwasan", "/system/lib" ARCH_SUFFIX "/vndk" };
|
||||
break;
|
||||
}
|
||||
|
||||
const std::vector<std::string> kExpectedSystemPermittedPath =
|
||||
resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system" }) :
|
||||
std::vector<std::string>({ "/system/lib" ARCH_SUFFIX }));
|
||||
|
||||
const std::vector<std::string> kExpectedVndkSearchPath =
|
||||
resolve_paths(is_asan ? std::vector<std::string>({ "/data", "/system/lib" ARCH_SUFFIX "/vndk"}) :
|
||||
std::vector<std::string>({ "/system/lib" ARCH_SUFFIX "/vndk"}));
|
||||
expected_default_search_path = resolve_paths(expected_default_search_path);
|
||||
// expected_default_permitted_path is skipped on purpose, permitted paths
|
||||
// do not get resolved in linker_config.cpp
|
||||
expected_system_search_path = resolve_paths(expected_system_search_path);
|
||||
// expected_system_permitted_path is skipped on purpose, permitted paths
|
||||
// do not get resolved in linker_config.cpp
|
||||
expected_vndk_search_path = resolve_paths(expected_vndk_search_path);
|
||||
|
||||
TemporaryFile tmp_file;
|
||||
close(tmp_file.fd);
|
||||
|
@ -149,7 +184,8 @@ static void run_linker_config_smoke_test(bool is_asan) {
|
|||
std::string error_msg;
|
||||
ASSERT_TRUE(Config::read_binary_config(tmp_file.path,
|
||||
executable_path.c_str(),
|
||||
is_asan,
|
||||
type == SmokeTestType::Asan,
|
||||
type == SmokeTestType::Hwasan,
|
||||
&config,
|
||||
&error_msg)) << error_msg;
|
||||
ASSERT_TRUE(config != nullptr);
|
||||
|
@ -162,8 +198,8 @@ static void run_linker_config_smoke_test(bool is_asan) {
|
|||
|
||||
ASSERT_TRUE(default_ns_config->isolated());
|
||||
ASSERT_FALSE(default_ns_config->visible());
|
||||
ASSERT_EQ(kExpectedDefaultSearchPath, default_ns_config->search_paths());
|
||||
ASSERT_EQ(kExpectedDefaultPermittedPath, default_ns_config->permitted_paths());
|
||||
ASSERT_EQ(expected_default_search_path, default_ns_config->search_paths());
|
||||
ASSERT_EQ(expected_default_permitted_path, default_ns_config->permitted_paths());
|
||||
|
||||
const auto& default_ns_links = default_ns_config->links();
|
||||
ASSERT_EQ(2U, default_ns_links.size());
|
||||
|
@ -202,14 +238,14 @@ static void run_linker_config_smoke_test(bool is_asan) {
|
|||
|
||||
ASSERT_TRUE(ns_system->isolated());
|
||||
ASSERT_TRUE(ns_system->visible());
|
||||
ASSERT_EQ(kExpectedSystemSearchPath, ns_system->search_paths());
|
||||
ASSERT_EQ(kExpectedSystemPermittedPath, ns_system->permitted_paths());
|
||||
ASSERT_EQ(expected_system_search_path, ns_system->search_paths());
|
||||
ASSERT_EQ(expected_system_permitted_path, ns_system->permitted_paths());
|
||||
|
||||
ASSERT_TRUE(ns_vndk != nullptr) << "vndk namespace was not found";
|
||||
|
||||
ASSERT_FALSE(ns_vndk->isolated()); // malformed bool property
|
||||
ASSERT_FALSE(ns_vndk->visible()); // undefined bool property
|
||||
ASSERT_EQ(kExpectedVndkSearchPath, ns_vndk->search_paths());
|
||||
ASSERT_EQ(expected_vndk_search_path, ns_vndk->search_paths());
|
||||
|
||||
const auto& ns_vndk_links = ns_vndk->links();
|
||||
ASSERT_EQ(1U, ns_vndk_links.size());
|
||||
|
@ -223,11 +259,15 @@ static void run_linker_config_smoke_test(bool is_asan) {
|
|||
}
|
||||
|
||||
TEST(linker_config, smoke) {
|
||||
run_linker_config_smoke_test(false);
|
||||
run_linker_config_smoke_test(SmokeTestType::None);
|
||||
}
|
||||
|
||||
TEST(linker_config, asan_smoke) {
|
||||
run_linker_config_smoke_test(true);
|
||||
run_linker_config_smoke_test(SmokeTestType::Asan);
|
||||
}
|
||||
|
||||
TEST(linker_config, hwasan_smoke) {
|
||||
run_linker_config_smoke_test(SmokeTestType::Hwasan);
|
||||
}
|
||||
|
||||
TEST(linker_config, ns_link_shared_libs_invalid_settings) {
|
||||
|
@ -259,6 +299,7 @@ TEST(linker_config, ns_link_shared_libs_invalid_settings) {
|
|||
ASSERT_FALSE(Config::read_binary_config(tmp_file.path,
|
||||
executable_path.c_str(),
|
||||
false,
|
||||
false,
|
||||
&config,
|
||||
&error_msg));
|
||||
ASSERT_TRUE(config == nullptr);
|
||||
|
@ -304,6 +345,7 @@ TEST(linker_config, dir_path_resolve) {
|
|||
ASSERT_TRUE(Config::read_binary_config(tmp_file.path,
|
||||
executable_path.c_str(),
|
||||
false,
|
||||
false,
|
||||
&config,
|
||||
&error_msg)) << error_msg;
|
||||
|
||||
|
|
|
@ -1115,6 +1115,30 @@ cc_test {
|
|||
],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "hwasan_test",
|
||||
enabled: false,
|
||||
// This does not use bionic_tests_defaults because it is not supported on
|
||||
// host.
|
||||
arch: {
|
||||
arm64: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
sanitize: {
|
||||
hwaddress: true,
|
||||
},
|
||||
srcs: [
|
||||
"hwasan_test.cpp",
|
||||
],
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
],
|
||||
data_libs: ["libtest_simple_hwasan", "libtest_simple_hwasan_nohwasan"],
|
||||
header_libs: ["bionic_libc_platform_headers"],
|
||||
test_suites: ["device-tests"],
|
||||
}
|
||||
|
||||
cc_test {
|
||||
name: "bionic-stress-tests",
|
||||
defaults: [
|
||||
|
|
|
@ -971,9 +971,15 @@ TEST(dlfcn, dlopen_executable_by_absolute_path) {
|
|||
}
|
||||
|
||||
#define ALTERNATE_PATH_TO_SYSTEM_LIB "/system/lib64/" ABI_STRING "/"
|
||||
#if __has_feature(hwaddress_sanitizer)
|
||||
#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "hwasan/libc.so"
|
||||
#define PATH_TO_BOOTSTRAP_LIBC PATH_TO_SYSTEM_LIB "bootstrap/hwasan/libc.so"
|
||||
#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "hwasan/libc.so"
|
||||
#else
|
||||
#define PATH_TO_LIBC PATH_TO_SYSTEM_LIB "libc.so"
|
||||
#define PATH_TO_BOOTSTRAP_LIBC PATH_TO_SYSTEM_LIB "bootstrap/libc.so"
|
||||
#define ALTERNATE_PATH_TO_LIBC ALTERNATE_PATH_TO_SYSTEM_LIB "libc.so"
|
||||
#endif
|
||||
|
||||
TEST(dlfcn, dladdr_libc) {
|
||||
#if defined(__GLIBC__)
|
||||
|
|
67
tests/hwasan_test.cpp
Normal file
67
tests/hwasan_test.cpp
Normal file
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <android-base/silent_death_test.h>
|
||||
#include <android-base/test_utils.h>
|
||||
|
||||
using HwasanDeathTest = SilentDeathTest;
|
||||
|
||||
TEST_F(HwasanDeathTest, UseAfterFree) {
|
||||
EXPECT_DEATH(
|
||||
{
|
||||
void* m = malloc(1);
|
||||
volatile char* x = const_cast<volatile char*>(reinterpret_cast<char*>(m));
|
||||
*x = 1;
|
||||
free(m);
|
||||
*x = 2;
|
||||
},
|
||||
"use-after-free");
|
||||
}
|
||||
|
||||
TEST_F(HwasanDeathTest, OutOfBounds) {
|
||||
EXPECT_DEATH(
|
||||
{
|
||||
void* m = malloc(1);
|
||||
volatile char* x = const_cast<volatile char*>(reinterpret_cast<char*>(m));
|
||||
x[1] = 1;
|
||||
},
|
||||
"buffer-overflow");
|
||||
}
|
||||
|
||||
// Check whether dlopen of /foo/bar.so checks /foo/hwasan/bar.so first.
|
||||
TEST(HwasanTest, DlopenAbsolutePath) {
|
||||
std::string path = android::base::GetExecutableDirectory() + "/libtest_simple_hwasan.so";
|
||||
ASSERT_EQ(0, access(path.c_str(), F_OK)); // Verify test setup.
|
||||
std::string hwasan_path =
|
||||
android::base::GetExecutableDirectory() + "/hwasan/libtest_simple_hwasan.so";
|
||||
ASSERT_EQ(0, access(hwasan_path.c_str(), F_OK)); // Verify test setup.
|
||||
|
||||
void* handle = dlopen(path.c_str(), RTLD_NOW);
|
||||
ASSERT_TRUE(handle != nullptr);
|
||||
uint32_t* compiled_with_hwasan =
|
||||
reinterpret_cast<uint32_t*>(dlsym(handle, "dlopen_testlib_compiled_with_hwasan"));
|
||||
EXPECT_TRUE(*compiled_with_hwasan);
|
||||
dlclose(handle);
|
||||
}
|
||||
|
||||
TEST(HwasanTest, IsRunningWithHWasan) {
|
||||
EXPECT_TRUE(running_with_hwasan());
|
||||
}
|
|
@ -242,6 +242,38 @@ cc_test_library {
|
|||
srcs: ["dlopen_testlib_simple.cpp"],
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Libraries used by hwasan_test
|
||||
// -----------------------------------------------------------------------------
|
||||
cc_test_library {
|
||||
name: "libtest_simple_hwasan",
|
||||
arch: {
|
||||
arm64: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
sanitize: {
|
||||
hwaddress: true,
|
||||
},
|
||||
relative_install_path: "hwasan",
|
||||
enabled: false,
|
||||
srcs: ["dlopen_testlib_simple_hwasan.cpp"],
|
||||
}
|
||||
|
||||
cc_test_library {
|
||||
// A weird name. This is the vanilla (non-HWASan) copy of the library that
|
||||
// is used for the hwasan test.
|
||||
name: "libtest_simple_hwasan_nohwasan",
|
||||
arch: {
|
||||
arm64: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
stem: "libtest_simple_hwasan",
|
||||
enabled: false,
|
||||
srcs: ["dlopen_testlib_simple_hwasan.cpp"],
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Library used by dlext direct unload on the namespace boundary tests
|
||||
// -----------------------------------------------------------------------------
|
||||
|
|
27
tests/libs/dlopen_testlib_simple_hwasan.cpp
Normal file
27
tests/libs/dlopen_testlib_simple_hwasan.cpp
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if __has_feature(hwaddress_sanitizer)
|
||||
extern "C" uint32_t dlopen_testlib_compiled_with_hwasan = true;
|
||||
#else
|
||||
extern "C" uint32_t dlopen_testlib_compiled_with_hwasan = false;
|
||||
#endif
|
||||
|
||||
extern "C" bool dlopen_testlib_simple_hwasan_func() {
|
||||
return true;
|
||||
}
|
Loading…
Reference in a new issue