Merge changes Ia359d9f2,Ibabbf559,I1b542e47,I4b6f48af,I82e442f0
* changes:
Fix bootstrap linker library searching
Remove dangling soinfo* from elf_readers_map_
Fix DL_WARN_documented_change URL
remove search_linked_namespaces param
Refactor linker lookup code a bit
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 8eb72dc..e34c796 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -537,10 +537,10 @@
static deleter_t deleter;
- static LoadTask* create(const char* name,
- soinfo* needed_by,
- android_namespace_t* start_from,
- std::unordered_map<const soinfo*, ElfReader>* readers_map) {
+ // needed_by is NULL iff dlopen is called from memory that isn't part of any known soinfo.
+ static LoadTask* create(const char* _Nonnull name, soinfo* _Nullable needed_by,
+ android_namespace_t* _Nonnull start_from,
+ std::unordered_map<const soinfo*, ElfReader>* _Nonnull readers_map) {
LoadTask* ptr = TypeBasedAllocator<LoadTask>::alloc();
return new (ptr) LoadTask(name, needed_by, start_from, readers_map);
}
@@ -602,6 +602,11 @@
return start_from_;
}
+ void remove_cached_elf_reader() {
+ CHECK(si_ != nullptr);
+ (*elf_readers_map_).erase(si_);
+ }
+
const ElfReader& get_elf_reader() const {
CHECK(si_ != nullptr);
return (*elf_readers_map_)[si_];
@@ -1040,47 +1045,24 @@
// If the name contains a slash, we should attempt to open it directly and not search the paths.
if (strchr(name, '/') != nullptr) {
- int fd = -1;
-
- if (strstr(name, kZipFileSeparator) != nullptr) {
- fd = open_library_in_zipfile(zip_archive_cache, name, file_offset, realpath);
- }
-
- if (fd == -1) {
- fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
- if (fd != -1) {
- *file_offset = 0;
- if (!realpath_fd(fd, realpath)) {
- if (!is_first_stage_init()) {
- PRINT("warning: unable to get realpath for the library \"%s\". Will use given path.",
- name);
- }
- *realpath = name;
- }
- }
- }
-
- return fd;
+ return open_library_at_path(zip_archive_cache, name, file_offset, realpath);
}
- // Otherwise we try LD_LIBRARY_PATH first, and fall back to the default library path
+ // LD_LIBRARY_PATH has the highest priority. We don't have to check accessibility when searching
+ // the namespace's path lists, because anything found on a namespace path list should always be
+ // accessible.
int fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_ld_library_paths(), realpath);
+
+ // Try the DT_RUNPATH, and verify that the library is accessible.
if (fd == -1 && needed_by != nullptr) {
fd = open_library_on_paths(zip_archive_cache, name, file_offset, needed_by->get_dt_runpath(), realpath);
- // Check if the library is accessible
if (fd != -1 && !ns->is_accessible(*realpath)) {
close(fd);
fd = -1;
}
}
-#if !defined(__ANDROID_APEX__)
- if (fd == -1) {
- std::vector<std::string> bootstrap_paths = { std::string(kSystemLibDir) + "/bootstrap" };
- fd = open_library_on_paths(zip_archive_cache, name, file_offset, bootstrap_paths, realpath);
- }
-#endif
-
+ // Finally search the namespace's main search path list.
if (fd == -1) {
fd = open_library_on_paths(zip_archive_cache, name, file_offset, ns->get_default_library_paths(), realpath);
}
@@ -1282,16 +1264,14 @@
}
soinfo* si = soinfo_alloc(ns, realpath.c_str(), &file_stat, file_offset, rtld_flags);
- if (si == nullptr) {
- return false;
- }
task->set_soinfo(si);
// Read the ELF header and some of the segments.
if (!task->read(realpath.c_str(), file_stat.st_size)) {
- soinfo_free(si);
+ task->remove_cached_elf_reader();
task->set_soinfo(nullptr);
+ soinfo_free(si);
return false;
}
@@ -1337,14 +1317,13 @@
soinfo* needed_by = task->get_needed_by();
const android_dlextinfo* extinfo = task->get_extinfo();
- off64_t file_offset;
- std::string realpath;
if (extinfo != nullptr && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
- file_offset = 0;
+ off64_t file_offset = 0;
if ((extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET) != 0) {
file_offset = extinfo->library_fd_offset;
}
+ std::string realpath;
if (!realpath_fd(extinfo->library_fd, &realpath)) {
if (!is_first_stage_init()) {
PRINT(
@@ -1362,10 +1341,12 @@
LD_LOG(kLogDlopen,
"load_library(ns=%s, task=%s, flags=0x%x, search_linked_namespaces=%d): calling "
- "open_library with realpath=%s",
- ns->get_name(), name, rtld_flags, search_linked_namespaces, realpath.c_str());
+ "open_library",
+ ns->get_name(), name, rtld_flags, search_linked_namespaces);
// Open the file.
+ off64_t file_offset;
+ std::string realpath;
int fd = open_library(ns, zip_archive_cache, name, needed_by, &file_offset, &realpath);
if (fd == -1) {
if (task->is_dt_needed()) {
@@ -1476,11 +1457,11 @@
LoadTask* task,
ZipArchiveCache* zip_archive_cache,
LoadTaskList* load_tasks,
- int rtld_flags,
- bool search_linked_namespaces) {
+ int rtld_flags) {
soinfo* candidate;
- if (find_loaded_library_by_soname(ns, task->get_name(), search_linked_namespaces, &candidate)) {
+ if (find_loaded_library_by_soname(ns, task->get_name(), true /* search_linked_namespaces */,
+ &candidate)) {
LD_LOG(kLogDlopen,
"find_library_internal(ns=%s, task=%s): Already loaded (by soname): %s",
ns->get_name(), task->get_name(), candidate->get_realpath());
@@ -1493,7 +1474,8 @@
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, search_linked_namespaces)) {
+ if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags,
+ true /* search_linked_namespaces */)) {
return true;
}
@@ -1508,39 +1490,33 @@
ns->get_name(), task->get_name(), g_default_namespace.get_name());
ns = &g_default_namespace;
if (load_library(ns, task, zip_archive_cache, load_tasks, rtld_flags,
- search_linked_namespaces)) {
+ true /* search_linked_namespaces */)) {
return true;
}
}
// END OF WORKAROUND
- if (search_linked_namespaces) {
- // if a library was not found - look into linked namespaces
- // preserve current dlerror in the case it fails.
- DlErrorRestorer dlerror_restorer;
- LD_LOG(kLogDlopen, "find_library_internal(ns=%s, task=%s): Trying %zu linked namespaces",
- ns->get_name(), task->get_name(), ns->linked_namespaces().size());
- for (auto& linked_namespace : ns->linked_namespaces()) {
- if (find_library_in_linked_namespace(linked_namespace, task)) {
- if (task->get_soinfo() == nullptr) {
- // try to load the library - once namespace boundary is crossed
- // we need to load a library within separate load_group
- // to avoid using symbols from foreign namespace while.
- //
- // However, actual linking is deferred until when the global group
- // is fully identified and is applied to all namespaces.
- // Otherwise, the libs in the linked namespace won't get symbols from
- // the global group.
- if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks, rtld_flags, false)) {
- LD_LOG(
- kLogDlopen, "find_library_internal(ns=%s, task=%s): Found in linked namespace %s",
- ns->get_name(), task->get_name(), linked_namespace.linked_namespace()->get_name());
- return true;
- }
- } else {
- // lib is already loaded
- return true;
- }
+ // if a library was not found - look into linked namespaces
+ // preserve current dlerror in the case it fails.
+ DlErrorRestorer dlerror_restorer;
+ LD_LOG(kLogDlopen, "find_library_internal(ns=%s, task=%s): Trying %zu linked namespaces",
+ ns->get_name(), task->get_name(), ns->linked_namespaces().size());
+ for (auto& linked_namespace : ns->linked_namespaces()) {
+ if (find_library_in_linked_namespace(linked_namespace, task)) {
+ // Library is already loaded.
+ if (task->get_soinfo() != nullptr) {
+ // n.b. This code path runs when find_library_in_linked_namespace found an already-loaded
+ // library by soname. That should only be possible with a greylist lookup, where we switch
+ // the namespace, because otherwise, find_library_in_linked_namespace is duplicating the
+ // soname scan done in this function's first call to find_loaded_library_by_soname.
+ return true;
+ }
+
+ if (load_library(linked_namespace.linked_namespace(), task, zip_archive_cache, load_tasks,
+ rtld_flags, false /* search_linked_namespaces */)) {
+ LD_LOG(kLogDlopen, "find_library_internal(ns=%s, task=%s): Found in linked namespace %s",
+ ns->get_name(), task->get_name(), linked_namespace.linked_namespace()->get_name());
+ return true;
}
}
}
@@ -1577,7 +1553,6 @@
int rtld_flags,
const android_dlextinfo* extinfo,
bool add_as_children,
- bool search_linked_namespaces,
std::vector<android_namespace_t*>* namespaces) {
// Step 0: prepare.
std::unordered_map<const soinfo*, ElfReader> readers_map;
@@ -1633,8 +1608,7 @@
task,
&zip_archive_cache,
&load_tasks,
- rtld_flags,
- search_linked_namespaces || is_dt_needed)) {
+ rtld_flags)) {
return false;
}
@@ -1876,8 +1850,7 @@
0,
rtld_flags,
extinfo,
- false /* add_as_children */,
- true /* search_linked_namespaces */)) {
+ false /* add_as_children */)) {
if (si != nullptr) {
soinfo_unload(si);
}
@@ -2443,6 +2416,21 @@
}
}
+std::vector<std::string> fix_lib_paths(std::vector<std::string> paths) {
+ // For the bootstrap linker, insert /system/${LIB}/bootstrap in front of /system/${LIB} in any
+ // namespace search path. The bootstrap linker should prefer to use the bootstrap bionic libraries
+ // (e.g. libc.so).
+#if !defined(__ANDROID_APEX__)
+ for (size_t i = 0; i < paths.size(); ++i) {
+ if (paths[i] == kSystemLibDir) {
+ paths.insert(paths.begin() + i, std::string(kSystemLibDir) + "/bootstrap");
+ ++i;
+ }
+ }
+#endif
+ return paths;
+}
+
android_namespace_t* create_namespace(const void* caller_addr,
const char* name,
const char* ld_library_path,
@@ -3298,9 +3286,8 @@
// Fail if app is targeting M or above.
int app_target_api_level = get_application_target_sdk_version();
if (app_target_api_level >= 23) {
- DL_ERR_AND_LOG("\"%s\" has text relocations (https://android.googlesource.com/platform/"
- "bionic/+/master/android-changes-for-ndk-developers.md#Text-Relocations-"
- "Enforced-for-API-level-23)", get_realpath());
+ DL_ERR_AND_LOG("\"%s\" has text relocations (%s#Text-Relocations-Enforced-for-API-level-23)",
+ get_realpath(), kBionicChangesUrl);
return false;
}
// Make segments writable to allow text relocations to work properly. We will later call
diff --git a/linker/linker.h b/linker/linker.h
index 2da1404..9b6af3b 100644
--- a/linker/linker.h
+++ b/linker/linker.h
@@ -71,6 +71,10 @@
DISALLOW_COPY_AND_ASSIGN(VersionTracker);
};
+static constexpr const char* kBionicChangesUrl =
+ "https://android.googlesource.com/platform/bionic/+/master/"
+ "android-changes-for-ndk-developers.md";
+
soinfo* get_libdl_info(const soinfo& linker_si);
soinfo* find_containing_library(const void* p);
diff --git a/linker/linker_globals.cpp b/linker/linker_globals.cpp
index bcc2a1e..31da02c 100644
--- a/linker/linker_globals.cpp
+++ b/linker/linker_globals.cpp
@@ -50,7 +50,7 @@
return sizeof(__linker_dl_err_buf);
}
-void DL_WARN_documented_change(int api_level, const char* doc_link, const char* fmt, ...) {
+void DL_WARN_documented_change(int api_level, const char* doc_fragment, const char* fmt, ...) {
std::string result{"Warning: "};
va_list ap;
@@ -60,8 +60,9 @@
android::base::StringAppendF(&result,
" and will not work when the app moves to API level %d or later "
- "(https://android.googlesource.com/platform/bionic/+/master/%s) "
- "(allowing for now because this app's target API level is still %d)",
- api_level, doc_link, get_application_target_sdk_version());
+ "(%s#%s) (allowing for now because this app's target API level is "
+ "still %d)",
+ api_level, kBionicChangesUrl, doc_fragment,
+ get_application_target_sdk_version());
DL_WARN("%s", result.c_str());
}
diff --git a/linker/linker_main.cpp b/linker/linker_main.cpp
index 98af54a..41bb4ba 100644
--- a/linker/linker_main.cpp
+++ b/linker/linker_main.cpp
@@ -460,7 +460,6 @@
RTLD_GLOBAL,
nullptr,
true /* add_as_children */,
- true /* search_linked_namespaces */,
&namespaces)) {
__linker_cannot_link(g_argv[0]);
} else if (needed_libraries_count == 0) {
diff --git a/linker/linker_main.h b/linker/linker_main.h
index 47d4bdb..724f43c 100644
--- a/linker/linker_main.h
+++ b/linker/linker_main.h
@@ -63,7 +63,6 @@
int rtld_flags,
const android_dlextinfo* extinfo,
bool add_as_children,
- bool search_linked_namespaces,
std::vector<android_namespace_t*>* namespaces = nullptr);
void solist_add_soinfo(soinfo* si);
diff --git a/linker/linker_namespaces.h b/linker/linker_namespaces.h
index 9561bb4..6843ebc 100644
--- a/linker/linker_namespaces.h
+++ b/linker/linker_namespaces.h
@@ -34,6 +34,8 @@
#include <vector>
#include <unordered_set>
+std::vector<std::string> fix_lib_paths(std::vector<std::string> paths);
+
struct android_namespace_t;
struct android_namespace_link_t {
@@ -100,10 +102,10 @@
return default_library_paths_;
}
void set_default_library_paths(std::vector<std::string>&& library_paths) {
- default_library_paths_ = std::move(library_paths);
+ default_library_paths_ = fix_lib_paths(std::move(library_paths));
}
void set_default_library_paths(const std::vector<std::string>& library_paths) {
- default_library_paths_ = library_paths;
+ default_library_paths_ = fix_lib_paths(library_paths);
}
const std::vector<std::string>& get_permitted_paths() const {