diff options
author | Dimitry Ivanov <dimitry@google.com> | 2016-05-18 07:33:50 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2016-05-18 07:33:50 +0000 |
commit | 041cf17cdd900f807d8d39d04802e9f31f2ffd74 (patch) | |
tree | 870a323fa0526156e95826d54f58e768d2cf4a5d | |
parent | 49cfc899a3708fae9175e44c0c02cd479fda8b36 (diff) | |
parent | dcaef3710df817db5652a1f3ab4646f43f5cd3ee (diff) | |
download | bionic-041cf17cdd900f807d8d39d04802e9f31f2ffd74.tar.gz |
Merge "Fix dlopen of main executable by absolute path" into nyc-dev
-rw-r--r-- | linker/linker.cpp | 24 | ||||
-rw-r--r-- | tests/dlext_test.cpp | 4 | ||||
-rw-r--r-- | tests/dlfcn_test.cpp | 23 | ||||
-rw-r--r-- | tests/gtest_main.cpp | 30 | ||||
-rw-r--r-- | tests/utils.h | 3 |
5 files changed, 61 insertions, 23 deletions
diff --git a/linker/linker.cpp b/linker/linker.cpp index a29a599f5..3112a1e37 100644 --- a/linker/linker.cpp +++ b/linker/linker.cpp @@ -4169,6 +4169,20 @@ static void init_default_namespace() { extern "C" int __system_properties_init(void); +static const char* get_executable_path() { + static std::string executable_path; + if (executable_path.empty()) { + char path[PATH_MAX]; + ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path)); + if (path_len == -1 || path_len >= static_cast<ssize_t>(sizeof(path))) { + __libc_fatal("readlink('/proc/self/exe') failed: %s", strerror(errno)); + } + executable_path = std::string(path, path_len); + } + + return executable_path.c_str(); +} + /* * This code is called after the linker has linked itself and * fixed it's own GOT. It is safe to make references to externs @@ -4215,7 +4229,13 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( } } - soinfo* si = soinfo_alloc(&g_default_namespace, args.argv[0], nullptr, 0, RTLD_GLOBAL); + const char* executable_path = get_executable_path(); + struct stat file_stat; + if (TEMP_FAILURE_RETRY(stat(executable_path, &file_stat)) != 0) { + __libc_fatal("unable to stat file for the executable \"%s\": %s", executable_path, strerror(errno)); + } + + soinfo* si = soinfo_alloc(&g_default_namespace, executable_path, &file_stat, 0, RTLD_GLOBAL); if (si == nullptr) { __libc_fatal("Couldn't allocate soinfo: out of memory?"); } @@ -4228,7 +4248,7 @@ static ElfW(Addr) __linker_init_post_relocation(KernelArgumentBlock& args, ElfW( // gdb aware of them before loading the rest of the dependency // tree. map->l_addr = 0; - map->l_name = args.argv[0]; + map->l_name = const_cast<char*>(executable_path); insert_link_map_into_debug_map(map); init_linker_info_for_gdb(linker_base); diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp index 49df57bb3..ee61d5f9b 100644 --- a/tests/dlext_test.cpp +++ b/tests/dlext_test.cpp @@ -805,7 +805,7 @@ TEST(dlext, ns_isolated) { handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); ASSERT_TRUE(handle2 == nullptr); ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed" - " or dlopened by \"" + get_executable_name() + "\" is not accessible" + " or dlopened by \"" + get_executable_path() + "\" is not accessible" " for the namespace \"private_isolated1\"", dlerror()); extinfo.library_namespace = ns_isolated2; @@ -907,7 +907,7 @@ TEST(dlext, ns_shared) { handle2 = android_dlopen_ext(lib_private_external_path.c_str(), RTLD_NOW, &extinfo); ASSERT_TRUE(handle2 == nullptr); ASSERT_EQ("dlopen failed: library \"" + lib_private_external_path + "\" needed" - " or dlopened by \"" + get_executable_name() + "\" is not accessible" + " or dlopened by \"" + get_executable_path() + "\" is not accessible" " for the namespace \"private_isolated_shared\"", dlerror()); // load libnstest_root.so to shared namespace in order to check that everything is different diff --git a/tests/dlfcn_test.cpp b/tests/dlfcn_test.cpp index 81479d51b..f842c66ca 100644 --- a/tests/dlfcn_test.cpp +++ b/tests/dlfcn_test.cpp @@ -790,15 +790,12 @@ TEST(dlfcn, dladdr_executable) { ASSERT_NE(rc, 0); // Zero on error, non-zero on success. // Get the name of this executable. - char executable_path[PATH_MAX]; - rc = readlink("/proc/self/exe", executable_path, sizeof(executable_path)); - ASSERT_NE(rc, -1); - executable_path[rc] = '\0'; + const std::string& executable_path = get_executable_path(); // The filename should be that of this executable. char dli_realpath[PATH_MAX]; ASSERT_TRUE(realpath(info.dli_fname, dli_realpath) != nullptr); - ASSERT_STREQ(executable_path, dli_realpath); + ASSERT_STREQ(executable_path.c_str(), dli_realpath); // The symbol name should be the symbol we looked up. ASSERT_STREQ(info.dli_sname, "DlSymTestFunction"); @@ -823,6 +820,22 @@ TEST(dlfcn, dladdr_executable) { ASSERT_EQ(0, dlclose(self)); } +TEST(dlfcn, dlopen_executable_by_absolute_path) { + void* handle1 = dlopen(nullptr, RTLD_NOW); + ASSERT_TRUE(handle1 != nullptr) << dlerror(); + + void* handle2 = dlopen(get_executable_path().c_str(), RTLD_NOW); + ASSERT_TRUE(handle2 != nullptr) << dlerror(); + +#if defined(__BIONIC__) + ASSERT_EQ(handle1, handle2); +#else + GTEST_LOG_(INFO) << "Skipping ASSERT_EQ(handle1, handle2) for glibc: " + "it loads a separate copy of the main executable " + "on dlopen by absolute path."; +#endif +} + #if defined(__LP64__) #define PATH_TO_SYSTEM_LIB "/system/lib64/" #else diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp index ad23aa80c..2b5864688 100644 --- a/tests/gtest_main.cpp +++ b/tests/gtest_main.cpp @@ -46,10 +46,10 @@ #endif -static std::string g_executable_name; +static std::string g_executable_path; -const std::string& get_executable_name() { - return g_executable_name; +const std::string& get_executable_path() { + return g_executable_path; } namespace testing { @@ -923,15 +923,8 @@ static void AddPathSeparatorInTestProgramPath(std::vector<char*>& args) { // The reason is that gtest uses clone() + execve() to run DeathTest in threadsafe mode, // and execve() doesn't read environment variable PATH, so execve() will not success // until we specify the absolute path or relative path of the test program directly. - if (strchr(args[0], '/') == NULL) { - char path[PATH_MAX]; - ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path)); - if (path_len <= 0 || path_len >= static_cast<ssize_t>(sizeof(path))) { - perror("readlink"); - exit(1); - } - path[path_len] = '\0'; - args[0] = strdup(path); + if (strchr(args[0], '/') == nullptr) { + args[0] = strdup(g_executable_path.c_str()); } } @@ -1118,8 +1111,19 @@ static bool PickOptions(std::vector<char*>& args, IsolationTestOptions& options) return true; } +static std::string get_proc_self_exe() { + char path[PATH_MAX]; + ssize_t path_len = readlink("/proc/self/exe", path, sizeof(path)); + if (path_len <= 0 || path_len >= static_cast<ssize_t>(sizeof(path))) { + perror("readlink"); + exit(1); + } + + return std::string(path, path_len); +} + int main(int argc, char** argv) { - g_executable_name = argv[0]; + g_executable_path = get_proc_self_exe(); std::vector<char*> arg_list; for (int i = 0; i < argc; ++i) { arg_list.push_back(argv[i]); diff --git a/tests/utils.h b/tests/utils.h index a335c6663..f8e003922 100644 --- a/tests/utils.h +++ b/tests/utils.h @@ -119,6 +119,7 @@ static inline void AssertChildExited(int pid, int expected_exit_status) { ASSERT_EQ(expected_exit_status, WEXITSTATUS(status)); } -const std::string& get_executable_name(); +// The absolute path to the executable +const std::string& get_executable_path(); #endif |