Merge "Support loading shared libraries from zip files"
This commit is contained in:
		@@ -57,7 +57,7 @@ LOCAL_ASFLAGS := $(LOCAL_CFLAGS)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 | 
					LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOCAL_STATIC_LIBRARIES := libc_nomalloc
 | 
					LOCAL_STATIC_LIBRARIES := libc_nomalloc libziparchive libutils libz liblog
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOCAL_FORCE_STATIC_EXECUTABLE := true
 | 
					LOCAL_FORCE_STATIC_EXECUTABLE := true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -57,6 +57,7 @@
 | 
				
			|||||||
#include "linker_phdr.h"
 | 
					#include "linker_phdr.h"
 | 
				
			||||||
#include "linker_relocs.h"
 | 
					#include "linker_relocs.h"
 | 
				
			||||||
#include "linker_reloc_iterators.h"
 | 
					#include "linker_reloc_iterators.h"
 | 
				
			||||||
 | 
					#include "ziparchive/zip_archive.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
 | 
					/* >>> IMPORTANT NOTE - READ ME BEFORE MODIFYING <<<
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
@@ -838,29 +839,109 @@ ElfW(Sym)* soinfo::elf_addr_lookup(const void* addr) {
 | 
				
			|||||||
  return nullptr;
 | 
					  return nullptr;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int open_library_on_path(const char* name, const char* const paths[]) {
 | 
					static int open_library_in_zipfile(const char* const path,
 | 
				
			||||||
  char buf[512];
 | 
					                                   off64_t* file_offset) {
 | 
				
			||||||
  for (size_t i = 0; paths[i] != nullptr; ++i) {
 | 
					  TRACE("Trying zip file open from path '%s'", path);
 | 
				
			||||||
    int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", paths[i], name);
 | 
					
 | 
				
			||||||
    if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
 | 
					  // Treat an '!' character inside a path as the separator between the name
 | 
				
			||||||
      PRINT("Warning: ignoring very long library path: %s/%s", paths[i], name);
 | 
					  // of the zip file on disk and the subdirectory to search within it.
 | 
				
			||||||
      continue;
 | 
					  // For example, if path is "foo.zip!bar/bas/x.so", then we search for
 | 
				
			||||||
    }
 | 
					  // "bar/bas/x.so" within "foo.zip".
 | 
				
			||||||
    int fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
 | 
					  const char* separator = strchr(path, '!');
 | 
				
			||||||
    if (fd != -1) {
 | 
					  if (separator == nullptr) {
 | 
				
			||||||
      return fd;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
    return -1;
 | 
					    return -1;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int open_library(const char* name) {
 | 
					  char buf[512];
 | 
				
			||||||
 | 
					  if (strlcpy(buf, path, sizeof(buf)) >= sizeof(buf)) {
 | 
				
			||||||
 | 
					    PRINT("Warning: ignoring very long library path: %s", path);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  buf[separator - path] = '\0';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  const char* zip_path = buf;
 | 
				
			||||||
 | 
					  const char* file_path = &buf[separator - path + 1];
 | 
				
			||||||
 | 
					  int fd = TEMP_FAILURE_RETRY(open(zip_path, O_RDONLY | O_CLOEXEC));
 | 
				
			||||||
 | 
					  if (fd == -1) {
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ZipArchiveHandle handle;
 | 
				
			||||||
 | 
					  if (OpenArchiveFd(fd, "", &handle, false) != 0) {
 | 
				
			||||||
 | 
					    // invalid zip-file (?)
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  auto archive_guard = make_scope_guard([&]() {
 | 
				
			||||||
 | 
					    CloseArchive(handle);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ZipEntry entry;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  if (FindEntry(handle, ZipEntryName(file_path), &entry) != 0) {
 | 
				
			||||||
 | 
					    // Entry was not found.
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // Check if it is properly stored
 | 
				
			||||||
 | 
					  if (entry.method != kCompressStored || (entry.offset % PAGE_SIZE) != 0) {
 | 
				
			||||||
 | 
					    close(fd);
 | 
				
			||||||
 | 
					    return -1;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  *file_offset = entry.offset;
 | 
				
			||||||
 | 
					  return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int open_library_on_path(const char* name,
 | 
				
			||||||
 | 
					                                const char* const paths[],
 | 
				
			||||||
 | 
					                                off64_t* file_offset) {
 | 
				
			||||||
 | 
					  char buf[512];
 | 
				
			||||||
 | 
					  int fd = -1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  for (size_t i = 0; paths[i] != nullptr && fd == -1; ++i) {
 | 
				
			||||||
 | 
					    const char* const path = paths[i];
 | 
				
			||||||
 | 
					    int n = __libc_format_buffer(buf, sizeof(buf), "%s/%s", path, name);
 | 
				
			||||||
 | 
					    if (n < 0 || n >= static_cast<int>(sizeof(buf))) {
 | 
				
			||||||
 | 
					      PRINT("Warning: ignoring very long library path: %s/%s", path, name);
 | 
				
			||||||
 | 
					      return -1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const char* separator = strchr(path, '!');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (separator != nullptr) {
 | 
				
			||||||
 | 
					      fd = open_library_in_zipfile(buf, file_offset);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (fd == -1) {
 | 
				
			||||||
 | 
					      fd = TEMP_FAILURE_RETRY(open(buf, O_RDONLY | O_CLOEXEC));
 | 
				
			||||||
 | 
					      if (fd != -1) {
 | 
				
			||||||
 | 
					        *file_offset = 0;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  return fd;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static int open_library(const char* name, off64_t* file_offset) {
 | 
				
			||||||
  TRACE("[ opening %s ]", name);
 | 
					  TRACE("[ opening %s ]", name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // If the name contains a slash, we should attempt to open it directly and not search the paths.
 | 
					  // If the name contains a slash, we should attempt to open it directly and not search the paths.
 | 
				
			||||||
  if (strchr(name, '/') != nullptr) {
 | 
					  if (strchr(name, '/') != nullptr) {
 | 
				
			||||||
 | 
					    if (strchr(name, '!') != nullptr) {
 | 
				
			||||||
 | 
					      int fd = open_library_in_zipfile(name, file_offset);
 | 
				
			||||||
 | 
					      if (fd != -1) {
 | 
				
			||||||
 | 
					        return fd;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
 | 
					    int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CLOEXEC));
 | 
				
			||||||
    if (fd != -1) {
 | 
					    if (fd != -1) {
 | 
				
			||||||
 | 
					      *file_offset = 0;
 | 
				
			||||||
      return fd;
 | 
					      return fd;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
 | 
					    // ...but nvidia binary blobs (at least) rely on this behavior, so fall through for now.
 | 
				
			||||||
@@ -870,9 +951,9 @@ static int open_library(const char* name) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
 | 
					  // Otherwise we try LD_LIBRARY_PATH first, and fall back to the built-in well known paths.
 | 
				
			||||||
  int fd = open_library_on_path(name, g_ld_library_paths);
 | 
					  int fd = open_library_on_path(name, g_ld_library_paths, file_offset);
 | 
				
			||||||
  if (fd == -1) {
 | 
					  if (fd == -1) {
 | 
				
			||||||
    fd = open_library_on_path(name, kDefaultLdPaths);
 | 
					    fd = open_library_on_path(name, kDefaultLdPaths, file_offset);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  return fd;
 | 
					  return fd;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@@ -886,7 +967,9 @@ static void for_each_dt_needed(const soinfo* si, F action) {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld_flags, const android_dlextinfo* extinfo) {
 | 
					static soinfo* load_library(LoadTaskList& load_tasks,
 | 
				
			||||||
 | 
					                            const char* name, int rtld_flags,
 | 
				
			||||||
 | 
					                            const android_dlextinfo* extinfo) {
 | 
				
			||||||
  int fd = -1;
 | 
					  int fd = -1;
 | 
				
			||||||
  off64_t file_offset = 0;
 | 
					  off64_t file_offset = 0;
 | 
				
			||||||
  ScopedFd file_guard(-1);
 | 
					  ScopedFd file_guard(-1);
 | 
				
			||||||
@@ -898,7 +981,7 @@ static soinfo* load_library(LoadTaskList& load_tasks, const char* name, int rtld
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  } else {
 | 
					  } else {
 | 
				
			||||||
    // Open the file.
 | 
					    // Open the file.
 | 
				
			||||||
    fd = open_library(name);
 | 
					    fd = open_library(name, &file_offset);
 | 
				
			||||||
    if (fd == -1) {
 | 
					    if (fd == -1) {
 | 
				
			||||||
      DL_ERR("library \"%s\" not found", name);
 | 
					      DL_ERR("library \"%s\" not found", name);
 | 
				
			||||||
      return nullptr;
 | 
					      return nullptr;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -29,6 +29,14 @@
 | 
				
			|||||||
#define ASSERT_SUBSTR(needle, haystack) \
 | 
					#define ASSERT_SUBSTR(needle, haystack) \
 | 
				
			||||||
    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
 | 
					    ASSERT_PRED_FORMAT2(::testing::IsSubstring, needle, haystack)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if defined(__LP64__)
 | 
				
			||||||
 | 
					#define LIBPATH_PREFIX "/nativetest64/libdlext_test_fd/"
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					#define LIBPATH_PREFIX "/nativetest/libdlext_test_fd/"
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define LIBZIPPATH LIBPATH_PREFIX "libdlext_test_fd_zipaligned.zip"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static bool g_called = false;
 | 
					static bool g_called = false;
 | 
				
			||||||
extern "C" void DlSymTestFunction() {
 | 
					extern "C" void DlSymTestFunction() {
 | 
				
			||||||
  g_called = true;
 | 
					  g_called = true;
 | 
				
			||||||
@@ -844,6 +852,46 @@ TEST(dlfcn, dlopen_symlink) {
 | 
				
			|||||||
  dlclose(handle2);
 | 
					  dlclose(handle2);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(dlfcn, dlopen_from_zip_absolute_path) {
 | 
				
			||||||
 | 
					  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void* handle = dlopen((lib_path + "!libdir/libdlext_test_fd.so").c_str(), RTLD_NOW);
 | 
				
			||||||
 | 
					  ASSERT_TRUE(handle != nullptr) << dlerror();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int (*fn)(void);
 | 
				
			||||||
 | 
					  fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
 | 
				
			||||||
 | 
					  ASSERT_TRUE(fn != nullptr);
 | 
				
			||||||
 | 
					  EXPECT_EQ(4, fn());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dlclose(handle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					TEST(dlfcn, dlopen_from_zip_ld_library_path) {
 | 
				
			||||||
 | 
					  const std::string lib_path = std::string(getenv("ANDROID_DATA")) + LIBZIPPATH + "!libdir";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  typedef void (*fn_t)(const char*);
 | 
				
			||||||
 | 
					  fn_t android_update_LD_LIBRARY_PATH =
 | 
				
			||||||
 | 
					      reinterpret_cast<fn_t>(dlsym(RTLD_DEFAULT, "android_update_LD_LIBRARY_PATH"));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ASSERT_TRUE(android_update_LD_LIBRARY_PATH != nullptr) << dlerror();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void* handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
 | 
				
			||||||
 | 
					  ASSERT_TRUE(handle == nullptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  android_update_LD_LIBRARY_PATH(lib_path.c_str());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  handle = dlopen("libdlext_test_fd.so", RTLD_NOW);
 | 
				
			||||||
 | 
					  ASSERT_TRUE(handle != nullptr) << dlerror();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int (*fn)(void);
 | 
				
			||||||
 | 
					  fn = reinterpret_cast<int (*)(void)>(dlsym(handle, "getRandomNumber"));
 | 
				
			||||||
 | 
					  ASSERT_TRUE(fn != nullptr);
 | 
				
			||||||
 | 
					  EXPECT_EQ(4, fn());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  dlclose(handle);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// libtest_dlopen_from_ctor_main.so depends on
 | 
					// libtest_dlopen_from_ctor_main.so depends on
 | 
				
			||||||
// libtest_dlopen_from_ctor.so which has a constructor
 | 
					// libtest_dlopen_from_ctor.so which has a constructor
 | 
				
			||||||
// that calls dlopen(libc...). This is to test the situation
 | 
					// that calls dlopen(libc...). This is to test the situation
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -35,7 +35,7 @@ my_shared_libs := \
 | 
				
			|||||||
$(LOCAL_BUILT_MODULE): PRIVATE_ALIGNMENT := 4096 # PAGE_SIZE
 | 
					$(LOCAL_BUILT_MODULE): PRIVATE_ALIGNMENT := 4096 # PAGE_SIZE
 | 
				
			||||||
$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
 | 
					$(LOCAL_BUILT_MODULE) : $(my_shared_libs) | $(ZIPALIGN)
 | 
				
			||||||
	@echo "Zipalign $(PRIVATE_ALIGNMENT): $@"
 | 
						@echo "Zipalign $(PRIVATE_ALIGNMENT): $@"
 | 
				
			||||||
	$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
 | 
						$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)/libdir
 | 
				
			||||||
	$(hide) cp $^ $(dir $@)
 | 
						$(hide) cp $^ $(dir $@)/libdir
 | 
				
			||||||
	$(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@).unaligned empty_file.txt *.so)
 | 
						$(hide) (cd $(dir $@) && touch empty_file.txt && zip -rD0 $(notdir $@).unaligned empty_file.txt libdir/*.so)
 | 
				
			||||||
	$(hide) $(ZIPALIGN) $(PRIVATE_ALIGNMENT) $@.unaligned $@
 | 
						$(hide) $(ZIPALIGN) $(PRIVATE_ALIGNMENT) $@.unaligned $@
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user