aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitry Ivanov <dimitry@google.com>2016-05-18 07:33:50 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2016-05-18 07:33:50 +0000
commit041cf17cdd900f807d8d39d04802e9f31f2ffd74 (patch)
tree870a323fa0526156e95826d54f58e768d2cf4a5d
parent49cfc899a3708fae9175e44c0c02cd479fda8b36 (diff)
parentdcaef3710df817db5652a1f3ab4646f43f5cd3ee (diff)
downloadbionic-041cf17cdd900f807d8d39d04802e9f31f2ffd74.tar.gz
Merge "Fix dlopen of main executable by absolute path" into nyc-dev
-rw-r--r--linker/linker.cpp24
-rw-r--r--tests/dlext_test.cpp4
-rw-r--r--tests/dlfcn_test.cpp23
-rw-r--r--tests/gtest_main.cpp30
-rw-r--r--tests/utils.h3
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