From 9b82136b987bc01224e3b42732334ea27c97d188 Mon Sep 17 00:00:00 2001 From: Dmitriy Ivanov Date: Thu, 2 Apr 2015 16:03:56 -0700 Subject: [PATCH] Add ANDROID_DLEXT_FORCE_LOAD flag This flag allows to force loading of the library in the case when for some reason multiple ELF files share the same filename (because the already-loaded library has been removed and overwritten, for example). Change-Id: I798d44409ee13d63eaa75d685e99c4d028d2b0c1 --- libc/include/android/dlext.h | 16 ++++++++++++++-- linker/linker.cpp | 22 ++++++++++++---------- tests/dlext_test.cpp | 34 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 12 deletions(-) diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h index 90daf30eb..f10a8a2a8 100644 --- a/libc/include/android/dlext.h +++ b/libc/include/android/dlext.h @@ -59,16 +59,28 @@ enum { /* If opening a library using library_fd read it starting at library_fd_offset. * This flag is only valid when ANDROID_DLEXT_USE_LIBRARY_FD is set. */ - ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET = 0x20, + /* When set, do not check if the library has already been loaded by file stat(2)s. + * + * This flag allows forced loading of the library in the case when for some + * reason multiple ELF files share the same filename (because the already-loaded + * library has been removed and overwritten, for example). + * + * Note that if the library has the same dt_soname as an old one and some other + * library has the soname in DT_NEEDED list, the first one will be used to resolve any + * dependencies. + */ + ANDROID_DLEXT_FORCE_LOAD = 0x40, + /* Mask of valid bits */ ANDROID_DLEXT_VALID_FLAG_BITS = ANDROID_DLEXT_RESERVED_ADDRESS | ANDROID_DLEXT_RESERVED_ADDRESS_HINT | ANDROID_DLEXT_WRITE_RELRO | ANDROID_DLEXT_USE_RELRO | ANDROID_DLEXT_USE_LIBRARY_FD | - ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET, + ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET | + ANDROID_DLEXT_FORCE_LOAD, }; typedef struct { diff --git a/linker/linker.cpp b/linker/linker.cpp index ebf125e1f..8703e4fe5 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -1014,16 +1014,18 @@ static soinfo* load_library(LoadTaskList& load_tasks, } // Check for symlink and other situations where - // file can have different names. - for (soinfo* si = solist; si != nullptr; si = si->next) { - if (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) { - TRACE("library \"%s\" is already loaded under different name/path \"%s\" - " - "will return existing soinfo", name, si->name); - return si; + // file can have different names, unless ANDROID_DLEXT_FORCE_LOAD is set + if (extinfo == nullptr || (extinfo->flags & ANDROID_DLEXT_FORCE_LOAD) == 0) { + for (soinfo* si = solist; si != nullptr; si = si->next) { + if (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) { + TRACE("library \"%s\" is already loaded under different name/path \"%s\" - " + "will return existing soinfo", name, si->name); + return si; + } } } diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index ca6a75a95..700abff5e 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -173,6 +173,40 @@ TEST_F(DlExtTest, ExtInfoUseOffsetWihtoutFd) { ASSERT_STREQ("dlopen failed: invalid extended flag combination (ANDROID_DLEXT_USE_LIBRARY_FD_OFFSET without ANDROID_DLEXT_USE_LIBRARY_FD): 0x20", dlerror()); } +TEST(dlext, android_dlopen_ext_force_load_smoke) { + // 1. Open actual file + void* handle = dlopen("libdlext_test.so", RTLD_NOW); + ASSERT_DL_NOTNULL(handle); + // 2. Open link with force_load flag set + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; + void* handle2 = android_dlopen_ext("libdlext_test_v2.so", RTLD_NOW, &extinfo); + ASSERT_DL_NOTNULL(handle2); + ASSERT_TRUE(handle != handle2); + + dlclose(handle2); + dlclose(handle); +} + +TEST(dlext, android_dlopen_ext_force_load_soname_exception) { + // Check if soname lookup still returns already loaded library + // when ANDROID_DLEXT_FORCE_LOAD flag is specified. + void* handle = dlopen("libdlext_test_v2.so", RTLD_NOW); + ASSERT_DL_NOTNULL(handle); + + android_dlextinfo extinfo; + extinfo.flags = ANDROID_DLEXT_FORCE_LOAD; + + // Note that 'libdlext_test.so' is dt_soname for libdlext_test_v2.so + void* handle2 = android_dlopen_ext("libdlext_test.so", RTLD_NOW, &extinfo); + + ASSERT_DL_NOTNULL(handle2); + ASSERT_TRUE(handle == handle2); + + dlclose(handle2); + dlclose(handle); +} + TEST(dlfcn, dlopen_from_zip_absolute_path) { const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;