Skip to content

Commit

Permalink
base/android/linker: Replace memfd with ASharedMemory
Browse files Browse the repository at this point in the history
Currently ASharedMemory is backed by ashmem on all Android releases.
There is a plan to reimplement it on top of memfd in the future.

Using memfd explicitly in Chrome was introduced to apply an R+
workaround allowing to open a file in the App Zygote Preload.
Unfortunately this workaround is blocked by SELinux policies.

There is an Android change (currently in review) to allow ashmem FDs
created by Preload to stay open across fork(2). It will go live not
earlier than in S.

Here, remove explicit use of memfd_create(2) and replace it with
ASharedMemory.

With this change The current usage of RELRO regions should be
unaffected: RELRO sharing mechanics in linkers is used only in
privileged+browser processes. It will start making a difference when the
app zygote starts creating RELRO regions.

Fly-by cleanups:

1. In *linker_jni.cc refer to the main comment instead of repeating.

2. Make the debug printing consistently use Log.i guarded by DEBUG
   instead of Log.d - these uses were introduced accidentally.

Bug: 1154224
Change-Id: I09effaa27c7f2f0c28f044783e8cad1ebc5c5706
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2960932
Commit-Queue: Egor Pasko <pasko@chromium.org>
Reviewed-by: Benoit L <lizeb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#892603}
  • Loading branch information
pasko authored and Chromium LUCI CQ committed Jun 15, 2021
1 parent 4920062 commit 56343f4
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 278 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

package org.chromium.base.library_loader;

import android.os.Build;

import org.chromium.base.Log;
import org.chromium.base.annotations.JniIgnoreNatives;
import org.chromium.base.metrics.RecordHistogram;
Expand All @@ -24,21 +22,13 @@
class ModernLinker extends Linker {
private static final String TAG = "ModernLinker";

// Whether to use memfd_create(2) for creating RELRO FD on supported systems.
// TODO(pasko): Remove this compile time constant when memfd reaches Stable (M91).
private static final boolean ALLOW_MEMFD = true;

ModernLinker() {}

@Override
protected boolean keepMemoryReservationUntilLoad() {
return true;
}

private static boolean useMemfd() {
return ALLOW_MEMFD && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R);
}

@Override
@GuardedBy("mLock")
protected void loadLibraryImplLocked(String library, @RelroSharingMode int relroMode) {
Expand All @@ -55,10 +45,11 @@ protected void loadLibraryImplLocked(String library, @RelroSharingMode int relro
} else if (relroMode == RelroSharingMode.PRODUCE) {
// Create the shared RELRO, and store it.
mLocalLibInfo.mLibFilePath = libFilePath;
if (nativeLoadLibrary(
libFilePath, mLocalLibInfo, true /* spawnRelroRegion */, useMemfd())) {
Log.d(TAG, "Successfully spawned RELRO: mLoadAddress=0x%x, mLoadSize=%d",
mLocalLibInfo.mLoadAddress, mLocalLibInfo.mLoadSize);
if (nativeLoadLibrary(libFilePath, mLocalLibInfo, true /* spawnRelroRegion */)) {
if (DEBUG) {
Log.i(TAG, "Successfully spawned RELRO: mLoadAddress=0x%x, mLoadSize=%d",
mLocalLibInfo.mLoadAddress, mLocalLibInfo.mLoadSize);
}
} else {
Log.e(TAG, "Unable to load with ModernLinker, using the system linker instead");
// System.loadLibrary() below implements the fallback.
Expand All @@ -73,9 +64,8 @@ protected void loadLibraryImplLocked(String library, @RelroSharingMode int relro
mState = State.DONE_PROVIDE_RELRO;
} else {
assert relroMode == RelroSharingMode.CONSUME;
assert libFilePath.equals(mRemoteLibInfo.mLibFilePath);
if (!nativeLoadLibrary(
libFilePath, mLocalLibInfo, false /* spawnRelroRegion */, useMemfd())) {
assert mRemoteLibInfo == null || libFilePath.equals(mRemoteLibInfo.mLibFilePath);
if (!nativeLoadLibrary(libFilePath, mLocalLibInfo, false /* spawnRelroRegion */)) {
resetAndThrow(String.format("Unable to load library: %s", libFilePath));
}
assert mLocalLibInfo.mRelroFd == -1;
Expand Down Expand Up @@ -104,11 +94,13 @@ protected void atomicReplaceRelroLocked(boolean relroAvailableImmediately) {
assert mRemoteLibInfo != null;
assert mState == State.DONE;
if (mRemoteLibInfo.mRelroFd == -1) return;
Log.d(TAG, "Received mRemoteLibInfo: mLoadAddress=0x%x, mLoadSize=%d",
mRemoteLibInfo.mLoadAddress, mRemoteLibInfo.mLoadSize);
nativeUseRelros(mRemoteLibInfo, useMemfd());
if (DEBUG) {
Log.i(TAG, "Received mRemoteLibInfo: mLoadAddress=0x%x, mLoadSize=%d",
mRemoteLibInfo.mLoadAddress, mRemoteLibInfo.mLoadSize);
}
nativeUseRelros(mRemoteLibInfo);
mRemoteLibInfo.close();
Log.d(TAG, "Immediate RELRO availability: %b", relroAvailableImmediately);
if (DEBUG) Log.i(TAG, "Immediate RELRO availability: %b", relroAvailableImmediately);
RecordHistogram.recordBooleanHistogram(
"ChromiumAndroidLinker.RelroAvailableImmediately", relroAvailableImmediately);
int status = nativeGetRelroSharingResult();
Expand All @@ -125,7 +117,7 @@ private void resetAndThrow(String message) {
}

private static native boolean nativeLoadLibrary(
String libFilePath, LibInfo libInfo, boolean spawnRelroRegion, boolean useMemfd);
private static native boolean nativeUseRelros(LibInfo libInfo, boolean useMemfd);
String libFilePath, LibInfo libInfo, boolean spawnRelroRegion);
private static native boolean nativeUseRelros(LibInfo libInfo);
private static native int nativeGetRelroSharingResult();
}
8 changes: 3 additions & 5 deletions base/android/linker/legacy_linker_jni.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is the version of the Android-specific Chromium linker that uses
// the crazy linker to load libraries.

// This source code *cannot* depend on anything from base/ or the C++
// STL, to keep the final library small, and avoid ugly dependency issues.
// This is a part of the Android-specific Chromium dynamic linker.
//
// See linker_jni.h for more details and the dependency rules.

#include "base/android/linker/legacy_linker_jni.h"

Expand Down
28 changes: 14 additions & 14 deletions base/android/linker/linker_jni.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// This is the Android-specific Chromium linker, a tiny shared library
// implementing a custom dynamic linker that can be used to load the
// real Chromium libraries.

// The main point of this linker is to be able to share the RELRO
// section of libcontentshell.so (or equivalent) between the browser and
// renderer process.

// This source code *cannot* depend on anything from base/ or the C++
// STL, to keep the final library small, and avoid ugly dependency issues.
// This is the Android-specific Chromium dynamic linker (loader of dynamic
// libraries), a tiny shared library implementing a custom dynamic linker that
// can be used to load the real Chromium libraries.
//
// The purpose of this custom linker is to be able to share the RELRO section of
// libcontentshell.so (or equivalent) between the browser process and all other
// processes it asks to create.
//
// This source code *cannot* depend on anything from //base or the C++ standard
// library to keep this DSO small and avoid dependency issues. An exception is
// made for std::unique_ptr as a risky header-only definition.

#ifndef BASE_ANDROID_LINKER_LINKER_JNI_H_
#define BASE_ANDROID_LINKER_LINKER_JNI_H_
Expand Down Expand Up @@ -92,17 +93,16 @@ class String {
size_t size_;
};

// Return true iff |address| is a valid address for the target CPU.
// Returns true iff casting a java-side |address| to uintptr_t does not lose
// bits.
inline bool IsValidAddress(jlong address) {
return static_cast<jlong>(static_cast<uintptr_t>(address)) == address;
}

// Find the jclass JNI reference corresponding to a given |class_name|.
// |env| is the current JNI environment handle.
// On success, return true and set |*clazz|.
extern bool InitClassReference(JNIEnv* env,
const char* class_name,
jclass* clazz);
bool InitClassReference(JNIEnv* env, const char* class_name, jclass* clazz);

// Initialize a jfieldID corresponding to the field of a given |clazz|,
// with name |field_name| and signature |field_sig|.
Expand Down

0 comments on commit 56343f4

Please sign in to comment.