Replace public library list with shared lib sonames (part 2/2)
This commit updates interface of libdl.c. 1. android_init_namespaces is replaces with android_init_anonymous_namespace 2. added 2 arguments to android_create_namespace to specify linked namespace and the list of shared libraries sonames. 3. symbol lookup does not get past boundary libraries (added check and test for it). Bug: http://b/26833548 Bug: http://b/21879602 Test: bionic-unit-tests --gtest_filter=dl*:Dl* Change-Id: I32921da487a02e5bd0d2fc528904d1228394bfb9
This commit is contained in:
parent
7d429d3c48
commit
7a34b9d57a
20 changed files with 524 additions and 126 deletions
|
@ -44,6 +44,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -43,6 +43,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -72,8 +72,8 @@ __attribute__((__weak__, visibility("default")))
|
|||
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(
|
||||
|
@ -85,6 +85,12 @@ struct android_namespace_t* __loader_android_create_namespace(
|
|||
struct android_namespace_t* parent,
|
||||
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*));
|
||||
|
||||
|
@ -146,9 +152,9 @@ uint32_t android_get_application_target_sdk_version() {
|
|||
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 @@ struct android_namespace_t* android_create_namespace(const char* name,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -43,6 +43,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -43,6 +43,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -43,6 +43,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -43,6 +43,7 @@ LIBC_PLATFORM {
|
|||
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;
|
||||
|
|
|
@ -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 @@ void __android_dlwarning(void* obj, void (*f)(void*, const char*)) {
|
|||
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 @@ android_namespace_t* __android_create_namespace(const char* name,
|
|||
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 @@ static const char ANDROID_LIBDL_STRTAB[] =
|
|||
// 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 @@ static ElfW(Sym) g_libdl_symtab[] = {
|
|||
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 @@ static ElfW(Sym) g_libdl_symtab[] = {
|
|||
// 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)));
|
||||
|
|
|
@ -185,10 +185,7 @@ static bool is_greylisted(const char* name, const soinfo* needed_by) {
|
|||
static const char* const* g_default_ld_paths;
|
||||
static std::vector<std::string> g_ld_preload_names;
|
||||
|
||||
static bool g_public_namespace_initialized;
|
||||
|
||||
// TODO (dimitry): Remove once interface between libnativeloader and the linker is updated
|
||||
static std::unordered_set<std::string> g_public_namespace_sonames;
|
||||
static bool g_anonymous_namespace_initialized;
|
||||
|
||||
#if STATS
|
||||
struct linker_stats_t {
|
||||
|
@ -656,11 +653,18 @@ typedef linked_list_t<soinfo> SoinfoLinkedList;
|
|||
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.
|
||||
|
@ -679,23 +683,30 @@ static bool walk_dependencies_tree(soinfo* root_soinfos[], size_t root_soinfos_s
|
|||
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;
|
||||
|
@ -703,20 +714,24 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* root, soinfo* skip_until,
|
|||
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;
|
||||
|
@ -731,8 +746,10 @@ static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
|||
|
||||
// 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.
|
||||
|
@ -745,7 +762,11 @@ static const ElfW(Sym)* dlsym_handle_lookup(soinfo* si, soinfo** found,
|
|||
}
|
||||
|
||||
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
|
||||
|
@ -800,8 +821,14 @@ static const ElfW(Sym)* dlsym_linear_lookup(android_namespace_t* ns,
|
|||
// 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) {
|
||||
|
@ -1542,8 +1569,12 @@ bool find_libraries(android_namespace_t* ns,
|
|||
(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;
|
||||
}
|
||||
});
|
||||
|
||||
bool linked = local_group.visit([&](soinfo* si) {
|
||||
|
@ -2001,39 +2032,42 @@ int do_dlclose(void* handle) {
|
|||
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;
|
||||
}
|
||||
|
||||
auto sonames = android::base::Split(public_ns_sonames, ":");
|
||||
|
||||
ProtectedDataGuard guard;
|
||||
|
||||
g_public_namespace_sonames = std::unordered_set<std::string>(sonames.begin(), sonames.end());
|
||||
|
||||
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;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -2051,8 +2085,8 @@ android_namespace_t* create_namespace(const void* caller_addr,
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -2089,13 +2123,36 @@ android_namespace_t* create_namespace(const void* caller_addr,
|
|||
add_soinfos_to_namespace(get_shared_group(parent_namespace), ns);
|
||||
}
|
||||
|
||||
// link it to default namespace
|
||||
// TODO (dimitry): replace this with user-supplied link once interface is updated
|
||||
ns->add_linked_namespace(&g_default_namespace, g_public_namespace_sonames);
|
||||
|
||||
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);
|
||||
|
|
|
@ -160,7 +160,7 @@ enum {
|
|||
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 @@ android_namespace_t* create_namespace(const void* caller_addr,
|
|||
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
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
*/
|
||||
|
||||
#include "linker_namespaces.h"
|
||||
#include "linker_soinfo.h"
|
||||
#include "linker_utils.h"
|
||||
|
||||
#include <vector>
|
||||
|
@ -57,3 +58,23 @@ bool android_namespace_t::is_accessible(const std::string& file) {
|
|||
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();
|
||||
}
|
||||
|
|
|
@ -118,6 +118,11 @@ struct android_namespace_t {
|
|||
// 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_;
|
||||
|
|
|
@ -634,6 +634,11 @@ void soinfo::add_secondary_namespace(android_namespace_t* secondary_ns) {
|
|||
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 @@ soinfo* soinfo::get_local_group_root() const {
|
|||
return local_group_root_;
|
||||
}
|
||||
|
||||
|
||||
void soinfo::set_mapped_by_caller(bool mapped_by_caller) {
|
||||
if (mapped_by_caller) {
|
||||
flags_ |= FLAG_MAPPED_BY_CALLER;
|
||||
|
|
|
@ -263,6 +263,7 @@ struct soinfo {
|
|||
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;
|
||||
|
|
|
@ -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 @@ extern struct android_namespace_t* android_create_namespace(const char* name,
|
|||
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
|
||||
|
|
|
@ -617,41 +617,54 @@ void DlExtRelroSharingTest::SpawnChildrenAndMeasurePss(const char* lib, bool sha
|
|||
// 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("", nullptr));
|
||||
ASSERT_STREQ("android_init_namespaces failed: error initializing public namespace: "
|
||||
"the list of public libraries is empty.", dlerror());
|
||||
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());
|
||||
|
||||
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 not NODELETE
|
||||
dlclose(handle_public);
|
||||
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());
|
||||
|
||||
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);
|
||||
|
@ -725,6 +738,16 @@ TEST(dlext, ns_smoke) {
|
|||
|
||||
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)
|
||||
|
@ -736,9 +759,187 @@ TEST(dlext, ns_smoke) {
|
|||
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);
|
||||
|
@ -746,13 +947,17 @@ TEST(dlext, ns_isolated) {
|
|||
|
||||
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",
|
||||
|
@ -762,6 +967,7 @@ TEST(dlext, ns_isolated) {
|
|||
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",
|
||||
|
@ -771,6 +977,7 @@ TEST(dlext, ns_isolated) {
|
|||
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());
|
||||
|
@ -844,7 +1051,8 @@ TEST(dlext, ns_isolated) {
|
|||
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);
|
||||
|
@ -852,7 +1060,7 @@ TEST(dlext, ns_shared) {
|
|||
|
||||
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.
|
||||
|
@ -861,17 +1069,24 @@ TEST(dlext, ns_shared) {
|
|||
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());
|
||||
|
@ -959,11 +1174,9 @@ TEST(dlext, ns_shared) {
|
|||
}
|
||||
|
||||
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.
|
||||
|
@ -972,11 +1185,14 @@ TEST(dlext, ns_shared_dlclose) {
|
|||
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;
|
||||
|
@ -1022,9 +1238,7 @@ TEST(dlext, ns_shared_dlclose) {
|
|||
|
||||
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";
|
||||
|
||||
|
@ -1036,6 +1250,7 @@ TEST(dlext, ns_isolated_rtld_global) {
|
|||
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",
|
||||
|
@ -1045,6 +1260,7 @@ TEST(dlext, ns_isolated_rtld_global) {
|
|||
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;
|
||||
|
@ -1057,12 +1273,15 @@ TEST(dlext, ns_isolated_rtld_global) {
|
|||
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()
|
||||
|
@ -1092,22 +1311,28 @@ TEST(dlext, ns_isolated_rtld_global) {
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -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 @@ libnstest_root_relative_install_path := private_namespace_libs
|
|||
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
|
||||
|
|
21
tests/libs/namespaces_public_internal.cpp
Normal file
21
tests/libs/namespaces_public_internal.cpp
Normal file
|
@ -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;
|
||||
}
|
|
@ -20,6 +20,14 @@ static const char* g_local_string = "This string is local to root library";
|
|||
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 @@ extern "C" const char* ns_get_public_extern_string() {
|
|||
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) {
|
||||
|
|
Loading…
Reference in a new issue