Merge "Load library using file handle."
This commit is contained in:
		@@ -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);
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										59
									
								
								libc/private/ScopedFd.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								libc/private/ScopedFd.h
									
									
									
									
									
										Normal file
									
								
							@@ -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
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -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_);
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -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))
 | 
			
		||||
 
 | 
			
		||||
@@ -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);
 | 
			
		||||
 
 | 
			
		||||
@@ -77,6 +77,19 @@ build_type := target
 | 
			
		||||
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
 | 
			
		||||
# -----------------------------------------------------------------------------
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user