| Index: android/java/src/org/chromium/base/library_loader/Linker.java
|
| diff --git a/android/java/src/org/chromium/base/library_loader/Linker.java b/android/java/src/org/chromium/base/library_loader/Linker.java
|
| index c769339620df9bae97d72735f05b030d064bb57a..ee62570fed75a0fa23a1717cd6f75e7fea2225cf 100644
|
| --- a/android/java/src/org/chromium/base/library_loader/Linker.java
|
| +++ b/android/java/src/org/chromium/base/library_loader/Linker.java
|
| @@ -56,7 +56,7 @@ import javax.annotation.Nullable;
|
| *
|
| * - Whether the browser process loads its native libraries at the same
|
| * addresses as the service ones (to save RAM by sharing the RELRO too)
|
| - * depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG below.
|
| + * depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG.
|
| *
|
| * Not using fixed library addresses in the browser process is preferred
|
| * for regular devices since it maintains the efficacy of ASLR as an
|
| @@ -67,20 +67,14 @@ import javax.annotation.Nullable;
|
| * it read-write (e.g. by calling mmap() or mprotect()) and modify its
|
| * content, altering values seen in other service processes.
|
| *
|
| - * - Unfortunately, certain Android systems use an old, buggy kernel, that
|
| - * doesn't check Ashmem region permissions correctly. See CVE-2011-1149
|
| - * for details. This linker probes the system on startup and will completely
|
| - * disable shared RELROs if it detects the problem. For the record, this is
|
| - * common for Android emulator system images (which are still based on 2.6.29)
|
| - *
|
| - * - Once the RELRO ashmem region is mapped into a service process' address
|
| - * space, the corresponding file descriptor is immediately closed. The
|
| + * - Once the RELRO ashmem region or file is mapped into a service process's
|
| + * address space, the corresponding file descriptor is immediately closed. The
|
| * file descriptor is kept opened in the browser process, because a copy needs
|
| * to be sent to each new potential service process.
|
| *
|
| * - The common library load addresses are randomized for each instance of
|
| - * the program on the device. See computeRandomBaseLoadAddress() for more
|
| - * details on how this is computed.
|
| + * the program on the device. See getRandomBaseLoadAddress() for more
|
| + * details on how this is obtained.
|
| *
|
| * - When loading several libraries in service processes, a simple incremental
|
| * approach from the original random base load address is used. This is
|
| @@ -93,8 +87,8 @@ import javax.annotation.Nullable;
|
| * Here's an explanation of how this class is supposed to be used:
|
| *
|
| * - Native shared libraries should be loaded with Linker.loadLibrary(),
|
| - * instead of System.loadLibrary(). The two functions take the same parameter
|
| - * and should behave the same (at a high level).
|
| + * instead of System.loadLibrary(). The two functions should behave the same
|
| + * (at a high level).
|
| *
|
| * - Before loading any library, prepareLibraryLoad() should be called.
|
| *
|
| @@ -143,9 +137,9 @@ import javax.annotation.Nullable;
|
| * a Binder call (note that the Bundle includes file descriptors and cannot
|
| * be added as an Intent extra).
|
| *
|
| - * - In a service process, finishLibraryLoad() will block until the RELRO
|
| - * section Bundle is received. This is typically done by calling
|
| - * useSharedRelros() from another thread.
|
| + * - In a service process, finishLibraryLoad() and/or loadLibrary() may
|
| + * block until the RELRO section Bundle is received. This is typically
|
| + * done by calling useSharedRelros() from another thread.
|
| *
|
| * This method also ensures the process uses the shared RELROs.
|
| */
|
| @@ -153,18 +147,8 @@ public abstract class Linker {
|
| // Log tag for this class.
|
| private static final String TAG = "cr.library_loader";
|
|
|
| - // Set to true to enable debug logs.
|
| - protected static final boolean DEBUG = false;
|
| -
|
| - // Used to pass the shared RELRO Bundle through Binder.
|
| - public static final String EXTRA_LINKER_SHARED_RELROS =
|
| - "org.chromium.base.android.linker.shared_relros";
|
| -
|
| - // Guards all access to the linker.
|
| - protected final Object mLock = new Object();
|
| -
|
| // Constants used to control the behaviour of the browser process with
|
| - // regards to the shared RELRO section.
|
| + // regards to the shared RELRO section. Not applicable to ModernLinker.
|
| // NEVER -> The browser never uses it itself.
|
| // LOW_RAM_ONLY -> It is only used on devices with low RAM.
|
| // ALWAYS -> It is always used.
|
| @@ -175,11 +159,13 @@ public abstract class Linker {
|
|
|
| // Configuration variable used to control how the browser process uses the
|
| // shared RELRO. Only change this while debugging linker-related issues.
|
| + // Not used by ModernLinker.
|
| // NOTE: This variable's name is known and expected by the Linker test scripts.
|
| public static final int BROWSER_SHARED_RELRO_CONFIG =
|
| BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY;
|
|
|
| - // Constants used to control the value of sMemoryDeviceConfig.
|
| + // Constants used to control the memory device config. Can be set explicitly
|
| + // by setMemoryDeviceConfigForTesting(). Not applicable to ModernLinker.
|
| // INIT -> Value is undetermined (will check at runtime).
|
| // LOW -> This is a low-memory device.
|
| // NORMAL -> This is not a low-memory device.
|
| @@ -189,9 +175,44 @@ public abstract class Linker {
|
|
|
| // Indicates if this is a low-memory device or not. The default is to
|
| // determine this by probing the system at runtime, but this can be forced
|
| - // for testing by calling setMemoryDeviceConfig().
|
| + // for testing by calling setMemoryDeviceConfigForTesting().
|
| + // Not used by ModernLinker.
|
| protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
|
|
|
| + // Name of the library that contains our JNI code.
|
| + protected static final String LINKER_JNI_LIBRARY = "chromium_android_linker";
|
| +
|
| + // Set to true to enable debug logs.
|
| + protected static final boolean DEBUG = false;
|
| +
|
| + // Used to pass the shared RELRO Bundle through Binder.
|
| + public static final String EXTRA_LINKER_SHARED_RELROS =
|
| + "org.chromium.base.android.linker.shared_relros";
|
| +
|
| + // Guards all access to the linker.
|
| + protected final Object mLock = new Object();
|
| +
|
| + // The name of a class that implements TestRunner.
|
| + private String mTestRunnerClassName = null;
|
| +
|
| + // Size of reserved Breakpad guard region. Should match the value of
|
| + // kBreakpadGuardRegionBytes on the JNI side. Used when computing the load
|
| + // addresses of multiple loaded libraries. Set to 0 to disable the guard.
|
| + protected static final int BREAKPAD_GUARD_REGION_BYTES = 16 * 1024 * 1024;
|
| +
|
| + // Size of the area requested when using ASLR to obtain a random load address.
|
| + // Should match the value of kAddressSpaceReservationSize on the JNI side.
|
| + // Used when computing the load addresses of multiple loaded libraries to
|
| + // ensure that we don't try to load outside the area originally requested.
|
| + protected static final int ADDRESS_SPACE_RESERVATION = 192 * 1024 * 1024;
|
| +
|
| + // Constants used to indicate a given Linker implementation, for testing.
|
| + // LEGACY -> Always uses the LegacyLinker implementation.
|
| + // MODERN -> Always uses the ModernLinker implementation.
|
| + // NOTE: These names are known and expected by the Linker test scripts.
|
| + public static final int LINKER_IMPLEMENTATION_LEGACY = 1;
|
| + public static final int LINKER_IMPLEMENTATION_MODERN = 2;
|
| +
|
| // Singleton.
|
| private static Linker sSingleton = null;
|
| private static Object sSingletonLock = new Object();
|
| @@ -199,19 +220,111 @@ public abstract class Linker {
|
| // Protected singleton constructor.
|
| protected Linker() {}
|
|
|
| - // Get singleton instance.
|
| + /**
|
| + * Get singleton instance. Returns either a LegacyLinker or a ModernLinker.
|
| + *
|
| + * @return the Linker implementation instance.
|
| + */
|
| public static final Linker getInstance() {
|
| synchronized (sSingletonLock) {
|
| if (sSingleton == null) {
|
| - // TODO(simonb): Extend later to return either a LegacyLinker
|
| - // or a ModernLinker instance.
|
| - sSingleton = new LegacyLinker();
|
| + // TODO(simonb): Check version once the Android M build version
|
| + // code becomes available.
|
| + // if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.<ANDROID-M>) {
|
| + if (false) {
|
| + sSingleton = ModernLinker.create();
|
| + } else {
|
| + sSingleton = LegacyLinker.create();
|
| + }
|
| + Log.i(TAG, "Using linker: " + sSingleton.getClass().getName());
|
| }
|
| return sSingleton;
|
| }
|
| }
|
|
|
| /**
|
| + * Check that native library linker tests are enabled.
|
| + * If not enabled, calls to testing functions will fail with an assertion
|
| + * error.
|
| + *
|
| + * @return true if native library linker tests are enabled.
|
| + */
|
| + public static boolean areLinkerTestsEnabled() {
|
| + return NativeLibraries.sEnableLinkerTests;
|
| + }
|
| +
|
| + /**
|
| + * Assert for testing.
|
| + * Hard assertion. Cannot be disabled. Used only by testing methods.
|
| + */
|
| + private static void assertForTesting(boolean flag) {
|
| + if (!flag) {
|
| + throw new AssertionError();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Assert NativeLibraries.sEnableLinkerTests is true.
|
| + * Hard assertion that we are in a testing context. Cannot be disabled. The
|
| + * test methods in this module permit injection of runnable code by class
|
| + * name. To protect against both malicious and accidental use of these
|
| + * methods, we ensure that NativeLibraries.sEnableLinkerTests is true when
|
| + * any is called.
|
| + */
|
| + private static void assertLinkerTestsAreEnabled() {
|
| + if (!NativeLibraries.sEnableLinkerTests) {
|
| + throw new AssertionError("Testing method called in non-testing context");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Set Linker implementation type.
|
| + * For testing. Sets either a LegacyLinker or a ModernLinker. Must be called
|
| + * before getInstance().
|
| + *
|
| + * @param type LINKER_IMPLEMENTATION_LEGACY or LINKER_IMPLEMENTATION_MODERN
|
| + */
|
| + public static final void setLinkerImplementationForTesting(int type) {
|
| + // Sanity check. This method may only be called during tests.
|
| + assertLinkerTestsAreEnabled();
|
| + assertForTesting(
|
| + type == LINKER_IMPLEMENTATION_LEGACY || type == LINKER_IMPLEMENTATION_MODERN);
|
| +
|
| + synchronized (sSingletonLock) {
|
| + assertForTesting(sSingleton == null);
|
| +
|
| + if (type == LINKER_IMPLEMENTATION_MODERN) {
|
| + sSingleton = ModernLinker.create();
|
| + } else if (type == LINKER_IMPLEMENTATION_LEGACY) {
|
| + sSingleton = LegacyLinker.create();
|
| + } else {
|
| + return;
|
| + }
|
| + Log.i(TAG, "Forced linker: " + sSingleton.getClass().getName());
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Get Linker implementation type.
|
| + * For testing.
|
| + *
|
| + * @return LINKER_IMPLEMENTATION_LEGACY or LINKER_IMPLEMENTATION_MODERN
|
| + */
|
| + public int getLinkerImplementationForTesting() {
|
| + // Sanity check. This method may only be called during tests.
|
| + assertLinkerTestsAreEnabled();
|
| + assertForTesting(sSingleton != null);
|
| +
|
| + if (sSingleton instanceof ModernLinker) {
|
| + return LINKER_IMPLEMENTATION_MODERN;
|
| + } else if (sSingleton instanceof LegacyLinker) {
|
| + return LINKER_IMPLEMENTATION_LEGACY;
|
| + }
|
| + Log.e(TAG, "Invalid linker: " + sSingleton.getClass().getName());
|
| + return 0;
|
| + }
|
| +
|
| + /**
|
| * A public interface used to run runtime linker tests after loading
|
| * libraries. Should only be used to implement the linker unit tests,
|
| * which is controlled by the value of NativeLibraries.sEnableLinkerTests
|
| @@ -220,32 +333,30 @@ public abstract class Linker {
|
| public interface TestRunner {
|
| /**
|
| * Run runtime checks and return true if they all pass.
|
| + *
|
| * @param memoryDeviceConfig The current memory device configuration.
|
| * @param inBrowserProcess true iff this is the browser process.
|
| + * @return true if all checks pass.
|
| */
|
| public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProcess);
|
| }
|
|
|
| - // The name of a class that implements TestRunner.
|
| - String mTestRunnerClassName = null;
|
| -
|
| /**
|
| * Set the TestRunner by its class name. It will be instantiated at
|
| * runtime after all libraries are loaded.
|
| + *
|
| * @param testRunnerClassName null or a String for the class name of the
|
| * TestRunner to use.
|
| */
|
| - public void setTestRunnerClassName(String testRunnerClassName) {
|
| + public void setTestRunnerClassNameForTesting(String testRunnerClassName) {
|
| if (DEBUG) {
|
| - Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
|
| - }
|
| - if (!NativeLibraries.sEnableLinkerTests) {
|
| - // Ignore this in production code to prevent malevolent runtime injection.
|
| - return;
|
| + Log.i(TAG, "setTestRunnerByClassNameForTesting(" + testRunnerClassName + ") called");
|
| }
|
| + // Sanity check. This method may only be called during tests.
|
| + assertLinkerTestsAreEnabled();
|
|
|
| synchronized (mLock) {
|
| - assert mTestRunnerClassName == null;
|
| + assertForTesting(mTestRunnerClassName == null);
|
| mTestRunnerClassName = testRunnerClassName;
|
| }
|
| }
|
| @@ -254,42 +365,193 @@ public abstract class Linker {
|
| * Call this to retrieve the name of the current TestRunner class name
|
| * if any. This can be useful to pass it from the browser process to
|
| * child ones.
|
| + *
|
| * @return null or a String holding the name of the class implementing
|
| - * the TestRunner set by calling setTestRunnerClassName() previously.
|
| + * the TestRunner set by calling setTestRunnerClassNameForTesting() previously.
|
| */
|
| - public String getTestRunnerClassName() {
|
| + public String getTestRunnerClassNameForTesting() {
|
| + // Sanity check. This method may only be called during tests.
|
| + assertLinkerTestsAreEnabled();
|
| +
|
| synchronized (mLock) {
|
| return mTestRunnerClassName;
|
| }
|
| }
|
|
|
| /**
|
| + * Instantiate and run the current TestRunner, if any. The TestRunner implementation
|
| + * must be instantiated _after_ all libraries are loaded to ensure that its
|
| + * native methods are properly registered.
|
| + *
|
| + * @param memoryDeviceConfig LegacyLinker memory config, or 0 if unused
|
| + * @param inBrowserProcess true if in the browser process
|
| + */
|
| + protected void runTestRunnerClassForTesting(int memoryDeviceConfig, boolean inBrowserProcess) {
|
| + if (DEBUG) {
|
| + Log.i(TAG, "runTestRunnerClassForTesting called");
|
| + }
|
| + // Sanity check. This method may only be called during tests.
|
| + assertLinkerTestsAreEnabled();
|
| +
|
| + synchronized (mLock) {
|
| + if (mTestRunnerClassName == null) {
|
| + return;
|
| + }
|
| + if (DEBUG) {
|
| + Log.i(TAG, "Instantiating " + mTestRunnerClassName);
|
| + }
|
| + TestRunner testRunner = null;
|
| + try {
|
| + testRunner = (TestRunner) Class.forName(mTestRunnerClassName).newInstance();
|
| + } catch (Exception e) {
|
| + Log.e(TAG, "Could not instantiate test runner class by name", e);
|
| + testRunner = null;
|
| + }
|
| + if (testRunner != null) {
|
| + if (!testRunner.runChecks(memoryDeviceConfig, inBrowserProcess)) {
|
| + Log.wtf(TAG, "Linker runtime tests failed in this process!!");
|
| + assertForTesting(false);
|
| + } else {
|
| + Log.i(TAG, "All linker tests passed!");
|
| + }
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| * Call this method before any other Linker method to force a specific
|
| * memory device configuration. Should only be used for testing.
|
| - * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
|
| + *
|
| + * @param memoryDeviceConfig MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
|
| */
|
| - public void setMemoryDeviceConfig(int memoryDeviceConfig) {
|
| + public void setMemoryDeviceConfigForTesting(int memoryDeviceConfig) {
|
| if (DEBUG) {
|
| - Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
|
| + Log.i(TAG, "setMemoryDeviceConfigForTesting(" + memoryDeviceConfig + ") called");
|
| }
|
| - // Sanity check. This method should only be called during tests.
|
| - assert NativeLibraries.sEnableLinkerTests;
|
| + // Sanity check. This method may only be called during tests.
|
| + assertLinkerTestsAreEnabled();
|
| + assertForTesting(memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
|
| + || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL);
|
| +
|
| synchronized (mLock) {
|
| - assert mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
|
| - assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
|
| - || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
|
| + assertForTesting(mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT);
|
| +
|
| + mMemoryDeviceConfig = memoryDeviceConfig;
|
| if (DEBUG) {
|
| - if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
|
| + if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
|
| Log.i(TAG, "Simulating a low-memory device");
|
| } else {
|
| Log.i(TAG, "Simulating a regular-memory device");
|
| }
|
| }
|
| - mMemoryDeviceConfig = memoryDeviceConfig;
|
| }
|
| }
|
|
|
| /**
|
| + * Determine whether a library is the linker library. Also deal with the
|
| + * component build that adds a .cr suffix to the name.
|
| + *
|
| + * @param library the name of the library.
|
| + * @return true is the library is the Linker's own JNI library.
|
| + */
|
| + public boolean isChromiumLinkerLibrary(String library) {
|
| + return library.equals(LINKER_JNI_LIBRARY) || library.equals(LINKER_JNI_LIBRARY + ".cr");
|
| + }
|
| +
|
| + /**
|
| + * Load the Linker JNI library. Throws UnsatisfiedLinkError on error.
|
| + * In a component build, the suffix ".cr" is added to each library name, so
|
| + * if the initial load fails we retry with a suffix.
|
| + */
|
| + protected void loadLinkerJNILibrary() {
|
| + String lib_name = "lib" + LINKER_JNI_LIBRARY + ".so";
|
| + if (DEBUG) {
|
| + Log.i(TAG, "Loading " + lib_name);
|
| + }
|
| + try {
|
| + System.loadLibrary(LINKER_JNI_LIBRARY);
|
| + } catch (UnsatisfiedLinkError e) {
|
| + Log.w(TAG, "Couldn't load " + lib_name + ", trying " + lib_name + ".so");
|
| + System.loadLibrary(LINKER_JNI_LIBRARY + ".cr");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Obtain a random base load address at which to place loaded libraries.
|
| + *
|
| + * @return new base load address
|
| + */
|
| + protected long getRandomBaseLoadAddress() {
|
| + // nativeGetRandomBaseLoadAddress() returns an address at which it has previously
|
| + // successfully mapped an area larger than the largest library we expect to load,
|
| + // on the basis that we will be able, with high probability, to map our library
|
| + // into it.
|
| + //
|
| + // One issue with this is that we do not yet know the size of the library that
|
| + // we will load is. If it is smaller than the size we used to obtain a random
|
| + // address the library mapping may still succeed. The other issue is that
|
| + // although highly unlikely, there is no guarantee that something else does not
|
| + // map into the area we are going to use between here and when we try to map into it.
|
| + //
|
| + // The above notes mean that all of this is probablistic. It is however okay to do
|
| + // because if, worst case and unlikely, we get unlucky in our choice of address,
|
| + // the back-out and retry without the shared RELRO in the ChildProcessService will
|
| + // keep things running.
|
| + final long address = nativeGetRandomBaseLoadAddress();
|
| + if (DEBUG) {
|
| + Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address));
|
| + }
|
| + return address;
|
| + }
|
| +
|
| + /**
|
| + * Load a native shared library with the Chromium linker. If the zip file
|
| + * is not null, the shared library must be uncompressed and page aligned
|
| + * inside the zipfile. Note the crazy linker treats libraries and files as
|
| + * equivalent, so you can only open one library in a given zip file. The
|
| + * library must not be the Chromium linker library.
|
| + *
|
| + * @param zipFilePath The path of the zip file containing the library (or null).
|
| + * @param libFilePath The path of the library (possibly in the zip file).
|
| + */
|
| + public void loadLibrary(@Nullable String zipFilePath, String libFilePath) {
|
| + if (DEBUG) {
|
| + Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath);
|
| + }
|
| + final boolean isFixedAddressPermitted = true;
|
| + loadLibraryImpl(zipFilePath, libFilePath, isFixedAddressPermitted);
|
| + }
|
| +
|
| + /**
|
| + * Load a native shared library with the Chromium linker, ignoring any
|
| + * requested fixed address for RELRO sharing. If the zip file
|
| + * is not null, the shared library must be uncompressed and page aligned
|
| + * inside the zipfile. Note the crazy linker treats libraries and files as
|
| + * equivalent, so you can only open one library in a given zip file. The
|
| + * library must not be the Chromium linker library.
|
| + *
|
| + * @param zipFilePath The path of the zip file containing the library (or null).
|
| + * @param libFilePath The path of the library (possibly in the zip file).
|
| + */
|
| + public void loadLibraryNoFixedAddress(@Nullable String zipFilePath, String libFilePath) {
|
| + if (DEBUG) {
|
| + Log.i(TAG, "loadLibraryAtAnyAddress: " + zipFilePath + ", " + libFilePath);
|
| + }
|
| + final boolean isFixedAddressPermitted = false;
|
| + loadLibraryImpl(zipFilePath, libFilePath, isFixedAddressPermitted);
|
| + }
|
| +
|
| + /**
|
| + * Call this method to determine if the chromium project must load the library
|
| + * directly from a zip file.
|
| + */
|
| + public boolean isInZipFile() {
|
| + // The auto-generated NativeLibraries.sUseLibraryInZipFile variable will be true
|
| + // if the library remains embedded in the APK zip file on the target.
|
| + return NativeLibraries.sUseLibraryInZipFile;
|
| + }
|
| +
|
| + /**
|
| * Call this method to determine if this chromium project must
|
| * use this linker. If not, System.loadLibrary() should be used to load
|
| * libraries instead.
|
| @@ -303,20 +565,12 @@ public abstract class Linker {
|
| public abstract boolean isUsingBrowserSharedRelros();
|
|
|
| /**
|
| - * Call this method to determine if the chromium project must load
|
| - * the library directly from the zip file.
|
| - */
|
| - public abstract boolean isInZipFile();
|
| -
|
| - /**
|
| * Call this method just before loading any native shared libraries in this process.
|
| */
|
| public abstract void prepareLibraryLoad();
|
|
|
| /**
|
| * Call this method just after loading all native shared libraries in this process.
|
| - * Note that when in a service process, this will block until the RELRO bundle is
|
| - * received, i.e. when another thread calls useSharedRelros().
|
| */
|
| public abstract void finishLibraryLoad();
|
|
|
| @@ -325,6 +579,7 @@ public abstract class Linker {
|
| * used in this process. If initServiceProcess() was previously called,
|
| * finishLibraryLoad() will not exit until this method is called in another
|
| * thread with a non-null value.
|
| + *
|
| * @param bundle The Bundle instance containing a map of shared RELRO sections
|
| * to use in this process.
|
| */
|
| @@ -333,6 +588,7 @@ public abstract class Linker {
|
| /**
|
| * Call this to retrieve the shared RELRO sections created in this process,
|
| * after loading all libraries.
|
| + *
|
| * @return a new Bundle instance, or null if RELRO sharing is disabled on
|
| * this system, or if initServiceProcess() was called previously.
|
| */
|
| @@ -348,6 +604,7 @@ public abstract class Linker {
|
| * Call this method before loading any libraries to indicate that this
|
| * process is ready to reuse shared RELRO sections from another one.
|
| * Typically used when starting service processes.
|
| + *
|
| * @param baseLoadAddress the base library load address to use.
|
| */
|
| public abstract void initServiceProcess(long baseLoadAddress);
|
| @@ -356,34 +613,28 @@ public abstract class Linker {
|
| * Retrieve the base load address of all shared RELRO sections.
|
| * This also enforces the creation of shared RELRO sections in
|
| * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
|
| + *
|
| * @return a common, random base load address, or 0 if RELRO sharing is
|
| * disabled.
|
| */
|
| public abstract long getBaseLoadAddress();
|
|
|
| /**
|
| - * Load a native shared library with the Chromium linker. If the zip file
|
| - * is not null, the shared library must be uncompressed and page aligned
|
| - * inside the zipfile. Note the crazy linker treats libraries and files as
|
| - * equivalent, so you can only open one library in a given zip file. The
|
| - * library must not be the Chromium linker library.
|
| + * Implements loading a native shared library with the Chromium linker.
|
| *
|
| * @param zipFilePath The path of the zip file containing the library (or null).
|
| * @param libFilePath The path of the library (possibly in the zip file).
|
| + * @param isFixedAddressPermitted If true, uses a fixed load address if one was
|
| + * supplied, otherwise ignores the fixed address and loads wherever available.
|
| */
|
| - public abstract void loadLibrary(@Nullable String zipFilePath, String libFilePath);
|
| -
|
| - /**
|
| - * Determine whether a library is the linker library. Also deal with the
|
| - * component build that adds a .cr suffix to the name.
|
| - */
|
| - public abstract boolean isChromiumLinkerLibrary(String library);
|
| + abstract void loadLibraryImpl(
|
| + @Nullable String zipFilePath, String libFilePath, boolean isFixedAddressPermitted);
|
|
|
| /**
|
| * Record information for a given library.
|
| * IMPORTANT: Native code knows about this class's fields, so
|
| * don't change them without modifying the corresponding C++ sources.
|
| - * Also, the LibInfo instance owns the ashmem file descriptor.
|
| + * Also, the LibInfo instance owns the shared RELRO file descriptor.
|
| */
|
| public static class LibInfo implements Parcelable {
|
|
|
| @@ -432,7 +683,7 @@ public abstract class Linker {
|
| fd.writeToParcel(out, 0);
|
| fd.close();
|
| } catch (java.io.IOException e) {
|
| - Log.e(TAG, "Cant' write LibInfo file descriptor to parcel", e);
|
| + Log.e(TAG, "Can't write LibInfo file descriptor to parcel", e);
|
| }
|
| }
|
| }
|
| @@ -479,7 +730,7 @@ public abstract class Linker {
|
| @AccessedByNative
|
| public long mRelroSize; // page-aligned size in memory, or 0.
|
| @AccessedByNative
|
| - public int mRelroFd; // ashmem file descriptor, or -1
|
| + public int mRelroFd; // shared RELRO file descriptor, or -1
|
| }
|
|
|
| // Create a Bundle from a map of LibInfo objects.
|
| @@ -488,7 +739,6 @@ public abstract class Linker {
|
| for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
|
| bundle.putParcelable(entry.getKey(), entry.getValue());
|
| }
|
| -
|
| return bundle;
|
| }
|
|
|
| @@ -508,4 +758,15 @@ public abstract class Linker {
|
| entry.getValue().close();
|
| }
|
| }
|
| +
|
| + /**
|
| + * Return a random address that should be free to be mapped with the given size.
|
| + * Maps an area large enough for the largest library we might attempt to load,
|
| + * and if successful then unmaps it and returns the address of the area allocated
|
| + * by the system (with ASLR). The idea is that this area should remain free of
|
| + * other mappings until we map our library into it.
|
| + *
|
| + * @return address to pass to future mmap, or 0 on error.
|
| + */
|
| + private static native long nativeGetRandomBaseLoadAddress();
|
| }
|
|
|