Fix lookup logic for linked namespaces
When looking for already loaded libraries include
linked namespaces to the search, but check if
the library is accessible from the main namespace.
Bug: http://b/36008422
Bug: http://b/35417197
Bug: http://b/34052337
Bug: http://b/36660652
Bug: https://issuetracker.google.com/36636090
Test: run bionic-unit-tests --gtest_filter=dl*:Dl*
Change-Id: Ic7c1d48114da3ca5dc6512ef03f595dd17b6ed17
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 60dff98..497fc2d 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1110,11 +1110,43 @@
}
}
+static bool find_loaded_library_by_inode(android_namespace_t* ns,
+ const struct stat& file_stat,
+ off64_t file_offset,
+ bool search_linked_namespaces,
+ soinfo** candidate) {
+
+ auto predicate = [&](soinfo* si) {
+ return si->get_st_dev() != 0 &&
+ si->get_st_ino() != 0 &&
+ si->get_st_dev() == file_stat.st_dev &&
+ si->get_st_ino() == file_stat.st_ino &&
+ si->get_file_offset() == file_offset;
+ };
+
+ *candidate = ns->soinfo_list().find_if(predicate);
+
+ if (*candidate == nullptr && search_linked_namespaces) {
+ for (auto& link : ns->linked_namespaces()) {
+ android_namespace_t* linked_ns = link.linked_namespace();
+ soinfo* si = linked_ns->soinfo_list().find_if(predicate);
+
+ if (si != nullptr && link.is_accessible(si->get_soname())) {
+ *candidate = si;
+ return true;
+ }
+ }
+ }
+
+ return *candidate != nullptr;
+}
+
static bool load_library(android_namespace_t* ns,
LoadTask* task,
LoadTaskList* load_tasks,
int rtld_flags,
- const std::string& realpath) {
+ const std::string& realpath,
+ bool search_linked_namespaces) {
off64_t file_offset = task->get_file_offset();
const char* name = task->get_name();
const android_dlextinfo* extinfo = task->get_extinfo();
@@ -1142,17 +1174,8 @@
// Check for symlink and other situations where
// file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set
if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) {
- auto predicate = [&](soinfo* si) {
- return si->get_st_dev() != 0 &&
- si->get_st_ino() != 0 &&
- si->get_st_dev() == file_stat.st_dev &&
- si->get_st_ino() == file_stat.st_ino &&
- si->get_file_offset() == file_offset;
- };
-
- soinfo* si = ns->soinfo_list().find_if(predicate);
-
- if (si != nullptr) {
+ soinfo* si = nullptr;
+ if (find_loaded_library_by_inode(ns, file_stat, file_offset, search_linked_namespaces, &si)) {
TRACE("library \"%s\" is already loaded under different name/path \"%s\" - "
"will return existing soinfo", name, si->get_realpath());
task->set_soinfo(si);
@@ -1247,7 +1270,8 @@
LoadTask* task,
ZipArchiveCache* zip_archive_cache,
LoadTaskList* load_tasks,
- int rtld_flags) {
+ int rtld_flags,
+ bool search_linked_namespaces) {
const char* name = task->get_name();
soinfo* needed_by = task->get_needed_by();
const android_dlextinfo* extinfo = task->get_extinfo();
@@ -1268,7 +1292,7 @@
task->set_fd(extinfo->library_fd, false);
task->set_file_offset(file_offset);
- return load_library(ns, task, load_tasks, rtld_flags, realpath);
+ return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
}
// Open the file.
@@ -1281,19 +1305,12 @@
task->set_fd(fd, true);
task->set_file_offset(file_offset);
- return load_library(ns, task, load_tasks, rtld_flags, realpath);
+ return load_library(ns, task, load_tasks, rtld_flags, realpath, search_linked_namespaces);
}
-// Returns true if library was found and false otherwise
static bool find_loaded_library_by_soname(android_namespace_t* ns,
- const char* name, soinfo** candidate) {
- *candidate = nullptr;
-
- // Ignore filename with path.
- if (strchr(name, '/') != nullptr) {
- return false;
- }
-
+ const char* name,
+ soinfo** candidate) {
return !ns->soinfo_list().visit([&](soinfo* si) {
const char* soname = si->get_soname();
if (soname != nullptr && (strcmp(name, soname) == 0)) {
@@ -1305,6 +1322,38 @@
});
}
+// Returns true if library was found and false otherwise
+static bool find_loaded_library_by_soname(android_namespace_t* ns,
+ const char* name,
+ bool search_linked_namespaces,
+ soinfo** candidate) {
+ *candidate = nullptr;
+
+ // Ignore filename with path.
+ if (strchr(name, '/') != nullptr) {
+ return false;
+ }
+
+ bool found = find_loaded_library_by_soname(ns, name, candidate);
+
+ if (!found && search_linked_namespaces) {
+ // if a library was not found - look into linked namespaces
+ for (auto& link : ns->linked_namespaces()) {
+ if (!link.is_accessible(name)) {
+ continue;
+ }
+
+ android_namespace_t* linked_ns = link.linked_namespace();
+
+ if (find_loaded_library_by_soname(linked_ns, name, candidate)) {
+ return true;
+ }
+ }
+ }
+
+ return found;
+}
+
static bool find_library_in_linked_namespace(const android_namespace_link_t& namespace_link,
LoadTask* task,
int rtld_flags) {
@@ -1314,7 +1363,7 @@
bool loaded = false;
std::string soname;
- if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
+ if (find_loaded_library_by_soname(ns, task->get_name(), false, &candidate)) {
loaded = true;
soname = candidate->get_soname();
} else {
@@ -1365,7 +1414,7 @@
bool search_linked_namespaces) {
soinfo* candidate;
- if (find_loaded_library_by_soname(ns, task->get_name(), &candidate)) {
+ if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
task->set_soinfo(candidate);
return true;
}
@@ -1375,7 +1424,7 @@
TRACE("[ \"%s\" find_loaded_library_by_soname failed (*candidate=%s@%p). Trying harder...]",
task->get_name(), candidate == nullptr ? "n/a" : candidate->get_realpath(), candidate);
- if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags)) {
+ if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags, search_linked_namespaces)) {
return true;
}