Merge "Match __bos0 to __pass_object_size0 in FORTIFY"
diff --git a/libdl/libdl.arm.map b/libdl/libdl.arm.map
index f452641..c0dcd5d 100644
--- a/libdl/libdl.arm.map
+++ b/libdl/libdl.arm.map
@@ -44,6 +44,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/libdl/libdl.arm64.map b/libdl/libdl.arm64.map
index 62f5ff4..3b797f7 100644
--- a/libdl/libdl.arm64.map
+++ b/libdl/libdl.arm64.map
@@ -43,6 +43,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/libdl/libdl.c b/libdl/libdl.c
index 3fbd7e5..6a95629 100644
--- a/libdl/libdl.c
+++ b/libdl/libdl.c
@@ -72,8 +72,8 @@
uint32_t __loader_android_get_application_target_sdk_version();
__attribute__((__weak__, visibility("default")))
-bool __loader_android_init_namespaces(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+bool __loader_android_init_anonymous_namespace(const char* shared_libs_sonames,
+ const char* library_search_path);
__attribute__((__weak__, visibility("default")))
struct android_namespace_t* __loader_android_create_namespace(
@@ -86,6 +86,12 @@
const void* caller_addr);
__attribute__((__weak__, visibility("default")))
+bool __loader_android_link_namespaces(
+ struct android_namespace_t* namespace_from,
+ struct android_namespace_t* namespace_to,
+ const char* shared_libs_sonames);
+
+__attribute__((__weak__, visibility("default")))
void __loader_android_dlwarning(void* obj, void (*f)(void*, const char*));
// Proxy calls to bionic loader
@@ -146,9 +152,9 @@
return __loader_android_get_application_target_sdk_version();
}
-bool android_init_namespaces(const char* public_ns_sonames,
- const char* anon_ns_library_path) {
- return __loader_android_init_namespaces(public_ns_sonames, anon_ns_library_path);
+bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+ const char* library_search_path) {
+ return __loader_android_init_anonymous_namespace(shared_libs_sonames, library_search_path);
}
struct android_namespace_t* android_create_namespace(const char* name,
@@ -167,6 +173,12 @@
caller_addr);
}
+bool android_link_namespaces(struct android_namespace_t* namespace_from,
+ struct android_namespace_t* namespace_to,
+ const char* shared_libs_sonames) {
+ return __loader_android_link_namespaces(namespace_from, namespace_to, shared_libs_sonames);
+}
+
void android_dlwarning(void* obj, void (*f)(void*, const char*)) {
__loader_android_dlwarning(obj, f);
}
diff --git a/libdl/libdl.map.txt b/libdl/libdl.map.txt
index cc044fe..245e016 100644
--- a/libdl/libdl.map.txt
+++ b/libdl/libdl.map.txt
@@ -43,6 +43,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/libdl/libdl.mips.map b/libdl/libdl.mips.map
index 62f5ff4..3b797f7 100644
--- a/libdl/libdl.mips.map
+++ b/libdl/libdl.mips.map
@@ -43,6 +43,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/libdl/libdl.mips64.map b/libdl/libdl.mips64.map
index 62f5ff4..3b797f7 100644
--- a/libdl/libdl.mips64.map
+++ b/libdl/libdl.mips64.map
@@ -43,6 +43,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/libdl/libdl.x86.map b/libdl/libdl.x86.map
index 62f5ff4..3b797f7 100644
--- a/libdl/libdl.x86.map
+++ b/libdl/libdl.x86.map
@@ -43,6 +43,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/libdl/libdl.x86_64.map b/libdl/libdl.x86_64.map
index 62f5ff4..3b797f7 100644
--- a/libdl/libdl.x86_64.map
+++ b/libdl/libdl.x86_64.map
@@ -43,6 +43,7 @@
android_set_application_target_sdk_version;
android_get_LD_LIBRARY_PATH;
android_update_LD_LIBRARY_PATH;
- android_init_namespaces;
+ android_init_anonymous_namespace;
android_create_namespace;
+ android_link_namespaces;
} LIBC_N;
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 0092179..4e8a364 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -30,8 +30,6 @@
#include "private/ScopedPthreadMutexLocker.h"
#include "private/ThreadLocalBuffer.h"
-/* This file hijacks the symbols stubbed out in libdl.so. */
-
static pthread_mutex_t g_dl_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
static char* __bionic_set_dlerror(char* new_value) {
@@ -155,12 +153,12 @@
get_dlwarning(obj, f);
}
-bool __android_init_namespaces(const char* public_ns_sonames,
- const char* anon_ns_library_path) {
+bool __android_init_anonymous_namespace(const char* shared_libs_sonames,
+ const char* library_search_path) {
ScopedPthreadMutexLocker locker(&g_dl_mutex);
- bool success = init_namespaces(public_ns_sonames, anon_ns_library_path);
+ bool success = init_anonymous_namespace(shared_libs_sonames, library_search_path);
if (!success) {
- __bionic_format_dlerror("android_init_namespaces failed", linker_get_error_buffer());
+ __bionic_format_dlerror("android_init_anonymous_namespace failed", linker_get_error_buffer());
}
return success;
@@ -190,6 +188,20 @@
return result;
}
+bool __android_link_namespaces(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to,
+ const char* shared_libs_sonames) {
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
+ bool success = link_namespaces(namespace_from, namespace_to, shared_libs_sonames);
+
+ if (!success) {
+ __bionic_format_dlerror("android_link_namespaces failed", linker_get_error_buffer());
+ }
+
+ return success;
+}
+
void __cfi_fail(uint64_t CallSiteTypeId, void* Ptr, void *DiagData, void *CallerPc) {
CFIShadowWriter::CfiFail(CallSiteTypeId, Ptr, DiagData, CallerPc);
}
@@ -226,15 +238,15 @@
// 01234567890 1234567890123456789012345678901234567890123456789012 3456789012345678901234567890123456789
"dlopen_ext\0__loader_android_set_application_target_sdk_version\0__loader_android_get_application_targ"
// 3*
- // 000000000011111 111112222222222333333333344444444 4455555555556666666666777777777788 8888888899999999 99
- // 012345678901234 567890123456789012345678901234567 8901234567890123456789012345678901 2345678901234567 89
- "et_sdk_version\0__loader_android_init_namespaces\0__loader_android_create_namespace\0__loader_dlvsym\0__"
+ // 000000000011111 111112222222222333333333344444444445555555 5556666666666777777777788888888889 999999999
+ // 012345678901234 567890123456789012345678901234567890123456 7890123456789012345678901234567890 123456789
+ "et_sdk_version\0__loader_android_init_anonymous_namespace\0__loader_android_create_namespace\0__loader_"
// 4*
- // 0000000000111111111122222 222223333333333444 4444444555555555566666666667777 77777788888888889999999999
- // 0123456789012345678901234 567890123456789012 3456789012345678901234567890123 45678901234567890123456789
- "loader_android_dlwarning\0__loader_cfi_fail\0"
+ // 0000000 000111111111122222222223333 333333444444444455 555555556666666666777777777788888 888889999999999
+ // 0123456 789012345678901234567890123 456789012345678901 234567890123456789012345678901234 567890123456789
+ "dlvsym\0__loader_android_dlwarning\0__loader_cfi_fail\0__loader_android_link_namespaces\0"
#if defined(__arm__)
- // 443
+ // 485
"__loader_dl_unwind_find_exidx\0"
#endif
;
@@ -256,13 +268,14 @@
ELFW(SYM_INITIALIZER)(183, &__android_dlopen_ext, 1),
ELFW(SYM_INITIALIZER)(211, &__android_set_application_target_sdk_version, 1),
ELFW(SYM_INITIALIZER)(263, &__android_get_application_target_sdk_version, 1),
- ELFW(SYM_INITIALIZER)(315, &__android_init_namespaces, 1),
- ELFW(SYM_INITIALIZER)(348, &__android_create_namespace, 1),
- ELFW(SYM_INITIALIZER)(382, &__dlvsym, 1),
- ELFW(SYM_INITIALIZER)(398, &__android_dlwarning, 1),
- ELFW(SYM_INITIALIZER)(425, &__cfi_fail, 1),
+ ELFW(SYM_INITIALIZER)(315, &__android_init_anonymous_namespace, 1),
+ ELFW(SYM_INITIALIZER)(357, &__android_create_namespace, 1),
+ ELFW(SYM_INITIALIZER)(391, &__dlvsym, 1),
+ ELFW(SYM_INITIALIZER)(407, &__android_dlwarning, 1),
+ ELFW(SYM_INITIALIZER)(434, &__cfi_fail, 1),
+ ELFW(SYM_INITIALIZER)(452, &__android_link_namespaces, 1),
#if defined(__arm__)
- ELFW(SYM_INITIALIZER)(443, &__dl_unwind_find_exidx, 1),
+ ELFW(SYM_INITIALIZER)(485, &__dl_unwind_find_exidx, 1),
#endif
};
@@ -279,9 +292,9 @@
// Note that adding any new symbols here requires stubbing them out in libdl.
static unsigned g_libdl_buckets[1] = { 1 };
#if defined(__arm__)
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 0 };
#else
-static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0 };
+static unsigned g_libdl_chains[] = { 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 0 };
#endif
static uint8_t __libdl_info_buf[sizeof(soinfo)] __attribute__((aligned(8)));
diff --git a/linker/linked_list.h b/linker/linked_list.h
index 092e831..b0dd4ce 100644
--- a/linker/linked_list.h
+++ b/linker/linked_list.h
@@ -136,6 +136,10 @@
tail_ = nullptr;
}
+ bool empty() {
+ return (head_ == nullptr);
+ }
+
template<typename F>
void for_each(F action) const {
visit([&] (T* si) {
@@ -179,6 +183,12 @@
}
}
+ void remove(T* element) {
+ remove_if([&](T* e) {
+ return e == element;
+ });
+ }
+
template<typename F>
T* find_if(F predicate) const {
for (LinkedListEntry<T>* e = head_; e != nullptr; e = e->next) {
diff --git a/linker/linker.cpp b/linker/linker.cpp
index b8dd216..136c2b6 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -185,8 +185,7 @@
static const char* const* g_default_ld_paths;
static std::vector<std::string> g_ld_preload_names;
-static bool g_public_namespace_initialized;
-static soinfo_list_t g_public_namespace;
+static bool g_anonymous_namespace_initialized;
#if STATS
struct linker_stats_t {
@@ -525,7 +524,8 @@
static deleter_t deleter;
- static LoadTask* create(const char* name, soinfo* needed_by,
+ static LoadTask* create(const char* name,
+ soinfo* needed_by,
std::unordered_map<const soinfo*, ElfReader>* readers_map) {
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
return new (ptr) LoadTask(name, needed_by, readers_map);
@@ -616,7 +616,8 @@
}
private:
- LoadTask(const char* name, soinfo* needed_by,
+ LoadTask(const char* name,
+ soinfo* needed_by,
std::unordered_map<const soinfo*, ElfReader>* readers_map)
: name_(name), needed_by_(needed_by), si_(nullptr),
fd_(-1), close_fd_(false), file_offset_(0), elf_readers_map_(readers_map),
@@ -652,11 +653,18 @@
typedef linked_list_t<const char> StringLinkedList;
typedef std::vector<LoadTask*> LoadTaskList;
+enum walk_action_result_t : uint32_t {
+ kWalkStop = 0,
+ kWalkContinue = 1,
+ kWalkSkip = 2
+};
// This function walks down the tree of soinfo dependencies
// in breadth-first order and
// * calls action(soinfo* si) for each node, and
-// * terminates walk if action returns false.
+// * terminates walk if action returns kWalkStop
+// * skips children of the node if action
+// return kWalkSkip
//
// walk_dependencies_tree returns false if walk was terminated
// by the action and true otherwise.
@@ -675,23 +683,30 @@
continue;
}
- if (!action(si)) {
+ walk_action_result_t result = action(si);
+
+ if (result == kWalkStop) {
return false;
}
visited.push_back(si);
- si->get_children().for_each([&](soinfo* child) {
- visit_list.push_back(child);
- });
+ if (result != kWalkSkip) {
+ si->get_children().for_each([&](soinfo* child) {
+ visit_list.push_back(child);
+ });
+ }
}
return true;
}
-static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
- soinfo** found, SymbolName& symbol_name,
+static const ElfW(Sym)* dlsym_handle_lookup(android_namespace_t* ns,
+ soinfo* root,
+ soinfo* skip_until,
+ soinfo** found,
+ SymbolName& symbol_name,
const version_info* vi) {
const ElfW(Sym)* result = nullptr;
bool skip_lookup = skip_until != nullptr;
@@ -699,20 +714,24 @@
walk_dependencies_tree(&root, 1, [&](soinfo* current_soinfo) {
if (skip_lookup) {
skip_lookup = current_soinfo != skip_until;
- return true;
+ return kWalkContinue;
+ }
+
+ if (!ns->is_accessible(current_soinfo)) {
+ return kWalkSkip;
}
if (!current_soinfo->find_symbol_by_name(symbol_name, vi, &result)) {
result = nullptr;
- return false;
+ return kWalkStop;
}
if (result != nullptr) {
*found = current_soinfo;
- return false;
+ return kWalkStop;
}
- return true;
+ return kWalkContinue;
});
return result;
@@ -727,8 +746,10 @@
// This is used by dlsym(3). It performs symbol lookup only within the
// specified soinfo object and its dependencies in breadth first order.
-static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
- const char* name, const version_info* vi) {
+static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si,
+ soinfo** found,
+ const char* name,
+ const version_info* vi) {
// According to man dlopen(3) and posix docs in the case when si is handle
// of the main executable we need to search not only in the executable and its
// dependencies but also in all libraries loaded with RTLD_GLOBAL.
@@ -741,7 +762,11 @@
}
SymbolName symbol_name(name);
- return dlsym_handle_lookup(si, nullptr, found, symbol_name, vi);
+ // note that the namespace is not the namespace associated with caller_addr
+ // we use ns associated with root si intentionally here. Using caller_ns
+ // causes problems when user uses dlopen_ext to open a library in the separate
+ // namespace and then calls dlsym() on the handle.
+ return dlsym_handle_lookup(si->get_primary_namespace(), si, nullptr, found, symbol_name, vi);
}
/* This is used by dlsym(3) to performs a global symbol lookup. If the
@@ -796,8 +821,14 @@
// case we already did it.
if (s == nullptr && caller != nullptr &&
(caller->get_rtld_flags() & RTLD_GLOBAL) == 0) {
- return dlsym_handle_lookup(caller->get_local_group_root(),
- (handle == RTLD_NEXT) ? caller : nullptr, found, symbol_name, vi);
+ soinfo* local_group_root = caller->get_local_group_root();
+
+ return dlsym_handle_lookup(local_group_root->get_primary_namespace(),
+ local_group_root,
+ (handle == RTLD_NEXT) ? caller : nullptr,
+ found,
+ symbol_name,
+ vi);
}
if (s != nullptr) {
@@ -1094,14 +1125,6 @@
soinfo* si = ns->soinfo_list().find_if(predicate);
- // check public namespace
- if (si == nullptr) {
- si = g_public_namespace.find_if(predicate);
- if (si != nullptr) {
- ns->add_soinfo(si);
- }
- }
-
if (si != nullptr) {
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
"will return existing soinfo", name, si->get_realpath());
@@ -1117,6 +1140,9 @@
if (!ns->is_accessible(realpath)) {
// TODO(dimitry): workaround for http://b/26394120 - the grey-list
+
+ // TODO(dimitry) before O release: add a namespace attribute to have this enabled
+ // only for classloader-namespaces
const soinfo* needed_by = task->is_dt_needed() ? task->get_needed_by() : nullptr;
if (is_greylisted(name, needed_by)) {
// print warning only if needed by non-system library
@@ -1249,11 +1275,79 @@
});
}
+static std::string resolve_soname(const std::string& name) {
+ // We assume that soname equals to basename here
+
+ // TODO(dimitry): consider having honest absolute-path -> soname resolution
+ // note that since we might end up refusing to load this library because
+ // it is not in shared libs list we need to get the soname without actually loading
+ // the library.
+ //
+ // On the other hand there are several places where we already assume that
+ // soname == basename in particular for any not-loaded library mentioned
+ // in DT_NEEDED list.
+ return basename(name.c_str());
+}
+
+
+static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
+ LoadTask* task,
+ int rtld_flags) {
+ android_namespace_t* ns = namespace_link.linked_namespace();
+
+ soinfo* candidate;
+ bool loaded = false;
+
+ std::string soname;
+ if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
+ loaded = true;
+ soname = candidate->get_soname();
+ } else {
+ soname = resolve_soname(task->get_name());
+ }
+
+ if (!namespace_link.is_accessible(soname.c_str())) {
+ // the library is not accessible via namespace_link
+ return false;
+ }
+
+ // if library is already loaded - return it
+ if (loaded) {
+ task->set_soinfo(candidate);
+ return true;
+ }
+
+ // try to load the library - once namespace boundary is crossed
+ // we need to load a library within separate load_group
+ // to avoid using symbols from foreign namespace while.
+ //
+ // All symbols during relocation should be resolved within a
+ // namespace to preserve library locality to a namespace.
+ const char* name = task->get_name();
+ if (find_libraries(ns,
+ task->get_needed_by(),
+ &name,
+ 1,
+ &candidate,
+ nullptr /* ld_preloads */,
+ 0 /* ld_preload_count*/,
+ rtld_flags,
+ nullptr /* extinfo*/,
+ false /* add_as_children */,
+ false /* search_linked_namespaces */)) {
+ task->set_soinfo(candidate);
+ return true;
+ }
+
+ return false;
+}
+
static bool find_library_internal(android_namespace_t* ns,
LoadTask* task,
ZipArchiveCache* zip_archive_cache,
LoadTaskList* load_tasks,
- int rtld_flags) {
+ int rtld_flags,
+ bool search_linked_namespaces) {
soinfo* candidate;
if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
@@ -1261,25 +1355,27 @@
return true;
}
- if (ns != &g_default_namespace) {
- // check public namespace
- candidate = g_public_namespace.find_if([&](soinfo* si) {
- return strcmp(task->get_name(), si->get_soname()) == 0;
- });
-
- if (candidate != nullptr) {
- ns->add_soinfo(candidate);
- task->set_soinfo(candidate);
- return true;
- }
- }
-
// Library might still be loaded, the accurate detection
// of this fact is done by load_library.
TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
- return load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags);
+ if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
+ return true;
+ }
+
+ if (search_linked_namespaces) {
+ // if a library was not found - look into linked namespaces
+ for (auto& linked_namespace : ns->linked_namespaces()) {
+ if (find_library_in_linked_namespace(linked_namespace,
+ task,
+ rtld_flags)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
}
static void soinfo_unload(soinfo* si);
@@ -1344,7 +1440,8 @@
size_t ld_preloads_count,
int rtld_flags,
const android_dlextinfo* extinfo,
- bool add_as_children) {
+ bool add_as_children,
+ bool search_linked_namespaces) {
// Step 0: prepare.
LoadTaskList load_tasks;
std::unordered_map<const soinfo*, ElfReader> readers_map;
@@ -1396,7 +1493,12 @@
task->set_extinfo(is_dt_needed ? nullptr : extinfo);
task->set_dt_needed(is_dt_needed);
- if(!find_library_internal(ns, task, &zip_archive_cache, &load_tasks, rtld_flags)) {
+ if (!find_library_internal(ns,
+ task,
+ &zip_archive_cache,
+ &load_tasks,
+ rtld_flags,
+ search_linked_namespaces || is_dt_needed)) {
return false;
}
@@ -1404,10 +1506,10 @@
if (is_dt_needed) {
needed_by->add_child(si);
- }
- if (si->is_linked()) {
- si->increment_ref_count();
+ if (si->is_linked()) {
+ si->increment_ref_count();
+ }
}
// When ld_preloads is not null, the first
@@ -1467,14 +1569,14 @@
(start_with != nullptr && add_as_children) ? &start_with : soinfos,
(start_with != nullptr && add_as_children) ? 1 : soinfos_count,
[&] (soinfo* si) {
- local_group.push_back(si);
- return true;
+ if (ns->is_accessible(si)) {
+ local_group.push_back(si);
+ return kWalkContinue;
+ } else {
+ return kWalkSkip;
+ }
});
- // We need to increment ref_count in case
- // the root of the local group was not linked.
- bool was_local_group_root_linked = local_group.front()->is_linked();
-
bool linked = local_group.visit([&](soinfo* si) {
if (!si->is_linked()) {
if (!si->link_image(global_group, local_group, extinfo) ||
@@ -1496,10 +1598,6 @@
failure_guard.disable();
}
- if (!was_local_group_root_linked) {
- local_group.front()->increment_ref_count();
- }
-
return linked;
}
@@ -1511,11 +1609,22 @@
if (name == nullptr) {
si = solist_get_somain();
- } else if (!find_libraries(ns, needed_by, &name, 1, &si, nullptr, 0, rtld_flags,
- extinfo, /* add_as_children */ false)) {
+ } else if (!find_libraries(ns,
+ needed_by,
+ &name,
+ 1,
+ &si,
+ nullptr,
+ 0,
+ rtld_flags,
+ extinfo,
+ false /* add_as_children */,
+ true /* search_linked_namespaces */)) {
return nullptr;
}
+ si->increment_ref_count();
+
return si;
}
@@ -1583,12 +1692,14 @@
TRACE("%s@%p needs to unload %s@%p", si->get_realpath(), si,
child->get_realpath(), child);
+ child->get_parents().remove(si);
+
if (local_unload_list.contains(child)) {
continue;
} else if (child->is_linked() && child->get_local_group_root() != root) {
external_unload_list.push_back(child);
- } else {
- unload_list.push_front(child);
+ } else if (child->get_parents().empty()) {
+ unload_list.push_back(child);
}
}
} else {
@@ -1923,56 +2034,42 @@
return 0;
}
-bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path) {
- if (g_public_namespace_initialized) {
- DL_ERR("public namespace has already been initialized.");
+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;
}
- if (public_ns_sonames == nullptr || public_ns_sonames[0] == '\0') {
- DL_ERR("error initializing public namespace: the list of public libraries is empty.");
- return false;
- }
-
- std::vector<std::string> sonames = android::base::Split(public_ns_sonames, ":");
-
ProtectedDataGuard guard;
- auto failure_guard = make_scope_guard([&]() {
- g_public_namespace.clear();
- });
-
- for (const auto& soname : sonames) {
- soinfo* candidate = nullptr;
-
- find_loaded_library_by_soname(&g_default_namespace, soname.c_str(), &candidate);
-
- if (candidate == nullptr) {
- DL_ERR("error initializing public namespace: a library with soname \"%s\""
- " was not found in the default namespace", soname.c_str());
- return false;
- }
-
- candidate->set_nodelete();
- g_public_namespace.push_back(candidate);
- }
-
- g_public_namespace_initialized = true;
+ g_anonymous_namespace_initialized = true;
// create anonymous namespace
// When the caller is nullptr - create_namespace will take global group
// from the anonymous namespace, which is fine because anonymous namespace
// is still pointing to the default one.
android_namespace_t* anon_ns =
- create_namespace(nullptr, "(anonymous)", nullptr, anon_ns_library_path,
- ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, &g_default_namespace);
+ create_namespace(nullptr,
+ "(anonymous)",
+ nullptr,
+ library_search_path,
+ // TODO (dimitry): change to isolated eventually.
+ ANDROID_NAMESPACE_TYPE_REGULAR,
+ nullptr,
+ &g_default_namespace);
if (anon_ns == nullptr) {
- g_public_namespace_initialized = false;
+ g_anonymous_namespace_initialized = false;
return false;
}
+
+ if (!link_namespaces(anon_ns, &g_default_namespace, shared_lib_sonames)) {
+ g_anonymous_namespace_initialized = false;
+ return false;
+ }
+
g_anonymous_namespace = anon_ns;
- failure_guard.disable();
+
return true;
}
@@ -1990,8 +2087,8 @@
uint64_t type,
const char* permitted_when_isolated_path,
android_namespace_t* parent_namespace) {
- if (!g_public_namespace_initialized) {
- DL_ERR("cannot create namespace: public namespace is not initialized.");
+ if (!g_anonymous_namespace_initialized) {
+ DL_ERR("cannot create namespace: anonymous namespace is not initialized.");
return nullptr;
}
@@ -2031,6 +2128,33 @@
return ns;
}
+bool link_namespaces(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to,
+ const char* shared_lib_sonames) {
+ if (namespace_to == nullptr) {
+ namespace_to = &g_default_namespace;
+ }
+
+ if (namespace_from == nullptr) {
+ DL_ERR("error linking namespaces: namespace_from is null.");
+ return false;
+ }
+
+ if (shared_lib_sonames == nullptr || shared_lib_sonames[0] == '\0') {
+ DL_ERR("error linking namespaces \"%s\"->\"%s\": the list of shared libraries is empty.",
+ namespace_from->get_name(), namespace_to->get_name());
+ return false;
+ }
+
+ auto sonames = android::base::Split(shared_lib_sonames, ":");
+ std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
+
+ ProtectedDataGuard guard;
+ namespace_from->add_linked_namespace(namespace_to, sonames_set);
+
+ return true;
+}
+
ElfW(Addr) call_ifunc_resolver(ElfW(Addr) resolver_addr) {
typedef ElfW(Addr) (*ifunc_resolver_t)(void);
ifunc_resolver_t ifunc_resolver = reinterpret_cast<ifunc_resolver_t>(resolver_addr);
diff --git a/linker/linker.h b/linker/linker.h
index 7746982..d5d4980 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -160,7 +160,7 @@
ANDROID_NAMESPACE_TYPE_ISOLATED,
};
-bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
+bool init_anonymous_namespace(const char* shared_lib_sonames, const char* library_search_path);
android_namespace_t* create_namespace(const void* caller_addr,
const char* name,
const char* ld_library_path,
@@ -169,4 +169,8 @@
const char* permitted_when_isolated_path,
android_namespace_t* parent_namespace);
+bool link_namespaces(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to,
+ const char* shared_lib_sonames);
+
#endif
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 7634465..d52b1d6 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -356,9 +356,17 @@
size_t needed_libraries_count = needed_library_name_list.size();
if (needed_libraries_count > 0 &&
- !find_libraries(&g_default_namespace, si, needed_library_names, needed_libraries_count,
- nullptr, &g_ld_preloads, ld_preloads_count, RTLD_GLOBAL, nullptr,
- /* add_as_children */ true)) {
+ !find_libraries(&g_default_namespace,
+ si,
+ needed_library_names,
+ needed_libraries_count,
+ nullptr,
+ &g_ld_preloads,
+ ld_preloads_count,
+ RTLD_GLOBAL,
+ nullptr,
+ true /* add_as_children */,
+ true /* search_linked_namespaces */)) {
__libc_fatal("CANNOT LINK EXECUTABLE \"%s\": %s", g_argv[0], linker_get_error_buffer());
} else if (needed_libraries_count == 0) {
if (!si->link_image(g_empty_list, soinfo_list_t::make_list(si), nullptr)) {
diff --git a/linker/linker_main.h b/linker/linker_main.h
index 0030f49..b68035b 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -58,7 +58,8 @@
size_t ld_preloads_count,
int rtld_flags,
const android_dlextinfo* extinfo,
- bool add_as_children);
+ bool add_as_children,
+ bool search_linked_namespaces);
void solist_add_soinfo(soinfo* si);
bool solist_remove_soinfo(soinfo* si);
diff --git a/linker/linker_namespaces.cpp b/linker/linker_namespaces.cpp
index 675f324..a7e14cc 100644
--- a/linker/linker_namespaces.cpp
+++ b/linker/linker_namespaces.cpp
@@ -27,6 +27,7 @@
*/
#include "linker_namespaces.h"
+#include "linker_soinfo.h"
#include "linker_utils.h"
#include <vector>
@@ -57,3 +58,23 @@
return false;
}
+bool android_namespace_t::is_accessible(soinfo* s) {
+ std::vector<soinfo*> soinfos;
+ soinfos.push_back(s);
+ s->get_parents().for_each([&](soinfo* parent_si) {
+ soinfos.push_back(parent_si);
+ });
+
+ return std::find_if(soinfos.begin(), soinfos.end(), [this](soinfo* si) {
+ if (si->get_primary_namespace() == this) {
+ return true;
+ }
+
+ const android_namespace_list_t& secondary_namespaces = si->get_secondary_namespaces();
+ if (secondary_namespaces.find(this) != secondary_namespaces.end()) {
+ return true;
+ }
+
+ return false;
+ }) != soinfos.end();
+}
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index c1cee8e..868b4a6 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -33,6 +33,29 @@
#include <string>
#include <vector>
+#include <unordered_set>
+
+struct android_namespace_t;
+
+struct android_namespace_link_t {
+ public:
+ android_namespace_link_t(android_namespace_t* linked_namespace,
+ const std::unordered_set<std::string>& shared_lib_sonames)
+ : linked_namespace_(linked_namespace), shared_lib_sonames_(shared_lib_sonames)
+ {}
+
+ android_namespace_t* linked_namespace() const {
+ return linked_namespace_;
+ }
+
+ bool is_accessible(const char* soname) const {
+ return shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
+ }
+
+ private:
+ android_namespace_t* const linked_namespace_;
+ const std::unordered_set<std::string> shared_lib_sonames_;
+};
struct android_namespace_t {
public:
@@ -65,6 +88,14 @@
permitted_paths_ = permitted_paths;
}
+ const std::vector<android_namespace_link_t>& linked_namespaces() const {
+ return linked_namespaces_;
+ }
+ void add_linked_namespace(android_namespace_t* linked_namespace,
+ const std::unordered_set<std::string>& shared_lib_sonames) {
+ linked_namespaces_.push_back(android_namespace_link_t(linked_namespace, shared_lib_sonames));
+ }
+
void add_soinfo(soinfo* si) {
soinfo_list_.push_back(si);
}
@@ -87,12 +118,22 @@
// always returns true for not isolated namespace.
bool is_accessible(const std::string& path);
+ // Returns true if si is accessible from this namespace. A soinfo
+ // is considered accessible when it belongs to this namespace
+ // or one of it's parent soinfos belongs to this namespace.
+ bool is_accessible(soinfo* si);
+
private:
const char* name_;
bool is_isolated_;
std::vector<std::string> ld_library_paths_;
std::vector<std::string> default_library_paths_;
std::vector<std::string> permitted_paths_;
+ // Loader looks into linked namespace if it was not able
+ // to find a library in this namespace. Note that library
+ // lookup in linked namespaces are limited by the list of
+ // shared sonames.
+ std::vector<android_namespace_link_t> linked_namespaces_;
soinfo_list_t soinfo_list_;
DISALLOW_COPY_AND_ASSIGN(android_namespace_t);
diff --git a/linker/linker_soinfo.cpp b/linker/linker_soinfo.cpp
index 16e42c2..6601dc1 100644
--- a/linker/linker_soinfo.cpp
+++ b/linker/linker_soinfo.cpp
@@ -634,6 +634,11 @@
secondary_namespaces_.push_back(secondary_ns);
}
+android_namespace_list_t& soinfo::get_secondary_namespaces() {
+ CHECK(has_min_version(3));
+ return secondary_namespaces_;
+}
+
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);
@@ -695,7 +700,6 @@
return local_group_root_;
}
-
void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
if (mapped_by_caller) {
flags_ |= FLAG_MAPPED_BY_CALLER;
diff --git a/linker/linker_soinfo.h b/linker/linker_soinfo.h
index 7ef5da2..71eb543 100644
--- a/linker/linker_soinfo.h
+++ b/linker/linker_soinfo.h
@@ -263,6 +263,7 @@
const std::vector<std::string>& get_dt_runpath() const;
android_namespace_t* get_primary_namespace();
void add_secondary_namespace(android_namespace_t* secondary_ns);
+ android_namespace_list_t& get_secondary_namespaces();
void set_mapped_by_caller(bool reserved_map);
bool is_mapped_by_caller() const;
diff --git a/tests/dlext_private.h b/tests/dlext_private.h
index 049db91..6b943ce 100644
--- a/tests/dlext_private.h
+++ b/tests/dlext_private.h
@@ -22,16 +22,15 @@
__BEGIN_DECLS
/*
- * Initializes public and anonymous namespaces. The public_ns_sonames is the list of sonames
- * to be included into public namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
- * The libraries in this list should be loaded prior to this call.
+ * Initializes anonymous namespaces. The shared_libs_sonames is the list of sonames
+ * to be shared by default namespace separated by colon. Example: "libc.so:libm.so:libdl.so".
*
- * The anon_ns_library_path is the search path for anonymous namespace. The anonymous namespace
+ * The library_search_path is the search path for anonymous namespace. The anonymous namespace
* is used in the case when linker cannot identify the caller of dlopen/dlsym. This happens
* for the code not loaded by dynamic linker; for example calls from the mono-compiled code.
*/
-extern bool android_init_namespaces(const char* public_ns_sonames,
- const char* anon_ns_library_path);
+extern bool android_init_anonymous_namespace(const char* shared_libs_sonames,
+ const char* library_search_path);
enum {
@@ -86,6 +85,10 @@
const char* permitted_when_isolated_path,
android_namespace_t* parent);
+extern bool android_link_namespaces(android_namespace_t* from,
+ android_namespace_t* to,
+ const char* shared_libs_sonames);
+
extern void android_set_application_target_sdk_version(uint32_t target);
__END_DECLS
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index e629e41..dcabae8 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -617,44 +617,54 @@
// Testing namespaces
static const char* g_public_lib = "libnstest_public.so";
+// These are libs shared with default namespace
+static const std::string g_core_shared_libs = "libc.so:libc++.so:libdl.so:libm.so";
+
TEST(dlext, ns_smoke) {
static const char* root_lib = "libnstest_root.so";
- std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+ std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
- ASSERT_FALSE(android_init_namespaces(path.c_str(), nullptr));
- ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
- "a library with soname \"libnstest_public.so\" was not found in the "
- "default namespace",
+ ASSERT_FALSE(android_init_anonymous_namespace("", nullptr));
+ ASSERT_STREQ("android_init_anonymous_namespace failed: error linking namespaces"
+ " \"(anonymous)\"->\"(default)\": the list of shared libraries is empty.",
dlerror());
- ASSERT_FALSE(android_init_namespaces("", nullptr));
- ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
- "the list of public libraries is empty.", dlerror());
-
const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
ASSERT_TRUE(handle_public != nullptr) << dlerror();
- ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+ ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror();
- // Check that libraries added to public namespace are NODELETE
+ // Check that libraries added to public namespace are not NODELETE
dlclose(handle_public);
- handle_public = dlopen((get_testlib_root() + "/public_namespace_libs/" + g_public_lib).c_str(),
- RTLD_NOW | RTLD_NOLOAD);
+ handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
+ ASSERT_TRUE(handle_public == nullptr);
+ ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path +
+ "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
- ASSERT_TRUE(handle_public != nullptr) << dlerror();
+ handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
+
+ // create "public namespace", share limited set of public libraries with
android_namespace_t* ns1 =
- android_create_namespace("private", nullptr,
+ android_create_namespace("private",
+ nullptr,
(get_testlib_root() + "/private_namespace_libs").c_str(),
- ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
+ ANDROID_NAMESPACE_TYPE_REGULAR,
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns1 != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns1, nullptr, shared_libs.c_str())) << dlerror();
android_namespace_t* ns2 =
- android_create_namespace("private_isolated", nullptr,
+ android_create_namespace("private_isolated",
+ nullptr,
(get_testlib_root() + "/private_namespace_libs").c_str(),
- ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr, nullptr);
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns2 != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns2, nullptr, shared_libs.c_str())) << dlerror();
// This should not have affect search path for default namespace:
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
@@ -728,6 +738,16 @@
ASSERT_TRUE(ns_get_dlopened_string1() != ns_get_dlopened_string2());
+ // Check that symbols from non-shared libraries a shared library depends on are not visible
+ // from original namespace.
+
+ fn_t ns_get_internal_extern_string =
+ reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_internal_extern_string"));
+ ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror();
+ ASSERT_TRUE(ns_get_internal_extern_string() == nullptr) <<
+ "ns_get_internal_extern_string() expected to return null but returns \"" <<
+ ns_get_internal_extern_string() << "\"";
+
dlclose(handle1);
// Check if handle2 is still alive (and well)
@@ -739,9 +759,187 @@
dlclose(handle2);
}
+TEST(dlext, ns_symbol_visibilty_one_namespace) {
+ static const char* root_lib = "libnstest_root.so";
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+ const std::string ns_search_path = get_testlib_root() + "/public_namespace_libs:" +
+ get_testlib_root() + "/private_namespace_libs";
+
+ android_namespace_t* ns =
+ android_create_namespace("one",
+ nullptr,
+ ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns;
+
+ void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ typedef const char* (*fn_t)();
+
+ // Check that relocation worked correctly
+ fn_t ns_get_internal_extern_string =
+ reinterpret_cast<fn_t>(dlsym(handle, "ns_get_internal_extern_string"));
+ ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror();
+ ASSERT_STREQ("This string is from a library a shared library depends on", ns_get_internal_extern_string());
+
+ fn_t internal_extern_string_fn =
+ reinterpret_cast<fn_t>(dlsym(handle, "internal_extern_string"));
+ ASSERT_TRUE(internal_extern_string_fn != nullptr) << dlerror();
+ ASSERT_STREQ("This string is from a library a shared library depends on", internal_extern_string_fn());
+}
+
+TEST(dlext, ns_symbol_visibilty_between_namespaces) {
+ static const char* root_lib = "libnstest_root.so";
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+ const std::string public_ns_search_path = get_testlib_root() + "/public_namespace_libs";
+ const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+
+ android_namespace_t* ns_public =
+ android_create_namespace("public",
+ nullptr,
+ public_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_namespace_t* ns_private =
+ android_create_namespace("private",
+ nullptr,
+ private_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, g_public_lib)) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_private;
+
+ void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ typedef const char* (*fn_t)();
+
+ // Check that relocation worked correctly
+ fn_t ns_get_internal_extern_string =
+ reinterpret_cast<fn_t>(dlsym(handle, "ns_get_internal_extern_string"));
+ ASSERT_TRUE(ns_get_internal_extern_string != nullptr) << dlerror();
+ ASSERT_TRUE(ns_get_internal_extern_string() == nullptr) <<
+ "ns_get_internal_extern_string() expected to return null but returns \"" <<
+ ns_get_internal_extern_string() << "\"";
+
+ fn_t internal_extern_string_fn =
+ reinterpret_cast<fn_t>(dlsym(handle, "internal_extern_string"));
+ ASSERT_TRUE(internal_extern_string_fn == nullptr);
+ ASSERT_STREQ("undefined symbol: internal_extern_string", dlerror());
+}
+
+TEST(dlext, ns_unload_between_namespaces) {
+ static const char* root_lib = "libnstest_root.so";
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+
+ const std::string public_ns_search_path = get_testlib_root() + "/public_namespace_libs";
+ const std::string private_ns_search_path = get_testlib_root() + "/private_namespace_libs";
+
+ android_namespace_t* ns_public =
+ android_create_namespace("public",
+ nullptr,
+ public_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_public, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_namespace_t* ns_private =
+ android_create_namespace("private",
+ nullptr,
+ private_ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns_private, ns_public, g_public_lib)) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_private, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns_private;
+
+ void* handle = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle != nullptr) << dlerror();
+
+ dlclose(handle);
+ // Check that root_lib was unloaded
+ handle = android_dlopen_ext(root_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_EQ(std::string("dlopen failed: library \"") + root_lib +
+ "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
+
+ // Check that shared library was unloaded in public ns
+ extinfo.library_namespace = ns_public;
+ handle = android_dlopen_ext(g_public_lib, RTLD_NOW | RTLD_NOLOAD, &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_EQ(std::string("dlopen failed: library \"") + g_public_lib +
+ "\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
+}
+
+TEST(dlext, ns_cyclic_namespaces) {
+ // Test that ns1->ns2->ns1 link does not break the loader
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
+ std::string shared_libs = g_core_shared_libs + ":libthatdoesnotexist.so";
+
+ const std::string ns_search_path = get_testlib_root() + "/public_namespace_libs";
+
+ android_namespace_t* ns1 =
+ android_create_namespace("ns1",
+ nullptr,
+ ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns1, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ android_namespace_t* ns2 =
+ android_create_namespace("ns1",
+ nullptr,
+ ns_search_path.c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ nullptr);
+
+ ASSERT_TRUE(android_link_namespaces(ns2, nullptr, g_core_shared_libs.c_str())) << dlerror();
+
+ ASSERT_TRUE(android_link_namespaces(ns2, ns1, shared_libs.c_str())) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns1, ns2, shared_libs.c_str())) << dlerror();
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
+ extinfo.library_namespace = ns1;
+
+ void* handle = android_dlopen_ext("libthatdoesnotexist.so", RTLD_NOW, &extinfo);
+ ASSERT_TRUE(handle == nullptr);
+ ASSERT_STREQ("dlopen failed: library \"libthatdoesnotexist.so\" not found", dlerror());
+}
+
TEST(dlext, ns_isolated) {
static const char* root_lib = "libnstest_root_not_isolated.so";
- std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+ std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
@@ -749,13 +947,17 @@
android_set_application_target_sdk_version(42U); // something > 23
- ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+ ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror();
android_namespace_t* ns_not_isolated =
- android_create_namespace("private", nullptr,
+ android_create_namespace("private",
+ nullptr,
(get_testlib_root() + "/private_namespace_libs").c_str(),
- ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
+ ANDROID_NAMESPACE_TYPE_REGULAR,
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_not_isolated, nullptr, shared_libs.c_str())) << dlerror();
android_namespace_t* ns_isolated =
android_create_namespace("private_isolated1",
@@ -765,6 +967,7 @@
nullptr,
nullptr);
ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_isolated, nullptr, shared_libs.c_str())) << dlerror();
android_namespace_t* ns_isolated2 =
android_create_namespace("private_isolated2",
@@ -774,6 +977,7 @@
get_testlib_root().c_str(),
nullptr);
ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_isolated2, nullptr, shared_libs.c_str())) << dlerror();
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
@@ -847,7 +1051,8 @@
TEST(dlext, ns_shared) {
static const char* root_lib = "libnstest_root_not_isolated.so";
static const char* root_lib_isolated = "libnstest_root.so";
- std::string path = std::string("libc.so:libc++.so:libdl.so:libm.so:") + g_public_lib;
+
+ std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
@@ -855,7 +1060,7 @@
android_set_application_target_sdk_version(42U); // something > 23
- ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+ ASSERT_TRUE(android_init_anonymous_namespace(shared_libs.c_str(), nullptr)) << dlerror();
// preload this library to the default namespace to check if it
// is shared later on.
@@ -864,17 +1069,24 @@
ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
android_namespace_t* ns_not_isolated =
- android_create_namespace("private", nullptr,
+ android_create_namespace("private",
+ nullptr,
(get_testlib_root() + "/private_namespace_libs").c_str(),
- ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
+ ANDROID_NAMESPACE_TYPE_REGULAR,
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_not_isolated, nullptr, shared_libs.c_str())) << dlerror();
android_namespace_t* ns_isolated_shared =
- android_create_namespace("private_isolated_shared", nullptr,
+ android_create_namespace("private_isolated_shared",
+ nullptr,
(get_testlib_root() + "/private_namespace_libs").c_str(),
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
- nullptr, nullptr);
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, nullptr, shared_libs.c_str())) << dlerror();
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
ASSERT_STREQ("dlopen failed: library \"libnstest_root_not_isolated.so\" not found", dlerror());
@@ -962,11 +1174,9 @@
}
TEST(dlext, ns_shared_dlclose) {
- std::string path = "libc.so:libc++.so:libdl.so:libm.so";
-
android_set_application_target_sdk_version(42U); // something > 23
- ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr)) << dlerror();
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr)) << dlerror();
// preload this library to the default namespace to check if it
// is shared later on.
@@ -975,11 +1185,14 @@
ASSERT_TRUE(handle_dlopened != nullptr) << dlerror();
android_namespace_t* ns_isolated_shared =
- android_create_namespace("private_isolated_shared", nullptr,
+ android_create_namespace("private_isolated_shared",
+ nullptr,
(get_testlib_root() + "/private_namespace_libs").c_str(),
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
- nullptr, nullptr);
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns_isolated_shared, nullptr, g_core_shared_libs.c_str())) << dlerror();
// Check if "libnstest_dlopened.so" is loaded (and the same)
android_dlextinfo extinfo;
@@ -1025,9 +1238,7 @@
TEST(dlext, ns_isolated_rtld_global) {
static const char* root_lib = "libnstest_root.so";
- std::string path = "libc.so:libc++.so:libdl.so:libm.so";
-
- ASSERT_TRUE(android_init_namespaces(path.c_str(), nullptr));
+ ASSERT_TRUE(android_init_anonymous_namespace(g_core_shared_libs.c_str(), nullptr));
const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs";
@@ -1039,6 +1250,7 @@
lib_public_path.c_str(),
nullptr);
ASSERT_TRUE(ns1 != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns1, nullptr, g_core_shared_libs.c_str())) << dlerror();
android_namespace_t* ns2 =
android_create_namespace("isolated2",
@@ -1048,6 +1260,7 @@
lib_public_path.c_str(),
nullptr);
ASSERT_TRUE(ns2 != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns2, nullptr, g_core_shared_libs.c_str())) << dlerror();
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
@@ -1060,12 +1273,15 @@
ASSERT_TRUE(handle_global != nullptr) << dlerror();
android_namespace_t* ns1_child =
- android_create_namespace("isolated1_child",
- nullptr,
- (get_testlib_root() + "/private_namespace_libs").c_str(),
- ANDROID_NAMESPACE_TYPE_ISOLATED,
- nullptr,
- ns1);
+ android_create_namespace("isolated1_child",
+ nullptr,
+ (get_testlib_root() + "/private_namespace_libs").c_str(),
+ ANDROID_NAMESPACE_TYPE_ISOLATED,
+ nullptr,
+ ns1);
+
+ ASSERT_TRUE(ns1_child != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns1_child, nullptr, g_core_shared_libs.c_str())) << dlerror();
// Now - only ns1 and ns1 child should be able to dlopen root_lib
// attempt to use ns2 should result in dlerror()
@@ -1095,22 +1311,28 @@
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;
+ std::string shared_libs = g_core_shared_libs + ":" + g_public_lib;
const std::string lib_public_path = get_testlib_root() + "/public_namespace_libs/" + g_public_lib;
void* handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
ASSERT_TRUE(handle_public != nullptr) << dlerror();
- ASSERT_TRUE(android_init_namespaces(path.c_str(), (get_testlib_root() + "/private_namespace_libs").c_str()))
- << dlerror();
+ ASSERT_TRUE(
+ android_init_anonymous_namespace(shared_libs.c_str(),
+ (get_testlib_root() + "/private_namespace_libs").c_str())
+ ) << dlerror();
- android_namespace_t* ns = android_create_namespace(
- "private", nullptr,
- (get_testlib_root() + "/private_namespace_libs").c_str(),
- ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
+ android_namespace_t* ns =
+ android_create_namespace("private",
+ nullptr,
+ (get_testlib_root() + "/private_namespace_libs").c_str(),
+ ANDROID_NAMESPACE_TYPE_REGULAR,
+ nullptr,
+ nullptr);
ASSERT_TRUE(ns != nullptr) << dlerror();
+ ASSERT_TRUE(android_link_namespaces(ns, nullptr, shared_libs.c_str())) << dlerror();
std::string private_library_absolute_path = get_testlib_root() + "/private_namespace_libs/" + root_lib;
diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp
index 3e9e85e..48fb6d1 100644
--- a/tests/dlfcn_test.cpp
+++ b/tests/dlfcn_test.cpp
@@ -1142,8 +1142,9 @@
g_fini_call_order_str += s;
}
-TEST(dlfcn, init_fini_call_order) {
- void* handle = dlopen("libtest_init_fini_order_root.so", RTLD_NOW);
+static void test_init_fini_call_order_for(const char* libname) {
+ g_fini_call_order_str.clear();
+ void* handle = dlopen(libname, RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
typedef int (*get_init_order_number_t)();
get_init_order_number_t get_init_order_number =
@@ -1158,6 +1159,11 @@
ASSERT_EQ("(root)(child)(grandchild)", g_fini_call_order_str);
}
+TEST(dlfcn, init_fini_call_order) {
+ test_init_fini_call_order_for("libtest_init_fini_order_root.so");
+ test_init_fini_call_order_for("libtest_init_fini_order_root2.so");
+}
+
TEST(dlfcn, symbol_versioning_use_v1) {
void* handle = dlopen("libtest_versioned_uselibv1.so", RTLD_NOW);
ASSERT_TRUE(handle != nullptr) << dlerror();
diff --git a/tests/libs/Android.bp b/tests/libs/Android.bp
index 31a0916..5eb16c5 100644
--- a/tests/libs/Android.bp
+++ b/tests/libs/Android.bp
@@ -448,13 +448,26 @@
}
// -----------------------------------------------------------------------------
-// Library used to check init/fini call order
+// Libraries used to check init/fini call order
// -----------------------------------------------------------------------------
cc_test_library {
name: "libtest_init_fini_order_root",
defaults: ["bionic_testlib_defaults"],
srcs: ["dlopen_check_init_fini_root.cpp"],
- shared_libs: ["libtest_init_fini_order_child"],
+ shared_libs: [
+ "libtest_init_fini_order_child",
+ "libtest_init_fini_order_grand_child",
+ ],
+}
+
+cc_test_library {
+ name: "libtest_init_fini_order_root2",
+ defaults: ["bionic_testlib_defaults"],
+ srcs: ["dlopen_check_init_fini_root.cpp"],
+ shared_libs: [
+ "libtest_init_fini_order_grand_child",
+ "libtest_init_fini_order_child",
+ ],
}
cc_test_library {
diff --git a/tests/libs/Android.build.linker_namespaces.mk b/tests/libs/Android.build.linker_namespaces.mk
index df6428c..cd9d7f1 100644
--- a/tests/libs/Android.build.linker_namespaces.mk
+++ b/tests/libs/Android.build.linker_namespaces.mk
@@ -25,10 +25,13 @@
# 2. Check that public libraries loaded in different namespaces are shared
# between them.
# 3. Check that namespace sticks on dlopen
+# 4. Check that having access to shared library (libnstest_public.so)
+# does not expose symbols from dependent library (libnstest_public_internal.so)
#
# Dependency tree (visibility)
# libnstest_root.so (this should be local to the namespace)
# +-> libnstest_public.so
+# +-> libnstest_public_internal.so
# +-> libnstest_private.so
#
# libnstest_dlopened.so (library in private namespace dlopened from libnstest_root.so)
@@ -39,7 +42,13 @@
module := libnstest_root
include $(LOCAL_PATH)/Android.build.testlib.target.mk
+libnstest_public_internal_src_files := namespaces_public_internal.cpp
+module := libnstest_public_internal
+libnstest_public_internal_relative_install_path := public_namespace_libs
+include $(LOCAL_PATH)/Android.build.testlib.target.mk
+
libnstest_public_src_files := namespaces_public.cpp
+libnstest_public_shared_libraries := libnstest_public_internal
module := libnstest_public
libnstest_public_relative_install_path := public_namespace_libs
include $(LOCAL_PATH)/Android.build.testlib.target.mk
diff --git a/tests/libs/namespaces_public_internal.cpp b/tests/libs/namespaces_public_internal.cpp
new file mode 100644
index 0000000..15ae398
--- /dev/null
+++ b/tests/libs/namespaces_public_internal.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+static const char* g_internal_extern_string = "This string is from a library a shared library depends on";
+
+extern "C" const char* internal_extern_string() {
+ return g_internal_extern_string;
+}
diff --git a/tests/libs/namespaces_root.cpp b/tests/libs/namespaces_root.cpp
index b0006c7..a551673 100644
--- a/tests/libs/namespaces_root.cpp
+++ b/tests/libs/namespaces_root.cpp
@@ -20,6 +20,14 @@
extern "C" const char* g_private_extern_string;
extern "C" const char* g_public_extern_string;
+// This is resolved only if public library is in the same namespace as
+// the root one. It should remain unresolved if looking up for public library
+// crosses namespace boundary.
+//
+// Defined in libnstest_public_internal.so on which libnstest_public.so
+// depends on
+extern "C" const char* __attribute__((weak)) internal_extern_string();
+
bool g_dlopened = false;
extern "C" const char* ns_get_local_string() {
@@ -34,6 +42,14 @@
return g_public_extern_string;
}
+extern "C" const char* ns_get_internal_extern_string() {
+ if (internal_extern_string != nullptr) {
+ return internal_extern_string();
+ } else {
+ return nullptr;
+ }
+}
+
extern "C" const char* ns_get_dlopened_string() {
void* handle = dlopen("libnstest_dlopened.so", RTLD_NOW | RTLD_GLOBAL);
if (handle == nullptr) {