summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitriy Ivanov <dimitry@google.com>2014-07-01 14:10:16 -0700
committerDmitriy Ivanov <dimitry@google.com>2014-07-02 13:20:47 -0700
commit04dc91ae763adc403a14c88b4c46f77b3d2d71a3 (patch)
treeaa8c5774929f43e2a13e308f93df4c65744f777d
parent4d299a2cf7880789e658f427196d1ca9fe02a9bc (diff)
downloadbionic-04dc91ae763adc403a14c88b4c46f77b3d2d71a3.zip
bionic-04dc91ae763adc403a14c88b4c46f77b3d2d71a3.tar.gz
bionic-04dc91ae763adc403a14c88b4c46f77b3d2d71a3.tar.bz2
Load library using file handle.
* This patch enables dlopen by file descriptor instead of path/name. Bug: 15984217 Change-Id: Ib39051e00567fb97070bf96d8ce63993877c0a01
-rw-r--r--libc/include/android/dlext.h9
-rw-r--r--libc/private/ScopedFd.h59
-rw-r--r--linker/linker.cpp20
-rw-r--r--linker/linker_phdr.cpp3
-rw-r--r--tests/Android.build.mk5
-rw-r--r--tests/dlext_test.cpp22
-rw-r--r--tests/libs/Android.mk13
7 files changed, 122 insertions, 9 deletions
diff --git a/libc/include/android/dlext.h b/libc/include/android/dlext.h
index 90962fa..616e08e 100644
--- a/libc/include/android/dlext.h
+++ b/libc/include/android/dlext.h
@@ -49,11 +49,17 @@ enum {
*/
ANDROID_DLEXT_USE_RELRO = 0x8,
+ /* Instruct dlopen to use library_fd instead of opening file by name.
+ * The filename parameter is still used to identify the library.
+ */
+ ANDROID_DLEXT_USE_LIBRARY_FD = 0x10,
+
/* 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_RELRO |
+ ANDROID_DLEXT_USE_LIBRARY_FD,
};
typedef struct {
@@ -61,6 +67,7 @@ typedef struct {
void* reserved_addr;
size_t reserved_size;
int relro_fd;
+ int library_fd;
} android_dlextinfo;
extern void* android_dlopen_ext(const char* filename, int flag, const android_dlextinfo* extinfo);
diff --git a/libc/private/ScopedFd.h b/libc/private/ScopedFd.h
new file mode 100644
index 0000000..e56c139
--- /dev/null
+++ b/libc/private/ScopedFd.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SCOPED_FD_H
+#define SCOPED_FD_H
+
+#include <unistd.h>
+#include "bionic_macros.h"
+
+// A smart pointer that closes the given fd on going out of scope.
+// Use this when the fd is incidental to the purpose of your function,
+// but needs to be cleaned up on exit.
+class ScopedFd {
+public:
+ explicit ScopedFd(int fd) : fd(fd) {
+ }
+
+ ~ScopedFd() {
+ reset();
+ }
+
+ int get() const {
+ return fd;
+ }
+
+ int release() __attribute__((warn_unused_result)) {
+ int localFd = fd;
+ fd = -1;
+ return localFd;
+ }
+
+ void reset(int new_fd = -1) {
+ if (fd != -1) {
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+ fd = new_fd;
+ }
+
+private:
+ int fd;
+
+ // Disallow copy and assignment.
+ DISALLOW_COPY_AND_ASSIGN(ScopedFd);
+};
+
+#endif // SCOPED_FD_H
diff --git a/linker/linker.cpp b/linker/linker.cpp
index bf923c1..2065231 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -42,6 +42,7 @@
#include "private/bionic_tls.h"
#include "private/KernelArgumentBlock.h"
#include "private/ScopedPthreadMutexLocker.h"
+#include "private/ScopedFd.h"
#include "linker.h"
#include "linker_debug.h"
@@ -696,11 +697,20 @@ static int open_library(const char* name) {
}
static soinfo* load_library(const char* name, int dlflags, const android_dlextinfo* extinfo) {
- // Open the file.
- int fd = open_library(name);
- if (fd == -1) {
+ int fd = -1;
+ ScopedFd file_guard(-1);
+
+ if (extinfo != NULL && (extinfo->flags & ANDROID_DLEXT_USE_LIBRARY_FD) != 0) {
+ fd = extinfo->library_fd;
+ } else {
+ // Open the file.
+ fd = open_library(name);
+ if (fd == -1) {
DL_ERR("library \"%s\" not found", name);
return NULL;
+ }
+
+ file_guard.reset(fd);
}
ElfReader elf_reader(name, fd);
@@ -744,7 +754,7 @@ static soinfo* load_library(const char* name, int dlflags, const android_dlextin
// At this point we know that whatever is loaded @ base is a valid ELF
// shared library whose segments are properly mapped in.
- TRACE("[ find_library_internal base=%p size=%zu name='%s' ]",
+ TRACE("[ load_library base=%p size=%zu name='%s' ]",
reinterpret_cast<void*>(si->base), si->size, si->name);
if (!soinfo_link_image(si, extinfo)) {
@@ -847,7 +857,7 @@ soinfo* do_dlopen(const char* name, int flags, const android_dlextinfo* extinfo)
return NULL;
}
if (extinfo != NULL && ((extinfo->flags & ~(ANDROID_DLEXT_VALID_FLAG_BITS)) != 0)) {
- DL_ERR("invalid extended flags to android_dlopen_ext: %x", extinfo->flags);
+ DL_ERR("invalid extended flags to android_dlopen_ext: %llx", extinfo->flags);
return NULL;
}
protect_data(PROT_READ | PROT_WRITE);
diff --git a/linker/linker_phdr.cpp b/linker/linker_phdr.cpp
index 12e9779..11585af 100644
--- a/linker/linker_phdr.cpp
+++ b/linker/linker_phdr.cpp
@@ -127,9 +127,6 @@ ElfReader::ElfReader(const char* name, int fd)
}
ElfReader::~ElfReader() {
- if (fd_ != -1) {
- close(fd_);
- }
if (phdr_mmap_ != NULL) {
munmap(phdr_mmap_, phdr_size_);
}
diff --git a/tests/Android.build.mk b/tests/Android.build.mk
index 62e9718..bb00648 100644
--- a/tests/Android.build.mk
+++ b/tests/Android.build.mk
@@ -26,6 +26,11 @@ endif
ifneq ($(findstring LIBRARY, $(build_target)),LIBRARY)
LOCAL_MODULE_STEM_32 := $(module)32
LOCAL_MODULE_STEM_64 := $(module)64
+else
+ifeq ($($(module)_install_to_out_data),true)
+ LOCAL_MODULE_PATH_32 := $(TARGET_OUT_DATA_NATIVE_TESTS)/$(module)
+ LOCAL_MODULE_PATH_64 := $(TARGET_OUT_DATA_NATIVE_TESTS)64/$(module)
+endif
endif
LOCAL_CLANG := $($(module)_clang_$(build_type))
diff --git a/tests/dlext_test.cpp b/tests/dlext_test.cpp
index b56fc41..da63046 100644
--- a/tests/dlext_test.cpp
+++ b/tests/dlext_test.cpp
@@ -45,6 +45,11 @@ typedef int (*fn)(void);
#define LIBNAME_NORELRO "libdlext_test_norelro.so"
#define LIBSIZE 1024*1024 // how much address space to reserve for it
+#if defined(__LP64__)
+#define LIBPATH "%s/nativetest64/libdlext_test_fd/libdlext_test_fd.so"
+#else
+#define LIBPATH "%s/nativetest/libdlext_test_fd/libdlext_test_fd.so"
+#endif
class DlExtTest : public ::testing::Test {
protected:
@@ -83,6 +88,23 @@ TEST_F(DlExtTest, ExtInfoNoFlags) {
EXPECT_EQ(4, f());
}
+TEST_F(DlExtTest, ExtInfoUseFd) {
+ const char* android_data = getenv("ANDROID_DATA");
+ ASSERT_TRUE(android_data != NULL);
+ char lib_path[PATH_MAX];
+ snprintf(lib_path, sizeof(lib_path), LIBPATH, android_data);
+
+ android_dlextinfo extinfo;
+ extinfo.flags = ANDROID_DLEXT_USE_LIBRARY_FD;
+ extinfo.library_fd = TEMP_FAILURE_RETRY(open(lib_path, O_RDONLY | O_CLOEXEC));
+ ASSERT_TRUE(extinfo.library_fd != -1);
+ handle_ = android_dlopen_ext(lib_path, RTLD_NOW, &extinfo);
+ ASSERT_DL_NOTNULL(handle_);
+ fn f = reinterpret_cast<fn>(dlsym(handle_, "getRandomNumber"));
+ ASSERT_DL_NOTNULL(f);
+ EXPECT_EQ(4, f());
+}
+
TEST_F(DlExtTest, Reserved) {
void* start = mmap(NULL, LIBSIZE, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS,
-1, 0);
diff --git a/tests/libs/Android.mk b/tests/libs/Android.mk
index efce5b5..a374e48 100644
--- a/tests/libs/Android.mk
+++ b/tests/libs/Android.mk
@@ -78,6 +78,19 @@ build_target := SHARED_LIBRARY
include $(TEST_PATH)/Android.build.mk
# -----------------------------------------------------------------------------
+# Library used by dlext tests - different name non-default location
+# -----------------------------------------------------------------------------
+libdlext_test_fd_src_files := \
+ dlext_test_library.cpp \
+
+libdlext_test_fd_install_to_out_data := true
+module := libdlext_test_fd
+module_tag := optional
+build_type := target
+build_target := SHARED_LIBRARY
+include $(TEST_PATH)/Android.build.mk
+
+# -----------------------------------------------------------------------------
# Library used by dlfcn tests
# -----------------------------------------------------------------------------
libtest_simple_src_files := \