Repo created
This commit is contained in:
parent
81b91f4139
commit
f8c34fa5ee
22732 changed files with 4815320 additions and 2 deletions
|
|
@ -0,0 +1,234 @@
|
|||
// Copyright 2014 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This is the version of the Android-specific Chromium linker that uses
|
||||
// the crazy linker to load libraries.
|
||||
|
||||
// This source code *cannot* depend on anything from base/ or the C++
|
||||
// STL, to keep the final library small, and avoid ugly dependency issues.
|
||||
|
||||
#include "base/android/linker/legacy_linker_jni.h"
|
||||
|
||||
#include <crazy_linker.h>
|
||||
#include <fcntl.h>
|
||||
#include <jni.h>
|
||||
#include <limits.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "base/android/linker/linker_jni.h"
|
||||
|
||||
namespace chromium_android_linker {
|
||||
namespace {
|
||||
|
||||
// The linker uses a single crazy_context_t object created on demand.
|
||||
// There is no need to protect this against concurrent access, locking
|
||||
// is already handled on the Java side.
|
||||
crazy_context_t* GetCrazyContext() {
|
||||
static crazy_context_t* s_crazy_context = nullptr;
|
||||
|
||||
if (!s_crazy_context) {
|
||||
// Create new context.
|
||||
s_crazy_context = crazy_context_create();
|
||||
|
||||
// Ensure libraries located in the same directory as the linker
|
||||
// can be loaded before system ones.
|
||||
crazy_add_search_path_for_address(
|
||||
reinterpret_cast<void*>(&GetCrazyContext));
|
||||
}
|
||||
|
||||
return s_crazy_context;
|
||||
}
|
||||
|
||||
// A scoped crazy_library_t that automatically closes the handle
|
||||
// on scope exit, unless Release() has been called.
|
||||
class ScopedLibrary {
|
||||
public:
|
||||
ScopedLibrary() : lib_(nullptr) {}
|
||||
|
||||
~ScopedLibrary() {
|
||||
if (lib_)
|
||||
crazy_library_close_with_context(lib_, GetCrazyContext());
|
||||
}
|
||||
|
||||
crazy_library_t* Get() { return lib_; }
|
||||
|
||||
crazy_library_t** GetPtr() { return &lib_; }
|
||||
|
||||
crazy_library_t* Release() {
|
||||
crazy_library_t* ret = lib_;
|
||||
lib_ = nullptr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
crazy_library_t* lib_;
|
||||
};
|
||||
|
||||
// Add a zip archive file path to the context's current search path
|
||||
// list. Making it possible to load libraries directly from it.
|
||||
JNI_GENERATOR_EXPORT bool
|
||||
Java_org_chromium_base_library_1loader_LegacyLinker_nativeAddZipArchivePath(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring apk_path_obj) {
|
||||
String apk_path(env, apk_path_obj);
|
||||
|
||||
char search_path[512];
|
||||
snprintf(search_path, sizeof(search_path), "%s!lib/" CURRENT_ABI "/",
|
||||
apk_path.c_str());
|
||||
|
||||
crazy_add_search_path(search_path);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load a library with the chromium linker. This will also call its
|
||||
// JNI_OnLoad() method, which shall register its methods. Note that
|
||||
// lazy native method resolution will _not_ work after this, because
|
||||
// Dalvik uses the system's dlsym() which won't see the new library,
|
||||
// so explicit registration is mandatory.
|
||||
//
|
||||
// |env| is the current JNI environment handle.
|
||||
// |clazz| is the static class handle for org.chromium.base.Linker,
|
||||
// and is ignored here.
|
||||
// |library_name| is the library name (e.g. libfoo.so).
|
||||
// |load_address| is an explicit load address.
|
||||
// |lib_info_obj| is a LibInfo handle used to communicate information
|
||||
// with the Java side.
|
||||
// Return true on success.
|
||||
JNI_GENERATOR_EXPORT bool
|
||||
Java_org_chromium_base_library_1loader_LegacyLinker_nativeLoadLibrary(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring lib_name_obj,
|
||||
jlong load_address,
|
||||
jobject lib_info_obj) {
|
||||
String library_name(env, lib_name_obj);
|
||||
LOG_INFO("Called for %s, at address 0x%llx", library_name.c_str(),
|
||||
static_cast<unsigned long long>(load_address));
|
||||
crazy_context_t* context = GetCrazyContext();
|
||||
|
||||
if (!IsValidAddress(load_address)) {
|
||||
LOG_ERROR("Invalid address 0x%llx",
|
||||
static_cast<unsigned long long>(load_address));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the desired load address (0 means randomize it).
|
||||
crazy_context_set_load_address(context, static_cast<size_t>(load_address));
|
||||
|
||||
ScopedLibrary library;
|
||||
if (!crazy_library_open(library.GetPtr(), library_name.c_str(), context)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
crazy_library_info_t info;
|
||||
if (!crazy_library_get_info(library.Get(), context, &info)) {
|
||||
LOG_ERROR("Could not get library information for %s: %s",
|
||||
library_name.c_str(), crazy_context_get_error(context));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Release library object to keep it alive after the function returns.
|
||||
library.Release();
|
||||
|
||||
s_lib_info_fields.SetLoadInfo(env, lib_info_obj, info.load_address,
|
||||
info.load_size);
|
||||
LOG_INFO("Success loading library %s", library_name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
JNI_GENERATOR_EXPORT jboolean
|
||||
Java_org_chromium_base_library_1loader_LegacyLinker_nativeCreateSharedRelro(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring library_name,
|
||||
jlong load_address,
|
||||
jobject lib_info_obj) {
|
||||
String lib_name(env, library_name);
|
||||
|
||||
LOG_INFO("Called for %s", lib_name.c_str());
|
||||
|
||||
if (!IsValidAddress(load_address)) {
|
||||
LOG_ERROR("Invalid address 0x%llx",
|
||||
static_cast<unsigned long long>(load_address));
|
||||
return false;
|
||||
}
|
||||
|
||||
ScopedLibrary library;
|
||||
if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
|
||||
LOG_ERROR("Could not find %s", lib_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
crazy_context_t* context = GetCrazyContext();
|
||||
size_t relro_start = 0;
|
||||
size_t relro_size = 0;
|
||||
int relro_fd = -1;
|
||||
|
||||
if (!crazy_library_create_shared_relro(
|
||||
library.Get(), context, static_cast<size_t>(load_address),
|
||||
&relro_start, &relro_size, &relro_fd)) {
|
||||
LOG_ERROR("Could not create shared RELRO sharing for %s: %s\n",
|
||||
lib_name.c_str(), crazy_context_get_error(context));
|
||||
return false;
|
||||
}
|
||||
|
||||
s_lib_info_fields.SetRelroInfo(env, lib_info_obj, relro_start, relro_size,
|
||||
relro_fd);
|
||||
return true;
|
||||
}
|
||||
|
||||
JNI_GENERATOR_EXPORT jboolean
|
||||
Java_org_chromium_base_library_1loader_LegacyLinker_nativeUseSharedRelro(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring library_name,
|
||||
jobject lib_info_obj) {
|
||||
String lib_name(env, library_name);
|
||||
|
||||
LOG_INFO("Called for %s, lib_info_ref=%p", lib_name.c_str(), lib_info_obj);
|
||||
|
||||
ScopedLibrary library;
|
||||
if (!crazy_library_find_by_name(lib_name.c_str(), library.GetPtr())) {
|
||||
LOG_ERROR("Could not find %s", lib_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
crazy_context_t* context = GetCrazyContext();
|
||||
size_t relro_start = 0;
|
||||
size_t relro_size = 0;
|
||||
int relro_fd = -1;
|
||||
s_lib_info_fields.GetRelroInfo(env, lib_info_obj, &relro_start, &relro_size,
|
||||
&relro_fd);
|
||||
|
||||
LOG_INFO("library=%s relro start=%p size=%p fd=%d", lib_name.c_str(),
|
||||
(void*)relro_start, (void*)relro_size, relro_fd);
|
||||
|
||||
if (!crazy_library_use_shared_relro(library.Get(), context, relro_start,
|
||||
relro_size, relro_fd)) {
|
||||
LOG_ERROR("Could not use shared RELRO for %s: %s", lib_name.c_str(),
|
||||
crazy_context_get_error(context));
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("Library %s using shared RELRO section!", lib_name.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool LegacyLinkerJNIInit(JavaVM* vm, JNIEnv* env) {
|
||||
LOG_INFO("Entering");
|
||||
|
||||
// Save JavaVM* handle into linker, so that it can call JNI_OnLoad()
|
||||
// automatically when loading libraries containing JNI entry points.
|
||||
crazy_set_java_vm(vm, JNI_VERSION_1_4);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace chromium_android_linker
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_ANDROID_LINKER_LEGACY_LINKER_JNI_H_
|
||||
#define BASE_ANDROID_LINKER_LEGACY_LINKER_JNI_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace chromium_android_linker {
|
||||
|
||||
// JNI_OnLoad() initialization hook for the legacy linker.
|
||||
// Sets up JNI and other initializations for native linker code.
|
||||
// |vm| is the Java VM handle passed to JNI_OnLoad().
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, returns true.
|
||||
extern bool LegacyLinkerJNIInit(JavaVM* vm, JNIEnv* env);
|
||||
|
||||
} // namespace chromium_android_linker
|
||||
|
||||
#endif // BASE_ANDROID_LINKER_LEGACY_LINKER_JNI_H_
|
||||
150
TMessagesProj/jni/voip/webrtc/base/android/linker/linker_jni.cc
Normal file
150
TMessagesProj/jni/voip/webrtc/base/android/linker/linker_jni.cc
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This is the Android-specific Chromium linker, a tiny shared library
|
||||
// implementing a custom dynamic linker that can be used to load the
|
||||
// real Chromium libraries.
|
||||
|
||||
// The main point of this linker is to be able to share the RELRO
|
||||
// section of libchrome.so (or equivalent) between renderer processes.
|
||||
|
||||
// This source code *cannot* depend on anything from base/ or the C++
|
||||
// STL, to keep the final library small, and avoid ugly dependency issues.
|
||||
|
||||
#include "base/android/linker/linker_jni.h"
|
||||
|
||||
#include <jni.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "base/android/linker/legacy_linker_jni.h"
|
||||
#include "base/android/linker/modern_linker_jni.h"
|
||||
|
||||
namespace chromium_android_linker {
|
||||
|
||||
// Variable containing LibInfo for the loaded library.
|
||||
LibInfo_class s_lib_info_fields;
|
||||
|
||||
// Simple scoped UTF String class constructor.
|
||||
String::String(JNIEnv* env, jstring str) {
|
||||
size_ = env->GetStringUTFLength(str);
|
||||
ptr_ = static_cast<char*>(::malloc(size_ + 1));
|
||||
|
||||
// Note: This runs before browser native code is loaded, and so cannot
|
||||
// rely on anything from base/. This means that we must use
|
||||
// GetStringUTFChars() and not base::android::ConvertJavaStringToUTF8().
|
||||
//
|
||||
// GetStringUTFChars() suffices because the only strings used here are
|
||||
// paths to APK files or names of shared libraries, all of which are
|
||||
// plain ASCII, defined and hard-coded by the Chromium Android build.
|
||||
//
|
||||
// For more: see
|
||||
// https://crbug.com/508876
|
||||
//
|
||||
// Note: GetStringUTFChars() returns Java UTF-8 bytes. This is good
|
||||
// enough for the linker though.
|
||||
const char* bytes = env->GetStringUTFChars(str, nullptr);
|
||||
::memcpy(ptr_, bytes, size_);
|
||||
ptr_[size_] = '\0';
|
||||
|
||||
env->ReleaseStringUTFChars(str, bytes);
|
||||
}
|
||||
|
||||
// Find the jclass JNI reference corresponding to a given |class_name|.
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, return true and set |*clazz|.
|
||||
bool InitClassReference(JNIEnv* env, const char* class_name, jclass* clazz) {
|
||||
*clazz = env->FindClass(class_name);
|
||||
if (!*clazz) {
|
||||
LOG_ERROR("Could not find class for %s", class_name);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Initialize a jfieldID corresponding to the field of a given |clazz|,
|
||||
// with name |field_name| and signature |field_sig|.
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, return true and set |*field_id|.
|
||||
bool InitFieldId(JNIEnv* env,
|
||||
jclass clazz,
|
||||
const char* field_name,
|
||||
const char* field_sig,
|
||||
jfieldID* field_id) {
|
||||
*field_id = env->GetFieldID(clazz, field_name, field_sig);
|
||||
if (!*field_id) {
|
||||
LOG_ERROR("Could not find ID for field '%s'", field_name);
|
||||
return false;
|
||||
}
|
||||
LOG_INFO("Found ID %p for field '%s'", *field_id, field_name);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Use Android ASLR to create a random address into which we expect to be
|
||||
// able to load libraries. Note that this is probabilistic; we unmap the
|
||||
// address we get from mmap and assume we can re-map into it later. This
|
||||
// works the majority of the time. If it doesn't, client code backs out and
|
||||
// then loads the library normally at any available address.
|
||||
// |env| is the current JNI environment handle, and |clazz| a class.
|
||||
// Returns the address selected by ASLR, or 0 on error.
|
||||
JNI_GENERATOR_EXPORT jlong
|
||||
Java_org_chromium_base_library_1loader_Linker_nativeGetRandomBaseLoadAddress(
|
||||
JNIEnv* env,
|
||||
jclass clazz) {
|
||||
size_t bytes = kAddressSpaceReservationSize;
|
||||
|
||||
void* address =
|
||||
mmap(nullptr, bytes, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (address == MAP_FAILED) {
|
||||
LOG_INFO("Random base load address not determinable");
|
||||
return 0;
|
||||
}
|
||||
munmap(address, bytes);
|
||||
|
||||
LOG_INFO("Random base load address is %p", address);
|
||||
return static_cast<jlong>(reinterpret_cast<uintptr_t>(address));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// JNI_OnLoad() initialization hook.
|
||||
bool LinkerJNIInit(JavaVM* vm, JNIEnv* env) {
|
||||
// Find LibInfo field ids.
|
||||
LOG_INFO("Caching field IDs");
|
||||
if (!s_lib_info_fields.Init(env)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// JNI_OnLoad() hook called when the linker library is loaded through
|
||||
// the regular System.LoadLibrary) API. This shall save the Java VM
|
||||
// handle and initialize LibInfo fields.
|
||||
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
LOG_INFO("Entering");
|
||||
// Get new JNIEnv
|
||||
JNIEnv* env;
|
||||
if (JNI_OK != vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_4)) {
|
||||
LOG_ERROR("Could not create JNIEnv");
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Initialize linker base and implementations.
|
||||
if (!LinkerJNIInit(vm, env) || !LegacyLinkerJNIInit(vm, env) ||
|
||||
!ModernLinkerJNIInit(vm, env)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
LOG_INFO("Done");
|
||||
return JNI_VERSION_1_4;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace chromium_android_linker
|
||||
|
||||
jint JNI_OnLoad(JavaVM* vm, void* reserved) {
|
||||
return chromium_android_linker::JNI_OnLoad(vm, reserved);
|
||||
}
|
||||
202
TMessagesProj/jni/voip/webrtc/base/android/linker/linker_jni.h
Normal file
202
TMessagesProj/jni/voip/webrtc/base/android/linker/linker_jni.h
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
// Copyright 2015 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// This is the Android-specific Chromium linker, a tiny shared library
|
||||
// implementing a custom dynamic linker that can be used to load the
|
||||
// real Chromium libraries.
|
||||
|
||||
// The main point of this linker is to be able to share the RELRO
|
||||
// section of libcontentshell.so (or equivalent) between the browser and
|
||||
// renderer process.
|
||||
|
||||
// This source code *cannot* depend on anything from base/ or the C++
|
||||
// STL, to keep the final library small, and avoid ugly dependency issues.
|
||||
|
||||
#ifndef BASE_ANDROID_LINKER_LINKER_JNI_H_
|
||||
#define BASE_ANDROID_LINKER_LINKER_JNI_H_
|
||||
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "build/build_config.h"
|
||||
|
||||
// Set this to 1 to enable debug traces to the Android log.
|
||||
// Note that LOG() from "base/logging.h" cannot be used, since it is
|
||||
// in base/ which hasn't been loaded yet.
|
||||
#define DEBUG 0
|
||||
|
||||
#define TAG "cr_ChromiumAndroidLinker"
|
||||
|
||||
#if DEBUG
|
||||
#define LOG_INFO(FORMAT, ...) \
|
||||
__android_log_print(ANDROID_LOG_INFO, TAG, "%s: " FORMAT, __FUNCTION__, \
|
||||
##__VA_ARGS__)
|
||||
#else
|
||||
#define LOG_INFO(FORMAT, ...) ((void)0)
|
||||
#endif
|
||||
#define LOG_ERROR(FORMAT, ...) \
|
||||
__android_log_print(ANDROID_LOG_ERROR, TAG, "%s: " FORMAT, __FUNCTION__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define UNUSED __attribute__((unused))
|
||||
|
||||
#if defined(ARCH_CPU_X86)
|
||||
// Dalvik JIT generated code doesn't guarantee 16-byte stack alignment on
|
||||
// x86 - use force_align_arg_pointer to realign the stack at the JNI
|
||||
// boundary. https://crbug.com/655248
|
||||
#define JNI_GENERATOR_EXPORT \
|
||||
extern "C" __attribute__((visibility("default"), force_align_arg_pointer))
|
||||
#else
|
||||
#define JNI_GENERATOR_EXPORT extern "C" __attribute__((visibility("default")))
|
||||
#endif
|
||||
|
||||
#if defined(__arm__) && defined(__ARM_ARCH_7A__)
|
||||
#define CURRENT_ABI "armeabi-v7a"
|
||||
#elif defined(__arm__)
|
||||
#define CURRENT_ABI "armeabi"
|
||||
#elif defined(__i386__)
|
||||
#define CURRENT_ABI "x86"
|
||||
#elif defined(__mips__)
|
||||
#define CURRENT_ABI "mips"
|
||||
#elif defined(__x86_64__)
|
||||
#define CURRENT_ABI "x86_64"
|
||||
#elif defined(__aarch64__)
|
||||
#define CURRENT_ABI "arm64-v8a"
|
||||
#else
|
||||
#error "Unsupported target abi"
|
||||
#endif
|
||||
|
||||
namespace chromium_android_linker {
|
||||
|
||||
// Larger than the largest library we might attempt to load.
|
||||
static const size_t kAddressSpaceReservationSize = 192 * 1024 * 1024;
|
||||
|
||||
// A simple scoped UTF String class that can be initialized from
|
||||
// a Java jstring handle. Modeled like std::string, which cannot
|
||||
// be used here.
|
||||
class String {
|
||||
public:
|
||||
String(JNIEnv* env, jstring str);
|
||||
|
||||
inline ~String() { ::free(ptr_); }
|
||||
|
||||
inline const char* c_str() const { return ptr_ ? ptr_ : ""; }
|
||||
inline size_t size() const { return size_; }
|
||||
|
||||
private:
|
||||
char* ptr_;
|
||||
size_t size_;
|
||||
};
|
||||
|
||||
// Return true iff |address| is a valid address for the target CPU.
|
||||
inline bool IsValidAddress(jlong address) {
|
||||
return static_cast<jlong>(static_cast<size_t>(address)) == address;
|
||||
}
|
||||
|
||||
// Find the jclass JNI reference corresponding to a given |class_name|.
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, return true and set |*clazz|.
|
||||
extern bool InitClassReference(JNIEnv* env,
|
||||
const char* class_name,
|
||||
jclass* clazz);
|
||||
|
||||
// Initialize a jfieldID corresponding to the field of a given |clazz|,
|
||||
// with name |field_name| and signature |field_sig|.
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, return true and set |*field_id|.
|
||||
extern bool InitFieldId(JNIEnv* env,
|
||||
jclass clazz,
|
||||
const char* field_name,
|
||||
const char* field_sig,
|
||||
jfieldID* field_id);
|
||||
|
||||
// Initialize a jfieldID corresponding to the static field of a given |clazz|,
|
||||
// with name |field_name| and signature |field_sig|.
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, return true and set |*field_id|.
|
||||
extern bool InitStaticFieldId(JNIEnv* env,
|
||||
jclass clazz,
|
||||
const char* field_name,
|
||||
const char* field_sig,
|
||||
jfieldID* field_id);
|
||||
|
||||
// Use Android ASLR to create a random library load address.
|
||||
// |env| is the current JNI environment handle, and |clazz| a class.
|
||||
// Returns the address selected by ASLR.
|
||||
extern jlong GetRandomBaseLoadAddress(JNIEnv* env, jclass clazz);
|
||||
|
||||
// A class used to model the field IDs of the org.chromium.base.Linker
|
||||
// LibInfo inner class, used to communicate data with the Java side
|
||||
// of the linker.
|
||||
struct LibInfo_class {
|
||||
jfieldID load_address_id;
|
||||
jfieldID load_size_id;
|
||||
jfieldID relro_start_id;
|
||||
jfieldID relro_size_id;
|
||||
jfieldID relro_fd_id;
|
||||
|
||||
// Initialize an instance.
|
||||
bool Init(JNIEnv* env) {
|
||||
jclass clazz;
|
||||
if (!InitClassReference(
|
||||
env, "org/chromium/base/library_loader/Linker$LibInfo", &clazz)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return InitFieldId(env, clazz, "mLoadAddress", "J", &load_address_id) &&
|
||||
InitFieldId(env, clazz, "mLoadSize", "J", &load_size_id) &&
|
||||
InitFieldId(env, clazz, "mRelroStart", "J", &relro_start_id) &&
|
||||
InitFieldId(env, clazz, "mRelroSize", "J", &relro_size_id) &&
|
||||
InitFieldId(env, clazz, "mRelroFd", "I", &relro_fd_id);
|
||||
}
|
||||
|
||||
void SetLoadInfo(JNIEnv* env,
|
||||
jobject library_info_obj,
|
||||
size_t load_address,
|
||||
size_t load_size) {
|
||||
env->SetLongField(library_info_obj, load_address_id, load_address);
|
||||
env->SetLongField(library_info_obj, load_size_id, load_size);
|
||||
}
|
||||
|
||||
void SetRelroInfo(JNIEnv* env,
|
||||
jobject library_info_obj,
|
||||
size_t relro_start,
|
||||
size_t relro_size,
|
||||
int relro_fd) {
|
||||
env->SetLongField(library_info_obj, relro_start_id, relro_start);
|
||||
env->SetLongField(library_info_obj, relro_size_id, relro_size);
|
||||
env->SetIntField(library_info_obj, relro_fd_id, relro_fd);
|
||||
}
|
||||
|
||||
// Use this instance to convert a RelroInfo reference into
|
||||
// a crazy_library_info_t.
|
||||
void GetRelroInfo(JNIEnv* env,
|
||||
jobject library_info_obj,
|
||||
size_t* relro_start,
|
||||
size_t* relro_size,
|
||||
int* relro_fd) {
|
||||
if (relro_start) {
|
||||
*relro_start = static_cast<size_t>(
|
||||
env->GetLongField(library_info_obj, relro_start_id));
|
||||
}
|
||||
|
||||
if (relro_size) {
|
||||
*relro_size = static_cast<size_t>(
|
||||
env->GetLongField(library_info_obj, relro_size_id));
|
||||
}
|
||||
|
||||
if (relro_fd) {
|
||||
*relro_fd = env->GetIntField(library_info_obj, relro_fd_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Variable containing LibInfo for the loaded library.
|
||||
extern LibInfo_class s_lib_info_fields;
|
||||
|
||||
} // namespace chromium_android_linker
|
||||
|
||||
#endif // BASE_ANDROID_LINKER_LINKER_JNI_H_
|
||||
|
|
@ -0,0 +1,582 @@
|
|||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Uses android_dlopen_ext() to share relocations.
|
||||
|
||||
// This source code *cannot* depend on anything from base/ or the C++
|
||||
// STL, to keep the final library small, and avoid ugly dependency issues.
|
||||
|
||||
#include "base/android/linker/modern_linker_jni.h"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <jni.h>
|
||||
#include <limits.h>
|
||||
#include <link.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include <android/dlext.h>
|
||||
#include "base/android/linker/linker_jni.h"
|
||||
|
||||
// From //base/posix/eintr_wrapper.h, but we don't want to depend on //base.
|
||||
#define HANDLE_EINTR(x) \
|
||||
({ \
|
||||
decltype(x) eintr_wrapper_result; \
|
||||
do { \
|
||||
eintr_wrapper_result = (x); \
|
||||
} while (eintr_wrapper_result == -1 && errno == EINTR); \
|
||||
eintr_wrapper_result; \
|
||||
})
|
||||
|
||||
// Not defined on all platforms. As this linker is only supported on ARM32/64,
|
||||
// x86/x86_64 and MIPS, page size is always 4k.
|
||||
#if !defined(PAGE_SIZE)
|
||||
#define PAGE_SIZE (1 << 12)
|
||||
#define PAGE_MASK (~(PAGE_SIZE - 1))
|
||||
#endif
|
||||
|
||||
#define PAGE_START(x) ((x)&PAGE_MASK)
|
||||
#define PAGE_END(x) PAGE_START((x) + (PAGE_SIZE - 1))
|
||||
|
||||
extern "C" {
|
||||
// <android/dlext.h> does not declare android_dlopen_ext() if __ANDROID_API__
|
||||
// is smaller than 21, so declare it here as a weak function. This will allow
|
||||
// detecting its availability at runtime. For API level 21 or higher, the
|
||||
// attribute is ignored due to the previous declaration.
|
||||
void* android_dlopen_ext(const char*, int, const android_dlextinfo*)
|
||||
__attribute__((weak_import));
|
||||
|
||||
// This function is exported by the dynamic linker but never declared in any
|
||||
// official header for some architecture/version combinations.
|
||||
int dl_iterate_phdr(int (*cb)(dl_phdr_info* info, size_t size, void* data),
|
||||
void* data) __attribute__((weak_import));
|
||||
} // extern "C"
|
||||
|
||||
namespace chromium_android_linker {
|
||||
namespace {
|
||||
|
||||
// Record of the Java VM passed to JNI_OnLoad().
|
||||
static JavaVM* s_java_vm = nullptr;
|
||||
|
||||
// Helper class for anonymous memory mapping.
|
||||
class ScopedAnonymousMmap {
|
||||
public:
|
||||
static ScopedAnonymousMmap ReserveAtAddress(void* address, size_t size);
|
||||
|
||||
~ScopedAnonymousMmap() {
|
||||
if (addr_ && owned_)
|
||||
munmap(addr_, size_);
|
||||
}
|
||||
|
||||
ScopedAnonymousMmap(ScopedAnonymousMmap&& o) {
|
||||
addr_ = o.addr_;
|
||||
size_ = o.size_;
|
||||
owned_ = o.owned_;
|
||||
o.Release();
|
||||
}
|
||||
|
||||
void* address() const { return addr_; }
|
||||
size_t size() const { return size_; }
|
||||
void Release() { owned_ = false; }
|
||||
|
||||
private:
|
||||
ScopedAnonymousMmap() = default;
|
||||
ScopedAnonymousMmap(void* addr, size_t size) : addr_(addr), size_(size) {}
|
||||
|
||||
private:
|
||||
bool owned_ = true;
|
||||
void* addr_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
|
||||
// Move only.
|
||||
ScopedAnonymousMmap(const ScopedAnonymousMmap&) = delete;
|
||||
ScopedAnonymousMmap& operator=(const ScopedAnonymousMmap&) = delete;
|
||||
};
|
||||
|
||||
// Reserves an address space range, starting at |address|.
|
||||
// If successful, returns a valid mapping, otherwise returns an empty one.
|
||||
ScopedAnonymousMmap ScopedAnonymousMmap::ReserveAtAddress(void* address,
|
||||
size_t size) {
|
||||
void* actual_address =
|
||||
mmap(address, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (actual_address == MAP_FAILED) {
|
||||
LOG_INFO("mmap failed: %s", strerror(errno));
|
||||
return {};
|
||||
}
|
||||
|
||||
if (actual_address && actual_address != address) {
|
||||
LOG_ERROR("Failed to obtain fixed address for load");
|
||||
return {};
|
||||
}
|
||||
|
||||
return {actual_address, size};
|
||||
}
|
||||
|
||||
// Starting with API level 26, the following functions from
|
||||
// libandroid.so should be used to create shared memory regions.
|
||||
//
|
||||
// This ensures compatibility with post-Q versions of Android that may not rely
|
||||
// on ashmem for shared memory.
|
||||
//
|
||||
// This is heavily inspired from //third_party/ashmem/ashmem-dev.c, which we
|
||||
// cannot reference directly to avoid increasing binary size. Also, we don't
|
||||
// need to support API level <26.
|
||||
//
|
||||
// *Not* threadsafe.
|
||||
struct SharedMemoryFunctions {
|
||||
SharedMemoryFunctions() {
|
||||
library_handle = dlopen("libandroid.so", RTLD_NOW);
|
||||
create = reinterpret_cast<CreateFunction>(
|
||||
dlsym(library_handle, "ASharedMemory_create"));
|
||||
set_protection = reinterpret_cast<SetProtectionFunction>(
|
||||
dlsym(library_handle, "ASharedMemory_setProt"));
|
||||
|
||||
if (!create || !set_protection)
|
||||
LOG_ERROR("Cannot get the shared memory functions from libandroid");
|
||||
}
|
||||
|
||||
~SharedMemoryFunctions() {
|
||||
if (library_handle)
|
||||
dlclose(library_handle);
|
||||
}
|
||||
|
||||
typedef int (*CreateFunction)(const char*, size_t);
|
||||
typedef int (*SetProtectionFunction)(int fd, int prot);
|
||||
|
||||
CreateFunction create;
|
||||
SetProtectionFunction set_protection;
|
||||
|
||||
void* library_handle;
|
||||
};
|
||||
|
||||
// Metadata about a library loaded at a given |address|.
|
||||
struct LoadedLibraryMetadata {
|
||||
explicit LoadedLibraryMetadata(void* address)
|
||||
: load_address(address),
|
||||
load_size(0),
|
||||
min_vaddr(0),
|
||||
relro_start(0),
|
||||
relro_size(0) {}
|
||||
|
||||
const void* load_address;
|
||||
|
||||
size_t load_size;
|
||||
size_t min_vaddr;
|
||||
size_t relro_start;
|
||||
size_t relro_size;
|
||||
};
|
||||
|
||||
// android_dlopen_ext() wrapper.
|
||||
// Returns false if no android_dlopen_ext() is available, otherwise true with
|
||||
// the return value from android_dlopen_ext() in |status|.
|
||||
bool AndroidDlopenExt(const char* filename,
|
||||
int flag,
|
||||
const android_dlextinfo& extinfo,
|
||||
void** status) {
|
||||
if (!android_dlopen_ext) {
|
||||
LOG_ERROR("android_dlopen_ext is not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO(
|
||||
"android_dlopen_ext:"
|
||||
" flags=0x%llx, reserved_addr=%p, reserved_size=%d",
|
||||
static_cast<long long>(extinfo.flags), extinfo.reserved_addr,
|
||||
static_cast<int>(extinfo.reserved_size));
|
||||
|
||||
*status = android_dlopen_ext(filename, flag, &extinfo);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback for dl_iterate_phdr(). Read phdrs to identify whether or not
|
||||
// this library's load address matches the |load_address| passed in
|
||||
// |data|. If yes, fills the metadata we care about in |data|.
|
||||
//
|
||||
// A non-zero return value terminates iteration.
|
||||
int FindLoadedLibraryMetadata(dl_phdr_info* info,
|
||||
size_t size UNUSED,
|
||||
void* data) {
|
||||
auto* metadata = reinterpret_cast<LoadedLibraryMetadata*>(data);
|
||||
|
||||
// Use max and min vaddr to compute the library's load size.
|
||||
auto min_vaddr = std::numeric_limits<ElfW(Addr)>::max();
|
||||
ElfW(Addr) max_vaddr = 0;
|
||||
|
||||
ElfW(Addr) min_relro_vaddr = ~0;
|
||||
ElfW(Addr) max_relro_vaddr = 0;
|
||||
|
||||
bool is_matching = false;
|
||||
for (int i = 0; i < info->dlpi_phnum; ++i) {
|
||||
const ElfW(Phdr)* phdr = &info->dlpi_phdr[i];
|
||||
switch (phdr->p_type) {
|
||||
case PT_LOAD: {
|
||||
// See if this segment's load address matches what we passed to
|
||||
// android_dlopen_ext as extinfo.reserved_addr.
|
||||
//
|
||||
// Here and below, the virtual address in memory is computed by
|
||||
// address == info->dlpi_addr + program_header->p_vaddr
|
||||
// that is, the p_vaddr fields is relative to the object base address.
|
||||
// See dl_iterate_phdr(3) for details.
|
||||
void* load_addr =
|
||||
reinterpret_cast<void*>(info->dlpi_addr + phdr->p_vaddr);
|
||||
// Matching is based on the load address, since we have no idea
|
||||
// where the relro segment is.
|
||||
if (load_addr == metadata->load_address)
|
||||
is_matching = true;
|
||||
|
||||
if (phdr->p_vaddr < min_vaddr)
|
||||
min_vaddr = phdr->p_vaddr;
|
||||
if (phdr->p_vaddr + phdr->p_memsz > max_vaddr)
|
||||
max_vaddr = phdr->p_vaddr + phdr->p_memsz;
|
||||
} break;
|
||||
case PT_GNU_RELRO:
|
||||
min_relro_vaddr = PAGE_START(phdr->p_vaddr);
|
||||
max_relro_vaddr = phdr->p_vaddr + phdr->p_memsz;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this library matches what we seek, return its load size.
|
||||
if (is_matching) {
|
||||
int page_size = sysconf(_SC_PAGESIZE);
|
||||
if (page_size != PAGE_SIZE)
|
||||
abort();
|
||||
|
||||
metadata->load_size = PAGE_END(max_vaddr) - PAGE_START(min_vaddr);
|
||||
metadata->min_vaddr = min_vaddr;
|
||||
|
||||
metadata->relro_size =
|
||||
PAGE_END(max_relro_vaddr) - PAGE_START(min_relro_vaddr);
|
||||
metadata->relro_start = info->dlpi_addr + PAGE_START(min_relro_vaddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Creates an android_dlextinfo struct so that a library is loaded inside the
|
||||
// space referenced by |mapping|.
|
||||
std::unique_ptr<android_dlextinfo> MakeAndroidDlextinfo(
|
||||
const ScopedAnonymousMmap& mapping) {
|
||||
auto info = std::make_unique<android_dlextinfo>();
|
||||
memset(info.get(), 0, sizeof(*info));
|
||||
info->flags = ANDROID_DLEXT_RESERVED_ADDRESS;
|
||||
info->reserved_addr = mapping.address();
|
||||
info->reserved_size = mapping.size();
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
// Copies the current relocations into a shared-memory file, and uses this file
|
||||
// as the relocations.
|
||||
//
|
||||
// Returns true for success, and populate |fd| with the relocations's fd in this
|
||||
// case.
|
||||
bool CopyAndRemapRelocations(const LoadedLibraryMetadata& metadata, int* fd) {
|
||||
LOG_INFO("Entering");
|
||||
void* relro_addr = reinterpret_cast<void*>(metadata.relro_start);
|
||||
|
||||
SharedMemoryFunctions fns;
|
||||
if (!fns.create)
|
||||
return false;
|
||||
|
||||
int shared_mem_fd = fns.create("cr_relro", metadata.relro_size);
|
||||
if (shared_mem_fd == -1) {
|
||||
LOG_ERROR("Cannot create the shared memory file");
|
||||
return false;
|
||||
}
|
||||
|
||||
int rw_flags = PROT_READ | PROT_WRITE;
|
||||
fns.set_protection(shared_mem_fd, rw_flags);
|
||||
|
||||
void* relro_copy_addr = mmap(nullptr, metadata.relro_size, rw_flags,
|
||||
MAP_SHARED, shared_mem_fd, 0);
|
||||
if (relro_copy_addr == MAP_FAILED) {
|
||||
LOG_ERROR("Cannot mmap() space for the copy");
|
||||
close(shared_mem_fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
memcpy(relro_copy_addr, relro_addr, metadata.relro_size);
|
||||
int retval = mprotect(relro_copy_addr, metadata.relro_size, PROT_READ);
|
||||
if (retval) {
|
||||
LOG_ERROR("Cannot call mprotect()");
|
||||
close(shared_mem_fd);
|
||||
munmap(relro_copy_addr, metadata.relro_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
void* new_addr =
|
||||
mremap(relro_copy_addr, metadata.relro_size, metadata.relro_size,
|
||||
MREMAP_MAYMOVE | MREMAP_FIXED, relro_addr);
|
||||
if (new_addr != relro_addr) {
|
||||
LOG_ERROR("mremap() error");
|
||||
close(shared_mem_fd);
|
||||
munmap(relro_copy_addr, metadata.relro_size);
|
||||
return false;
|
||||
}
|
||||
|
||||
*fd = shared_mem_fd;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Gathers metadata about the library loaded at |addr|.
|
||||
//
|
||||
// Returns true for success.
|
||||
bool GetLoadedLibraryMetadata(LoadedLibraryMetadata* metadata) {
|
||||
LOG_INFO("Called for %p", metadata->load_address);
|
||||
|
||||
if (!dl_iterate_phdr) {
|
||||
LOG_ERROR("No dl_iterate_phdr() found");
|
||||
return false;
|
||||
}
|
||||
int status = dl_iterate_phdr(&FindLoadedLibraryMetadata, metadata);
|
||||
if (!status) {
|
||||
LOG_ERROR("Failed to find library at address %p", metadata->load_address);
|
||||
return false;
|
||||
}
|
||||
|
||||
LOG_INFO("Relro start address = %p, size = %d",
|
||||
reinterpret_cast<void*>(metadata->relro_start),
|
||||
static_cast<int>(metadata->relro_size));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Resizes the address space reservation to the actual required size.
|
||||
// Failure here is only a warning, as at worst this wastes virtual address
|
||||
// space, not actual memory.
|
||||
void ResizeMapping(const ScopedAnonymousMmap& mapping,
|
||||
const LoadedLibraryMetadata& metadata) {
|
||||
// Trim the reservation mapping to match the library's actual size. Failure
|
||||
// to resize is not a fatal error. At worst we lose a portion of virtual
|
||||
// address space that we might otherwise have recovered. Note that trimming
|
||||
// the mapping here requires that we have already released the scoped
|
||||
// mapping.
|
||||
const uintptr_t uintptr_addr = reinterpret_cast<uintptr_t>(mapping.address());
|
||||
if (mapping.size() > metadata.load_size) {
|
||||
// Unmap the part of the reserved address space that is beyond the end of
|
||||
// the loaded library data.
|
||||
void* unmap = reinterpret_cast<void*>(uintptr_addr + metadata.load_size);
|
||||
const size_t length = mapping.size() - metadata.load_size;
|
||||
if (munmap(unmap, length) == -1) {
|
||||
LOG_ERROR("WARNING: unmap of %d bytes at %p failed: %s",
|
||||
static_cast<int>(length), unmap, strerror(errno));
|
||||
}
|
||||
} else {
|
||||
LOG_ERROR("WARNING: library reservation was too small");
|
||||
}
|
||||
}
|
||||
|
||||
// Calls JNI_OnLoad() in the library referenced by |handle|.
|
||||
// Returns true for success.
|
||||
bool CallJniOnLoad(void* handle) {
|
||||
LOG_INFO("Entering");
|
||||
// Locate and if found then call the loaded library's JNI_OnLoad() function.
|
||||
using JNI_OnLoadFunctionPtr = int (*)(void* vm, void* reserved);
|
||||
auto jni_onload =
|
||||
reinterpret_cast<JNI_OnLoadFunctionPtr>(dlsym(handle, "JNI_OnLoad"));
|
||||
if (jni_onload != nullptr) {
|
||||
// Check that JNI_OnLoad returns a usable JNI version.
|
||||
int jni_version = (*jni_onload)(s_java_vm, nullptr);
|
||||
if (jni_version < JNI_VERSION_1_4) {
|
||||
LOG_ERROR("JNI version is invalid: %d", jni_version);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load the library at |path| at address |wanted_address| if possible, and
|
||||
// creates a file with relro at |relocations_path|.
|
||||
//
|
||||
// In case of success, returns a readonly file descriptor to the relocations,
|
||||
// otherwise returns -1.
|
||||
int LoadCreateSharedRelocations(const String& path, void* wanted_address) {
|
||||
LOG_INFO("Entering");
|
||||
ScopedAnonymousMmap mapping = ScopedAnonymousMmap::ReserveAtAddress(
|
||||
wanted_address, kAddressSpaceReservationSize);
|
||||
if (!mapping.address())
|
||||
return -1;
|
||||
|
||||
std::unique_ptr<android_dlextinfo> dlextinfo = MakeAndroidDlextinfo(mapping);
|
||||
void* handle = nullptr;
|
||||
if (!AndroidDlopenExt(path.c_str(), RTLD_NOW, *dlextinfo, &handle)) {
|
||||
LOG_ERROR("android_dlopen_ext() error");
|
||||
return -1;
|
||||
}
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR("android_dlopen_ext: %s", dlerror());
|
||||
return -1;
|
||||
}
|
||||
mapping.Release();
|
||||
|
||||
LoadedLibraryMetadata metadata{mapping.address()};
|
||||
bool ok = GetLoadedLibraryMetadata(&metadata);
|
||||
int relro_fd = -1;
|
||||
if (ok) {
|
||||
ResizeMapping(mapping, metadata);
|
||||
CopyAndRemapRelocations(metadata, &relro_fd);
|
||||
}
|
||||
|
||||
if (!CallJniOnLoad(handle))
|
||||
return false;
|
||||
|
||||
return relro_fd;
|
||||
}
|
||||
|
||||
// Load the library at |path| at address |wanted_address| if possible, and
|
||||
// uses the relocations in |relocations_fd| if possible.
|
||||
bool LoadUseSharedRelocations(const String& path,
|
||||
void* wanted_address,
|
||||
int relocations_fd) {
|
||||
LOG_INFO("Entering");
|
||||
ScopedAnonymousMmap mapping = ScopedAnonymousMmap::ReserveAtAddress(
|
||||
wanted_address, kAddressSpaceReservationSize);
|
||||
if (!mapping.address())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<android_dlextinfo> dlextinfo = MakeAndroidDlextinfo(mapping);
|
||||
void* handle = nullptr;
|
||||
if (!AndroidDlopenExt(path.c_str(), RTLD_NOW, *dlextinfo, &handle)) {
|
||||
LOG_ERROR("No android_dlopen_ext function found");
|
||||
return false;
|
||||
}
|
||||
if (handle == nullptr) {
|
||||
LOG_ERROR("android_dlopen_ext: %s", dlerror());
|
||||
return false;
|
||||
}
|
||||
mapping.Release();
|
||||
|
||||
LoadedLibraryMetadata metadata{mapping.address()};
|
||||
bool ok = GetLoadedLibraryMetadata(&metadata);
|
||||
if (!ok) {
|
||||
LOG_ERROR("Cannot get library's metadata");
|
||||
return false;
|
||||
}
|
||||
|
||||
ResizeMapping(mapping, metadata);
|
||||
void* shared_relro_mapping_address = mmap(
|
||||
nullptr, metadata.relro_size, PROT_READ, MAP_SHARED, relocations_fd, 0);
|
||||
if (shared_relro_mapping_address == MAP_FAILED) {
|
||||
LOG_ERROR("Cannot map the relocations");
|
||||
return false;
|
||||
}
|
||||
|
||||
void* current_relro_address = reinterpret_cast<void*>(metadata.relro_start);
|
||||
int retval = memcmp(shared_relro_mapping_address, current_relro_address,
|
||||
metadata.relro_size);
|
||||
if (!retval) {
|
||||
void* new_addr = mremap(shared_relro_mapping_address, metadata.relro_size,
|
||||
metadata.relro_size, MREMAP_MAYMOVE | MREMAP_FIXED,
|
||||
current_relro_address);
|
||||
if (new_addr != current_relro_address) {
|
||||
LOG_ERROR("Cannot call mremap()");
|
||||
munmap(shared_relro_mapping_address, metadata.relro_size);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
munmap(shared_relro_mapping_address, metadata.relro_size);
|
||||
LOG_ERROR("Relocations are not identical, giving up.");
|
||||
}
|
||||
|
||||
if (!CallJniOnLoad(handle))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadNoSharedRelocations(const String& path) {
|
||||
void* handle = dlopen(path.c_str(), RTLD_NOW);
|
||||
if (!handle) {
|
||||
LOG_ERROR("dlopen: %s", dlerror());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CallJniOnLoad(handle))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
JNI_GENERATOR_EXPORT jboolean
|
||||
Java_org_chromium_base_library_1loader_ModernLinker_nativeLoadLibraryCreateRelros(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring jdlopen_ext_path,
|
||||
jlong load_address,
|
||||
jobject lib_info_obj) {
|
||||
LOG_INFO("Entering");
|
||||
|
||||
String library_path(env, jdlopen_ext_path);
|
||||
|
||||
if (!IsValidAddress(load_address)) {
|
||||
LOG_ERROR("Invalid address 0x%llx", static_cast<long long>(load_address));
|
||||
return false;
|
||||
}
|
||||
void* address = reinterpret_cast<void*>(load_address);
|
||||
|
||||
int fd = LoadCreateSharedRelocations(library_path, address);
|
||||
if (fd == -1)
|
||||
return false;
|
||||
|
||||
// Note the shared RELRO fd in the supplied libinfo object. In this
|
||||
// implementation the RELRO start is set to the library's load address,
|
||||
// and the RELRO size is unused.
|
||||
const size_t cast_addr = reinterpret_cast<size_t>(address);
|
||||
s_lib_info_fields.SetRelroInfo(env, lib_info_obj, cast_addr, 0, fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JNI_GENERATOR_EXPORT jboolean
|
||||
Java_org_chromium_base_library_1loader_ModernLinker_nativeLoadLibraryUseRelros(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring jdlopen_ext_path,
|
||||
jlong load_address,
|
||||
jint relro_fd) {
|
||||
LOG_INFO("Entering");
|
||||
|
||||
String library_path(env, jdlopen_ext_path);
|
||||
|
||||
if (!IsValidAddress(load_address)) {
|
||||
LOG_ERROR("Invalid address 0x%llx", static_cast<long long>(load_address));
|
||||
return false;
|
||||
}
|
||||
void* address = reinterpret_cast<void*>(load_address);
|
||||
|
||||
return LoadUseSharedRelocations(library_path, address, relro_fd);
|
||||
}
|
||||
|
||||
JNI_GENERATOR_EXPORT jboolean
|
||||
Java_org_chromium_base_library_1loader_ModernLinker_nativeLoadLibraryNoRelros(
|
||||
JNIEnv* env,
|
||||
jclass clazz,
|
||||
jstring jdlopen_ext_path) {
|
||||
String library_path(env, jdlopen_ext_path);
|
||||
return LoadNoSharedRelocations(library_path);
|
||||
}
|
||||
|
||||
bool ModernLinkerJNIInit(JavaVM* vm, JNIEnv* env) {
|
||||
s_java_vm = vm;
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace chromium_android_linker
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2019 The Chromium Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef BASE_ANDROID_LINKER_MODERN_LINKER_JNI_H_
|
||||
#define BASE_ANDROID_LINKER_MODERN_LINKER_JNI_H_
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
namespace chromium_android_linker {
|
||||
|
||||
// JNI_OnLoad() initialization hook for the modern linker.
|
||||
// Sets up JNI and other initializations for native linker code.
|
||||
// |vm| is the Java VM handle passed to JNI_OnLoad().
|
||||
// |env| is the current JNI environment handle.
|
||||
// On success, returns true.
|
||||
extern bool ModernLinkerJNIInit(JavaVM* vm, JNIEnv* env);
|
||||
|
||||
} // namespace chromium_android_linker
|
||||
|
||||
#endif // BASE_ANDROID_LINKER_MODERN_LINKER_JNI_H_
|
||||
Loading…
Add table
Add a link
Reference in a new issue