Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3880)

Unified Diff: android/java/src/org/chromium/base/library_loader/Linker.java

Issue 2043183002: Update to Chromium //base at Chromium commit 01cb97b2e09618bbc3a60c7348f0a844eea20547. (Closed) Base URL: https://github.com/domokit/base.git@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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();
}

Powered by Google App Engine
This is Rietveld 408576698