};
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;
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;
// 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;
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;
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;
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;
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:
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);
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);
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)
<< "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;
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();