1 // Copyright 2015 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 package org.chromium.base.library_loader; 6 7 import android.os.Build; 8 import android.os.Bundle; 9 import android.os.Parcel; 10 import android.os.ParcelFileDescriptor; 11 import android.os.Parcelable; 12 13 import org.chromium.base.ContextUtils; 14 import org.chromium.base.Log; 15 import org.chromium.base.annotations.AccessedByNative; 16 17 import java.util.HashMap; 18 import java.util.Locale; 19 import java.util.Map; 20 21 import javax.annotation.Nullable; 22 23 /* 24 * Technical note: 25 * 26 * The point of this class is to provide an alternative to System.loadLibrary() 27 * to load native shared libraries. One specific feature that it supports is the 28 * ability to save RAM by sharing the ELF RELRO sections between renderer 29 * processes. 30 * 31 * When two processes load the same native library at the _same_ memory address, 32 * the content of their RELRO section (which includes C++ vtables or any 33 * constants that contain pointers) will be largely identical [1]. 34 * 35 * By default, the RELRO section is backed by private RAM in each process, 36 * which is still significant on mobile (e.g. 1.28 MB / process on Chrome 30 for 37 * Android). 38 * 39 * However, it is possible to save RAM by creating a shared memory region, 40 * copy the RELRO content into it, then have each process swap its private, 41 * regular RELRO, with a shared, read-only, mapping of the shared one. 42 * 43 * This trick saves 98% of the RELRO section size per extra process, after the 44 * first one. On the other hand, this requires careful communication between 45 * the process where the shared RELRO is created and the one(s) where it is used. 46 * 47 * Note that swapping the regular RELRO with the shared one is not an atomic 48 * operation. Care must be taken that no other thread tries to run native code 49 * that accesses it during it. In practice, this means the swap must happen 50 * before library native code is executed. 51 * 52 * [1] The exceptions are pointers to external, randomized, symbols, like 53 * those from some system libraries, but these are very few in practice. 54 */ 55 56 /* 57 * Security considerations: 58 * 59 * - Whether the browser process loads its native libraries at the same 60 * addresses as the service ones (to save RAM by sharing the RELRO too) 61 * depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG. 62 * 63 * Not using fixed library addresses in the browser process is preferred 64 * for regular devices since it maintains the efficacy of ASLR as an 65 * exploit mitigation across the render <-> browser privilege boundary. 66 * 67 * - The shared RELRO memory region is always forced read-only after creation, 68 * which means it is impossible for a compromised service process to map 69 * it read-write (e.g. by calling mmap() or mprotect()) and modify its 70 * content, altering values seen in other service processes. 71 * 72 * - Once the RELRO ashmem region or file is mapped into a service process's 73 * address space, the corresponding file descriptor is immediately closed. The 74 * file descriptor is kept opened in the browser process, because a copy needs 75 * to be sent to each new potential service process. 76 * 77 * - The common library load addresses are randomized for each instance of 78 * the program on the device. See getRandomBaseLoadAddress() for more 79 * details on how this is obtained. 80 * 81 * - When loading several libraries in service processes, a simple incremental 82 * approach from the original random base load address is used. This is 83 * sufficient to deal correctly with component builds (which can use dozens 84 * of shared libraries), while regular builds always embed a single shared 85 * library per APK. 86 */ 87 88 /** 89 * Here's an explanation of how this class is supposed to be used: 90 * 91 * - Native shared libraries should be loaded with Linker.loadLibrary(), 92 * instead of System.loadLibrary(). The two functions should behave the same 93 * (at a high level). 94 * 95 * - Before loading any library, prepareLibraryLoad() should be called. 96 * 97 * - After loading all libraries, finishLibraryLoad() should be called, before 98 * running any native code from any of the libraries (except their static 99 * constructors, which can't be avoided). 100 * 101 * - A service process shall call either initServiceProcess() or 102 * disableSharedRelros() early (i.e. before any loadLibrary() call). 103 * Otherwise, the linker considers that it is running inside the browser 104 * process. This is because various Chromium projects have vastly 105 * different initialization paths. 106 * 107 * disableSharedRelros() completely disables shared RELROs, and loadLibrary() 108 * will behave exactly like System.loadLibrary(). 109 * 110 * initServiceProcess(baseLoadAddress) indicates that shared RELROs are to be 111 * used in this process. 112 * 113 * - The browser is in charge of deciding where in memory each library should 114 * be loaded. This address must be passed to each service process (see 115 * ChromiumLinkerParams.java in content for a helper class to do so). 116 * 117 * - The browser will also generate shared RELROs for each library it loads. 118 * More specifically, by default when in the browser process, the linker 119 * will: 120 * 121 * - Load libraries randomly (just like System.loadLibrary()). 122 * - Compute the fixed address to be used to load the same library 123 * in service processes. 124 * - Create a shared memory region populated with the RELRO region 125 * content pre-relocated for the specific fixed address above. 126 * 127 * Note that these shared RELRO regions cannot be used inside the browser 128 * process. They are also never mapped into it. 129 * 130 * This behaviour is altered by the BROWSER_SHARED_RELRO_CONFIG configuration 131 * variable below, which may force the browser to load the libraries at 132 * fixed addresses too. 133 * 134 * - Once all libraries are loaded in the browser process, one can call 135 * getSharedRelros() which returns a Bundle instance containing a map that 136 * links each loaded library to its shared RELRO region. 137 * 138 * This Bundle must be passed to each service process, for example through 139 * a Binder call (note that the Bundle includes file descriptors and cannot 140 * be added as an Intent extra). 141 * 142 * - In a service process, finishLibraryLoad() and/or loadLibrary() may 143 * block until the RELRO section Bundle is received. This is typically 144 * done by calling useSharedRelros() from another thread. 145 * 146 * This method also ensures the process uses the shared RELROs. 147 */ 148 public abstract class Linker { 149 // Log tag for this class. 150 private static final String TAG = "LibraryLoader"; 151 152 // Name of the library that contains our JNI code. 153 private static final String LINKER_JNI_LIBRARY = "chromium_android_linker"; 154 155 // Constants used to control the behaviour of the browser process with 156 // regards to the shared RELRO section. Not applicable to ModernLinker. 157 // NEVER -> The browser never uses it itself. 158 // LOW_RAM_ONLY -> It is only used on devices with low RAM. 159 // ALWAYS -> It is always used. 160 // NOTE: These names are known and expected by the Linker test scripts. 161 public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0; 162 public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1; 163 public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2; 164 165 // Configuration variable used to control how the browser process uses the 166 // shared RELRO. Only change this while debugging linker-related issues. 167 // Not used by ModernLinker. 168 // NOTE: This variable's name is known and expected by the Linker test scripts. 169 public static final int BROWSER_SHARED_RELRO_CONFIG = 170 BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY; 171 172 // Constants used to control the memory device config. Can be set explicitly 173 // by setMemoryDeviceConfigForTesting(). Not applicable to ModernLinker. 174 // INIT -> Value is undetermined (will check at runtime). 175 // LOW -> This is a low-memory device. 176 // NORMAL -> This is not a low-memory device. 177 public static final int MEMORY_DEVICE_CONFIG_INIT = 0; 178 public static final int MEMORY_DEVICE_CONFIG_LOW = 1; 179 public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2; 180 181 // Indicates if this is a low-memory device or not. The default is to 182 // determine this by probing the system at runtime, but this can be forced 183 // for testing by calling setMemoryDeviceConfigForTesting(). 184 // Not used by ModernLinker. 185 protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT; 186 187 // Set to true to enable debug logs. 188 protected static final boolean DEBUG = false; 189 190 // Used to pass the shared RELRO Bundle through Binder. 191 public static final String EXTRA_LINKER_SHARED_RELROS = 192 "org.chromium.base.android.linker.shared_relros"; 193 194 // Guards all access to the linker. 195 protected final Object mLock = new Object(); 196 197 // The name of a class that implements TestRunner. 198 private String mTestRunnerClassName = null; 199 200 // Size of reserved Breakpad guard region. Should match the value of 201 // kBreakpadGuardRegionBytes on the JNI side. Used when computing the load 202 // addresses of multiple loaded libraries. Set to 0 to disable the guard. 203 protected static final int BREAKPAD_GUARD_REGION_BYTES = 16 * 1024 * 1024; 204 205 // Size of the area requested when using ASLR to obtain a random load address. 206 // Should match the value of kAddressSpaceReservationSize on the JNI side. 207 // Used when computing the load addresses of multiple loaded libraries to 208 // ensure that we don't try to load outside the area originally requested. 209 protected static final int ADDRESS_SPACE_RESERVATION = 192 * 1024 * 1024; 210 211 // Constants used to indicate a given Linker implementation, for testing. 212 // LEGACY -> Always uses the LegacyLinker implementation. 213 // MODERN -> Always uses the ModernLinker implementation. 214 // NOTE: These names are known and expected by the Linker test scripts. 215 public static final int LINKER_IMPLEMENTATION_LEGACY = 1; 216 public static final int LINKER_IMPLEMENTATION_MODERN = 2; 217 218 // Singleton. 219 private static Linker sSingleton = null; 220 private static Object sSingletonLock = new Object(); 221 222 // Protected singleton constructor. Linker()223 protected Linker() { } 224 225 /** 226 * Get singleton instance. Returns either a LegacyLinker or a ModernLinker. 227 * 228 * Returns a ModernLinker if running on Android M or later, otherwise returns 229 * a LegacyLinker. 230 * 231 * ModernLinker requires OS features from Android M and later: a system linker 232 * that handles packed relocations and load from APK, and android_dlopen_ext() 233 * for shared RELRO support. It cannot run on Android releases earlier than M. 234 * 235 * LegacyLinker runs on all Android releases but it is slower and more complex 236 * than ModernLinker, so ModernLinker is preferred for Android M and later. 237 * 238 * @return the Linker implementation instance. 239 */ getInstance()240 public static final Linker getInstance() { 241 synchronized (sSingletonLock) { 242 if (sSingleton == null) { 243 // With incremental install, it's important to fall back to the "normal" 244 // library loading path in order for the libraries to be found. 245 String appClass = 246 ContextUtils.getApplicationContext().getApplicationInfo().className; 247 boolean isIncrementalInstall = 248 appClass != null && appClass.contains("incrementalinstall"); 249 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !isIncrementalInstall) { 250 sSingleton = ModernLinker.create(); 251 } else { 252 sSingleton = LegacyLinker.create(); 253 } 254 Log.i(TAG, "Using linker: " + sSingleton.getClass().getName()); 255 } 256 return sSingleton; 257 } 258 } 259 260 /** 261 * Check that native library linker tests are enabled. 262 * If not enabled, calls to testing functions will fail with an assertion 263 * error. 264 * 265 * @return true if native library linker tests are enabled. 266 */ areTestsEnabled()267 public static boolean areTestsEnabled() { 268 return NativeLibraries.sEnableLinkerTests; 269 } 270 271 /** 272 * Assert for testing. 273 * Hard assertion. Cannot be disabled. Used only by testing methods. 274 */ assertForTesting(boolean flag)275 private static void assertForTesting(boolean flag) { 276 if (!flag) { 277 throw new AssertionError(); 278 } 279 } 280 281 /** 282 * Assert NativeLibraries.sEnableLinkerTests is true. 283 * Hard assertion that we are in a testing context. Cannot be disabled. The 284 * test methods in this module permit injection of runnable code by class 285 * name. To protect against both malicious and accidental use of these 286 * methods, we ensure that NativeLibraries.sEnableLinkerTests is true when 287 * any is called. 288 */ assertLinkerTestsAreEnabled()289 private static void assertLinkerTestsAreEnabled() { 290 if (!NativeLibraries.sEnableLinkerTests) { 291 throw new AssertionError("Testing method called in non-testing context"); 292 } 293 } 294 295 /** 296 * Set Linker implementation type. 297 * For testing. Sets either a LegacyLinker or a ModernLinker. Must be called 298 * before getInstance(). 299 * 300 * @param type LINKER_IMPLEMENTATION_LEGACY or LINKER_IMPLEMENTATION_MODERN 301 */ setImplementationForTesting(int type)302 public static final void setImplementationForTesting(int type) { 303 // Sanity check. This method may only be called during tests. 304 assertLinkerTestsAreEnabled(); 305 assertForTesting(type == LINKER_IMPLEMENTATION_LEGACY 306 || type == LINKER_IMPLEMENTATION_MODERN); 307 308 synchronized (sSingletonLock) { 309 assertForTesting(sSingleton == null); 310 311 if (type == LINKER_IMPLEMENTATION_MODERN) { 312 sSingleton = ModernLinker.create(); 313 } else if (type == LINKER_IMPLEMENTATION_LEGACY) { 314 sSingleton = LegacyLinker.create(); 315 } 316 Log.i(TAG, "Forced linker: " + sSingleton.getClass().getName()); 317 } 318 } 319 320 /** 321 * Get Linker implementation type. 322 * For testing. 323 * 324 * @return LINKER_IMPLEMENTATION_LEGACY or LINKER_IMPLEMENTATION_MODERN 325 */ getImplementationForTesting()326 public final int getImplementationForTesting() { 327 // Sanity check. This method may only be called during tests. 328 assertLinkerTestsAreEnabled(); 329 330 synchronized (sSingletonLock) { 331 assertForTesting(sSingleton == this); 332 333 if (sSingleton instanceof ModernLinker) { 334 return LINKER_IMPLEMENTATION_MODERN; 335 } else if (sSingleton instanceof LegacyLinker) { 336 return LINKER_IMPLEMENTATION_LEGACY; 337 } else { 338 Log.wtf(TAG, "Invalid linker: " + sSingleton.getClass().getName()); 339 assertForTesting(false); 340 } 341 return 0; 342 } 343 } 344 345 /** 346 * A public interface used to run runtime linker tests after loading 347 * libraries. Should only be used to implement the linker unit tests, 348 * which is controlled by the value of NativeLibraries.sEnableLinkerTests 349 * configured at build time. 350 */ 351 public interface TestRunner { 352 /** 353 * Run runtime checks and return true if they all pass. 354 * 355 * @param memoryDeviceConfig The current memory device configuration. 356 * @param inBrowserProcess true iff this is the browser process. 357 * @return true if all checks pass. 358 */ runChecks(int memoryDeviceConfig, boolean inBrowserProcess)359 public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProcess); 360 } 361 362 /** 363 * Set the TestRunner by its class name. It will be instantiated at 364 * runtime after all libraries are loaded. 365 * 366 * @param testRunnerClassName null or a String for the class name of the 367 * TestRunner to use. 368 */ setTestRunnerClassNameForTesting(String testRunnerClassName)369 public final void setTestRunnerClassNameForTesting(String testRunnerClassName) { 370 if (DEBUG) { 371 Log.i(TAG, "setTestRunnerClassNameForTesting(" + testRunnerClassName + ") called"); 372 } 373 // Sanity check. This method may only be called during tests. 374 assertLinkerTestsAreEnabled(); 375 376 synchronized (mLock) { 377 assertForTesting(mTestRunnerClassName == null); 378 mTestRunnerClassName = testRunnerClassName; 379 } 380 } 381 382 /** 383 * Call this to retrieve the name of the current TestRunner class name 384 * if any. This can be useful to pass it from the browser process to 385 * child ones. 386 * 387 * @return null or a String holding the name of the class implementing 388 * the TestRunner set by calling setTestRunnerClassNameForTesting() previously. 389 */ getTestRunnerClassNameForTesting()390 public final String getTestRunnerClassNameForTesting() { 391 // Sanity check. This method may only be called during tests. 392 assertLinkerTestsAreEnabled(); 393 394 synchronized (mLock) { 395 return mTestRunnerClassName; 396 } 397 } 398 399 /** 400 * Set up the Linker for a test. 401 * Convenience function that calls setImplementationForTesting() to force an 402 * implementation, and then setTestRunnerClassNameForTesting() to set the test 403 * class name. 404 * 405 * On first call, instantiates a Linker of the requested type and sets its test 406 * runner class name. On subsequent calls, checks that the singleton produced by 407 * the first call matches the requested type and test runner class name. 408 */ setupForTesting(int type, String testRunnerClassName)409 public static final void setupForTesting(int type, String testRunnerClassName) { 410 if (DEBUG) { 411 Log.i(TAG, "setupForTesting(" + type + ", " + testRunnerClassName + ") called"); 412 } 413 // Sanity check. This method may only be called during tests. 414 assertLinkerTestsAreEnabled(); 415 416 synchronized (sSingletonLock) { 417 // If this is the first call, configure the Linker to the given type and test class. 418 if (sSingleton == null) { 419 setImplementationForTesting(type); 420 sSingleton.setTestRunnerClassNameForTesting(testRunnerClassName); 421 return; 422 } 423 424 // If not the first call, check that the Linker configuration matches this request. 425 assertForTesting(sSingleton.getImplementationForTesting() == type); 426 String ourTestRunnerClassName = sSingleton.getTestRunnerClassNameForTesting(); 427 if (testRunnerClassName == null) { 428 assertForTesting(ourTestRunnerClassName == null); 429 } else { 430 assertForTesting(ourTestRunnerClassName.equals(testRunnerClassName)); 431 } 432 } 433 } 434 435 /** 436 * Instantiate and run the current TestRunner, if any. The TestRunner implementation 437 * must be instantiated _after_ all libraries are loaded to ensure that its 438 * native methods are properly registered. 439 * 440 * @param memoryDeviceConfig LegacyLinker memory config, or 0 if unused 441 * @param inBrowserProcess true if in the browser process 442 */ runTestRunnerClassForTesting(int memoryDeviceConfig, boolean inBrowserProcess)443 protected final void runTestRunnerClassForTesting(int memoryDeviceConfig, 444 boolean inBrowserProcess) { 445 if (DEBUG) { 446 Log.i(TAG, "runTestRunnerClassForTesting called"); 447 } 448 // Sanity check. This method may only be called during tests. 449 assertLinkerTestsAreEnabled(); 450 451 synchronized (mLock) { 452 if (mTestRunnerClassName == null) { 453 Log.wtf(TAG, "Linker runtime tests not set up for this process"); 454 assertForTesting(false); 455 } 456 if (DEBUG) { 457 Log.i(TAG, "Instantiating " + mTestRunnerClassName); 458 } 459 TestRunner testRunner = null; 460 try { 461 testRunner = (TestRunner) Class.forName(mTestRunnerClassName).newInstance(); 462 } catch (Exception e) { 463 Log.wtf(TAG, "Could not instantiate test runner class by name", e); 464 assertForTesting(false); 465 } 466 467 if (!testRunner.runChecks(memoryDeviceConfig, inBrowserProcess)) { 468 Log.wtf(TAG, "Linker runtime tests failed in this process"); 469 assertForTesting(false); 470 } 471 472 Log.i(TAG, "All linker tests passed"); 473 } 474 } 475 476 /** 477 * Call this method before any other Linker method to force a specific 478 * memory device configuration. Should only be used for testing. 479 * 480 * @param memoryDeviceConfig MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL. 481 */ setMemoryDeviceConfigForTesting(int memoryDeviceConfig)482 public final void setMemoryDeviceConfigForTesting(int memoryDeviceConfig) { 483 if (DEBUG) { 484 Log.i(TAG, "setMemoryDeviceConfigForTesting(" + memoryDeviceConfig + ") called"); 485 } 486 // Sanity check. This method may only be called during tests. 487 assertLinkerTestsAreEnabled(); 488 assertForTesting(memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW 489 || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL); 490 491 synchronized (mLock) { 492 assertForTesting(mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT); 493 494 mMemoryDeviceConfig = memoryDeviceConfig; 495 if (DEBUG) { 496 if (mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) { 497 Log.i(TAG, "Simulating a low-memory device"); 498 } else { 499 Log.i(TAG, "Simulating a regular-memory device"); 500 } 501 } 502 } 503 } 504 505 /** 506 * Determine whether a library is the linker library. Also deal with the 507 * component build that adds a .cr suffix to the name. 508 * 509 * @param library the name of the library. 510 * @return true is the library is the Linker's own JNI library. 511 */ isChromiumLinkerLibrary(String library)512 public boolean isChromiumLinkerLibrary(String library) { 513 return library.equals(LINKER_JNI_LIBRARY) || library.equals(LINKER_JNI_LIBRARY + ".cr"); 514 } 515 516 /** 517 * Load the Linker JNI library. Throws UnsatisfiedLinkError on error. 518 * In a component build, the suffix ".cr" is added to each library name, so 519 * if the initial load fails we retry with a suffix. 520 */ loadLinkerJniLibrary()521 protected static void loadLinkerJniLibrary() { 522 String libName = "lib" + LINKER_JNI_LIBRARY + ".so"; 523 if (DEBUG) { 524 Log.i(TAG, "Loading " + libName); 525 } 526 try { 527 System.loadLibrary(LINKER_JNI_LIBRARY); 528 } catch (UnsatisfiedLinkError e) { 529 Log.w(TAG, "Couldn't load " + libName + ", trying " + libName + ".cr"); 530 System.loadLibrary(LINKER_JNI_LIBRARY + ".cr"); 531 } 532 } 533 534 /** 535 * Obtain a random base load address at which to place loaded libraries. 536 * 537 * @return new base load address 538 */ getRandomBaseLoadAddress()539 protected long getRandomBaseLoadAddress() { 540 // nativeGetRandomBaseLoadAddress() returns an address at which it has previously 541 // successfully mapped an area larger than the largest library we expect to load, 542 // on the basis that we will be able, with high probability, to map our library 543 // into it. 544 // 545 // One issue with this is that we do not yet know the size of the library that 546 // we will load is. If it is smaller than the size we used to obtain a random 547 // address the library mapping may still succeed. The other issue is that 548 // although highly unlikely, there is no guarantee that something else does not 549 // map into the area we are going to use between here and when we try to map into it. 550 // 551 // The above notes mean that all of this is probablistic. It is however okay to do 552 // because if, worst case and unlikely, we get unlucky in our choice of address, 553 // the back-out and retry without the shared RELRO in the ChildProcessService will 554 // keep things running. 555 final long address = nativeGetRandomBaseLoadAddress(); 556 if (DEBUG) { 557 Log.i(TAG, String.format(Locale.US, "Random native base load address: 0x%x", address)); 558 } 559 return address; 560 } 561 562 /** 563 * Load a native shared library with the Chromium linker. If the zip file 564 * is not null, the shared library must be uncompressed and page aligned 565 * inside the zipfile. Note the crazy linker treats libraries and files as 566 * equivalent, so you can only open one library in a given zip file. The 567 * library must not be the Chromium linker library. 568 * 569 * @param zipFilePath The path of the zip file containing the library (or null). 570 * @param libFilePath The path of the library (possibly in the zip file). 571 */ loadLibrary(@ullable String zipFilePath, String libFilePath)572 public void loadLibrary(@Nullable String zipFilePath, String libFilePath) { 573 if (DEBUG) { 574 Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath); 575 } 576 final boolean isFixedAddressPermitted = true; 577 loadLibraryImpl(zipFilePath, libFilePath, isFixedAddressPermitted); 578 } 579 580 /** 581 * Load a native shared library with the Chromium linker, ignoring any 582 * requested fixed address for RELRO sharing. If the zip file 583 * is not null, the shared library must be uncompressed and page aligned 584 * inside the zipfile. Note the crazy linker treats libraries and files as 585 * equivalent, so you can only open one library in a given zip file. The 586 * library must not be the Chromium linker library. 587 * 588 * @param zipFilePath The path of the zip file containing the library (or null). 589 * @param libFilePath The path of the library (possibly in the zip file). 590 */ loadLibraryNoFixedAddress(@ullable String zipFilePath, String libFilePath)591 public void loadLibraryNoFixedAddress(@Nullable String zipFilePath, String libFilePath) { 592 if (DEBUG) { 593 Log.i(TAG, "loadLibraryAtAnyAddress: " + zipFilePath + ", " + libFilePath); 594 } 595 final boolean isFixedAddressPermitted = false; 596 loadLibraryImpl(zipFilePath, libFilePath, isFixedAddressPermitted); 597 } 598 599 /** 600 * Call this method to determine if the chromium project must load the library 601 * directly from a zip file. 602 */ isInZipFile()603 public static boolean isInZipFile() { 604 // The auto-generated NativeLibraries.sUseLibraryInZipFile variable will be true 605 // if the library remains embedded in the APK zip file on the target. 606 return NativeLibraries.sUseLibraryInZipFile; 607 } 608 609 /** 610 * Call this method to determine if this chromium project must 611 * use this linker. If not, System.loadLibrary() should be used to load 612 * libraries instead. 613 */ isUsed()614 public static boolean isUsed() { 615 // The auto-generated NativeLibraries.sUseLinker variable will be true if the 616 // build has not explicitly disabled Linker features. 617 return NativeLibraries.sUseLinker; 618 } 619 620 /** 621 * Call this method to determine if the linker will try to use shared RELROs 622 * for the browser process. 623 */ isUsingBrowserSharedRelros()624 public abstract boolean isUsingBrowserSharedRelros(); 625 626 /** 627 * Call this method just before loading any native shared libraries in this process. 628 */ prepareLibraryLoad()629 public abstract void prepareLibraryLoad(); 630 631 /** 632 * Call this method just after loading all native shared libraries in this process. 633 */ finishLibraryLoad()634 public abstract void finishLibraryLoad(); 635 636 /** 637 * Call this to send a Bundle containing the shared RELRO sections to be 638 * used in this process. If initServiceProcess() was previously called, 639 * finishLibraryLoad() will not exit until this method is called in another 640 * thread with a non-null value. 641 * 642 * @param bundle The Bundle instance containing a map of shared RELRO sections 643 * to use in this process. 644 */ useSharedRelros(Bundle bundle)645 public abstract void useSharedRelros(Bundle bundle); 646 647 /** 648 * Call this to retrieve the shared RELRO sections created in this process, 649 * after loading all libraries. 650 * 651 * @return a new Bundle instance, or null if RELRO sharing is disabled on 652 * this system, or if initServiceProcess() was called previously. 653 */ getSharedRelros()654 public abstract Bundle getSharedRelros(); 655 656 657 /** 658 * Call this method before loading any libraries to indicate that this 659 * process shall neither create or reuse shared RELRO sections. 660 */ disableSharedRelros()661 public abstract void disableSharedRelros(); 662 663 /** 664 * Call this method before loading any libraries to indicate that this 665 * process is ready to reuse shared RELRO sections from another one. 666 * Typically used when starting service processes. 667 * 668 * @param baseLoadAddress the base library load address to use. 669 */ initServiceProcess(long baseLoadAddress)670 public abstract void initServiceProcess(long baseLoadAddress); 671 672 /** 673 * Retrieve the base load address of all shared RELRO sections. 674 * This also enforces the creation of shared RELRO sections in 675 * prepareLibraryLoad(), which can later be retrieved with getSharedRelros(). 676 * 677 * @return a common, random base load address, or 0 if RELRO sharing is 678 * disabled. 679 */ getBaseLoadAddress()680 public abstract long getBaseLoadAddress(); 681 682 /** 683 * Implements loading a native shared library with the Chromium linker. 684 * 685 * @param zipFilePath The path of the zip file containing the library (or null). 686 * @param libFilePath The path of the library (possibly in the zip file). 687 * @param isFixedAddressPermitted If true, uses a fixed load address if one was 688 * supplied, otherwise ignores the fixed address and loads wherever available. 689 */ loadLibraryImpl(@ullable String zipFilePath, String libFilePath, boolean isFixedAddressPermitted)690 abstract void loadLibraryImpl(@Nullable String zipFilePath, 691 String libFilePath, 692 boolean isFixedAddressPermitted); 693 694 /** 695 * Record information for a given library. 696 * IMPORTANT: Native code knows about this class's fields, so 697 * don't change them without modifying the corresponding C++ sources. 698 * Also, the LibInfo instance owns the shared RELRO file descriptor. 699 */ 700 public static class LibInfo implements Parcelable { 701 LibInfo()702 public LibInfo() { 703 mLoadAddress = 0; 704 mLoadSize = 0; 705 mRelroStart = 0; 706 mRelroSize = 0; 707 mRelroFd = -1; 708 } 709 close()710 public void close() { 711 if (mRelroFd >= 0) { 712 try { 713 ParcelFileDescriptor.adoptFd(mRelroFd).close(); 714 } catch (java.io.IOException e) { 715 if (DEBUG) { 716 Log.e(TAG, "Failed to close fd: " + mRelroFd); 717 } 718 } 719 mRelroFd = -1; 720 } 721 } 722 723 // from Parcelable LibInfo(Parcel in)724 public LibInfo(Parcel in) { 725 mLoadAddress = in.readLong(); 726 mLoadSize = in.readLong(); 727 mRelroStart = in.readLong(); 728 mRelroSize = in.readLong(); 729 ParcelFileDescriptor fd = ParcelFileDescriptor.CREATOR.createFromParcel(in); 730 // If CreateSharedRelro fails, the OS file descriptor will be -1 and |fd| will be null. 731 mRelroFd = (fd == null) ? -1 : fd.detachFd(); 732 } 733 734 // from Parcelable 735 @Override writeToParcel(Parcel out, int flags)736 public void writeToParcel(Parcel out, int flags) { 737 if (mRelroFd >= 0) { 738 out.writeLong(mLoadAddress); 739 out.writeLong(mLoadSize); 740 out.writeLong(mRelroStart); 741 out.writeLong(mRelroSize); 742 try { 743 ParcelFileDescriptor fd = ParcelFileDescriptor.fromFd(mRelroFd); 744 fd.writeToParcel(out, 0); 745 fd.close(); 746 } catch (java.io.IOException e) { 747 Log.e(TAG, "Can't write LibInfo file descriptor to parcel", e); 748 } 749 } 750 } 751 752 // from Parcelable 753 @Override describeContents()754 public int describeContents() { 755 return Parcelable.CONTENTS_FILE_DESCRIPTOR; 756 } 757 758 // from Parcelable 759 public static final Parcelable.Creator<LibInfo> CREATOR = 760 new Parcelable.Creator<LibInfo>() { 761 @Override 762 public LibInfo createFromParcel(Parcel in) { 763 return new LibInfo(in); 764 } 765 766 @Override 767 public LibInfo[] newArray(int size) { 768 return new LibInfo[size]; 769 } 770 }; 771 772 @Override toString()773 public String toString() { 774 return String.format(Locale.US, 775 "[load=0x%x-0x%x relro=0x%x-0x%x fd=%d]", 776 mLoadAddress, 777 mLoadAddress + mLoadSize, 778 mRelroStart, 779 mRelroStart + mRelroSize, 780 mRelroFd); 781 } 782 783 // IMPORTANT: Don't change these fields without modifying the 784 // native code that accesses them directly! 785 @AccessedByNative 786 public long mLoadAddress; // page-aligned library load address. 787 @AccessedByNative 788 public long mLoadSize; // page-aligned library load size. 789 @AccessedByNative 790 public long mRelroStart; // page-aligned address in memory, or 0 if none. 791 @AccessedByNative 792 public long mRelroSize; // page-aligned size in memory, or 0. 793 @AccessedByNative 794 public int mRelroFd; // shared RELRO file descriptor, or -1 795 } 796 797 // Create a Bundle from a map of LibInfo objects. createBundleFromLibInfoMap(HashMap<String, LibInfo> map)798 protected Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) { 799 Bundle bundle = new Bundle(map.size()); 800 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { 801 bundle.putParcelable(entry.getKey(), entry.getValue()); 802 } 803 return bundle; 804 } 805 806 // Create a new LibInfo map from a Bundle. createLibInfoMapFromBundle(Bundle bundle)807 protected HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) { 808 HashMap<String, LibInfo> map = new HashMap<String, LibInfo>(); 809 for (String library : bundle.keySet()) { 810 LibInfo libInfo = bundle.getParcelable(library); 811 map.put(library, libInfo); 812 } 813 return map; 814 } 815 816 // Call the close() method on all values of a LibInfo map. closeLibInfoMap(HashMap<String, LibInfo> map)817 protected void closeLibInfoMap(HashMap<String, LibInfo> map) { 818 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { 819 entry.getValue().close(); 820 } 821 } 822 823 /** 824 * Return a random address that should be free to be mapped with the given size. 825 * Maps an area large enough for the largest library we might attempt to load, 826 * and if successful then unmaps it and returns the address of the area allocated 827 * by the system (with ASLR). The idea is that this area should remain free of 828 * other mappings until we map our library into it. 829 * 830 * @return address to pass to future mmap, or 0 on error. 831 */ nativeGetRandomBaseLoadAddress()832 private static native long nativeGetRandomBaseLoadAddress(); 833 } 834