Linker.java revision a1401311d1ab56c4ed0a474bd38c108f75cb0cd9
1// Copyright 2014 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
5package org.chromium.base.library_loader;
6
7import android.os.Bundle;
8import android.os.Parcel;
9import android.os.ParcelFileDescriptor;
10import android.os.Parcelable;
11import android.util.Log;
12
13import org.chromium.base.SysUtils;
14
15import java.io.File;
16import java.io.FileInputStream;
17import java.util.HashMap;
18import java.util.Locale;
19import java.util.Map;
20
21/*
22 * Technical note:
23 *
24 * The point of this class is to provide an alternative to System.loadLibrary()
25 * to load native shared libraries. One specific feature that it supports is the
26 * ability to save RAM by sharing the ELF RELRO sections between renderer
27 * processes.
28 *
29 * When two processes load the same native library at the _same_ memory address,
30 * the content of their RELRO section (which includes C++ vtables or any
31 * constants that contain pointers) will be largely identical [1].
32 *
33 * By default, the RELRO section is backed by private RAM in each process,
34 * which is still significant on mobile (e.g. 1.28 MB / process on Chrome 30 for
35 * Android).
36 *
37 * However, it is possible to save RAM by creating a shared memory region,
38 * copy the RELRO content into it, then have each process swap its private,
39 * regular RELRO, with a shared, read-only, mapping of the shared one.
40 *
41 * This trick saves 98% of the RELRO section size per extra process, after the
42 * first one. On the other hand, this requires careful communication between
43 * the process where the shared RELRO is created and the one(s) where it is used.
44 *
45 * Note that swapping the regular RELRO with the shared one is not an atomic
46 * operation. Care must be taken that no other thread tries to run native code
47 * that accesses it during it. In practice, this means the swap must happen
48 * before library native code is executed.
49 *
50 * [1] The exceptions are pointers to external, randomized, symbols, like
51 * those from some system libraries, but these are very few in practice.
52 */
53
54/*
55 * Security considerations:
56 *
57 * - Whether the browser process loads its native libraries at the same
58 *   addresses as the service ones (to save RAM by sharing the RELRO too)
59 *   depends on the configuration variable BROWSER_SHARED_RELRO_CONFIG below.
60 *
61 *   Not using fixed library addresses in the browser process is preferred
62 *   for regular devices since it maintains the efficacy of ASLR as an
63 *   exploit mitigation across the render <-> browser privilege boundary.
64 *
65 * - The shared RELRO memory region is always forced read-only after creation,
66 *   which means it is impossible for a compromised service process to map
67 *   it read-write (e.g. by calling mmap() or mprotect()) and modify its
68 *   content, altering values seen in other service processes.
69 *
70 * - Unfortunately, certain Android systems use an old, buggy kernel, that
71 *   doesn't check Ashmem region permissions correctly. See CVE-2011-1149
72 *   for details. This linker probes the system on startup and will completely
73 *   disable shared RELROs if it detects the problem. For the record, this is
74 *   common for Android emulator system images (which are still based on 2.6.29)
75 *
76 * - Once the RELRO ashmem region is mapped into a service process' address
77 *   space, the corresponding file descriptor is immediately closed. The
78 *   file descriptor is kept opened in the browser process, because a copy needs
79 *   to be sent to each new potential service process.
80 *
81 * - The common library load addresses are randomized for each instance of
82 *   the program on the device. See computeRandomBaseLoadAddress() for more
83 *   details on how this is computed.
84 *
85 * - When loading several libraries in service processes, a simple incremental
86 *   approach from the original random base load address is used. This is
87 *   sufficient to deal correctly with component builds (which can use dozens
88 *   of shared libraries), while regular builds always embed a single shared
89 *   library per APK.
90 */
91
92/**
93 * Here's an explanation of how this class is supposed to be used:
94 *
95 *  - Native shared libraries should be loaded with Linker.loadLibrary(),
96 *    instead of System.loadLibrary(). The two functions take the same parameter
97 *    and should behave the same (at a high level).
98 *
99 *  - Before loading any library, prepareLibraryLoad() should be called.
100 *
101 *  - After loading all libraries, finishLibraryLoad() should be called, before
102 *    running any native code from any of the libraries (except their static
103 *    constructors, which can't be avoided).
104 *
105 *  - A service process shall call either initServiceProcess() or
106 *    disableSharedRelros() early (i.e. before any loadLibrary() call).
107 *    Otherwise, the linker considers that it is running inside the browser
108 *    process. This is because various Chromium projects have vastly
109 *    different initialization paths.
110 *
111 *    disableSharedRelros() completely disables shared RELROs, and loadLibrary()
112 *    will behave exactly like System.loadLibrary().
113 *
114 *    initServiceProcess(baseLoadAddress) indicates that shared RELROs are to be
115 *    used in this process.
116 *
117 *  - The browser is in charge of deciding where in memory each library should
118 *    be loaded. This address must be passed to each service process (see
119 *    ChromiumLinkerParams.java in content for a helper class to do so).
120 *
121 *  - The browser will also generate shared RELROs for each library it loads.
122 *    More specifically, by default when in the browser process, the linker
123 *    will:
124 *
125 *       - Load libraries randomly (just like System.loadLibrary()).
126 *       - Compute the fixed address to be used to load the same library
127 *         in service processes.
128 *       - Create a shared memory region populated with the RELRO region
129 *         content pre-relocated for the specific fixed address above.
130 *
131 *    Note that these shared RELRO regions cannot be used inside the browser
132 *    process. They are also never mapped into it.
133 *
134 *    This behaviour is altered by the BROWSER_SHARED_RELRO_CONFIG configuration
135 *    variable below, which may force the browser to load the libraries at
136 *    fixed addresses to.
137 *
138 *  - Once all libraries are loaded in the browser process, one can call
139 *    getSharedRelros() which returns a Bundle instance containing a map that
140 *    links each loaded library to its shared RELRO region.
141 *
142 *    This Bundle must be passed to each service process, for example through
143 *    a Binder call (note that the Bundle includes file descriptors and cannot
144 *    be added as an Intent extra).
145 *
146 *  - In a service process, finishLibraryLoad() will block until the RELRO
147 *    section Bundle is received. This is typically done by calling
148 *    useSharedRelros() from another thread.
149 *
150 *    This method also ensures the process uses the shared RELROs.
151 */
152public class Linker {
153
154    // Log tag for this class. This must match the name of the linker's native library.
155    private static final String TAG = "chromium_android_linker";
156
157    // Set to true to enable debug logs.
158    private static final boolean DEBUG = false;
159
160    // Constants used to control the behaviour of the browser process with
161    // regards to the shared RELRO section.
162    //   NEVER        -> The browser never uses it itself.
163    //   LOW_RAM_ONLY -> It is only used on devices with low RAM.
164    //   ALWAYS       -> It is always used.
165    // NOTE: These names are known and expected by the Linker test scripts.
166    public static final int BROWSER_SHARED_RELRO_CONFIG_NEVER = 0;
167    public static final int BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY = 1;
168    public static final int BROWSER_SHARED_RELRO_CONFIG_ALWAYS = 2;
169
170    // Configuration variable used to control how the browser process uses the
171    // shared RELRO. Only change this while debugging linker-related issues.
172    // NOTE: This variable's name is known and expected by the Linker test scripts.
173    public static final int BROWSER_SHARED_RELRO_CONFIG =
174            BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY;
175
176    // Constants used to control the value of sMemoryDeviceConfig.
177    //   INIT         -> Value is undetermined (will check at runtime).
178    //   LOW          -> This is a low-memory device.
179    //   NORMAL       -> This is not a low-memory device.
180    public static final int MEMORY_DEVICE_CONFIG_INIT = 0;
181    public static final int MEMORY_DEVICE_CONFIG_LOW = 1;
182    public static final int MEMORY_DEVICE_CONFIG_NORMAL = 2;
183
184    // Indicates if this is a low-memory device or not. The default is to
185    // determine this by probing the system at runtime, but this can be forced
186    // for testing by calling setMemoryDeviceConfig().
187    private static int sMemoryDeviceConfig = MEMORY_DEVICE_CONFIG_INIT;
188
189    // Becomes true after linker initialization.
190    private static boolean sInitialized = false;
191
192    // Set to true to indicate that the system supports safe sharing of RELRO sections.
193    private static boolean sRelroSharingSupported = false;
194
195    // Set to true if this runs in the browser process. Disabled by initServiceProcess().
196    private static boolean sInBrowserProcess = true;
197
198    // Becomes true to indicate this process needs to wait for a shared RELRO in
199    // finishLibraryLoad().
200    private static boolean sWaitForSharedRelros = false;
201
202    // Becomes true when initialization determines that the browser process can use the
203    // shared RELRO.
204    private static boolean sBrowserUsesSharedRelro = false;
205
206    // The map of all RELRO sections either created or used in this process.
207    private static Bundle sSharedRelros = null;
208
209    // Current common random base load address.
210    private static long sBaseLoadAddress = 0;
211
212    // Current fixed-location load address for the next library called by loadLibrary().
213    private static long sCurrentLoadAddress = 0;
214
215    // Becomes true if any library fails to load at a given, non-0, fixed address.
216    private static boolean sLoadAtFixedAddressFailed = false;
217
218    // Becomes true once prepareLibraryLoad() has been called.
219    private static boolean sPrepareLibraryLoadCalled = false;
220
221    // Used internally to initialize the linker's static data. Assume lock is held.
222    private static void ensureInitializedLocked() {
223        assert Thread.holdsLock(Linker.class);
224
225        if (!sInitialized) {
226            sRelroSharingSupported = false;
227            if (NativeLibraries.USE_LINKER) {
228                if (DEBUG) Log.i(TAG, "Loading lib" + TAG + ".so");
229                try {
230                    System.loadLibrary(TAG);
231                } catch (UnsatisfiedLinkError  e) {
232                    // In a component build, the ".cr" suffix is added to each library name.
233                    System.loadLibrary(TAG + ".cr");
234                }
235                sRelroSharingSupported = nativeCanUseSharedRelro();
236                if (!sRelroSharingSupported)
237                    Log.w(TAG, "This system cannot safely share RELRO sections");
238                else {
239                    if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
240                }
241
242                if (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT) {
243                    sMemoryDeviceConfig = SysUtils.isLowEndDevice() ?
244                            MEMORY_DEVICE_CONFIG_LOW : MEMORY_DEVICE_CONFIG_NORMAL;
245                }
246
247                switch (BROWSER_SHARED_RELRO_CONFIG) {
248                    case BROWSER_SHARED_RELRO_CONFIG_NEVER:
249                        sBrowserUsesSharedRelro = false;
250                        break;
251                    case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
252                        sBrowserUsesSharedRelro =
253                                (sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW);
254                        if (sBrowserUsesSharedRelro)
255                            Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
256                        break;
257                    case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
258                        Log.w(TAG, "Beware: shared RELROs used in all processes!");
259                        sBrowserUsesSharedRelro = true;
260                        break;
261                    default:
262                        assert false : "Unreached";
263                        break;
264                }
265            } else {
266                if (DEBUG) Log.i(TAG, "Linker disabled");
267            }
268
269            if (!sRelroSharingSupported) {
270                // Sanity.
271                sBrowserUsesSharedRelro = false;
272                sWaitForSharedRelros = false;
273            }
274
275            sInitialized = true;
276        }
277    }
278
279    /**
280     * A public interface used to run runtime linker tests after loading
281     * libraries. Should only be used to implement the linker unit tests,
282     * which is controlled by the value of NativeLibraries.ENABLE_LINKER_TESTS
283     * configured at build time.
284     */
285    public interface TestRunner {
286        /**
287         * Run runtime checks and return true if they all pass.
288         * @param memoryDeviceConfig The current memory device configuration.
289         * @param inBrowserProcess true iff this is the browser process.
290         */
291        public boolean runChecks(int memoryDeviceConfig, boolean inBrowserProcess);
292    }
293
294    // The name of a class that implements TestRunner.
295    static String sTestRunnerClassName = null;
296
297    /**
298     * Set the TestRunner by its class name. It will be instantiated at
299     * runtime after all libraries are loaded.
300     * @param testRunnerClassName null or a String for the class name of the
301     * TestRunner to use.
302     */
303    public static void setTestRunnerClassName(String testRunnerClassName) {
304        if (DEBUG) Log.i(TAG, "setTestRunnerByClassName(" + testRunnerClassName + ") called");
305
306        if (!NativeLibraries.ENABLE_LINKER_TESTS) {
307            // Ignore this in production code to prevent malvolent runtime injection.
308            return;
309        }
310
311        synchronized (Linker.class) {
312            assert sTestRunnerClassName == null;
313            sTestRunnerClassName = testRunnerClassName;
314        }
315    }
316
317    /**
318     * Call this to retrieve the name of the current TestRunner class name
319     * if any. This can be useful to pass it from the browser process to
320     * child ones.
321     * @return null or a String holding the name of the class implementing
322     * the TestRunner set by calling setTestRunnerClassName() previously.
323     */
324    public static String getTestRunnerClassName() {
325        synchronized (Linker.class) {
326            return sTestRunnerClassName;
327        }
328    }
329
330    /**
331     * Call this method before any other Linker method to force a specific
332     * memory device configuration. Should only be used for testing.
333     * @param memoryDeviceConfig either MEMORY_DEVICE_CONFIG_LOW or MEMORY_DEVICE_CONFIG_NORMAL.
334     */
335    public static void setMemoryDeviceConfig(int memoryDeviceConfig) {
336        if (DEBUG) Log.i(TAG, "setMemoryDeviceConfig(" + memoryDeviceConfig + ") called");
337        // Sanity check. This method should only be called during tests.
338        assert NativeLibraries.ENABLE_LINKER_TESTS;
339        synchronized (Linker.class) {
340            assert sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_INIT;
341            assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW ||
342                   memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
343            if (DEBUG) {
344                if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW)
345                    Log.i(TAG, "Simulating a low-memory device");
346                else
347                    Log.i(TAG, "Simulating a regular-memory device");
348            }
349            sMemoryDeviceConfig = memoryDeviceConfig;
350        }
351    }
352
353    /**
354     * Call this method to determine if this chromium project must
355     * use this linker. If not, System.loadLibrary() should be used to load
356     * libraries instead.
357     */
358    public static boolean isUsed() {
359        // Only GYP targets that are APKs and have the 'use_chromium_linker' variable
360        // defined as 1 will use this linker. For all others (the default), the
361        // auto-generated NativeLibraries.USE_LINKER variable will be false.
362        if (!NativeLibraries.USE_LINKER)
363            return false;
364
365        synchronized (Linker.class) {
366            ensureInitializedLocked();
367            // At the moment, there is also no point in using this linker if the
368            // system does not support RELRO sharing safely.
369            return sRelroSharingSupported;
370        }
371    }
372
373    /**
374     * Call this method just before loading any native shared libraries in this process.
375     */
376    public static void prepareLibraryLoad() {
377        if (DEBUG) Log.i(TAG, "prepareLibraryLoad() called");
378        synchronized (Linker.class) {
379            sPrepareLibraryLoadCalled = true;
380
381            if (sInBrowserProcess) {
382                // Force generation of random base load address, as well
383                // as creation of shared RELRO sections in this process.
384                setupBaseLoadAddressLocked();
385            }
386        }
387    }
388
389    /**
390     * Call this method just after loading all native shared libraries in this process.
391     * Note that when in a service process, this will block until the RELRO bundle is
392     * received, i.e. when another thread calls useSharedRelros().
393     */
394    public static void finishLibraryLoad() {
395        if (DEBUG) Log.i(TAG, "finishLibraryLoad() called");
396        synchronized (Linker.class) {
397            if (DEBUG) Log.i(TAG, String.format(
398                    Locale.US,
399                    "sInBrowserProcess=%s sBrowserUsesSharedRelro=%s sWaitForSharedRelros=%s",
400                    sInBrowserProcess ? "true" : "false",
401                    sBrowserUsesSharedRelro ? "true" : "false",
402                    sWaitForSharedRelros ? "true" : "false"));
403
404            if (sLoadedLibraries == null) {
405                if (DEBUG) Log.i(TAG, "No libraries loaded");
406            } else {
407                if (sInBrowserProcess) {
408                    // Create new Bundle containing RELRO section information
409                    // for all loaded libraries. Make it available to getSharedRelros().
410                    sSharedRelros = createBundleFromLibInfoMap(sLoadedLibraries);
411                    if (DEBUG) {
412                        Log.i(TAG, "Shared RELRO created");
413                        dumpBundle(sSharedRelros);
414                    }
415
416                    if (sBrowserUsesSharedRelro) {
417                        useSharedRelrosLocked(sSharedRelros);
418                    }
419                }
420
421                if (sWaitForSharedRelros) {
422                    assert !sInBrowserProcess;
423
424                    // Wait until the shared relro bundle is received from useSharedRelros().
425                    while (sSharedRelros == null) {
426                        try {
427                            Linker.class.wait();
428                        } catch (InterruptedException ie) {
429                            // no-op
430                        }
431                    }
432                    useSharedRelrosLocked(sSharedRelros);
433                    // Clear the Bundle to ensure its file descriptor references can't be reused.
434                    sSharedRelros.clear();
435                    sSharedRelros = null;
436                }
437            }
438
439            if (NativeLibraries.ENABLE_LINKER_TESTS && sTestRunnerClassName != null) {
440                // The TestRunner implementation must be instantiated _after_
441                // all libraries are loaded to ensure that its native methods
442                // are properly registered.
443                if (DEBUG) Log.i(TAG, "Instantiating " + sTestRunnerClassName);
444                TestRunner testRunner = null;
445                try {
446                    testRunner = (TestRunner)
447                            Class.forName(sTestRunnerClassName).newInstance();
448                } catch (Exception e) {
449                    Log.e(TAG, "Could not extract test runner class name", e);
450                    testRunner = null;
451                }
452                if (testRunner != null) {
453                    if (!testRunner.runChecks(sMemoryDeviceConfig, sInBrowserProcess)) {
454                        Log.wtf(TAG, "Linker runtime tests failed in this process!!");
455                        assert false;
456                    } else {
457                        Log.i(TAG, "All linker tests passed!");
458                    }
459                }
460            }
461        }
462        if (DEBUG) Log.i(TAG, "finishLibraryLoad() exiting");
463    }
464
465    /**
466     * Call this to send a Bundle containing the shared RELRO sections to be
467     * used in this process. If initServiceProcess() was previously called,
468     * finishLibraryLoad() will not exit until this method is called in another
469     * thread with a non-null value.
470     * @param bundle The Bundle instance containing a map of shared RELRO sections
471     * to use in this process.
472     */
473    public static void useSharedRelros(Bundle bundle) {
474        // Ensure the bundle uses the application's class loader, not the framework
475        // one which doesn't know anything about LibInfo.
476        if (bundle != null)
477            bundle.setClassLoader(LibInfo.class.getClassLoader());
478
479        if (DEBUG) Log.i(TAG, "useSharedRelros() called with " + bundle);
480
481        synchronized (Linker.class) {
482            // Note that in certain cases, this can be called before
483            // initServiceProcess() in service processes.
484            sSharedRelros = bundle;
485            // Tell any listener blocked in finishLibraryLoad() about it.
486            Linker.class.notifyAll();
487        }
488    }
489
490    /**
491     * Call this to retrieve the shared RELRO sections created in this process,
492     * after loading all libraries.
493     * @return a new Bundle instance, or null if RELRO sharing is disabled on
494     * this system, or if initServiceProcess() was called previously.
495     */
496    public static Bundle getSharedRelros() {
497        if (DEBUG) Log.i(TAG, "getSharedRelros() called");
498        synchronized (Linker.class) {
499            if (!sInBrowserProcess) {
500                if (DEBUG) Log.i(TAG, "... returning null Bundle");
501                return null;
502            }
503
504            // Return the Bundle created in finishLibraryLoad().
505            if (DEBUG) Log.i(TAG, "... returning " + sSharedRelros);
506            return sSharedRelros;
507        }
508    }
509
510
511    /**
512     * Call this method before loading any libraries to indicate that this
513     * process shall neither create or reuse shared RELRO sections.
514     */
515    public static void disableSharedRelros() {
516        if (DEBUG) Log.i(TAG, "disableSharedRelros() called");
517        synchronized (Linker.class) {
518            sInBrowserProcess = false;
519            sWaitForSharedRelros = false;
520            sBrowserUsesSharedRelro = false;
521        }
522    }
523
524    /**
525     * Call this method before loading any libraries to indicate that this
526     * process is ready to reuse shared RELRO sections from another one.
527     * Typically used when starting service processes.
528     * @param baseLoadAddress the base library load address to use.
529     */
530    public static void initServiceProcess(long baseLoadAddress) {
531        if (DEBUG) {
532            Log.i(TAG, String.format(
533                    Locale.US, "initServiceProcess(0x%x) called", baseLoadAddress));
534        }
535        synchronized (Linker.class) {
536            ensureInitializedLocked();
537            sInBrowserProcess = false;
538            sBrowserUsesSharedRelro = false;
539            if (sRelroSharingSupported) {
540                sWaitForSharedRelros = true;
541                sBaseLoadAddress = baseLoadAddress;
542                sCurrentLoadAddress = baseLoadAddress;
543            }
544        }
545    }
546
547    /**
548     * Retrieve the base load address of all shared RELRO sections.
549     * This also enforces the creation of shared RELRO sections in
550     * prepareLibraryLoad(), which can later be retrieved with getSharedRelros().
551     * @return a common, random base load address, or 0 if RELRO sharing is
552     * disabled.
553     */
554    public static long getBaseLoadAddress() {
555        synchronized (Linker.class) {
556            ensureInitializedLocked();
557            if (!sInBrowserProcess) {
558                Log.w(TAG, "Shared RELRO sections are disabled in this process!");
559                return 0;
560            }
561
562            setupBaseLoadAddressLocked();
563            if (DEBUG) Log.i(TAG, String.format(Locale.US, "getBaseLoadAddress() returns 0x%x",
564                                                sBaseLoadAddress));
565            return sBaseLoadAddress;
566        }
567    }
568
569    // Used internally to lazily setup the common random base load address.
570    private static void setupBaseLoadAddressLocked() {
571        assert Thread.holdsLock(Linker.class);
572        if (sBaseLoadAddress == 0) {
573            long address = computeRandomBaseLoadAddress();
574            sBaseLoadAddress = address;
575            sCurrentLoadAddress = address;
576            if (address == 0) {
577                // If the computed address is 0, there are issues with the
578                // entropy source, so disable RELRO shared / fixed load addresses.
579                Log.w(TAG, "Disabling shared RELROs due to bad entropy sources");
580                sBrowserUsesSharedRelro = false;
581                sWaitForSharedRelros = false;
582            }
583        }
584    }
585
586
587    /**
588     * Compute a random base load address where to place loaded libraries.
589     * @return new base load address, or 0 if the system does not support
590     * RELRO sharing.
591     */
592    private static long computeRandomBaseLoadAddress() {
593        // The kernel ASLR feature will place randomized mappings starting
594        // from this address. Never try to load anything above this
595        // explicitly to avoid random conflicts.
596        final long baseAddressLimit = 0x40000000;
597
598        // Start loading libraries from this base address.
599        final long baseAddress = 0x20000000;
600
601        // Maximum randomized base address value. Used to ensure a margin
602        // of 192 MB below baseAddressLimit.
603        final long baseAddressMax = baseAddressLimit - 192 * 1024 * 1024;
604
605        // The maximum limit of the desired random offset.
606        final long pageSize = nativeGetPageSize();
607        final int offsetLimit = (int) ((baseAddressMax - baseAddress) / pageSize);
608
609        // Get the greatest power of 2 that is smaller or equal to offsetLimit.
610        int numBits = 30;
611        for (; numBits > 1; numBits--) {
612            if ((1 << numBits) <= offsetLimit)
613                break;
614        }
615
616        if (DEBUG) {
617            final int maxValue = (1 << numBits) - 1;
618            Log.i(TAG, String.format(Locale.US, "offsetLimit=%d numBits=%d maxValue=%d (0x%x)",
619                offsetLimit, numBits, maxValue, maxValue));
620        }
621
622        // Find a random offset between 0 and (2^numBits - 1), included.
623        int offset = getRandomBits(numBits);
624        long address = 0;
625        if (offset >= 0)
626            address = baseAddress + offset * pageSize;
627
628        if (DEBUG) {
629            Log.i(TAG,
630                  String.format(Locale.US, "Linker.computeRandomBaseLoadAddress() return 0x%x",
631                                address));
632        }
633        return address;
634    }
635
636    /**
637     * Return a cryptographically-strong random number of numBits bits.
638     * @param numBits The number of bits in the result. Must be in 1..31 range.
639     * @return A random integer between 0 and (2^numBits - 1), inclusive, or -1
640     * in case of error (e.g. if /dev/urandom can't be opened or read).
641     */
642    private static int getRandomBits(int numBits) {
643        // Sanity check.
644        assert numBits > 0;
645        assert numBits < 32;
646
647        FileInputStream input;
648        try {
649            // A naive implementation would read a 32-bit integer then use modulo, but
650            // this introduces a slight bias. Instead, read 32-bit integers from the
651            // entropy source until the value is positive but smaller than maxLimit.
652            input = new FileInputStream(new File("/dev/urandom"));
653        } catch (Exception e) {
654            Log.e(TAG, "Could not open /dev/urandom", e);
655            return -1;
656        }
657
658        int result = 0;
659        try {
660            for (int n = 0; n < 4; n++) {
661                result = (result << 8) | (input.read() & 255);
662            }
663        } catch (Exception e) {
664            Log.e(TAG, "Could not read /dev/urandom", e);
665            return -1;
666        } finally {
667            try {
668                input.close();
669            } catch (Exception e) {
670                // Can't really do anything here.
671            }
672        }
673        result &= (1 << numBits) - 1;
674
675        if (DEBUG) {
676            Log.i(TAG, String.format(
677                    Locale.US, "getRandomBits(%d) returned %d", numBits, result));
678        }
679
680        return result;
681    }
682
683    // Used for debugging only.
684    private static void dumpBundle(Bundle bundle) {
685        if (DEBUG) Log.i(TAG, "Bundle has " + bundle.size() + " items: " + bundle);
686    }
687
688    /**
689     * Use the shared RELRO section from a Bundle received form another process.
690     * Call this after calling setBaseLoadAddress() then loading all libraries
691     * with loadLibrary().
692     * @param bundle Bundle instance generated with createSharedRelroBundle() in
693     * another process.
694     */
695    private static void useSharedRelrosLocked(Bundle bundle) {
696        assert Thread.holdsLock(Linker.class);
697
698        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() called");
699
700        if (bundle == null) {
701            if (DEBUG) Log.i(TAG, "null bundle!");
702            return;
703        }
704
705        if (!sRelroSharingSupported) {
706            if (DEBUG) Log.i(TAG, "System does not support RELRO sharing");
707            return;
708        }
709
710        if (sLoadedLibraries == null) {
711            if (DEBUG) Log.i(TAG, "No libraries loaded!");
712            return;
713        }
714
715        if (DEBUG) dumpBundle(bundle);
716        HashMap<String, LibInfo> relroMap = createLibInfoMapFromBundle(bundle);
717
718        // Apply the RELRO section to all libraries that were already loaded.
719        for (Map.Entry<String, LibInfo> entry : relroMap.entrySet()) {
720            String libName = entry.getKey();
721            LibInfo libInfo = entry.getValue();
722            if (!nativeUseSharedRelro(libName, libInfo)) {
723                Log.w(TAG, "Could not use shared RELRO section for " + libName);
724            } else {
725                if (DEBUG) Log.i(TAG, "Using shared RELRO section for " + libName);
726            }
727        }
728
729        // In service processes, close all file descriptors from the map now.
730        if (!sInBrowserProcess)
731            closeLibInfoMap(relroMap);
732
733        if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
734    }
735
736    /**
737     * Returns whether the linker was unable to load one library at a given fixed address.
738     *
739     * @return true if at least one library was not loaded at the expected fixed address.
740     */
741    public static boolean loadAtFixedAddressFailed() {
742        return sLoadAtFixedAddressFailed;
743    }
744
745    /**
746     * Load a native shared library with the Chromium linker.
747     * If neither initSharedRelro() or readFromBundle() were called
748     * previously, this uses the standard linker (i.e. System.loadLibrary()).
749     *
750     * @param library The library's base name.
751     */
752    public static void loadLibrary(String library) {
753        if (DEBUG) Log.i(TAG, "loadLibrary: " + library);
754
755        // Don't self-load the linker. This is because the build system is
756        // not clever enough to understand that all the libraries packaged
757        // in the final .apk don't need to be explicitly loaded.
758        // Also deal with the component build that adds a .cr suffix to the name.
759        if (library.equals(TAG) || library.equals(TAG + ".cr")) {
760            if (DEBUG) Log.i(TAG, "ignoring self-linker load");
761            return;
762        }
763
764        synchronized (Linker.class) {
765            ensureInitializedLocked();
766
767            // Security: Ensure prepareLibraryLoad() was called before.
768            // In theory, this can be done lazily here, but it's more consistent
769            // to use a pair of functions (i.e. prepareLibraryLoad() + finishLibraryLoad())
770            // that wrap all calls to loadLibrary() in the library loader.
771            assert sPrepareLibraryLoadCalled;
772
773            String libName = System.mapLibraryName(library);
774
775            if (sLoadedLibraries == null)
776              sLoadedLibraries = new HashMap<String, LibInfo>();
777
778            if (sLoadedLibraries.containsKey(libName)) {
779                if (DEBUG) Log.i(TAG, "Not loading " + libName + " twice");
780                return;
781            }
782
783            LibInfo libInfo = new LibInfo();
784            long loadAddress = 0;
785            if ((sInBrowserProcess && sBrowserUsesSharedRelro) || sWaitForSharedRelros) {
786                // Load the library at a fixed address.
787                loadAddress = sCurrentLoadAddress;
788            }
789
790            if (!nativeLoadLibrary(libName, loadAddress, libInfo)) {
791                String errorMessage = "Unable to load library: " + libName;
792                Log.e(TAG, errorMessage);
793                throw new UnsatisfiedLinkError(errorMessage);
794            }
795            // Keep track whether the library has been loaded at the expected load address.
796            if (loadAddress != 0 && loadAddress != libInfo.mLoadAddress)
797                sLoadAtFixedAddressFailed = true;
798
799            // Print the load address to the logcat when testing the linker. The format
800            // of the string is expected by the Python test_runner script as one of:
801            //    BROWSER_LIBRARY_ADDRESS: <library-name> <address>
802            //    RENDERER_LIBRARY_ADDRESS: <library-name> <address>
803            // Where <library-name> is the library name, and <address> is the hexadecimal load
804            // address.
805            if (NativeLibraries.ENABLE_LINKER_TESTS) {
806                Log.i(TAG, String.format(
807                        Locale.US,
808                        "%s_LIBRARY_ADDRESS: %s %x",
809                        sInBrowserProcess ? "BROWSER" : "RENDERER",
810                        libName,
811                        libInfo.mLoadAddress));
812            }
813
814            if (sInBrowserProcess) {
815                // Create a new shared RELRO section at the 'current' fixed load address.
816                if (!nativeCreateSharedRelro(libName, sCurrentLoadAddress, libInfo)) {
817                    Log.w(TAG, String.format(Locale.US,
818                            "Could not create shared RELRO for %s at %x", libName,
819                            sCurrentLoadAddress));
820                } else {
821                    if (DEBUG) Log.i(TAG,
822                        String.format(
823                            Locale.US,
824                            "Created shared RELRO for %s at %x: %s",
825                            libName,
826                            sCurrentLoadAddress,
827                            libInfo.toString()));
828                }
829            }
830
831            if (sCurrentLoadAddress != 0) {
832                // Compute the next current load address. If sBaseLoadAddress
833                // is not 0, this is an explicit library load address. Otherwise,
834                // this is an explicit load address for relocated RELRO sections
835                // only.
836                sCurrentLoadAddress = libInfo.mLoadAddress + libInfo.mLoadSize;
837            }
838
839            sLoadedLibraries.put(libName, libInfo);
840            if (DEBUG) Log.i(TAG, "Library details " + libInfo.toString());
841        }
842    }
843
844    /**
845     * Native method used to load a library.
846     * @param library Platform specific library name (e.g. libfoo.so)
847     * @param loadAddress Explicit load address, or 0 for randomized one.
848     * @param libInfo If not null, the mLoadAddress and mLoadSize fields
849     * of this LibInfo instance will set on success.
850     * @return true for success, false otherwise.
851     */
852    private static native boolean nativeLoadLibrary(String library,
853                                                    long loadAddress,
854                                                    LibInfo libInfo);
855
856    /**
857     * Native method used to create a shared RELRO section.
858     * If the library was already loaded at the same address using
859     * nativeLoadLibrary(), this creates the RELRO for it. Otherwise,
860     * this loads a new temporary library at the specified address,
861     * creates and extracts the RELRO section from it, then unloads it.
862     * @param library Library name.
863     * @param loadAddress load address, which can be different from the one
864     * used to load the library in the current process!
865     * @param libInfo libInfo instance. On success, the mRelroStart, mRelroSize
866     * and mRelroFd will be set.
867     * @return true on success, false otherwise.
868     */
869    private static native boolean nativeCreateSharedRelro(String library,
870                                                          long loadAddress,
871                                                          LibInfo libInfo);
872
873    /**
874     * Native method used to use a shared RELRO section.
875     * @param library Library name.
876     * @param libInfo A LibInfo instance containing valid RELRO information
877     * @return true on success.
878     */
879    private static native boolean nativeUseSharedRelro(String library,
880                                                       LibInfo libInfo);
881
882    /**
883     * Checks that the system supports shared RELROs. Old Android kernels
884     * have a bug in the way they check Ashmem region protection flags, which
885     * makes using shared RELROs unsafe. This method performs a simple runtime
886     * check for this misfeature, even though nativeEnableSharedRelro() will
887     * always fail if this returns false.
888     */
889    private static native boolean nativeCanUseSharedRelro();
890
891    // Returns the native page size in bytes.
892    private static native long nativeGetPageSize();
893
894    /**
895     * Record information for a given library.
896     * IMPORTANT: Native code knows about this class's fields, so
897     * don't change them without modifying the corresponding C++ sources.
898     * Also, the LibInfo instance owns the ashmem file descriptor.
899     */
900    public static class LibInfo implements Parcelable {
901
902        public LibInfo() {
903            mLoadAddress = 0;
904            mLoadSize = 0;
905            mRelroStart = 0;
906            mRelroSize = 0;
907            mRelroFd = -1;
908        }
909
910        public void close() {
911            if (mRelroFd >= 0) {
912                try {
913                    ParcelFileDescriptor.adoptFd(mRelroFd).close();
914                } catch (java.io.IOException e) {
915                    if (DEBUG) Log.e(TAG, "Failed to close fd: " + mRelroFd);
916                }
917                mRelroFd = -1;
918            }
919        }
920
921        // from Parcelable
922        public LibInfo(Parcel in) {
923            mLoadAddress = in.readLong();
924            mLoadSize = in.readLong();
925            mRelroStart = in.readLong();
926            mRelroSize = in.readLong();
927            ParcelFileDescriptor fd = in.readFileDescriptor();
928            mRelroFd = fd.detachFd();
929        }
930
931        // from Parcelable
932        @Override
933        public void writeToParcel(Parcel out, int flags) {
934            if (mRelroFd >= 0) {
935                out.writeLong(mLoadAddress);
936                out.writeLong(mLoadSize);
937                out.writeLong(mRelroStart);
938                out.writeLong(mRelroSize);
939                try {
940                    ParcelFileDescriptor fd = ParcelFileDescriptor.fromFd(mRelroFd);
941                    fd.writeToParcel(out, 0);
942                    fd.close();
943                } catch (java.io.IOException e) {
944                    Log.e(TAG, "Cant' write LibInfo file descriptor to parcel", e);
945                }
946            }
947        }
948
949        // from Parcelable
950        @Override
951        public int describeContents() {
952            return Parcelable.CONTENTS_FILE_DESCRIPTOR;
953        }
954
955        // from Parcelable
956        public static final Parcelable.Creator<LibInfo> CREATOR =
957                new Parcelable.Creator<LibInfo>() {
958                    @Override
959                    public LibInfo createFromParcel(Parcel in) {
960                        return new LibInfo(in);
961                    }
962
963                    @Override
964                    public LibInfo[] newArray(int size) {
965                        return new LibInfo[size];
966                    }
967                };
968
969        @Override
970        public String toString() {
971            return String.format(Locale.US,
972                                 "[load=0x%x-0x%x relro=0x%x-0x%x fd=%d]",
973                                 mLoadAddress,
974                                 mLoadAddress + mLoadSize,
975                                 mRelroStart,
976                                 mRelroStart + mRelroSize,
977                                 mRelroFd);
978        }
979
980        // IMPORTANT: Don't change these fields without modifying the
981        // native code that accesses them directly!
982        public long mLoadAddress; // page-aligned library load address.
983        public long mLoadSize;    // page-aligned library load size.
984        public long mRelroStart;  // page-aligned address in memory, or 0 if none.
985        public long mRelroSize;   // page-aligned size in memory, or 0.
986        public int  mRelroFd;     // ashmem file descriptor, or -1
987    }
988
989    // Create a Bundle from a map of LibInfo objects.
990    private static Bundle createBundleFromLibInfoMap(HashMap<String, LibInfo> map) {
991        Bundle bundle = new Bundle(map.size());
992        for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
993            bundle.putParcelable(entry.getKey(), entry.getValue());
994        }
995
996        return bundle;
997    }
998
999    // Create a new LibInfo map from a Bundle.
1000    private static HashMap<String, LibInfo> createLibInfoMapFromBundle(Bundle bundle) {
1001        HashMap<String, LibInfo> map = new HashMap<String, LibInfo>();
1002        for (String library : bundle.keySet()) {
1003            LibInfo libInfo = bundle.getParcelable(library);
1004            map.put(library, libInfo);
1005        }
1006        return map;
1007    }
1008
1009    // Call the close() method on all values of a LibInfo map.
1010    private static void closeLibInfoMap(HashMap<String, LibInfo> map) {
1011        for (Map.Entry<String, LibInfo> entry : map.entrySet()) {
1012            entry.getValue().close();
1013        }
1014    }
1015
1016    // The map of libraries that are currently loaded in this process.
1017    private static HashMap<String, LibInfo> sLoadedLibraries = null;
1018
1019    // Used to pass the shared RELRO Bundle through Binder.
1020    public static final String EXTRA_LINKER_SHARED_RELROS =
1021        "org.chromium.base.android.linker.shared_relros";
1022}
1023