Merge "linker: Allow caller to specify parent namespace"
This commit is contained in:
commit
42abf3d241
|
@ -147,15 +147,22 @@ bool android_init_namespaces(const char* public_ns_sonames,
|
|||
return success;
|
||||
}
|
||||
|
||||
android_namespace_t* android_create_namespace(const char* name, const char* ld_library_path,
|
||||
const char* default_library_path, uint64_t type,
|
||||
const char* permitted_when_isolated_path) {
|
||||
android_namespace_t* android_create_namespace(const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path,
|
||||
android_namespace_t* parent_namespace) {
|
||||
void* caller_addr = __builtin_return_address(0);
|
||||
ScopedPthreadMutexLocker locker(&g_dl_mutex);
|
||||
|
||||
android_namespace_t* result = create_namespace(caller_addr, name, ld_library_path,
|
||||
default_library_path, type,
|
||||
permitted_when_isolated_path);
|
||||
android_namespace_t* result = create_namespace(caller_addr,
|
||||
name,
|
||||
ld_library_path,
|
||||
default_library_path,
|
||||
type,
|
||||
permitted_when_isolated_path,
|
||||
parent_namespace);
|
||||
|
||||
if (result == nullptr) {
|
||||
__bionic_format_dlerror("android_create_namespace failed", linker_get_error_buffer());
|
||||
|
|
|
@ -138,6 +138,7 @@ struct android_namespace_t {
|
|||
};
|
||||
|
||||
android_namespace_t g_default_namespace;
|
||||
|
||||
static std::unordered_map<uintptr_t, soinfo*> g_soinfo_handles_map;
|
||||
static android_namespace_t* g_anonymous_namespace = &g_default_namespace;
|
||||
|
||||
|
@ -1887,6 +1888,26 @@ static soinfo::soinfo_list_t make_global_group(android_namespace_t* ns) {
|
|||
return global_group;
|
||||
}
|
||||
|
||||
// This function provides a list of libraries to be shared
|
||||
// by the namespace. For the default namespace this is the global
|
||||
// group (see make_global_group). For all others this is a group
|
||||
// of RTLD_GLOBAL libraries (which includes the global group from
|
||||
// the default namespace).
|
||||
static soinfo::soinfo_list_t get_shared_group(android_namespace_t* ns) {
|
||||
if (ns == &g_default_namespace) {
|
||||
return make_global_group(ns);
|
||||
}
|
||||
|
||||
soinfo::soinfo_list_t shared_group;
|
||||
ns->soinfo_list().for_each([&](soinfo* si) {
|
||||
if ((si->get_rtld_flags() & RTLD_GLOBAL) != 0) {
|
||||
shared_group.push_back(si);
|
||||
}
|
||||
});
|
||||
|
||||
return shared_group;
|
||||
}
|
||||
|
||||
static void shuffle(std::vector<LoadTask*>* v) {
|
||||
for (size_t i = 0, size = v->size(); i < size; ++i) {
|
||||
size_t n = size - i;
|
||||
|
@ -2432,7 +2453,7 @@ bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_
|
|||
// 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);
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
|
||||
|
||||
if (anon_ns == nullptr) {
|
||||
g_public_namespace_initialized = false;
|
||||
|
@ -2448,7 +2469,8 @@ android_namespace_t* create_namespace(const void* caller_addr,
|
|||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path) {
|
||||
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.");
|
||||
return nullptr;
|
||||
|
@ -2460,6 +2482,11 @@ android_namespace_t* create_namespace(const void* caller_addr,
|
|||
caller_soinfo->get_primary_namespace() :
|
||||
g_anonymous_namespace;
|
||||
|
||||
// if parent_namespace is nullptr -> set it to the caller namespace
|
||||
if (parent_namespace == nullptr) {
|
||||
parent_namespace = caller_ns;
|
||||
}
|
||||
|
||||
ProtectedDataGuard guard;
|
||||
std::vector<std::string> ld_library_paths;
|
||||
std::vector<std::string> default_library_paths;
|
||||
|
@ -2477,11 +2504,11 @@ android_namespace_t* create_namespace(const void* caller_addr,
|
|||
ns->set_permitted_paths(std::move(permitted_paths));
|
||||
|
||||
if ((type & ANDROID_NAMESPACE_TYPE_SHARED) != 0) {
|
||||
// If shared - clone the caller namespace
|
||||
ns->add_soinfos(caller_ns->soinfo_list());
|
||||
// If shared - clone the parent namespace
|
||||
ns->add_soinfos(parent_namespace->soinfo_list());
|
||||
} else {
|
||||
// If not shared - copy only the global group
|
||||
ns->add_soinfos(make_global_group(caller_ns));
|
||||
// If not shared - copy only the shared group
|
||||
ns->add_soinfos(get_shared_group(parent_namespace));
|
||||
}
|
||||
|
||||
return ns;
|
||||
|
|
|
@ -497,8 +497,12 @@ enum {
|
|||
};
|
||||
|
||||
bool init_namespaces(const char* public_ns_sonames, const char* anon_ns_library_path);
|
||||
android_namespace_t* create_namespace(const void* caller_addr, const char* name,
|
||||
const char* ld_library_path, const char* default_library_path,
|
||||
uint64_t type, const char* permitted_when_isolated_path);
|
||||
android_namespace_t* create_namespace(const void* caller_addr,
|
||||
const char* name,
|
||||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path,
|
||||
android_namespace_t* parent_namespace);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -83,7 +83,8 @@ extern struct android_namespace_t* android_create_namespace(const char* name,
|
|||
const char* ld_library_path,
|
||||
const char* default_library_path,
|
||||
uint64_t type,
|
||||
const char* permitted_when_isolated_path);
|
||||
const char* permitted_when_isolated_path,
|
||||
android_namespace_t* parent);
|
||||
|
||||
extern void android_set_application_target_sdk_version(uint32_t target);
|
||||
|
||||
|
|
|
@ -652,13 +652,13 @@ TEST(dlext, ns_smoke) {
|
|||
android_namespace_t* ns1 =
|
||||
android_create_namespace("private", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
|
||||
ASSERT_TRUE(ns1 != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns2 =
|
||||
android_create_namespace("private_isolated", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr, nullptr);
|
||||
ASSERT_TRUE(ns2 != nullptr) << dlerror();
|
||||
|
||||
// This should not have affect search path for default namespace:
|
||||
|
@ -760,19 +760,25 @@ TEST(dlext, ns_isolated) {
|
|||
android_namespace_t* ns_not_isolated =
|
||||
android_create_namespace("private", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
|
||||
ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns_isolated =
|
||||
android_create_namespace("private_isolated1", nullptr,
|
||||
android_create_namespace("private_isolated1",
|
||||
nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED, nullptr);
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
nullptr,
|
||||
nullptr);
|
||||
ASSERT_TRUE(ns_isolated != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns_isolated2 =
|
||||
android_create_namespace("private_isolated2",
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
nullptr, ANDROID_NAMESPACE_TYPE_ISOLATED, lib_path.c_str());
|
||||
nullptr,
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
lib_path.c_str(),
|
||||
nullptr);
|
||||
ASSERT_TRUE(ns_isolated2 != nullptr) << dlerror();
|
||||
|
||||
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
|
||||
|
@ -867,14 +873,14 @@ TEST(dlext, ns_shared) {
|
|||
android_namespace_t* ns_not_isolated =
|
||||
android_create_namespace("private", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
|
||||
ASSERT_TRUE(ns_not_isolated != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns_isolated_shared =
|
||||
android_create_namespace("private_isolated_shared", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
|
||||
nullptr);
|
||||
nullptr, nullptr);
|
||||
ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
|
||||
|
||||
ASSERT_TRUE(dlopen(root_lib, RTLD_NOW) == nullptr);
|
||||
|
@ -981,7 +987,7 @@ TEST(dlext, ns_shared_dlclose) {
|
|||
android_create_namespace("private_isolated_shared", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED | ANDROID_NAMESPACE_TYPE_SHARED,
|
||||
nullptr);
|
||||
nullptr, nullptr);
|
||||
ASSERT_TRUE(ns_isolated_shared != nullptr) << dlerror();
|
||||
|
||||
// Check if "libnstest_dlopened.so" is loaded (and the same)
|
||||
|
@ -1026,6 +1032,78 @@ TEST(dlext, ns_shared_dlclose) {
|
|||
<< "Error: " << g_public_lib << " is accessible in shared namespace";
|
||||
}
|
||||
|
||||
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));
|
||||
|
||||
const std::string lib_path = std::string(getenv("ANDROID_DATA")) + NATIVE_TESTS_PATH;
|
||||
|
||||
const std::string lib_public_path = lib_path + "/public_namespace_libs";
|
||||
|
||||
android_namespace_t* ns1 =
|
||||
android_create_namespace("isolated1",
|
||||
nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
lib_public_path.c_str(),
|
||||
nullptr);
|
||||
ASSERT_TRUE(ns1 != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns2 =
|
||||
android_create_namespace("isolated2",
|
||||
nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
lib_public_path.c_str(),
|
||||
nullptr);
|
||||
ASSERT_TRUE(ns2 != nullptr) << dlerror();
|
||||
|
||||
android_dlextinfo extinfo;
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns1;
|
||||
|
||||
void* handle_global = android_dlopen_ext((lib_public_path + "/" + g_public_lib).c_str(),
|
||||
RTLD_GLOBAL,
|
||||
&extinfo);
|
||||
|
||||
ASSERT_TRUE(handle_global != nullptr) << dlerror();
|
||||
|
||||
android_namespace_t* ns1_child =
|
||||
android_create_namespace("isolated1_child",
|
||||
nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_ISOLATED,
|
||||
nullptr,
|
||||
ns1);
|
||||
|
||||
// Now - only ns1 and ns1 child should be able to dlopen root_lib
|
||||
// attempt to use ns2 should result in dlerror()
|
||||
|
||||
// Check ns1_child first.
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns1_child;
|
||||
|
||||
void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||
ASSERT_TRUE(handle1 != nullptr) << dlerror();
|
||||
|
||||
// now ns1
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns1;
|
||||
|
||||
handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||
ASSERT_TRUE(handle1 != nullptr) << dlerror();
|
||||
|
||||
// and ns2 should fail
|
||||
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
|
||||
extinfo.library_namespace = ns2;
|
||||
|
||||
handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
|
||||
ASSERT_TRUE(handle1 == nullptr);
|
||||
ASSERT_STREQ("dlopen failed: library \"libnstest_public.so\" not found", dlerror());
|
||||
}
|
||||
|
||||
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;
|
||||
|
@ -1043,7 +1121,7 @@ TEST(dlext, ns_anonymous) {
|
|||
android_namespace_t* ns = android_create_namespace(
|
||||
"private", nullptr,
|
||||
(lib_path + "/private_namespace_libs").c_str(),
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr);
|
||||
ANDROID_NAMESPACE_TYPE_REGULAR, nullptr, nullptr);
|
||||
|
||||
ASSERT_TRUE(ns != nullptr) << dlerror();
|
||||
|
||||
|
|
Loading…
Reference in New Issue