Merge changes Id8a3b7dc,I00ded8f9,I02f78ad7
* changes:
Make the legacy inline headers compile standalone.
Don't redefine __ANDROID_API__.
Move <sys/_sigdefs.h> and <sys/_errdefs.h> to private.
diff --git a/linker/linker.cpp b/linker/linker.cpp
index bda713e..77f5359 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -110,6 +110,7 @@
void add_soinfos(const soinfo::soinfo_list_t& soinfos) {
for (auto si : soinfos) {
add_soinfo(si);
+ si->add_secondary_namespace(this);
}
}
@@ -146,6 +147,7 @@
static LinkerTypeAllocator<LinkedListEntry<soinfo>> g_soinfo_links_allocator;
static LinkerTypeAllocator<android_namespace_t> g_namespace_allocator;
+static LinkerTypeAllocator<LinkedListEntry<android_namespace_t>> g_namespace_list_allocator;
static soinfo* solist;
static soinfo* sonext;
@@ -286,6 +288,14 @@
g_soinfo_links_allocator.free(entry);
}
+LinkedListEntry<android_namespace_t>* NamespaceListAllocator::alloc() {
+ return g_namespace_list_allocator.alloc();
+}
+
+void NamespaceListAllocator::free(LinkedListEntry<android_namespace_t>* entry) {
+ g_namespace_list_allocator.free(entry);
+}
+
static soinfo* soinfo_alloc(android_namespace_t* ns, const char* name,
struct stat* file_stat, off64_t file_offset,
uint32_t rtld_flags) {
@@ -349,9 +359,6 @@
sonext = prev;
}
- // remove from the namespace
- si->get_namespace()->remove_soinfo(si);
-
si->~soinfo();
g_soinfo_allocator.free(si);
}
@@ -843,7 +850,7 @@
}
this->rtld_flags_ = rtld_flags;
- this->namespace_ = ns;
+ this->primary_namespace_ = ns;
}
soinfo::~soinfo() {
@@ -1003,6 +1010,7 @@
g_soinfo_allocator.protect_all(protection);
g_soinfo_links_allocator.protect_all(protection);
g_namespace_allocator.protect_all(protection);
+ g_namespace_list_allocator.protect_all(protection);
}
static size_t ref_count_;
@@ -2122,7 +2130,7 @@
TRACE("deprecated (old format of soinfo): %s needs to unload %s",
si->get_realpath(), library_name);
- soinfo* needed = find_library(si->get_namespace(),
+ soinfo* needed = find_library(si->get_primary_namespace(),
library_name, RTLD_NOLOAD, nullptr, nullptr);
if (needed != nullptr) {
@@ -2172,6 +2180,10 @@
return std::string(sym_name) + ", version " + sym_ver;
}
+static android_namespace_t* get_caller_namespace(soinfo* caller) {
+ return caller != nullptr ? caller->get_primary_namespace() : g_anonymous_namespace;
+}
+
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
// Use basic string manipulation calls to avoid snprintf.
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.
@@ -2208,7 +2220,7 @@
return nullptr;
}
- android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
+ android_namespace_t* ns = get_caller_namespace(caller);
if (extinfo != nullptr) {
if ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0) {
@@ -2302,7 +2314,7 @@
soinfo* found = nullptr;
const ElfW(Sym)* sym = nullptr;
soinfo* caller = find_containing_library(caller_addr);
- android_namespace_t* ns = caller != nullptr ? caller->get_namespace() : g_anonymous_namespace;
+ android_namespace_t* ns = get_caller_namespace(caller);
version_info vi_instance;
version_info* vi = nullptr;
@@ -2415,7 +2427,7 @@
soinfo* caller_soinfo = find_containing_library(caller_addr);
android_namespace_t* caller_ns = caller_soinfo != nullptr ?
- caller_soinfo->get_namespace() :
+ caller_soinfo->get_primary_namespace() :
g_anonymous_namespace;
ProtectedDataGuard guard;
@@ -3023,10 +3035,6 @@
// DT_FINI should be called after DT_FINI_ARRAY if both are present.
call_function("DT_FINI", fini_func_);
-
- // This is needed on second call to dlopen
- // after library has been unloaded with RTLD_NODELETE
- constructors_called = false;
}
void soinfo::add_child(soinfo* child) {
@@ -3054,9 +3062,20 @@
});
});
- // 2. Once everything untied - clear local lists.
+ // 2. Remove from the primary namespace
+ primary_namespace_->remove_soinfo(this);
+ primary_namespace_ = nullptr;
+
+ // 3. Remove from secondary namespaces
+ secondary_namespaces_.for_each([&](android_namespace_t* ns) {
+ ns->remove_soinfo(this);
+ });
+
+
+ // 4. Once everything untied - clear local lists.
parents_.clear();
children_.clear();
+ secondary_namespaces_.clear();
}
dev_t soinfo::get_st_dev() const {
@@ -3190,14 +3209,19 @@
return g_empty_runpath;
}
-android_namespace_t* soinfo::get_namespace() {
+android_namespace_t* soinfo::get_primary_namespace() {
if (has_min_version(3)) {
- return namespace_;
+ return primary_namespace_;
}
return &g_default_namespace;
}
+void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
+ CHECK(has_min_version(3));
+ secondary_namespaces_.push_back(secondary_ns);
+}
+
ElfW(Addr) soinfo::resolve_symbol_address(const ElfW(Sym)* s) const {
if (ELF_ST_TYPE(s->st_info) == STT_GNU_IFUNC) {
return call_ifunc_resolver(s->st_value + load_bias);
diff --git a/linker/linker.h b/linker/linker.h
index 81f93ac..4e2e0b9 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -114,6 +114,16 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(SoinfoListAllocator);
};
+class NamespaceListAllocator {
+ public:
+ static LinkedListEntry<android_namespace_t>* alloc();
+ static void free(LinkedListEntry<android_namespace_t>* entry);
+
+ private:
+ // unconstructable
+ DISALLOW_IMPLICIT_CONSTRUCTORS(NamespaceListAllocator);
+};
+
class SymbolName {
public:
explicit SymbolName(const char* name)
@@ -166,6 +176,7 @@
struct soinfo {
public:
typedef LinkedList<soinfo, SoinfoListAllocator> soinfo_list_t;
+ typedef LinkedList<android_namespace_t, NamespaceListAllocator> android_namespace_list_t;
#if defined(__work_around_b_24465209__)
private:
char old_name_[SOINFO_NAME_LEN];
@@ -342,7 +353,8 @@
void set_dt_runpath(const char *);
const std::vector<std::string>& get_dt_runpath() const;
- android_namespace_t* get_namespace();
+ android_namespace_t* get_primary_namespace();
+ void add_secondary_namespace(android_namespace_t* secondary_ns);
void set_mapped_by_caller(bool reserved_map);
bool is_mapped_by_caller() const;
@@ -414,7 +426,8 @@
// version >= 3
std::vector<std::string> dt_runpath_;
- android_namespace_t* namespace_;
+ android_namespace_t* primary_namespace_;
+ android_namespace_list_t secondary_namespaces_;
uintptr_t handle_;
friend soinfo* get_libdl_info();
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index bbdc024..87e5dbc 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -959,6 +959,70 @@
dlclose(handle2);
}
+TEST(dlext, ns_shared_dlclose) {
+ std::string path = "libc.so:libc++.so:libdl.so:libm.so";
+
+ const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
+
+ android_set_application_target_sdk_version(42U); // something > 23
+
+ ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+
+ // preload this library to the default namespace to check if it
+ // is shared later on.
+ void* handle_dlopened =
+ dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
+
+ android_namespace_t* ns_isolated_shared =
+ android_create_namespace("private_isolated_shared", nullptr,
+ (lib_path + "/private_namespace_libs").c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
+ nullptr);
+ ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
+
+ // Check if "libnstest_dlopened.so" is loaded (and the same)
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_isolated_shared;
+
+ void* handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+ ASSERT_TRUE(handle == handle_dlopened);
+ dlclose(handle);
+ dlclose(handle_dlopened);
+
+ // And now check that the library cannot be found by soname (and is no longer loaded)
+ handle = android_dlopen_ext("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in shared namespace";
+
+ handle = android_dlopen_ext((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+ RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in shared namespace";
+
+ handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_NOLOAD);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in default namespace";
+
+ handle = dlopen((lib_path + "/private_namespace_libs/libnstest_dlopened.so").c_str(),
+ RTLD_NOW | RTLD_NOLOAD);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: libnstest_dlopened.so is still accessible in default namespace";
+
+ // Now lets see if the soinfo area gets reused in the wrong way:
+ // load a library to default namespace.
+ const std::string lib_public_path = lib_path + "/public_namespace_libs/" + g_public_lib;
+ void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+ ASSERT_TRUE(handle_public != nullptr) << dlerror();
+
+ // try to find it in shared namespace
+ handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr)
+ << "Error: " << g_public_lib << " is accessible in shared namespace";
+}
+
TEST(dlext, ns_anonymous) {
static const char* root_lib = "libnstest_root.so";
std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;