Merge "Fix lookup logic for linked namespaces"

am: 6a2c7f5a68

Change-Id: I6af8cccc6ca6a18ced2f4843621563319fdc29f5
This commit is contained in:
Dimitry Ivanov 2017-04-02 02:20:13 +00:00 committed by android-build-merger
commit e3f66625e3
2 changed files with 127 additions and 35 deletions

View file

@ -1112,11 +1112,43 @@ static void for_each_dt_needed(const ElfReader& elf_reader, F action) {
}
}
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();
@ -1144,17 +1176,8 @@ static bool load_library(android_namespace_t* ns,
// 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);
@ -1249,7 +1272,8 @@ static bool load_library(android_namespace_t* ns,
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();
@ -1270,7 +1294,7 @@ static bool load_library(android_namespace_t* ns,
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.
@ -1283,19 +1307,12 @@ static bool load_library(android_namespace_t* ns,
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)) {
@ -1307,6 +1324,38 @@ static bool find_loaded_library_by_soname(android_namespace_t* ns,
});
}
// 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) {
@ -1316,7 +1365,7 @@ static bool find_library_in_linked_namespace(const android_namespace_link_t& nam
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 {
@ -1367,7 +1416,7 @@ static bool find_library_internal(android_namespace_t* ns,
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;
}
@ -1377,7 +1426,7 @@ static bool find_library_internal(android_namespace_t* ns,
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;
}

View file

@ -672,8 +672,59 @@ TEST(dlext, ns_smoke) {
ASSERT_TRUE(handle != nullptr) << dlerror();
dlclose(handle);
// dlopen for a public library using an absolute path should work
// 1. For isolated namespaces
android_dlextinfo extinfo;
extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
extinfo.library_namespace = ns2;
handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
ASSERT_TRUE(handle != nullptr) << dlerror();
ASSERT_TRUE(handle == handle_public);
dlclose(handle);
// 1.1 even if it wasn't loaded before
dlclose(handle_public);
handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
ASSERT_TRUE(handle_public == nullptr);
ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path +
"\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
ASSERT_TRUE(handle != nullptr) << dlerror();
handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
ASSERT_TRUE(handle == handle_public);
dlclose(handle);
// 2. And for regular namespaces (make sure it does not load second copy of the library)
extinfo.library_namespace = ns1;
handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
ASSERT_TRUE(handle != nullptr) << dlerror();
ASSERT_TRUE(handle == handle_public);
dlclose(handle);
// 2.1 Unless it was not loaded before - in which case it will load a duplicate.
// TODO(dimitry): This is broken. Maybe we need to deprecate non-isolated namespaces?
dlclose(handle_public);
handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW | RTLD_NOLOAD);
ASSERT_TRUE(handle_public == nullptr);
ASSERT_EQ(std::string("dlopen failed: library \"") + lib_public_path +
"\" wasn't loaded and RTLD_NOLOAD prevented it", dlerror());
handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
ASSERT_TRUE(handle != nullptr) << dlerror();
handle_public = dlopen(lib_public_path.c_str(), RTLD_NOW);
ASSERT_TRUE(handle != handle_public);
dlclose(handle);
extinfo.library_namespace = ns1;
void* handle1 = android_dlopen_ext(root_lib, RTLD_NOW, &extinfo);
@ -685,14 +736,6 @@ TEST(dlext, ns_smoke) {
ASSERT_TRUE(handle1 != handle2);
// dlopen for a public library using an absolute path should work for isolated namespaces
extinfo.library_namespace = ns2;
handle = android_dlopen_ext(lib_public_path.c_str(), RTLD_NOW, &extinfo);
ASSERT_TRUE(handle != nullptr) << dlerror();
ASSERT_TRUE(handle == handle_public);
dlclose(handle);
typedef const char* (*fn_t)();
fn_t ns_get_local_string1 = reinterpret_cast<fn_t>(dlsym(handle1, "ns_get_local_string"));