linker: Allow link namespaces without name filters
This commit allows users to create a link without soname filters between
two linker namespaces.
The motivation is to establish one-way shared library isolation. For
example, assume that there are two linker namespaces `default` and
`vndk`. We would like to limit the shared libraries that can be used by
the `default` namespace. In the meanwhile, we would like to allow the
`vndk` namespace to use shared libs from the `default` namespace if the
soname cannot be find in the search path or loaded sonames of the `vndk`
namespace.
shared_libs = %VNDK_CORE_LIBRARIES%
shared_libs += %VNDK_SAMEPROCESS_LIBRARIES%
vndk <-------------------------------------------- default
\_______________________________________________/^
allow_all_shared_libs = true
android_link_namespaces_all_libs() is added to libdl, but it is
versioned as LIBC_PRIVATE. android_link_namespaces_all_libs() is only
for unit tests.
Bug: 69824336
Test: adb shell /data/nativetest/linker-unit-tests/linker-unit-tests32
Test: adb shell /data/nativetest64/linker-unit-tests/linker-unit-tests64
Test: adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests
Test: adb shell /data/nativetest64/bionic-unit-tests/bionic-unit-tests
Test: Update /system/etc/ld.config*.txt and check whether the vndk
linker namespace of the vendor process can access the shared libs from
the default linker namespace.
Change-Id: I2879f0c5f5af60c7e56f8f743ebd2872e552286b
diff --git a/linker/dlfcn.cpp b/linker/dlfcn.cpp
index 7f40f90..4b84537 100644
--- a/linker/dlfcn.cpp
+++ b/linker/dlfcn.cpp
@@ -65,6 +65,8 @@
bool __loader_android_link_namespaces(android_namespace_t* namespace_from,
android_namespace_t* namespace_to,
const char* shared_libs_sonames) __LINKER_PUBLIC__;
+bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to) __LINKER_PUBLIC__;
void __loader_android_set_application_target_sdk_version(uint32_t target) __LINKER_PUBLIC__;
void __loader_android_update_LD_LIBRARY_PATH(const char* ld_library_path) __LINKER_PUBLIC__;
void __loader_cfi_fail(uint64_t CallSiteTypeId,
@@ -266,6 +268,19 @@
return success;
}
+bool __loader_android_link_namespaces_all_libs(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to) {
+ ScopedPthreadMutexLocker locker(&g_dl_mutex);
+
+ bool success = link_namespaces_all_libs(namespace_from, namespace_to);
+
+ if (!success) {
+ __bionic_format_dlerror("android_link_namespaces_all_libs failed", linker_get_error_buffer());
+ }
+
+ return success;
+}
+
android_namespace_t* __loader_android_get_exported_namespace(const char* name) {
return get_exported_namespace(name);
}
diff --git a/linker/ld_android.cpp b/linker/ld_android.cpp
index c4ce1b9..4a05772 100644
--- a/linker/ld_android.cpp
+++ b/linker/ld_android.cpp
@@ -49,6 +49,7 @@
__strong_alias(__loader_android_get_exported_namespace, __internal_linker_error);
__strong_alias(__loader_android_init_anonymous_namespace, __internal_linker_error);
__strong_alias(__loader_android_link_namespaces, __internal_linker_error);
+__strong_alias(__loader_android_link_namespaces_all_libs, __internal_linker_error);
__strong_alias(__loader_android_set_application_target_sdk_version, __internal_linker_error);
__strong_alias(__loader_android_update_LD_LIBRARY_PATH, __internal_linker_error);
__strong_alias(__loader_cfi_fail, __internal_linker_error);
diff --git a/linker/linker.arm.map b/linker/linker.arm.map
index 4a3f177..a58e7c8 100644
--- a/linker/linker.arm.map
+++ b/linker/linker.arm.map
@@ -17,6 +17,7 @@
__loader_android_dlwarning;
__loader_cfi_fail;
__loader_android_link_namespaces;
+ __loader_android_link_namespaces_all_libs;
__loader_android_get_exported_namespace;
__loader_dl_unwind_find_exidx;
__loader_add_thread_local_dtor;
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 05efc55..0b8d5ee 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1430,7 +1430,7 @@
}
// returning true with empty soinfo means that the library is okay to be
- // loaded in the namespace buy has not yet been loaded there before.
+ // loaded in the namespace but has not yet been loaded there before.
task->set_soinfo(nullptr);
return true;
}
@@ -2363,7 +2363,8 @@
add_soinfos_to_namespace(parent_namespace->soinfo_list(), ns);
// and copy parent namespace links
for (auto& link : parent_namespace->linked_namespaces()) {
- ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames());
+ ns->add_linked_namespace(link.linked_namespace(), link.shared_lib_sonames(),
+ link.allow_all_shared_libs());
}
} else {
// If not shared - copy only the shared group
@@ -2399,7 +2400,25 @@
std::unordered_set<std::string> sonames_set(sonames.begin(), sonames.end());
ProtectedDataGuard guard;
- namespace_from->add_linked_namespace(namespace_to, sonames_set);
+ namespace_from->add_linked_namespace(namespace_to, sonames_set, false);
+
+ return true;
+}
+
+bool link_namespaces_all_libs(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to) {
+ if (namespace_from == nullptr) {
+ DL_ERR("error linking namespaces: namespace_from is null.");
+ return false;
+ }
+
+ if (namespace_to == nullptr) {
+ DL_ERR("error linking namespaces: namespace_to is null.");
+ return false;
+ }
+
+ ProtectedDataGuard guard;
+ namespace_from->add_linked_namespace(namespace_to, std::unordered_set<std::string>(), true);
return true;
}
@@ -3763,7 +3782,11 @@
auto it_to = namespaces.find(ns_link.ns_name());
CHECK(it_to != namespaces.end());
android_namespace_t* namespace_to = it_to->second;
- link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
+ if (ns_link.allow_all_shared_libs()) {
+ link_namespaces_all_libs(namespace_from, namespace_to);
+ } else {
+ link_namespaces(namespace_from, namespace_to, ns_link.shared_libs().c_str());
+ }
}
}
// we can no longer rely on the fact that libdl.so is part of default namespace
diff --git a/linker/linker.generic.map b/linker/linker.generic.map
index 04f4c8a..45bb0b5 100644
--- a/linker/linker.generic.map
+++ b/linker/linker.generic.map
@@ -17,6 +17,7 @@
__loader_android_dlwarning;
__loader_cfi_fail;
__loader_android_link_namespaces;
+ __loader_android_link_namespaces_all_libs;
__loader_android_get_exported_namespace;
__loader_add_thread_local_dtor;
__loader_remove_thread_local_dtor;
diff --git a/linker/linker.h b/linker/linker.h
index 6ebca4c..29d40fa 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -180,6 +180,9 @@
android_namespace_t* namespace_to,
const char* shared_lib_sonames);
+bool link_namespaces_all_libs(android_namespace_t* namespace_from,
+ android_namespace_t* namespace_to);
+
android_namespace_t* get_exported_namespace(const char* name);
void increment_dso_handle_reference_counter(void* dso_handle);
diff --git a/linker/linker_config.cpp b/linker/linker_config.cpp
index 60b7ad9..83c2f36 100644
--- a/linker/linker_config.cpp
+++ b/linker/linker_config.cpp
@@ -489,12 +489,15 @@
return false;
}
+ bool allow_all_shared_libs = properties.get_bool(property_name_prefix + ".link." +
+ linked_ns_name + ".allow_all_shared_libs");
+
std::string shared_libs = properties.get_string(property_name_prefix +
".link." +
linked_ns_name +
".shared_libs", &lineno);
- if (shared_libs.empty()) {
+ if (!allow_all_shared_libs && shared_libs.empty()) {
*error_msg = create_error_msg(ld_config_file_path,
lineno,
std::string("list of shared_libs for ") +
@@ -505,7 +508,15 @@
return false;
}
- ns_config->add_namespace_link(linked_ns_name, shared_libs);
+ if (allow_all_shared_libs && !shared_libs.empty()) {
+ *error_msg = create_error_msg(ld_config_file_path, lineno,
+ std::string("both shared_libs and allow_all_shared_libs "
+ "are set for ") +
+ name + "->" + linked_ns_name + " link.");
+ return false;
+ }
+
+ ns_config->add_namespace_link(linked_ns_name, shared_libs, allow_all_shared_libs);
}
ns_config->set_isolated(properties.get_bool(property_name_prefix + ".isolated"));
diff --git a/linker/linker_config.h b/linker/linker_config.h
index dde9362..0c50d57 100644
--- a/linker/linker_config.h
+++ b/linker/linker_config.h
@@ -43,8 +43,10 @@
class NamespaceLinkConfig {
public:
NamespaceLinkConfig() = default;
- NamespaceLinkConfig(const std::string& ns_name, const std::string& shared_libs)
- : ns_name_(ns_name), shared_libs_(shared_libs) {}
+ NamespaceLinkConfig(const std::string& ns_name, const std::string& shared_libs,
+ bool allow_all_shared_libs)
+ : ns_name_(ns_name), shared_libs_(shared_libs),
+ allow_all_shared_libs_(allow_all_shared_libs) {}
const std::string& ns_name() const {
return ns_name_;
@@ -54,9 +56,14 @@
return shared_libs_;
}
+ bool allow_all_shared_libs() const {
+ return allow_all_shared_libs_;
+ }
+
private:
std::string ns_name_;
std::string shared_libs_;
+ bool allow_all_shared_libs_;
};
class NamespaceConfig {
@@ -89,8 +96,9 @@
return namespace_links_;
}
- void add_namespace_link(const std::string& ns_name, const std::string& shared_libs) {
- namespace_links_.push_back(NamespaceLinkConfig(ns_name, shared_libs));
+ void add_namespace_link(const std::string& ns_name, const std::string& shared_libs,
+ bool allow_all_shared_libs) {
+ namespace_links_.push_back(NamespaceLinkConfig(ns_name, shared_libs, allow_all_shared_libs));
}
void set_isolated(bool isolated) {
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 16906d6..a7fe0d5 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -40,8 +40,10 @@
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)
+ const std::unordered_set<std::string>& shared_lib_sonames,
+ bool allow_all_shared_libs)
+ : linked_namespace_(linked_namespace), shared_lib_sonames_(shared_lib_sonames),
+ allow_all_shared_libs_(allow_all_shared_libs)
{}
android_namespace_t* linked_namespace() const {
@@ -53,12 +55,17 @@
}
bool is_accessible(const char* soname) const {
- return shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
+ return allow_all_shared_libs_ || shared_lib_sonames_.find(soname) != shared_lib_sonames_.end();
+ }
+
+ bool allow_all_shared_libs() const {
+ return allow_all_shared_libs_;
}
private:
android_namespace_t* const linked_namespace_;
const std::unordered_set<std::string> shared_lib_sonames_;
+ bool allow_all_shared_libs_;
};
struct android_namespace_t {
@@ -105,8 +112,10 @@
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));
+ const std::unordered_set<std::string>& shared_lib_sonames,
+ bool allow_all_shared_libs) {
+ linked_namespaces_.push_back(
+ android_namespace_link_t(linked_namespace, shared_lib_sonames, allow_all_shared_libs));
}
void add_soinfo(soinfo* si) {
diff --git a/linker/tests/linker_config_test.cpp b/linker/tests/linker_config_test.cpp
index 4c0dcdd..e716879 100644
--- a/linker/tests/linker_config_test.cpp
+++ b/linker/tests/linker_config_test.cpp
@@ -81,6 +81,8 @@
"namespace.vndk.search.paths = /system/${LIB}/vndk\n"
"namespace.vndk.asan.search.paths = /data\n"
"namespace.vndk.asan.search.paths += /system/${LIB}/vndk\n"
+ "namespace.vndk.links = default\n"
+ "namespace.vndk.link.default.allow_all_shared_libs = true\n"
"\n";
static bool write_version(const std::string& path, uint32_t version) {
@@ -154,10 +156,14 @@
const auto& default_ns_links = default_ns_config->links();
ASSERT_EQ(2U, default_ns_links.size());
+
ASSERT_EQ("system", default_ns_links[0].ns_name());
ASSERT_EQ("libc.so:libm.so:libdl.so:libstdc++.so", default_ns_links[0].shared_libs());
+ ASSERT_FALSE(default_ns_links[0].allow_all_shared_libs());
+
ASSERT_EQ("vndk", default_ns_links[1].ns_name());
ASSERT_EQ("libcutils.so:libbase.so", default_ns_links[1].shared_libs());
+ ASSERT_FALSE(default_ns_links[1].allow_all_shared_libs());
auto& ns_configs = config->namespace_configs();
ASSERT_EQ(3U, ns_configs.size());
@@ -187,8 +193,13 @@
ASSERT_TRUE(ns_vndk != nullptr) << "vndk namespace was not found";
ASSERT_FALSE(ns_vndk->isolated()); // malformed bool property
- ASSERT_FALSE(ns_vndk->visible()); // undefined bool property
+ ASSERT_FALSE(ns_vndk->visible()); // undefined bool property
ASSERT_EQ(kExpectedVndkSearchPath, ns_vndk->search_paths());
+
+ const auto& ns_vndk_links = ns_vndk->links();
+ ASSERT_EQ(1U, ns_vndk_links.size());
+ ASSERT_EQ("default", ns_vndk_links[0].ns_name());
+ ASSERT_TRUE(ns_vndk_links[0].allow_all_shared_libs());
}
TEST(linker_config, smoke) {
@@ -198,3 +209,40 @@
TEST(linker_config, asan_smoke) {
run_linker_config_smoke_test(true);
}
+
+TEST(linker_config, ns_link_shared_libs_invalid_settings) {
+ // This unit test ensures an error is emitted when a namespace link in ld.config.txt specifies
+ // both shared_libs and allow_all_shared_libs.
+
+ static const char config_str[] =
+ "dir.test = /data/local/tmp\n"
+ "\n"
+ "[test]\n"
+ "additional.namespaces = system\n"
+ "namespace.default.links = system\n"
+ "namespace.default.link.system.shared_libs = libc.so:libm.so\n"
+ "namespace.default.link.system.allow_all_shared_libs = true\n"
+ "\n";
+
+ TemporaryFile tmp_file;
+ close(tmp_file.fd);
+ tmp_file.fd = -1;
+
+ android::base::WriteStringToFile(config_str, tmp_file.path);
+
+ TemporaryDir tmp_dir;
+
+ std::string executable_path = std::string(tmp_dir.path) + "/some-binary";
+
+ const Config* config = nullptr;
+ std::string error_msg;
+ ASSERT_FALSE(Config::read_binary_config(tmp_file.path,
+ executable_path.c_str(),
+ false,
+ &config,
+ &error_msg));
+ ASSERT_TRUE(config == nullptr);
+ ASSERT_EQ(std::string(tmp_file.path) + ":6: "
+ "error: both shared_libs and allow_all_shared_libs are set for default->system link.",
+ error_msg);
+}