| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package org.chromium.base.library_loader; | 5 package org.chromium.base.library_loader; |
| 6 | 6 |
| 7 import android.os.Bundle; | 7 import android.os.Bundle; |
| 8 import android.os.Parcel; | 8 import android.os.Parcel; |
| 9 import android.os.ParcelFileDescriptor; | 9 import android.os.ParcelFileDescriptor; |
| 10 import android.os.Parcelable; | 10 import android.os.Parcelable; |
| 11 import android.util.Log; | |
| 12 | 11 |
| 13 import org.chromium.base.CalledByNative; | 12 import org.chromium.base.Log; |
| 14 import org.chromium.base.SysUtils; | |
| 15 import org.chromium.base.ThreadUtils; | |
| 16 import org.chromium.base.annotations.AccessedByNative; | 13 import org.chromium.base.annotations.AccessedByNative; |
| 17 | 14 |
| 18 import java.io.FileNotFoundException; | |
| 19 import java.util.HashMap; | 15 import java.util.HashMap; |
| 20 import java.util.Locale; | 16 import java.util.Locale; |
| 21 import java.util.Map; | 17 import java.util.Map; |
| 22 | 18 |
| 23 import javax.annotation.Nullable; | 19 import javax.annotation.Nullable; |
| 24 | 20 |
| 25 /* | 21 /* |
| 26 * Technical note: | 22 * Technical note: |
| 27 * | 23 * |
| 28 * The point of this class is to provide an alternative to System.loadLibrary() | 24 * The point of this class is to provide an alternative to System.loadLibrary() |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 * This Bundle must be passed to each service process, for example through | 142 * This Bundle must be passed to each service process, for example through |
| 147 * a Binder call (note that the Bundle includes file descriptors and cannot | 143 * a Binder call (note that the Bundle includes file descriptors and cannot |
| 148 * be added as an Intent extra). | 144 * be added as an Intent extra). |
| 149 * | 145 * |
| 150 * - In a service process, finishLibraryLoad() will block until the RELRO | 146 * - In a service process, finishLibraryLoad() will block until the RELRO |
| 151 * section Bundle is received. This is typically done by calling | 147 * section Bundle is received. This is typically done by calling |
| 152 * useSharedRelros() from another thread. | 148 * useSharedRelros() from another thread. |
| 153 * | 149 * |
| 154 * This method also ensures the process uses the shared RELROs. | 150 * This method also ensures the process uses the shared RELROs. |
| 155 */ | 151 */ |
| 156 public class Linker { | 152 public abstract class Linker { |
| 157 | 153 // Log tag for this class. |
| 158 // Log tag for this class. This must match the name of the linker's native l
ibrary. | 154 private static final String TAG = "cr.library_loader"; |
| 159 private static final String TAG = "chromium_android_linker"; | |
| 160 | 155 |
| 161 // Set to true to enable debug logs. | 156 // Set to true to enable debug logs. |
| 162 private static final boolean DEBUG = false; | 157 protected static final boolean DEBUG = false; |
| 158 |
| 159 // Used to pass the shared RELRO Bundle through Binder. |
| 160 public static final String EXTRA_LINKER_SHARED_RELROS = |
| 161 "org.chromium.base.android.linker.shared_relros"; |
| 162 |
| 163 // Guards all access to the linker. |
| 164 protected final Object mLock = new Object(); |
| 163 | 165 |
| 164 // Constants used to control the behaviour of the browser process with | 166 // Constants used to control the behaviour of the browser process with |
| 165 // regards to the shared RELRO section. | 167 // regards to the shared RELRO section. |
| 166 // NEVER -> The browser never uses it itself. | 168 // NEVER -> The browser never uses it itself. |
| 167 // LOW_RAM_ONLY -> It is only used on devices with low RAM. | 169 // LOW_RAM_ONLY -> It is only used on devices with low RAM. |
| 168 // ALWAYS -> It is always used. | 170 // ALWAYS -> It is always used. |
| 169 // NOTE: These names are known and expected by the Linker test scripts. | 171 // NOTE: These names are known and expected by the Linker test scripts. |
| 170 public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0; | 172 public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0; |
| 171 public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1; | 173 public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1; |
| 172 public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2; | 174 public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2; |
| 173 | 175 |
| 174 // Configuration variable used to control how the browser process uses the | 176 // Configuration variable used to control how the browser process uses the |
| 175 // shared RELRO. Only change this while debugging linker-related issues. | 177 // shared RELRO. Only change this while debugging linker-related issues. |
| 176 // NOTE: This variable's name is known and expected by the Linker test scrip
ts. | 178 // NOTE: This variable's name is known and expected by the Linker test scrip
ts. |
| 177 public static final int BROWSER_SHARED_RELRO_CONFIG = | 179 public static final int BROWSER_SHARED_RELRO_CONFIG = |
| 178 BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY; | 180 BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY; |
| 179 | 181 |
| 180 // Constants used to control the value of sMemoryDeviceConfig. | 182 // Constants used to control the value of sMemoryDeviceConfig. |
| 181 // INIT -> Value is undetermined (will check at runtime). | 183 // INIT -> Value is undetermined (will check at runtime). |
| 182 // LOW -> This is a low-memory device. | 184 // LOW -> This is a low-memory device. |
| 183 // NORMAL -> This is not a low-memory device. | 185 // NORMAL -> This is not a low-memory device. |
| 184 public static final int MEMORY_DEVICE_CONFIG_INIT = 0; | 186 public static final int MEMORY_DEVICE_CONFIG_INIT = 0; |
| 185 public static final int MEMORY_DEVICE_CONFIG_LOW = 1; | 187 public static final int MEMORY_DEVICE_CONFIG_LOW = 1; |
| 186 public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2; | 188 public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2; |
| 187 | 189 |
| 188 // Indicates if this is a low-memory device or not. The default is to | 190 // Indicates if this is a low-memory device or not. The default is to |
| 189 // determine this by probing the system at runtime, but this can be forced | 191 // determine this by probing the system at runtime, but this can be forced |
| 190 // for testing by calling setMemoryDeviceConfig(). | 192 // for testing by calling setMemoryDeviceConfig(). |
| 191 private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT; | 193 protected int mMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT; |
| 192 | 194 |
| 193 // Becomes true after linker initialization. | 195 // Singleton. |
| 194 private static boolean sInitialized = false; | 196 private static Linker sSingleton = null; |
| 197 private static Object sSingletonLock = new Object(); |
| 195 | 198 |
| 196 // Set to true to indicate that the system supports safe sharing of RELRO se
ctions. | 199 // Protected singleton constructor. |
| 197 private static boolean sRelroSharingSupported = false; | 200 protected Linker() {} |
| 198 | 201 |
| 199 // Set to true if this runs in the browser process. Disabled by initServiceP
rocess(). | 202 // Get singleton instance. |
| 200 // TODO(petrcermak): This flag can be incorrectly set to false (even though
this might run in | 203 public static final Linker getInstance() { |
| 201 // the browser process) on low-memory devices. | 204 synchronized (sSingletonLock) { |
| 202 private static boolean sInBrowserProcess = true; | 205 if (sSingleton == null) { |
| 203 | 206 // TODO(simonb): Extend later to return either a LegacyLinker |
| 204 // Becomes true to indicate this process needs to wait for a shared RELRO in | 207 // or a ModernLinker instance. |
| 205 // finishLibraryLoad(). | 208 sSingleton = new LegacyLinker(); |
| 206 private static boolean sWaitForSharedRelros = false; | |
| 207 | |
| 208 // Becomes true when initialization determines that the browser process can
use the | |
| 209 // shared RELRO. | |
| 210 private static boolean sBrowserUsesSharedRelro = false; | |
| 211 | |
| 212 // The map of all RELRO sections either created or used in this process. | |
| 213 private static Bundle sSharedRelros = null; | |
| 214 | |
| 215 // Current common random base load address. | |
| 216 private static long sBaseLoadAddress = 0; | |
| 217 | |
| 218 // Current fixed-location load address for the next library called by loadLi
brary(). | |
| 219 private static long sCurrentLoadAddress = 0; | |
| 220 | |
| 221 // Becomes true once prepareLibraryLoad() has been called. | |
| 222 private static boolean sPrepareLibraryLoadCalled = false; | |
| 223 | |
| 224 // Used internally to initialize the linker's static data. Assume lock is he
ld. | |
| 225 private static void ensureInitializedLocked() { | |
| 226 assert Thread.holdsLock(Linker.class); | |
| 227 | |
| 228 if (!sInitialized) { | |
| 229 sRelroSharingSupported = false; | |
| 230 if (NativeLibraries.sUseLinker) { | |
| 231 if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so"); | |
| 232 try { | |
| 233 System.loadLibrary(TAG); | |
| 234 } catch (UnsatisfiedLinkError e) { | |
| 235 // In a component build, the ".cr" suffix is added to each l
ibrary name. | |
| 236 Log.w(TAG, "Couldn't load lib" + TAG + ".so, trying lib" + T
AG + ".cr.so"); | |
| 237 System.loadLibrary(TAG + ".cr"); | |
| 238 } | |
| 239 sRelroSharingSupported = nativeCanUseSharedRelro(); | |
| 240 if (!sRelroSharingSupported) { | |
| 241 Log.w(TAG, "This system cannot safely share RELRO sections")
; | |
| 242 } else { | |
| 243 if (DEBUG) Log.i(TAG, "This system supports safe shared RELR
O sections"); | |
| 244 } | |
| 245 | |
| 246 if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) { | |
| 247 sMemoryDeviceConfig = SysUtils.isLowEndDevice() | |
| 248 ? MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NO
RMAL; | |
| 249 } | |
| 250 | |
| 251 switch (BROWSER_SHARED_RELRO_CONFIG) { | |
| 252 case BROWSER_SHARED_RELRO_CONFIG_NEVER: | |
| 253 sBrowserUsesSharedRelro = false; | |
| 254 break; | |
| 255 case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY: | |
| 256 sBrowserUsesSharedRelro = | |
| 257 (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
); | |
| 258 if (sBrowserUsesSharedRelro) { | |
| 259 Log.w(TAG, "Low-memory device: shared RELROs used in
all processes"); | |
| 260 } | |
| 261 break; | |
| 262 case BROWSER_SHARED_RELRO_CONFIG_ALWAYS: | |
| 263 Log.w(TAG, "Beware: shared RELROs used in all processes!
"); | |
| 264 sBrowserUsesSharedRelro = true; | |
| 265 break; | |
| 266 default: | |
| 267 assert false : "Unreached"; | |
| 268 break; | |
| 269 } | |
| 270 } else { | |
| 271 if (DEBUG) Log.i(TAG, "Linker disabled"); | |
| 272 } | 209 } |
| 273 | 210 return sSingleton; |
| 274 if (!sRelroSharingSupported) { | |
| 275 // Sanity. | |
| 276 sBrowserUsesSharedRelro = false; | |
| 277 sWaitForSharedRelros = false; | |
| 278 } | |
| 279 | |
| 280 sInitialized = true; | |
| 281 } | 211 } |
| 282 } | 212 } |
| 283 | 213 |
| 284 /** | 214 /** |
| 285 * A public interface used to run runtime linker tests after loading | 215 * A public interface used to run runtime linker tests after loading |
| 286 * libraries. Should only be used to implement the linker unit tests, | 216 * libraries. Should only be used to implement the linker unit tests, |
| 287 * which is controlled by the value of NativeLibraries.sEnableLinkerTests | 217 * which is controlled by the value of NativeLibraries.sEnableLinkerTests |
| 288 * configured at build time. | 218 * configured at build time. |
| 289 */ | 219 */ |
| 290 public interface TestRunner { | 220 public interface TestRunner { |
| 291 /** | 221 /** |
| 292 * Run runtime checks and return true if they all pass. | 222 * Run runtime checks and return true if they all pass. |
| 293 * @param memoryDeviceConfig The current memory device configuration. | 223 * @param memoryDeviceConfig The current memory device configuration. |
| 294 * @param inBrowserProcess true iff this is the browser process. | 224 * @param inBrowserProcess true iff this is the browser process. |
| 295 */ | 225 */ |
| 296 public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProces
s); | 226 public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProces
s); |
| 297 } | 227 } |
| 298 | 228 |
| 299 // The name of a class that implements TestRunner. | 229 // The name of a class that implements TestRunner. |
| 300 static String sTestRunnerClassName = null; | 230 String mTestRunnerClassName = null; |
| 301 | 231 |
| 302 /** | 232 /** |
| 303 * Set the TestRunner by its class name. It will be instantiated at | 233 * Set the TestRunner by its class name. It will be instantiated at |
| 304 * runtime after all libraries are loaded. | 234 * runtime after all libraries are loaded. |
| 305 * @param testRunnerClassName null or a String for the class name of the | 235 * @param testRunnerClassName null or a String for the class name of the |
| 306 * TestRunner to use. | 236 * TestRunner to use. |
| 307 */ | 237 */ |
| 308 public static void setTestRunnerClassName(String testRunnerClassName) { | 238 public void setTestRunnerClassName(String testRunnerClassName) { |
| 309 if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName
+ ") called"); | 239 if (DEBUG) { |
| 310 | 240 Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") ca
lled"); |
| 241 } |
| 311 if (!NativeLibraries.sEnableLinkerTests) { | 242 if (!NativeLibraries.sEnableLinkerTests) { |
| 312 // Ignore this in production code to prevent malvolent runtime injec
tion. | 243 // Ignore this in production code to prevent malevolent runtime inje
ction. |
| 313 return; | 244 return; |
| 314 } | 245 } |
| 315 | 246 |
| 316 synchronized (Linker.class) { | 247 synchronized (mLock) { |
| 317 assert sTestRunnerClassName == null; | 248 assert mTestRunnerClassName == null; |
| 318 sTestRunnerClassName = testRunnerClassName; | 249 mTestRunnerClassName = testRunnerClassName; |
| 319 } | 250 } |
| 320 } | 251 } |
| 321 | 252 |
| 322 /** | 253 /** |
| 323 * Call this to retrieve the name of the current TestRunner class name | 254 * Call this to retrieve the name of the current TestRunner class name |
| 324 * if any. This can be useful to pass it from the browser process to | 255 * if any. This can be useful to pass it from the browser process to |
| 325 * child ones. | 256 * child ones. |
| 326 * @return null or a String holding the name of the class implementing | 257 * @return null or a String holding the name of the class implementing |
| 327 * the TestRunner set by calling setTestRunnerClassName() previously. | 258 * the TestRunner set by calling setTestRunnerClassName() previously. |
| 328 */ | 259 */ |
| 329 public static String getTestRunnerClassName() { | 260 public String getTestRunnerClassName() { |
| 330 synchronized (Linker.class) { | 261 synchronized (mLock) { |
| 331 return sTestRunnerClassName; | 262 return mTestRunnerClassName; |
| 332 } | 263 } |
| 333 } | 264 } |
| 334 | 265 |
| 335 /** | 266 /** |
| 336 * Call this method before any other Linker method to force a specific | 267 * Call this method before any other Linker method to force a specific |
| 337 * memory device configuration. Should only be used for testing. | 268 * memory device configuration. Should only be used for testing. |
| 338 * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVIC
E_CONFIG_NORMAL. | 269 * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVIC
E_CONFIG_NORMAL. |
| 339 */ | 270 */ |
| 340 public static void setMemoryDeviceConfig(int memoryDeviceConfig) { | 271 public void setMemoryDeviceConfig(int memoryDeviceConfig) { |
| 341 if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ")
called"); | 272 if (DEBUG) { |
| 273 Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called
"); |
| 274 } |
| 342 // Sanity check. This method should only be called during tests. | 275 // Sanity check. This method should only be called during tests. |
| 343 assert NativeLibraries.sEnableLinkerTests; | 276 assert NativeLibraries.sEnableLinkerTests; |
| 344 synchronized (Linker.class) { | 277 synchronized (mLock) { |
| 345 assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT; | 278 assert mMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT; |
| 346 assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW | 279 assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW |
| 347 || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL; | 280 || memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL; |
| 348 if (DEBUG) { | 281 if (DEBUG) { |
| 349 if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) { | 282 if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) { |
| 350 Log.i(TAG, "Simulating a low-memory device"); | 283 Log.i(TAG, "Simulating a low-memory device"); |
| 351 } else { | 284 } else { |
| 352 Log.i(TAG, "Simulating a regular-memory device"); | 285 Log.i(TAG, "Simulating a regular-memory device"); |
| 353 } | 286 } |
| 354 } | 287 } |
| 355 sMemoryDeviceConfig = memoryDeviceConfig; | 288 mMemoryDeviceConfig = memoryDeviceConfig; |
| 356 } | 289 } |
| 357 } | 290 } |
| 358 | 291 |
| 359 /** | 292 /** |
| 360 * Call this method to determine if this chromium project must | 293 * Call this method to determine if this chromium project must |
| 361 * use this linker. If not, System.loadLibrary() should be used to load | 294 * use this linker. If not, System.loadLibrary() should be used to load |
| 362 * libraries instead. | 295 * libraries instead. |
| 363 */ | 296 */ |
| 364 public static boolean isUsed() { | 297 public abstract boolean isUsed(); |
| 365 // Only GYP targets that are APKs and have the 'use_chromium_linker' var
iable | |
| 366 // defined as 1 will use this linker. For all others (the default), the | |
| 367 // auto-generated NativeLibraries.sUseLinker variable will be false. | |
| 368 if (!NativeLibraries.sUseLinker) return false; | |
| 369 | |
| 370 synchronized (Linker.class) { | |
| 371 ensureInitializedLocked(); | |
| 372 // At the moment, there is also no point in using this linker if the | |
| 373 // system does not support RELRO sharing safely. | |
| 374 return sRelroSharingSupported; | |
| 375 } | |
| 376 } | |
| 377 | 298 |
| 378 /** | 299 /** |
| 379 * Call this method to determine if the linker will try to use shared RELROs | 300 * Call this method to determine if the linker will try to use shared RELROs |
| 380 * for the browser process. | 301 * for the browser process. |
| 381 */ | 302 */ |
| 382 public static boolean isUsingBrowserSharedRelros() { | 303 public abstract boolean isUsingBrowserSharedRelros(); |
| 383 synchronized (Linker.class) { | |
| 384 ensureInitializedLocked(); | |
| 385 return sBrowserUsesSharedRelro; | |
| 386 } | |
| 387 } | |
| 388 | 304 |
| 389 /** | 305 /** |
| 390 * Call this method to determine if the chromium project must load | 306 * Call this method to determine if the chromium project must load |
| 391 * the library directly from the zip file. | 307 * the library directly from the zip file. |
| 392 */ | 308 */ |
| 393 public static boolean isInZipFile() { | 309 public abstract boolean isInZipFile(); |
| 394 return NativeLibraries.sUseLibraryInZipFile; | |
| 395 } | |
| 396 | 310 |
| 397 /** | 311 /** |
| 398 * Call this method just before loading any native shared libraries in this
process. | 312 * Call this method just before loading any native shared libraries in this
process. |
| 399 */ | 313 */ |
| 400 public static void prepareLibraryLoad() { | 314 public abstract void prepareLibraryLoad(); |
| 401 if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called"); | |
| 402 synchronized (Linker.class) { | |
| 403 sPrepareLibraryLoadCalled = true; | |
| 404 | |
| 405 if (sInBrowserProcess) { | |
| 406 // Force generation of random base load address, as well | |
| 407 // as creation of shared RELRO sections in this process. | |
| 408 setupBaseLoadAddressLocked(); | |
| 409 } | |
| 410 } | |
| 411 } | |
| 412 | 315 |
| 413 /** | 316 /** |
| 414 * Call this method just after loading all native shared libraries in this p
rocess. | 317 * Call this method just after loading all native shared libraries in this p
rocess. |
| 415 * Note that when in a service process, this will block until the RELRO bund
le is | 318 * Note that when in a service process, this will block until the RELRO bund
le is |
| 416 * received, i.e. when another thread calls useSharedRelros(). | 319 * received, i.e. when another thread calls useSharedRelros(). |
| 417 */ | 320 */ |
| 418 public static void finishLibraryLoad() { | 321 public abstract void finishLibraryLoad(); |
| 419 if (DEBUG) Log.i(TAG, "finishLibraryLoad() called"); | |
| 420 synchronized (Linker.class) { | |
| 421 if (DEBUG) Log.i(TAG, String.format( | |
| 422 Locale.US, | |
| 423 "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSha
redRelros=%s", | |
| 424 sInBrowserProcess ? "true" : "false", | |
| 425 sBrowserUsesSharedRelro ? "true" : "false", | |
| 426 sWaitForSharedRelros ? "true" : "false")); | |
| 427 | |
| 428 if (sLoadedLibraries == null) { | |
| 429 if (DEBUG) Log.i(TAG, "No libraries loaded"); | |
| 430 } else { | |
| 431 if (sInBrowserProcess) { | |
| 432 // Create new Bundle containing RELRO section information | |
| 433 // for all loaded libraries. Make it available to getSharedR
elros(). | |
| 434 sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries)
; | |
| 435 if (DEBUG) { | |
| 436 Log.i(TAG, "Shared RELRO created"); | |
| 437 dumpBundle(sSharedRelros); | |
| 438 } | |
| 439 | |
| 440 if (sBrowserUsesSharedRelro) { | |
| 441 useSharedRelrosLocked(sSharedRelros); | |
| 442 } | |
| 443 } | |
| 444 | |
| 445 if (sWaitForSharedRelros) { | |
| 446 assert !sInBrowserProcess; | |
| 447 | |
| 448 // Wait until the shared relro bundle is received from useSh
aredRelros(). | |
| 449 while (sSharedRelros == null) { | |
| 450 try { | |
| 451 Linker.class.wait(); | |
| 452 } catch (InterruptedException ie) { | |
| 453 // no-op | |
| 454 } | |
| 455 } | |
| 456 useSharedRelrosLocked(sSharedRelros); | |
| 457 // Clear the Bundle to ensure its file descriptor references
can't be reused. | |
| 458 sSharedRelros.clear(); | |
| 459 sSharedRelros = null; | |
| 460 } | |
| 461 } | |
| 462 | |
| 463 if (NativeLibraries.sEnableLinkerTests && sTestRunnerClassName != nu
ll) { | |
| 464 // The TestRunner implementation must be instantiated _after_ | |
| 465 // all libraries are loaded to ensure that its native methods | |
| 466 // are properly registered. | |
| 467 if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName); | |
| 468 TestRunner testRunner = null; | |
| 469 try { | |
| 470 testRunner = (TestRunner) | |
| 471 Class.forName(sTestRunnerClassName).newInstance(); | |
| 472 } catch (Exception e) { | |
| 473 Log.e(TAG, "Could not extract test runner class name", e); | |
| 474 testRunner = null; | |
| 475 } | |
| 476 if (testRunner != null) { | |
| 477 if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserPro
cess)) { | |
| 478 Log.wtf(TAG, "Linker runtime tests failed in this proces
s!!"); | |
| 479 assert false; | |
| 480 } else { | |
| 481 Log.i(TAG, "All linker tests passed!"); | |
| 482 } | |
| 483 } | |
| 484 } | |
| 485 } | |
| 486 if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting"); | |
| 487 } | |
| 488 | 322 |
| 489 /** | 323 /** |
| 490 * Call this to send a Bundle containing the shared RELRO sections to be | 324 * Call this to send a Bundle containing the shared RELRO sections to be |
| 491 * used in this process. If initServiceProcess() was previously called, | 325 * used in this process. If initServiceProcess() was previously called, |
| 492 * finishLibraryLoad() will not exit until this method is called in another | 326 * finishLibraryLoad() will not exit until this method is called in another |
| 493 * thread with a non-null value. | 327 * thread with a non-null value. |
| 494 * @param bundle The Bundle instance containing a map of shared RELRO sectio
ns | 328 * @param bundle The Bundle instance containing a map of shared RELRO sectio
ns |
| 495 * to use in this process. | 329 * to use in this process. |
| 496 */ | 330 */ |
| 497 public static void useSharedRelros(Bundle bundle) { | 331 public abstract void useSharedRelros(Bundle bundle); |
| 498 // Ensure the bundle uses the application's class loader, not the framew
ork | |
| 499 // one which doesn't know anything about LibInfo. | |
| 500 // Also, hold a fresh copy of it so the caller can't recycle it. | |
| 501 Bundle clonedBundle = null; | |
| 502 if (bundle != null) { | |
| 503 bundle.setClassLoader(LibInfo.class.getClassLoader()); | |
| 504 clonedBundle = new Bundle(LibInfo.class.getClassLoader()); | |
| 505 Parcel parcel = Parcel.obtain(); | |
| 506 bundle.writeToParcel(parcel, 0); | |
| 507 parcel.setDataPosition(0); | |
| 508 clonedBundle.readFromParcel(parcel); | |
| 509 parcel.recycle(); | |
| 510 } | |
| 511 if (DEBUG) { | |
| 512 Log.i(TAG, "useSharedRelros() called with " + bundle | |
| 513 + ", cloned " + clonedBundle); | |
| 514 } | |
| 515 synchronized (Linker.class) { | |
| 516 // Note that in certain cases, this can be called before | |
| 517 // initServiceProcess() in service processes. | |
| 518 sSharedRelros = clonedBundle; | |
| 519 // Tell any listener blocked in finishLibraryLoad() about it. | |
| 520 Linker.class.notifyAll(); | |
| 521 } | |
| 522 } | |
| 523 | 332 |
| 524 /** | 333 /** |
| 525 * Call this to retrieve the shared RELRO sections created in this process, | 334 * Call this to retrieve the shared RELRO sections created in this process, |
| 526 * after loading all libraries. | 335 * after loading all libraries. |
| 527 * @return a new Bundle instance, or null if RELRO sharing is disabled on | 336 * @return a new Bundle instance, or null if RELRO sharing is disabled on |
| 528 * this system, or if initServiceProcess() was called previously. | 337 * this system, or if initServiceProcess() was called previously. |
| 529 */ | 338 */ |
| 530 public static Bundle getSharedRelros() { | 339 public abstract Bundle getSharedRelros(); |
| 531 if (DEBUG) Log.i(TAG, "getSharedRelros() called"); | |
| 532 synchronized (Linker.class) { | |
| 533 if (!sInBrowserProcess) { | |
| 534 if (DEBUG) Log.i(TAG, "... returning null Bundle"); | |
| 535 return null; | |
| 536 } | |
| 537 | |
| 538 // Return the Bundle created in finishLibraryLoad(). | |
| 539 if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros); | |
| 540 return sSharedRelros; | |
| 541 } | |
| 542 } | |
| 543 | |
| 544 | 340 |
| 545 /** | 341 /** |
| 546 * Call this method before loading any libraries to indicate that this | 342 * Call this method before loading any libraries to indicate that this |
| 547 * process shall neither create or reuse shared RELRO sections. | 343 * process shall neither create or reuse shared RELRO sections. |
| 548 */ | 344 */ |
| 549 public static void disableSharedRelros() { | 345 public abstract void disableSharedRelros(); |
| 550 if (DEBUG) Log.i(TAG, "disableSharedRelros() called"); | |
| 551 synchronized (Linker.class) { | |
| 552 sInBrowserProcess = false; | |
| 553 sWaitForSharedRelros = false; | |
| 554 sBrowserUsesSharedRelro = false; | |
| 555 } | |
| 556 } | |
| 557 | 346 |
| 558 /** | 347 /** |
| 559 * Call this method before loading any libraries to indicate that this | 348 * Call this method before loading any libraries to indicate that this |
| 560 * process is ready to reuse shared RELRO sections from another one. | 349 * process is ready to reuse shared RELRO sections from another one. |
| 561 * Typically used when starting service processes. | 350 * Typically used when starting service processes. |
| 562 * @param baseLoadAddress the base library load address to use. | 351 * @param baseLoadAddress the base library load address to use. |
| 563 */ | 352 */ |
| 564 public static void initServiceProcess(long baseLoadAddress) { | 353 public abstract void initServiceProcess(long baseLoadAddress); |
| 565 if (DEBUG) { | |
| 566 Log.i(TAG, String.format( | |
| 567 Locale.US, "initServiceProcess(0x%x) called", baseLoadAddres
s)); | |
| 568 } | |
| 569 synchronized (Linker.class) { | |
| 570 ensureInitializedLocked(); | |
| 571 sInBrowserProcess = false; | |
| 572 sBrowserUsesSharedRelro = false; | |
| 573 if (sRelroSharingSupported) { | |
| 574 sWaitForSharedRelros = true; | |
| 575 sBaseLoadAddress = baseLoadAddress; | |
| 576 sCurrentLoadAddress = baseLoadAddress; | |
| 577 } | |
| 578 } | |
| 579 } | |
| 580 | 354 |
| 581 /** | 355 /** |
| 582 * Retrieve the base load address of all shared RELRO sections. | 356 * Retrieve the base load address of all shared RELRO sections. |
| 583 * This also enforces the creation of shared RELRO sections in | 357 * This also enforces the creation of shared RELRO sections in |
| 584 * prepareLibraryLoad(), which can later be retrieved with getSharedRelros()
. | 358 * prepareLibraryLoad(), which can later be retrieved with getSharedRelros()
. |
| 585 * @return a common, random base load address, or 0 if RELRO sharing is | 359 * @return a common, random base load address, or 0 if RELRO sharing is |
| 586 * disabled. | 360 * disabled. |
| 587 */ | 361 */ |
| 588 public static long getBaseLoadAddress() { | 362 public abstract long getBaseLoadAddress(); |
| 589 synchronized (Linker.class) { | |
| 590 ensureInitializedLocked(); | |
| 591 if (!sInBrowserProcess) { | |
| 592 Log.w(TAG, "Shared RELRO sections are disabled in this process!"
); | |
| 593 return 0; | |
| 594 } | |
| 595 | |
| 596 setupBaseLoadAddressLocked(); | |
| 597 if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress()
returns 0x%x", | |
| 598 sBaseLoadAddress)); | |
| 599 return sBaseLoadAddress; | |
| 600 } | |
| 601 } | |
| 602 | |
| 603 // Used internally to lazily setup the common random base load address. | |
| 604 private static void setupBaseLoadAddressLocked() { | |
| 605 assert Thread.holdsLock(Linker.class); | |
| 606 if (sBaseLoadAddress == 0) { | |
| 607 long address = computeRandomBaseLoadAddress(); | |
| 608 sBaseLoadAddress = address; | |
| 609 sCurrentLoadAddress = address; | |
| 610 if (address == 0) { | |
| 611 // If the computed address is 0, there are issues with finding e
nough | |
| 612 // free address space, so disable RELRO shared / fixed load addr
esses. | |
| 613 Log.w(TAG, "Disabling shared RELROs due address space pressure")
; | |
| 614 sBrowserUsesSharedRelro = false; | |
| 615 sWaitForSharedRelros = false; | |
| 616 } | |
| 617 } | |
| 618 } | |
| 619 | |
| 620 | |
| 621 /** | |
| 622 * Compute a random base load address at which to place loaded libraries. | |
| 623 * @return new base load address, or 0 if the system does not support | |
| 624 * RELRO sharing. | |
| 625 */ | |
| 626 private static long computeRandomBaseLoadAddress() { | |
| 627 // nativeGetRandomBaseLoadAddress() returns an address at which it has p
reviously | |
| 628 // successfully mapped an area of the given size, on the basis that we w
ill be | |
| 629 // able, with high probability, to map our library into it. | |
| 630 // | |
| 631 // One issue with this is that we do not yet know the size of the librar
y that | |
| 632 // we will load is. So here we pass a value that we expect will always b
e larger | |
| 633 // than that needed. If it is smaller the library mapping may still succ
eed. The | |
| 634 // other issue is that although highly unlikely, there is no guarantee t
hat | |
| 635 // something else does not map into the area we are going to use between
here and | |
| 636 // when we try to map into it. | |
| 637 // | |
| 638 // The above notes mean that all of this is probablistic. It is however
okay to do | |
| 639 // because if, worst case and unlikely, we get unlucky in our choice of
address, | |
| 640 // the back-out and retry without the shared RELRO in the ChildProcessSe
rvice will | |
| 641 // keep things running. | |
| 642 final long maxExpectedBytes = 192 * 1024 * 1024; | |
| 643 final long address = nativeGetRandomBaseLoadAddress(maxExpectedBytes); | |
| 644 if (DEBUG) { | |
| 645 Log.i(TAG, String.format(Locale.US, "Random native base load address
: 0x%x", address)); | |
| 646 } | |
| 647 return address; | |
| 648 } | |
| 649 | |
| 650 // Used for debugging only. | |
| 651 private static void dumpBundle(Bundle bundle) { | |
| 652 if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundl
e); | |
| 653 } | |
| 654 | |
| 655 /** | |
| 656 * Use the shared RELRO section from a Bundle received form another process. | |
| 657 * Call this after calling setBaseLoadAddress() then loading all libraries | |
| 658 * with loadLibrary(). | |
| 659 * @param bundle Bundle instance generated with createSharedRelroBundle() in | |
| 660 * another process. | |
| 661 */ | |
| 662 private static void useSharedRelrosLocked(Bundle bundle) { | |
| 663 assert Thread.holdsLock(Linker.class); | |
| 664 | |
| 665 if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called"); | |
| 666 | |
| 667 if (bundle == null) { | |
| 668 if (DEBUG) Log.i(TAG, "null bundle!"); | |
| 669 return; | |
| 670 } | |
| 671 | |
| 672 if (!sRelroSharingSupported) { | |
| 673 if (DEBUG) Log.i(TAG, "System does not support RELRO sharing"); | |
| 674 return; | |
| 675 } | |
| 676 | |
| 677 if (sLoadedLibraries == null) { | |
| 678 if (DEBUG) Log.i(TAG, "No libraries loaded!"); | |
| 679 return; | |
| 680 } | |
| 681 | |
| 682 if (DEBUG) dumpBundle(bundle); | |
| 683 HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle); | |
| 684 | |
| 685 // Apply the RELRO section to all libraries that were already loaded. | |
| 686 for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) { | |
| 687 String libName = entry.getKey(); | |
| 688 LibInfo libInfo = entry.getValue(); | |
| 689 if (!nativeUseSharedRelro(libName, libInfo)) { | |
| 690 Log.w(TAG, "Could not use shared RELRO section for " + libName); | |
| 691 } else { | |
| 692 if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libNam
e); | |
| 693 } | |
| 694 } | |
| 695 | |
| 696 // In service processes, close all file descriptors from the map now. | |
| 697 if (!sInBrowserProcess) closeLibInfoMap(relroMap); | |
| 698 | |
| 699 if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting"); | |
| 700 } | |
| 701 | 363 |
| 702 /** | 364 /** |
| 703 * Load a native shared library with the Chromium linker. If the zip file | 365 * Load a native shared library with the Chromium linker. If the zip file |
| 704 * is not null, the shared library must be uncompressed and page aligned | 366 * is not null, the shared library must be uncompressed and page aligned |
| 705 * inside the zipfile. Note the crazy linker treats libraries and files as | 367 * inside the zipfile. Note the crazy linker treats libraries and files as |
| 706 * equivalent, so you can only open one library in a given zip file. The | 368 * equivalent, so you can only open one library in a given zip file. The |
| 707 * library must not be the Chromium linker library. | 369 * library must not be the Chromium linker library. |
| 708 * | 370 * |
| 709 * @param zipFilePath The path of the zip file containing the library (or nu
ll). | 371 * @param zipFilePath The path of the zip file containing the library (or nu
ll). |
| 710 * @param libFilePath The path of the library (possibly in the zip file). | 372 * @param libFilePath The path of the library (possibly in the zip file). |
| 711 */ | 373 */ |
| 712 public static void loadLibrary(@Nullable String zipFilePath, String libFileP
ath) { | 374 public abstract void loadLibrary(@Nullable String zipFilePath, String libFil
ePath); |
| 713 if (DEBUG) Log.i(TAG, "loadLibrary: " + zipFilePath + ", " + libFilePath
); | |
| 714 | |
| 715 synchronized (Linker.class) { | |
| 716 ensureInitializedLocked(); | |
| 717 | |
| 718 // Security: Ensure prepareLibraryLoad() was called before. | |
| 719 // In theory, this can be done lazily here, but it's more consistent | |
| 720 // to use a pair of functions (i.e. prepareLibraryLoad() + finishLib
raryLoad()) | |
| 721 // that wrap all calls to loadLibrary() in the library loader. | |
| 722 assert sPrepareLibraryLoadCalled; | |
| 723 | |
| 724 if (sLoadedLibraries == null) sLoadedLibraries = new HashMap<String,
LibInfo>(); | |
| 725 | |
| 726 if (sLoadedLibraries.containsKey(libFilePath)) { | |
| 727 if (DEBUG) Log.i(TAG, "Not loading " + libFilePath + " twice"); | |
| 728 return; | |
| 729 } | |
| 730 | |
| 731 LibInfo libInfo = new LibInfo(); | |
| 732 long loadAddress = 0; | |
| 733 if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForShared
Relros) { | |
| 734 // Load the library at a fixed address. | |
| 735 loadAddress = sCurrentLoadAddress; | |
| 736 } | |
| 737 | |
| 738 String sharedRelRoName = libFilePath; | |
| 739 if (zipFilePath != null) { | |
| 740 if (!nativeLoadLibraryInZipFile(zipFilePath, libFilePath, loadAd
dress, libInfo)) { | |
| 741 String errorMessage = "Unable to load library: " + libFilePa
th | |
| 742 + ", in: " + zipFilePath; | |
| 743 Log.e(TAG, errorMessage); | |
| 744 throw new UnsatisfiedLinkError(errorMessage); | |
| 745 } | |
| 746 sharedRelRoName = zipFilePath; | |
| 747 } else { | |
| 748 if (!nativeLoadLibrary(libFilePath, loadAddress, libInfo)) { | |
| 749 String errorMessage = "Unable to load library: " + libFilePa
th; | |
| 750 Log.e(TAG, errorMessage); | |
| 751 throw new UnsatisfiedLinkError(errorMessage); | |
| 752 } | |
| 753 } | |
| 754 | |
| 755 // Print the load address to the logcat when testing the linker. The
format | |
| 756 // of the string is expected by the Python test_runner script as one
of: | |
| 757 // BROWSER_LIBRARY_ADDRESS: <library-name> <address> | |
| 758 // RENDERER_LIBRARY_ADDRESS: <library-name> <address> | |
| 759 // Where <library-name> is the library name, and <address> is the he
xadecimal load | |
| 760 // address. | |
| 761 if (NativeLibraries.sEnableLinkerTests) { | |
| 762 Log.i(TAG, String.format( | |
| 763 Locale.US, | |
| 764 "%s_LIBRARY_ADDRESS: %s %x", | |
| 765 sInBrowserProcess ? "BROWSER" : "RENDERER", | |
| 766 libFilePath, | |
| 767 libInfo.mLoadAddress)); | |
| 768 } | |
| 769 | |
| 770 if (sInBrowserProcess) { | |
| 771 // Create a new shared RELRO section at the 'current' fixed load
address. | |
| 772 if (!nativeCreateSharedRelro(sharedRelRoName, sCurrentLoadAddres
s, libInfo)) { | |
| 773 Log.w(TAG, String.format(Locale.US, | |
| 774 "Could not create shared RELRO for %s at %x", libFil
ePath, | |
| 775 sCurrentLoadAddress)); | |
| 776 } else { | |
| 777 if (DEBUG) Log.i(TAG, | |
| 778 String.format( | |
| 779 Locale.US, | |
| 780 "Created shared RELRO for %s at %x: %s", | |
| 781 sharedRelRoName, | |
| 782 sCurrentLoadAddress, | |
| 783 libInfo.toString())); | |
| 784 } | |
| 785 } | |
| 786 | |
| 787 if (sCurrentLoadAddress != 0) { | |
| 788 // Compute the next current load address. If sBaseLoadAddress | |
| 789 // is not 0, this is an explicit library load address. Otherwise
, | |
| 790 // this is an explicit load address for relocated RELRO sections | |
| 791 // only. | |
| 792 sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize; | |
| 793 } | |
| 794 | |
| 795 sLoadedLibraries.put(sharedRelRoName, libInfo); | |
| 796 if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString()); | |
| 797 } | |
| 798 } | |
| 799 | 375 |
| 800 /** | 376 /** |
| 801 * Determine whether a library is the linker library. Also deal with the | 377 * Determine whether a library is the linker library. Also deal with the |
| 802 * component build that adds a .cr suffix to the name. | 378 * component build that adds a .cr suffix to the name. |
| 803 */ | 379 */ |
| 804 public static boolean isChromiumLinkerLibrary(String library) { | 380 public abstract boolean isChromiumLinkerLibrary(String library); |
| 805 return library.equals(TAG) || library.equals(TAG + ".cr"); | |
| 806 } | |
| 807 | |
| 808 /** | |
| 809 * Get the full library path in zip file (lib/<abi>/crazy.<lib_name>). | |
| 810 * | |
| 811 * @param library The library's base name. | |
| 812 * @return the library path. | |
| 813 */ | |
| 814 public static String getLibraryFilePathInZipFile(String library) throws File
NotFoundException { | |
| 815 synchronized (Linker.class) { | |
| 816 ensureInitializedLocked(); | |
| 817 | |
| 818 String path = nativeGetLibraryFilePathInZipFile(library); | |
| 819 if (path.equals("")) { | |
| 820 throw new FileNotFoundException( | |
| 821 "Failed to retrieve path in zip file for library " + lib
rary); | |
| 822 } | |
| 823 return path; | |
| 824 } | |
| 825 } | |
| 826 | |
| 827 /** | |
| 828 * Check whether a library is page aligned and uncompressed in the APK file. | |
| 829 * | |
| 830 * @param apkFile Filename of the APK. | |
| 831 * @param library The library's base name. | |
| 832 * @return true if page aligned and uncompressed. | |
| 833 */ | |
| 834 public static boolean checkLibraryIsMappableInApk(String apkFile, String lib
rary) { | |
| 835 synchronized (Linker.class) { | |
| 836 ensureInitializedLocked(); | |
| 837 | |
| 838 if (DEBUG) Log.i(TAG, "checkLibraryIsMappableInApk: " + apkFile + ",
" + library); | |
| 839 boolean aligned = nativeCheckLibraryIsMappableInApk(apkFile, library
); | |
| 840 if (DEBUG) Log.i(TAG, library + " is " + (aligned ? "" : "NOT ") | |
| 841 + "page aligned in " + apkFile); | |
| 842 return aligned; | |
| 843 } | |
| 844 } | |
| 845 | |
| 846 /** | |
| 847 * Move activity from the native thread to the main UI thread. | |
| 848 * Called from native code on its own thread. Posts a callback from | |
| 849 * the UI thread back to native code. | |
| 850 * | |
| 851 * @param opaque Opaque argument. | |
| 852 */ | |
| 853 @CalledByNative | |
| 854 public static void postCallbackOnMainThread(final long opaque) { | |
| 855 ThreadUtils.postOnUiThread(new Runnable() { | |
| 856 @Override | |
| 857 public void run() { | |
| 858 nativeRunCallbackOnUiThread(opaque); | |
| 859 } | |
| 860 }); | |
| 861 } | |
| 862 | |
| 863 /** | |
| 864 * Native method to run callbacks on the main UI thread. | |
| 865 * Supplied by the crazy linker and called by postCallbackOnMainThread. | |
| 866 * @param opaque Opaque crazy linker arguments. | |
| 867 */ | |
| 868 private static native void nativeRunCallbackOnUiThread(long opaque); | |
| 869 | |
| 870 /** | |
| 871 * Native method used to load a library. | |
| 872 * @param library Platform specific library name (e.g. libfoo.so) | |
| 873 * @param loadAddress Explicit load address, or 0 for randomized one. | |
| 874 * @param libInfo If not null, the mLoadAddress and mLoadSize fields | |
| 875 * of this LibInfo instance will set on success. | |
| 876 * @return true for success, false otherwise. | |
| 877 */ | |
| 878 private static native boolean nativeLoadLibrary(String library, | |
| 879 long loadAddress, | |
| 880 LibInfo libInfo); | |
| 881 | |
| 882 /** | |
| 883 * Native method used to load a library which is inside a zipfile. | |
| 884 * @param zipfileName Filename of the zip file containing the library. | |
| 885 * @param library Platform specific library name (e.g. libfoo.so) | |
| 886 * @param loadAddress Explicit load address, or 0 for randomized one. | |
| 887 * @param libInfo If not null, the mLoadAddress and mLoadSize fields | |
| 888 * of this LibInfo instance will set on success. | |
| 889 * @return true for success, false otherwise. | |
| 890 */ | |
| 891 private static native boolean nativeLoadLibraryInZipFile(String zipfileName, | |
| 892 String libraryName, | |
| 893 long loadAddress, | |
| 894 LibInfo libInfo); | |
| 895 | |
| 896 /** | |
| 897 * Native method used to create a shared RELRO section. | |
| 898 * If the library was already loaded at the same address using | |
| 899 * nativeLoadLibrary(), this creates the RELRO for it. Otherwise, | |
| 900 * this loads a new temporary library at the specified address, | |
| 901 * creates and extracts the RELRO section from it, then unloads it. | |
| 902 * @param library Library name. | |
| 903 * @param loadAddress load address, which can be different from the one | |
| 904 * used to load the library in the current process! | |
| 905 * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize | |
| 906 * and mRelroFd will be set. | |
| 907 * @return true on success, false otherwise. | |
| 908 */ | |
| 909 private static native boolean nativeCreateSharedRelro(String library, | |
| 910 long loadAddress, | |
| 911 LibInfo libInfo); | |
| 912 | |
| 913 /** | |
| 914 * Native method used to use a shared RELRO section. | |
| 915 * @param library Library name. | |
| 916 * @param libInfo A LibInfo instance containing valid RELRO information | |
| 917 * @return true on success. | |
| 918 */ | |
| 919 private static native boolean nativeUseSharedRelro(String library, | |
| 920 LibInfo libInfo); | |
| 921 | |
| 922 /** | |
| 923 * Checks that the system supports shared RELROs. Old Android kernels | |
| 924 * have a bug in the way they check Ashmem region protection flags, which | |
| 925 * makes using shared RELROs unsafe. This method performs a simple runtime | |
| 926 * check for this misfeature, even though nativeEnableSharedRelro() will | |
| 927 * always fail if this returns false. | |
| 928 */ | |
| 929 private static native boolean nativeCanUseSharedRelro(); | |
| 930 | |
| 931 /** | |
| 932 * Return a random address that should be free to be mapped with the given s
ize. | |
| 933 * Maps an area of size bytes, and if successful then unmaps it and returns | |
| 934 * the address of the area allocated by the system (with ASLR). The idea is | |
| 935 * that this area should remain free of other mappings until we map our libr
ary | |
| 936 * into it. | |
| 937 * @param sizeBytes Size of area in bytes to search for. | |
| 938 * @return address to pass to future mmap, or 0 on error. | |
| 939 */ | |
| 940 private static native long nativeGetRandomBaseLoadAddress(long sizeBytes); | |
| 941 | |
| 942 /** | |
| 943 * Native method used to get the full library path in zip file | |
| 944 * (lib/<abi>/crazy.<lib_name>). | |
| 945 * | |
| 946 * @param library The library's base name. | |
| 947 * @return the library path (or empty string on failure). | |
| 948 */ | |
| 949 private static native String nativeGetLibraryFilePathInZipFile(String librar
y); | |
| 950 | |
| 951 /** | |
| 952 * Native method which checks whether a library is page aligned and | |
| 953 * uncompressed in the APK file. | |
| 954 * | |
| 955 * @param apkFile Filename of the APK. | |
| 956 * @param library The library's base name. | |
| 957 * @return true if page aligned and uncompressed. | |
| 958 */ | |
| 959 private static native boolean nativeCheckLibraryIsMappableInApk(String apkFi
le, String library); | |
| 960 | 381 |
| 961 /** | 382 /** |
| 962 * Record information for a given library. | 383 * Record information for a given library. |
| 963 * IMPORTANT: Native code knows about this class's fields, so | 384 * IMPORTANT: Native code knows about this class's fields, so |
| 964 * don't change them without modifying the corresponding C++ sources. | 385 * don't change them without modifying the corresponding C++ sources. |
| 965 * Also, the LibInfo instance owns the ashmem file descriptor. | 386 * Also, the LibInfo instance owns the ashmem file descriptor. |
| 966 */ | 387 */ |
| 967 public static class LibInfo implements Parcelable { | 388 public static class LibInfo implements Parcelable { |
| 968 | 389 |
| 969 public LibInfo() { | 390 public LibInfo() { |
| 970 mLoadAddress = 0; | 391 mLoadAddress = 0; |
| 971 mLoadSize = 0; | 392 mLoadSize = 0; |
| 972 mRelroStart = 0; | 393 mRelroStart = 0; |
| 973 mRelroSize = 0; | 394 mRelroSize = 0; |
| 974 mRelroFd = -1; | 395 mRelroFd = -1; |
| 975 } | 396 } |
| 976 | 397 |
| 977 public void close() { | 398 public void close() { |
| 978 if (mRelroFd >= 0) { | 399 if (mRelroFd >= 0) { |
| 979 try { | 400 try { |
| 980 ParcelFileDescriptor.adoptFd(mRelroFd).close(); | 401 ParcelFileDescriptor.adoptFd(mRelroFd).close(); |
| 981 } catch (java.io.IOException e) { | 402 } catch (java.io.IOException e) { |
| 982 if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd); | 403 if (DEBUG) { |
| 404 Log.e(TAG, "Failed to close fd: " + mRelroFd); |
| 405 } |
| 983 } | 406 } |
| 984 mRelroFd = -1; | 407 mRelroFd = -1; |
| 985 } | 408 } |
| 986 } | 409 } |
| 987 | 410 |
| 988 // from Parcelable | 411 // from Parcelable |
| 989 public LibInfo(Parcel in) { | 412 public LibInfo(Parcel in) { |
| 990 mLoadAddress = in.readLong(); | 413 mLoadAddress = in.readLong(); |
| 991 mLoadSize = in.readLong(); | 414 mLoadSize = in.readLong(); |
| 992 mRelroStart = in.readLong(); | 415 mRelroStart = in.readLong(); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1053 public long mLoadSize; // page-aligned library load size. | 476 public long mLoadSize; // page-aligned library load size. |
| 1054 @AccessedByNative | 477 @AccessedByNative |
| 1055 public long mRelroStart; // page-aligned address in memory, or 0 if non
e. | 478 public long mRelroStart; // page-aligned address in memory, or 0 if non
e. |
| 1056 @AccessedByNative | 479 @AccessedByNative |
| 1057 public long mRelroSize; // page-aligned size in memory, or 0. | 480 public long mRelroSize; // page-aligned size in memory, or 0. |
| 1058 @AccessedByNative | 481 @AccessedByNative |
| 1059 public int mRelroFd; // ashmem file descriptor, or -1 | 482 public int mRelroFd; // ashmem file descriptor, or -1 |
| 1060 } | 483 } |
| 1061 | 484 |
| 1062 // Create a Bundle from a map of LibInfo objects. | 485 // Create a Bundle from a map of LibInfo objects. |
| 1063 private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> ma
p) { | 486 protected Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) { |
| 1064 Bundle bundle = new Bundle(map.size()); | 487 Bundle bundle = new Bundle(map.size()); |
| 1065 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { | 488 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { |
| 1066 bundle.putParcelable(entry.getKey(), entry.getValue()); | 489 bundle.putParcelable(entry.getKey(), entry.getValue()); |
| 1067 } | 490 } |
| 1068 | 491 |
| 1069 return bundle; | 492 return bundle; |
| 1070 } | 493 } |
| 1071 | 494 |
| 1072 // Create a new LibInfo map from a Bundle. | 495 // Create a new LibInfo map from a Bundle. |
| 1073 private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bu
ndle) { | 496 protected HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle)
{ |
| 1074 HashMap<String, LibInfo> map = new HashMap<String, LibInfo>(); | 497 HashMap<String, LibInfo> map = new HashMap<String, LibInfo>(); |
| 1075 for (String library : bundle.keySet()) { | 498 for (String library : bundle.keySet()) { |
| 1076 LibInfo libInfo = bundle.getParcelable(library); | 499 LibInfo libInfo = bundle.getParcelable(library); |
| 1077 map.put(library, libInfo); | 500 map.put(library, libInfo); |
| 1078 } | 501 } |
| 1079 return map; | 502 return map; |
| 1080 } | 503 } |
| 1081 | 504 |
| 1082 // Call the close() method on all values of a LibInfo map. | 505 // Call the close() method on all values of a LibInfo map. |
| 1083 private static void closeLibInfoMap(HashMap<String, LibInfo> map) { | 506 protected void closeLibInfoMap(HashMap<String, LibInfo> map) { |
| 1084 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { | 507 for (Map.Entry<String, LibInfo> entry : map.entrySet()) { |
| 1085 entry.getValue().close(); | 508 entry.getValue().close(); |
| 1086 } | 509 } |
| 1087 } | 510 } |
| 1088 | |
| 1089 // The map of libraries that are currently loaded in this process. | |
| 1090 private static HashMap<String, LibInfo> sLoadedLibraries = null; | |
| 1091 | |
| 1092 // Used to pass the shared RELRO Bundle through Binder. | |
| 1093 public static final String EXTRA_LINKER_SHARED_RELROS = | |
| 1094 "org.chromium.base.android.linker.shared_relros"; | |
| 1095 } | 511 } |
| OLD | NEW |