Merge "Fix a few bionic test failures caused by hwasan global instrumentation."
diff --git a/android-changes-for-ndk-developers.md b/android-changes-for-ndk-developers.md
index 0fe16bf..84456f9 100644
--- a/android-changes-for-ndk-developers.md
+++ b/android-changes-for-ndk-developers.md
@@ -1,8 +1,11 @@
-# Android changes for NDK developers
+# Android linker changes for NDK developers
This document details important changes related to native code
loading in various Android releases.
+See also [bionic status](docs/status.md) for general libc/libm/libdl
+behavior changes.
+
Required tools: the NDK has an _arch_-linux-android-readelf binary
(e.g. arm-linux-androideabi-readelf or i686-linux-android-readelf)
for each architecture (under toolchains/), but you can use readelf for
diff --git a/docs/native_allocator.md b/docs/native_allocator.md
index 2d06e2f..82a98fe 100644
--- a/docs/native_allocator.md
+++ b/docs/native_allocator.md
@@ -266,16 +266,16 @@
To run these benchmarks, first copy the trace files to the target and
unzip them using these commands:
- adb shell push system/extras/dumps /data/local/tmp
- adb shell 'cd /data/local/tmp/dumps && for name in *.zip; do unzip $name; done'
+ adb shell push system/extras/traces /data/local/tmp
+ adb shell 'cd /data/local/tmp/traces && for name in *.zip; do unzip $name; done'
Since all of the traces come from applications, the `memory_replay` program
will always call `mallopt(M_DECAY_TIME, 1)' before running the trace.
Run the benchmark thusly:
- adb shell memory_replay64 /data/local/tmp/dumps/XXX.txt
- adb shell memory_replay32 /data/local/tmp/dumps/XXX.txt
+ adb shell memory_replay64 /data/local/tmp/traces/XXX.txt
+ adb shell memory_replay32 /data/local/tmp/traces/XXX.txt
Where XXX.txt is the name of a trace file.
diff --git a/docs/status.md b/docs/status.md
index 4466a3c..6968a18 100644
--- a/docs/status.md
+++ b/docs/status.md
@@ -1,5 +1,11 @@
# Android bionic status
+This document details libc/libm/libdl additions and behavior changes.
+
+See also
+[Android linker changes for NDK developers](../android-changes-for-ndk-developers.md)
+for changes related to native code loading in various Android releases.
+
## Bionic function availability
### POSIX
diff --git a/libc/bionic/fdsan.cpp b/libc/bionic/fdsan.cpp
index 4ebc796..dd3a96e 100644
--- a/libc/bionic/fdsan.cpp
+++ b/libc/bionic/fdsan.cpp
@@ -106,8 +106,30 @@
}
void __libc_init_fdsan() {
- constexpr auto default_level = ANDROID_FDSAN_ERROR_LEVEL_FATAL;
- android_fdsan_set_error_level_from_property(default_level);
+ constexpr auto default_level = ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE;
+ const prop_info* pi = __system_property_find(kFdsanPropertyName);
+ if (!pi) {
+ android_fdsan_set_error_level(default_level);
+ return;
+ }
+ __system_property_read_callback(
+ pi,
+ [](void*, const char*, const char* value, uint32_t) {
+ if (strcasecmp(value, "1") == 0 || strcasecmp(value, "fatal") == 0) {
+ android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
+ } else if (strcasecmp(value, "warn") == 0) {
+ android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
+ } else if (strcasecmp(value, "warn_once") == 0) {
+ android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
+ } else {
+ if (strlen(value) != 0 && strcasecmp(value, "0") != 0) {
+ async_safe_format_log(ANDROID_LOG_ERROR, "libc",
+ "debug.fdsan set to unknown value '%s', disabling", value);
+ }
+ android_fdsan_set_error_level(default_level);
+ }
+ },
+ nullptr);
}
static FdTable& GetFdTable() {
@@ -333,45 +355,6 @@
return atomic_exchange(&GetFdTable().error_level, new_level);
}
-android_fdsan_error_level android_fdsan_set_error_level_from_property(
- android_fdsan_error_level default_level) {
- const prop_info* pi = __system_property_find(kFdsanPropertyName);
- if (!pi) {
- return android_fdsan_set_error_level(default_level);
- }
-
- struct callback_data {
- android_fdsan_error_level default_value;
- android_fdsan_error_level result;
- };
-
- callback_data data;
- data.default_value = default_level;
-
- __system_property_read_callback(
- pi,
- [](void* arg, const char*, const char* value, uint32_t) {
- callback_data* data = static_cast<callback_data*>(arg);
-
- if (strcasecmp(value, "1") == 0 || strcasecmp(value, "fatal") == 0) {
- data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_FATAL);
- } else if (strcasecmp(value, "warn") == 0) {
- data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ALWAYS);
- } else if (strcasecmp(value, "warn_once") == 0) {
- data->result = android_fdsan_set_error_level(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
- } else {
- if (strlen(value) != 0 && strcasecmp(value, "0") != 0) {
- async_safe_format_log(ANDROID_LOG_ERROR, "libc",
- "debug.fdsan set to unknown value '%s', disabling", value);
- }
- data->result = android_fdsan_set_error_level(data->default_value);
- }
- },
- &data);
-
- return data.result;
-}
-
int close(int fd) {
int rc = android_fdsan_close_with_tag(fd, 0);
if (rc == -1 && errno == EINTR) {
diff --git a/libc/bionic/fortify.cpp b/libc/bionic/fortify.cpp
index cf37666..3b804b0 100644
--- a/libc/bionic/fortify.cpp
+++ b/libc/bionic/fortify.cpp
@@ -249,7 +249,7 @@
// This is a variant of __stpncpy_chk, but it also checks to make
// sure we don't read beyond the end of "src". The code for this is
// based on the original version of stpncpy, but modified to check
-// how much we read from "src" at the end of the copy operation.
+// how much we read from "src" during the copy operation.
char* __stpncpy_chk2(char* dst, const char* src, size_t n, size_t dst_len, size_t src_len) {
__check_buffer_access("stpncpy", "write into", n, dst_len);
if (n != 0) {
@@ -257,6 +257,11 @@
const char* s = src;
do {
+ size_t s_copy_len = static_cast<size_t>(s - src);
+ if (__predict_false(s_copy_len >= src_len)) {
+ __fortify_fatal("stpncpy: detected read past end of %zu-byte buffer", src_len);
+ }
+
if ((*d++ = *s++) == 0) {
// NUL pad the remaining n-1 bytes.
while (--n != 0) {
@@ -265,11 +270,6 @@
break;
}
} while (--n != 0);
-
- size_t s_copy_len = static_cast<size_t>(s - src);
- if (__predict_false(s_copy_len > src_len)) {
- __fortify_fatal("stpncpy: detected read past end of %zu-byte buffer", src_len);
- }
}
return dst;
@@ -360,7 +360,7 @@
// This is a variant of __strncpy_chk, but it also checks to make
// sure we don't read beyond the end of "src". The code for this is
// based on the original version of strncpy, but modified to check
-// how much we read from "src" at the end of the copy operation.
+// how much we read from "src" during the copy operation.
char* __strncpy_chk2(char* dst, const char* src, size_t n, size_t dst_len, size_t src_len) {
__check_buffer_access("strncpy", "write into", n, dst_len);
if (n != 0) {
@@ -368,6 +368,11 @@
const char* s = src;
do {
+ size_t s_copy_len = static_cast<size_t>(s - src);
+ if (__predict_false(s_copy_len >= src_len)) {
+ __fortify_fatal("strncpy: detected read past end of %zu-byte buffer", src_len);
+ }
+
if ((*d++ = *s++) == 0) {
// NUL pad the remaining n-1 bytes.
while (--n != 0) {
@@ -376,11 +381,6 @@
break;
}
} while (--n != 0);
-
- size_t s_copy_len = static_cast<size_t>(s - src);
- if (__predict_false(s_copy_len > src_len)) {
- __fortify_fatal("strncpy: detected read past end of %zu-byte buffer", src_len);
- }
}
return dst;
diff --git a/libc/include/android/fdsan.h b/libc/include/android/fdsan.h
index 83b9318..1169ed0 100644
--- a/libc/include/android/fdsan.h
+++ b/libc/include/android/fdsan.h
@@ -197,8 +197,4 @@
*/
enum android_fdsan_error_level android_fdsan_set_error_level(enum android_fdsan_error_level new_level) __INTRODUCED_IN(29) __attribute__((__weak__));
-/*
- * Set the error level to the global setting if available, or a default value.
- */
-enum android_fdsan_error_level android_fdsan_set_error_level_from_property(enum android_fdsan_error_level default_level) __INTRODUCED_IN(30) __attribute__((__weak__));
__END_DECLS
diff --git a/libc/include/bits/timespec.h b/libc/include/bits/timespec.h
index 0497cfe..daad03f 100644
--- a/libc/include/bits/timespec.h
+++ b/libc/include/bits/timespec.h
@@ -46,7 +46,7 @@
struct timespec {
/** Number of seconds. */
time_t tv_sec;
- /** Number of nanoseconds. Must be less than 1,000,000. */
+ /** Number of nanoseconds. Must be less than 1,000,000,000. */
long tv_nsec;
};
#endif
diff --git a/linker/linker.cpp b/linker/linker.cpp
index e41194d..d581dd8 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -76,6 +76,7 @@
static std::unordered_map<void*, size_t> g_dso_handle_counters;
+static bool g_anonymous_namespace_set = false;
static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
static std::unordered_map<std::string, android_namespace_t*> g_exported_namespaces;
@@ -90,6 +91,8 @@
static const char* const kLdConfigFilePath = "/system/etc/ld.config.txt";
static const char* const kLdConfigVndkLiteFilePath = "/system/etc/ld.config.vndk_lite.txt";
+static const char* const kLdGeneratedConfigFilePath = "/dev/linkerconfig/ld.config.txt";
+
#if defined(__LP64__)
static const char* const kSystemLibDir = "/system/lib64";
static const char* const kOdmLibDir = "/odm/lib64";
@@ -270,8 +273,6 @@
static std::vector<std::string> g_ld_preload_names;
-static bool g_anonymous_namespace_initialized;
-
#if STATS
struct linker_stats_t {
int count[kRelocMax];
@@ -2479,14 +2480,29 @@
return 0;
}
-bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
- if (g_anonymous_namespace_initialized) {
- DL_ERR("anonymous namespace has already been initialized.");
- return false;
+// Make ns as the anonymous namespace that is a namespace used when
+// we fail to determine the caller address (e.g., call from mono-jited code)
+// Since there can be multiple anonymous namespace in a process, subsequent
+// call to this function causes an error.
+static bool set_anonymous_namespace(android_namespace_t* ns) {
+ if (!g_anonymous_namespace_set && ns != nullptr) {
+ CHECK(ns->is_also_used_as_anonymous());
+ g_anonymous_namespace = ns;
+ g_anonymous_namespace_set = true;
+ return true;
}
+ return false;
+}
+// TODO(b/130388701) remove this. Currently, this is used only for testing
+// where we don't have classloader namespace.
+bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path) {
ProtectedDataGuard guard;
+ // Test-only feature: we need to change the anonymous namespace multiple times
+ // while the test is running.
+ g_anonymous_namespace_set = false;
+
// create anonymous namespace
// When the caller is nullptr - create_namespace will take global group
// from the anonymous namespace, which is fine because anonymous namespace
@@ -2496,21 +2512,18 @@
"(anonymous)",
nullptr,
library_search_path,
- ANDROID_NAMESPACE_TYPE_ISOLATED,
+ ANDROID_NAMESPACE_TYPE_ISOLATED |
+ ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS,
nullptr,
&g_default_namespace);
- if (anon_ns == nullptr) {
- return false;
- }
+ CHECK(anon_ns != nullptr);
if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
+ // TODO: delete anon_ns
return false;
}
- g_anonymous_namespace = anon_ns;
- g_anonymous_namespace_initialized = true;
-
return true;
}
@@ -2550,6 +2563,7 @@
ns->set_name(name);
ns->set_isolated((type & ANDROID_NAMESPACE_TYPE_ISOLATED) != 0);
ns->set_greylist_enabled((type & ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED) != 0);
+ ns->set_also_used_as_anonymous((type & ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS) != 0);
if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
// append parent namespace paths.
@@ -2581,6 +2595,16 @@
ns->set_default_library_paths(std::move(default_library_paths));
ns->set_permitted_paths(std::move(permitted_paths));
+ if (ns->is_also_used_as_anonymous() && !set_anonymous_namespace(ns)) {
+ DL_ERR("failed to set namespace: [name=\"%s\", ld_library_path=\"%s\", default_library_paths=\"%s\""
+ " permitted_paths=\"%s\"] as the anonymous namespace",
+ ns->get_name(),
+ android::base::Join(ns->get_ld_library_paths(), ':').c_str(),
+ android::base::Join(ns->get_default_library_paths(), ':').c_str(),
+ android::base::Join(ns->get_permitted_paths(), ':').c_str());
+ return nullptr;
+ }
+
return ns;
}
@@ -4150,6 +4174,13 @@
}
#endif
+ // Use generated linker config if flag is set
+ // TODO(b/138920271) Do not check property once it is confirmed as stable
+ if (android::base::GetBoolProperty("sys.linker.use_generated_config", false) &&
+ file_exists(kLdGeneratedConfigFilePath)) {
+ return kLdGeneratedConfigFilePath;
+ }
+
std::string path = get_ld_config_file_apex_path(executable_path);
if (!path.empty()) {
if (file_exists(path.c_str())) {
diff --git a/linker/linker.h b/linker/linker.h
index 782da1c..89390b3 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -165,6 +165,13 @@
*/
ANDROID_NAMESPACE_TYPE_GREYLIST_ENABLED = 0x08000000,
+ /* This flag instructs linker to use this namespace as the anonymous
+ * namespace. There can be only one anonymous namespace in a process. If there
+ * already an anonymous namespace in the process, using this flag when
+ * creating a new namespace causes an error
+ */
+ ANDROID_NAMESPACE_TYPE_ALSO_USED_AS_ANONYMOUS = 0x10000000,
+
ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED = ANDROID_NAMESPACE_TYPE_SHARED |
ANDROID_NAMESPACE_TYPE_ISOLATED,
};
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 11d3d29..fd1592d 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -63,6 +63,8 @@
static void get_elf_base_from_phdr(const ElfW(Phdr)* phdr_table, size_t phdr_count,
ElfW(Addr)* base, ElfW(Addr)* load_bias);
+static void set_bss_vma_name(soinfo* si);
+
// These should be preserved static to avoid emitting
// RELATIVE relocations for the part of the code running
// before linker links itself.
@@ -366,6 +368,8 @@
si->set_main_executable();
init_link_map_head(*si);
+ set_bss_vma_name(si);
+
// Use the executable's PT_INTERP string as the solinker filename in the
// dynamic linker's module list. gdb reads both PT_INTERP and the module list,
// and if the paths for the linker are different, gdb will report that the
@@ -570,6 +574,31 @@
async_safe_fatal("Could not find a PHDR: broken executable?");
}
+/*
+ * Set anonymous VMA name for .bss section. For DSOs loaded by the linker, this
+ * is done by ElfReader. This function is here for DSOs loaded by the kernel,
+ * namely the linker itself and the main executable.
+ */
+static void set_bss_vma_name(soinfo* si) {
+ for (size_t i = 0; i < si->phnum; ++i) {
+ auto phdr = &si->phdr[i];
+
+ if (phdr->p_type != PT_LOAD) {
+ continue;
+ }
+
+ ElfW(Addr) seg_start = phdr->p_vaddr + si->load_bias;
+ ElfW(Addr) seg_page_end = PAGE_END(seg_start + phdr->p_memsz);
+ ElfW(Addr) seg_file_end = PAGE_END(seg_start + phdr->p_filesz);
+
+ if (seg_page_end > seg_file_end) {
+ prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME,
+ reinterpret_cast<void*>(seg_file_end), seg_page_end - seg_file_end,
+ ".bss");
+ }
+ }
+}
+
// Detect an attempt to run the linker on itself. e.g.:
// /system/bin/linker64 /system/bin/linker64
// Use priority-1 to run this constructor before other constructors.
@@ -660,6 +689,9 @@
// couldn't make system calls on x86 at that point, but we can now...
if (!tmp_linker_so.protect_relro()) __linker_cannot_link(args.argv[0]);
+ // And we can set VMA name for the bss section now
+ set_bss_vma_name(&tmp_linker_so);
+
// Initialize the linker's static libc's globals
__libc_init_globals();
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 215ad05..9561bb4 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -72,7 +72,10 @@
struct android_namespace_t {
public:
- android_namespace_t() : is_isolated_(false), is_greylist_enabled_(false) {}
+ android_namespace_t() :
+ is_isolated_(false),
+ is_greylist_enabled_(false),
+ is_also_used_as_anonymous_(false) {}
const char* get_name() const { return name_.c_str(); }
void set_name(const char* name) { name_ = name; }
@@ -83,6 +86,9 @@
bool is_greylist_enabled() const { return is_greylist_enabled_; }
void set_greylist_enabled(bool enabled) { is_greylist_enabled_ = enabled; }
+ bool is_also_used_as_anonymous() const { return is_also_used_as_anonymous_; }
+ void set_also_used_as_anonymous(bool yes) { is_also_used_as_anonymous_ = yes; }
+
const std::vector<std::string>& get_ld_library_paths() const {
return ld_library_paths_;
}
@@ -164,6 +170,7 @@
std::string name_;
bool is_isolated_;
bool is_greylist_enabled_;
+ bool is_also_used_as_anonymous_;
std::vector<std::string> ld_library_paths_;
std::vector<std::string> default_library_paths_;
std::vector<std::string> permitted_paths_;
diff --git a/linker/linker_sdk_versions.cpp b/linker/linker_sdk_versions.cpp
index 29c0f4a..b06f3e6 100644
--- a/linker/linker_sdk_versions.cpp
+++ b/linker/linker_sdk_versions.cpp
@@ -26,12 +26,9 @@
* SUCH DAMAGE.
*/
-#include <atomic>
-
-#include <android/api-level.h>
-#include <android/fdsan.h>
-
#include "linker.h"
+#include <android/api-level.h>
+#include <atomic>
static std::atomic<int> g_target_sdk_version(__ANDROID_API__);
@@ -41,10 +38,6 @@
target = __ANDROID_API__;
}
g_target_sdk_version = target;
-
- if (target < 30) {
- android_fdsan_set_error_level_from_property(ANDROID_FDSAN_ERROR_LEVEL_WARN_ONCE);
- }
}
int get_application_target_sdk_version() {
diff --git a/tests/leak_test.cpp b/tests/leak_test.cpp
index 6005209..3cc1a0a 100644
--- a/tests/leak_test.cpp
+++ b/tests/leak_test.cpp
@@ -17,6 +17,7 @@
#include <err.h>
#include <inttypes.h>
#include <pthread.h>
+#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>
@@ -30,26 +31,28 @@
#include <vector>
#include <android-base/macros.h>
+#include <android-base/threads.h>
#include "utils.h"
using namespace std::chrono_literals;
-static void WaitUntilAllExited(pid_t* pids, size_t pid_count) {
+static void WaitUntilAllThreadsExited(pid_t* tids, size_t tid_count) {
// Wait until all children have exited.
bool alive = true;
while (alive) {
alive = false;
- for (size_t i = 0; i < pid_count; ++i) {
- if (pids[i] != 0) {
- if (kill(pids[i], 0) == 0) {
+ for (size_t i = 0; i < tid_count; ++i) {
+ if (tids[i] != 0) {
+ if (tgkill(getpid(), tids[i], 0) == 0) {
alive = true;
} else {
EXPECT_EQ(errno, ESRCH);
- pids[i] = 0; // Skip in next loop.
+ tids[i] = 0; // Skip in next loop.
}
}
}
+ sched_yield();
}
}
@@ -155,7 +158,7 @@
pthread_barrier_wait(&barrier);
ASSERT_EQ(pthread_barrier_destroy(&barrier), 0);
- WaitUntilAllExited(tids, arraysize(tids));
+ WaitUntilAllThreadsExited(tids, threads_count);
// A native bridge implementation might need a warm up pass to reach a steady state.
// http://b/37920774.