Merge "Delete legacy fs-verity support" am: 81568fa22f am: b4661e274c
Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1966068 Change-Id: I797f197a29a811795fc5be5339be1afbde2e5fcd
This commit is contained in:
@@ -407,20 +407,6 @@ public class ApkSignatureSchemeV2Verifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] generateApkVerityRootHash(String apkPath)
|
|
||||||
throws IOException, SignatureNotFoundException, DigestException,
|
|
||||||
NoSuchAlgorithmException {
|
|
||||||
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
|
|
||||||
SignatureInfo signatureInfo = findSignature(apk);
|
|
||||||
VerifiedSigner vSigner = verify(apk, false);
|
|
||||||
if (vSigner.verityRootHash == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return VerityBuilder.generateApkVerityRootHash(
|
|
||||||
apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verified APK Signature Scheme v2 signer.
|
* Verified APK Signature Scheme v2 signer.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -444,20 +444,6 @@ public class ApkSignatureSchemeV3Verifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static byte[] generateApkVerityRootHash(String apkPath)
|
|
||||||
throws NoSuchAlgorithmException, DigestException, IOException,
|
|
||||||
SignatureNotFoundException {
|
|
||||||
try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) {
|
|
||||||
SignatureInfo signatureInfo = findSignature(apk);
|
|
||||||
VerifiedSigner vSigner = verify(apk, false);
|
|
||||||
if (vSigner.verityRootHash == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return VerityBuilder.generateApkVerityRootHash(
|
|
||||||
apk, ByteBuffer.wrap(vSigner.verityRootHash), signatureInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verified APK Signature Scheme v3 signer, including the proof of rotation structure.
|
* Verified APK Signature Scheme v3 signer, including the proof of rotation structure.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -550,27 +550,6 @@ public class ApkSignatureVerifier {
|
|||||||
return ApkSignatureSchemeV2Verifier.generateApkVerity(apkPath, bufferFactory);
|
return ApkSignatureSchemeV2Verifier.generateApkVerity(apkPath, bufferFactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates the FSVerity root hash from FSVerity header, extensions and Merkle tree root hash
|
|
||||||
* in Signing Block.
|
|
||||||
*
|
|
||||||
* @return FSverity root hash
|
|
||||||
*/
|
|
||||||
public static byte[] generateApkVerityRootHash(String apkPath)
|
|
||||||
throws NoSuchAlgorithmException, DigestException, IOException {
|
|
||||||
// first try v3
|
|
||||||
try {
|
|
||||||
return ApkSignatureSchemeV3Verifier.generateApkVerityRootHash(apkPath);
|
|
||||||
} catch (SignatureNotFoundException e) {
|
|
||||||
// try older version
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
return ApkSignatureSchemeV2Verifier.generateApkVerityRootHash(apkPath);
|
|
||||||
} catch (SignatureNotFoundException e) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extended signing details.
|
* Extended signing details.
|
||||||
* @hide for internal use only.
|
* @hide for internal use only.
|
||||||
|
|||||||
@@ -143,25 +143,6 @@ public abstract class VerityBuilder {
|
|||||||
return generateFsVerityTreeInternal(apk, salt, levelOffset, tree);
|
return generateFsVerityTreeInternal(apk, salt, levelOffset, tree);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Calculates the apk-verity root hash for integrity measurement. This needs to be consistent
|
|
||||||
* to what kernel returns.
|
|
||||||
*/
|
|
||||||
@NonNull
|
|
||||||
static byte[] generateApkVerityRootHash(@NonNull RandomAccessFile apk,
|
|
||||||
@NonNull ByteBuffer apkDigest, @NonNull SignatureInfo signatureInfo)
|
|
||||||
throws NoSuchAlgorithmException, DigestException, IOException {
|
|
||||||
assertSigningBlockAlignedAndHasFullPages(signatureInfo);
|
|
||||||
|
|
||||||
ByteBuffer footer = ByteBuffer.allocate(CHUNK_SIZE_BYTES).order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
generateApkVerityFooter(apk, signatureInfo, footer);
|
|
||||||
footer.flip();
|
|
||||||
|
|
||||||
MessageDigest md = MessageDigest.getInstance(JCA_DIGEST_ALGORITHM);
|
|
||||||
md.update(footer);
|
|
||||||
md.update(apkDigest);
|
|
||||||
return md.digest();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates the apk-verity header and hash tree to be used by kernel for the given apk. This
|
* Generates the apk-verity header and hash tree to be used by kernel for the given apk. This
|
||||||
|
|||||||
@@ -18,28 +18,15 @@ package com.android.internal.security;
|
|||||||
|
|
||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.SharedMemory;
|
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.system.ErrnoException;
|
|
||||||
import android.system.Os;
|
import android.system.Os;
|
||||||
import android.system.OsConstants;
|
import android.system.OsConstants;
|
||||||
import android.util.Pair;
|
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.util.apk.ApkSignatureVerifier;
|
|
||||||
import android.util.apk.ByteBufferFactory;
|
|
||||||
import android.util.apk.SignatureNotFoundException;
|
|
||||||
|
|
||||||
import libcore.util.HexEncoding;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.security.DigestException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
|
|
||||||
/** Provides fsverity related operations. */
|
/** Provides fsverity related operations. */
|
||||||
public abstract class VerityUtils {
|
public abstract class VerityUtils {
|
||||||
@@ -57,8 +44,6 @@ public abstract class VerityUtils {
|
|||||||
/** SHA256 hash size. */
|
/** SHA256 hash size. */
|
||||||
private static final int HASH_SIZE_BYTES = 32;
|
private static final int HASH_SIZE_BYTES = 32;
|
||||||
|
|
||||||
private static final boolean DEBUG = false;
|
|
||||||
|
|
||||||
public static boolean isFsVeritySupported() {
|
public static boolean isFsVeritySupported() {
|
||||||
return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R
|
return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.R
|
||||||
|| SystemProperties.getInt("ro.apk_verity.mode", 0) == 2;
|
|| SystemProperties.getInt("ro.apk_verity.mode", 0) == 2;
|
||||||
@@ -123,204 +108,4 @@ public abstract class VerityUtils {
|
|||||||
private static native int measureFsverityNative(@NonNull String filePath,
|
private static native int measureFsverityNative(@NonNull String filePath,
|
||||||
@NonNull byte[] digest);
|
@NonNull byte[] digest);
|
||||||
private static native int statxForFsverityNative(@NonNull String filePath);
|
private static native int statxForFsverityNative(@NonNull String filePath);
|
||||||
|
|
||||||
/**
|
|
||||||
* Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped.
|
|
||||||
*
|
|
||||||
* @deprecated This is only used for previous fs-verity implementation, and should never be used
|
|
||||||
* on new devices.
|
|
||||||
* @return {@code SetupResult} that contains the result code, and when success, the
|
|
||||||
* {@code FileDescriptor} to read all the data from.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath);
|
|
||||||
}
|
|
||||||
SharedMemory shm = null;
|
|
||||||
try {
|
|
||||||
final byte[] signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath);
|
|
||||||
if (signedVerityHash == null) {
|
|
||||||
if (DEBUG) {
|
|
||||||
Slog.d(TAG, "Skip verity tree generation since there is no signed root hash");
|
|
||||||
}
|
|
||||||
return SetupResult.skipped();
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<SharedMemory, Integer> result =
|
|
||||||
generateFsVerityIntoSharedMemory(apkPath, signedVerityHash);
|
|
||||||
shm = result.first;
|
|
||||||
int contentSize = result.second;
|
|
||||||
FileDescriptor rfd = shm.getFileDescriptor();
|
|
||||||
if (rfd == null || !rfd.valid()) {
|
|
||||||
return SetupResult.failed();
|
|
||||||
}
|
|
||||||
return SetupResult.ok(Os.dup(rfd), contentSize);
|
|
||||||
} catch (IOException | SecurityException | DigestException | NoSuchAlgorithmException
|
|
||||||
| SignatureNotFoundException | ErrnoException e) {
|
|
||||||
Slog.e(TAG, "Failed to set up apk verity: ", e);
|
|
||||||
return SetupResult.failed();
|
|
||||||
} finally {
|
|
||||||
if (shm != null) {
|
|
||||||
shm.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@see ApkSignatureVerifier#generateApkVerityRootHash(String)}.
|
|
||||||
* @deprecated This is only used for previous fs-verity implementation, and should never be used
|
|
||||||
* on new devices.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static byte[] generateApkVerityRootHash(@NonNull String apkPath)
|
|
||||||
throws NoSuchAlgorithmException, DigestException, IOException {
|
|
||||||
return ApkSignatureVerifier.generateApkVerityRootHash(apkPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@see ApkSignatureVerifier#getVerityRootHash(String)}.
|
|
||||||
* @deprecated This is only used for previous fs-verity implementation, and should never be used
|
|
||||||
* on new devices.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static byte[] getVerityRootHash(@NonNull String apkPath)
|
|
||||||
throws IOException, SignatureNotFoundException {
|
|
||||||
return ApkSignatureVerifier.getVerityRootHash(apkPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a pair of {@code SharedMemory} and {@code Integer}. The {@code SharedMemory} contains
|
|
||||||
* Merkle tree and fsverity headers for the given apk, in the form that can immediately be used
|
|
||||||
* for fsverity setup. The data is aligned to the beginning of {@code SharedMemory}, and has
|
|
||||||
* length equals to the returned {@code Integer}.
|
|
||||||
*/
|
|
||||||
private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath,
|
|
||||||
@NonNull byte[] expectedRootHash)
|
|
||||||
throws IOException, DigestException, NoSuchAlgorithmException,
|
|
||||||
SignatureNotFoundException {
|
|
||||||
TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory();
|
|
||||||
byte[] generatedRootHash =
|
|
||||||
ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory);
|
|
||||||
// We only generate Merkle tree once here, so it's important to make sure the root hash
|
|
||||||
// matches the signed one in the apk.
|
|
||||||
if (!Arrays.equals(expectedRootHash, generatedRootHash)) {
|
|
||||||
throw new SecurityException("verity hash mismatch: "
|
|
||||||
+ bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash));
|
|
||||||
}
|
|
||||||
|
|
||||||
int contentSize = shmBufferFactory.getBufferLimit();
|
|
||||||
SharedMemory shm = shmBufferFactory.releaseSharedMemory();
|
|
||||||
if (shm == null) {
|
|
||||||
throw new IllegalStateException("Failed to generate verity tree into shared memory");
|
|
||||||
}
|
|
||||||
if (!shm.setProtect(OsConstants.PROT_READ)) {
|
|
||||||
throw new SecurityException("Failed to set up shared memory correctly");
|
|
||||||
}
|
|
||||||
return Pair.create(shm, contentSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String bytesToString(byte[] bytes) {
|
|
||||||
return HexEncoding.encodeToString(bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated This is only used for previous fs-verity implementation, and should never be used
|
|
||||||
* on new devices.
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public static class SetupResult {
|
|
||||||
/** Result code if verity is set up correctly. */
|
|
||||||
private static final int RESULT_OK = 1;
|
|
||||||
|
|
||||||
/** Result code if signature is not provided. */
|
|
||||||
private static final int RESULT_SKIPPED = 2;
|
|
||||||
|
|
||||||
/** Result code if the setup failed. */
|
|
||||||
private static final int RESULT_FAILED = 3;
|
|
||||||
|
|
||||||
private final int mCode;
|
|
||||||
private final FileDescriptor mFileDescriptor;
|
|
||||||
private final int mContentSize;
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
@Deprecated
|
|
||||||
public static SetupResult ok(@NonNull FileDescriptor fileDescriptor, int contentSize) {
|
|
||||||
return new SetupResult(RESULT_OK, fileDescriptor, contentSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
@Deprecated
|
|
||||||
public static SetupResult skipped() {
|
|
||||||
return new SetupResult(RESULT_SKIPPED, null, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @deprecated */
|
|
||||||
@Deprecated
|
|
||||||
public static SetupResult failed() {
|
|
||||||
return new SetupResult(RESULT_FAILED, null, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
private SetupResult(int code, FileDescriptor fileDescriptor, int contentSize) {
|
|
||||||
this.mCode = code;
|
|
||||||
this.mFileDescriptor = fileDescriptor;
|
|
||||||
this.mContentSize = contentSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isFailed() {
|
|
||||||
return mCode == RESULT_FAILED;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isOk() {
|
|
||||||
return mCode == RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
public @NonNull FileDescriptor getUnownedFileDescriptor() {
|
|
||||||
return mFileDescriptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getContentSize() {
|
|
||||||
return mContentSize;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** A {@code ByteBufferFactory} that creates a shared memory backed {@code ByteBuffer}. */
|
|
||||||
private static class TrackedShmBufferFactory implements ByteBufferFactory {
|
|
||||||
private SharedMemory mShm;
|
|
||||||
private ByteBuffer mBuffer;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ByteBuffer create(int capacity) {
|
|
||||||
try {
|
|
||||||
if (DEBUG) Slog.d(TAG, "Creating shared memory for apk verity");
|
|
||||||
// NB: This method is supposed to be called once according to the contract with
|
|
||||||
// ApkSignatureSchemeV2Verifier.
|
|
||||||
if (mBuffer != null) {
|
|
||||||
throw new IllegalStateException("Multiple instantiation from this factory");
|
|
||||||
}
|
|
||||||
mShm = SharedMemory.create("apkverity", capacity);
|
|
||||||
if (!mShm.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE)) {
|
|
||||||
throw new SecurityException("Failed to set protection");
|
|
||||||
}
|
|
||||||
mBuffer = mShm.mapReadWrite();
|
|
||||||
return mBuffer;
|
|
||||||
} catch (ErrnoException e) {
|
|
||||||
throw new SecurityException("Failed to set protection", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public SharedMemory releaseSharedMemory() {
|
|
||||||
if (mBuffer != null) {
|
|
||||||
SharedMemory.unmap(mBuffer);
|
|
||||||
mBuffer = null;
|
|
||||||
}
|
|
||||||
SharedMemory tmp = mShm;
|
|
||||||
mShm = null;
|
|
||||||
return tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getBufferLimit() {
|
|
||||||
return mBuffer == null ? -1 : mBuffer.limit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,6 @@ import com.android.server.SystemService;
|
|||||||
import dalvik.system.BlockGuard;
|
import dalvik.system.BlockGuard;
|
||||||
import dalvik.system.VMRuntime;
|
import dalvik.system.VMRuntime;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@@ -681,28 +680,6 @@ public class Installer extends SystemService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)
|
|
||||||
throws InstallerException {
|
|
||||||
if (!checkBeforeRemote()) return;
|
|
||||||
BlockGuard.getVmPolicy().onPathAccess(filePath);
|
|
||||||
try {
|
|
||||||
mInstalld.installApkVerity(filePath, verityInput, contentSize);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw InstallerException.from(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertFsverityRootHashMatches(String filePath, @NonNull byte[] expectedHash)
|
|
||||||
throws InstallerException {
|
|
||||||
if (!checkBeforeRemote()) return;
|
|
||||||
BlockGuard.getVmPolicy().onPathAccess(filePath);
|
|
||||||
try {
|
|
||||||
mInstalld.assertFsverityRootHashMatches(filePath, expectedHash);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw InstallerException.from(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
|
public boolean reconcileSecondaryDexFile(String apkPath, String packageName, int uid,
|
||||||
String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
|
String[] isas, @Nullable String volumeUuid, int flags) throws InstallerException {
|
||||||
for (int i = 0; i < isas.length; i++) {
|
for (int i = 0; i < isas.length; i++) {
|
||||||
|
|||||||
@@ -12118,14 +12118,14 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
* Returns if forced apk verification can be skipped for the whole package, including splits.
|
* Returns if forced apk verification can be skipped for the whole package, including splits.
|
||||||
*/
|
*/
|
||||||
private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
|
private boolean canSkipForcedPackageVerification(AndroidPackage pkg) {
|
||||||
if (!canSkipForcedApkVerification(pkg.getBaseApkPath())) {
|
if (!VerityUtils.hasFsverity(pkg.getBaseApkPath())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// TODO: Allow base and splits to be verified individually.
|
// TODO: Allow base and splits to be verified individually.
|
||||||
String[] splitCodePaths = pkg.getSplitCodePaths();
|
String[] splitCodePaths = pkg.getSplitCodePaths();
|
||||||
if (!ArrayUtils.isEmpty(splitCodePaths)) {
|
if (!ArrayUtils.isEmpty(splitCodePaths)) {
|
||||||
for (int i = 0; i < splitCodePaths.length; i++) {
|
for (int i = 0; i < splitCodePaths.length; i++) {
|
||||||
if (!canSkipForcedApkVerification(splitCodePaths[i])) {
|
if (!VerityUtils.hasFsverity(splitCodePaths[i])) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -12133,33 +12133,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns if forced apk verification can be skipped, depending on current FSVerity setup and
|
|
||||||
* whether the apk contains signed root hash. Note that the signer's certificate still needs to
|
|
||||||
* match one in a trusted source, and should be done separately.
|
|
||||||
*/
|
|
||||||
private boolean canSkipForcedApkVerification(String apkPath) {
|
|
||||||
if (!PackageManagerServiceUtils.isLegacyApkVerityEnabled()) {
|
|
||||||
return VerityUtils.hasFsverity(apkPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final byte[] rootHashObserved = VerityUtils.generateApkVerityRootHash(apkPath);
|
|
||||||
if (rootHashObserved == null) {
|
|
||||||
return false; // APK does not contain Merkle tree root hash.
|
|
||||||
}
|
|
||||||
synchronized (mInstallLock) {
|
|
||||||
// Returns whether the observed root hash matches what kernel has.
|
|
||||||
mInstaller.assertFsverityRootHashMatches(apkPath, rootHashObserved);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (InstallerException | IOException | DigestException |
|
|
||||||
NoSuchAlgorithmException e) {
|
|
||||||
Slog.w(TAG, "Error in fsverity check. Fallback to full apk verification.", e);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a new package to the internal data structures during platform initialization.
|
* Adds a new package to the internal data structures during platform initialization.
|
||||||
* <p>After adding, the package is known to the system and available for querying.
|
* <p>After adding, the package is known to the system and available for querying.
|
||||||
@@ -21192,9 +21165,7 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
*/
|
*/
|
||||||
private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
|
private void setUpFsVerityIfPossible(AndroidPackage pkg) throws InstallerException,
|
||||||
PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
|
PrepareFailure, IOException, DigestException, NoSuchAlgorithmException {
|
||||||
final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
|
if (!PackageManagerServiceUtils.isApkVerityEnabled()) {
|
||||||
final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
|
|
||||||
if (!standardMode && !legacyMode) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21205,19 +21176,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
|
|
||||||
// Collect files we care for fs-verity setup.
|
// Collect files we care for fs-verity setup.
|
||||||
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
|
ArrayMap<String, String> fsverityCandidates = new ArrayMap<>();
|
||||||
if (legacyMode) {
|
|
||||||
synchronized (mLock) {
|
|
||||||
final PackageSetting ps = mSettings.getPackageLPr(pkg.getPackageName());
|
|
||||||
if (ps != null && ps.isPrivileged()) {
|
|
||||||
fsverityCandidates.put(pkg.getBaseApkPath(), null);
|
|
||||||
if (pkg.getSplitCodePaths() != null) {
|
|
||||||
for (String splitPath : pkg.getSplitCodePaths()) {
|
|
||||||
fsverityCandidates.put(splitPath, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// NB: These files will become only accessible if the signing key is loaded in kernel's
|
// NB: These files will become only accessible if the signing key is loaded in kernel's
|
||||||
// .fs-verity keyring.
|
// .fs-verity keyring.
|
||||||
fsverityCandidates.put(pkg.getBaseApkPath(),
|
fsverityCandidates.put(pkg.getBaseApkPath(),
|
||||||
@@ -21240,13 +21198,11 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
|
for (Map.Entry<String, String> entry : fsverityCandidates.entrySet()) {
|
||||||
final String filePath = entry.getKey();
|
final String filePath = entry.getKey();
|
||||||
final String signaturePath = entry.getValue();
|
final String signaturePath = entry.getValue();
|
||||||
|
|
||||||
if (!legacyMode) {
|
|
||||||
// fs-verity is optional for now. Only set up if signature is provided.
|
// fs-verity is optional for now. Only set up if signature is provided.
|
||||||
if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
|
if (new File(signaturePath).exists() && !VerityUtils.hasFsverity(filePath)) {
|
||||||
try {
|
try {
|
||||||
@@ -21256,31 +21212,6 @@ public class PackageManagerService extends IPackageManager.Stub
|
|||||||
"Failed to enable fs-verity: " + e);
|
"Failed to enable fs-verity: " + e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN.
|
|
||||||
final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(filePath);
|
|
||||||
if (result.isOk()) {
|
|
||||||
if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling verity to " + filePath);
|
|
||||||
final FileDescriptor fd = result.getUnownedFileDescriptor();
|
|
||||||
try {
|
|
||||||
final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath);
|
|
||||||
try {
|
|
||||||
// A file may already have fs-verity, e.g. when reused during a split
|
|
||||||
// install. If the measurement succeeds, no need to attempt to set up.
|
|
||||||
mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
|
|
||||||
} catch (InstallerException e) {
|
|
||||||
mInstaller.installApkVerity(filePath, fd, result.getContentSize());
|
|
||||||
mInstaller.assertFsverityRootHashMatches(filePath, rootHash);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
IoUtils.closeQuietly(fd);
|
|
||||||
}
|
|
||||||
} else if (result.isFailed()) {
|
|
||||||
throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE,
|
|
||||||
"Failed to generate verity");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -591,12 +591,6 @@ public class PackageManagerServiceUtils {
|
|||||||
/** Default is to not use fs-verity since it depends on kernel support. */
|
/** Default is to not use fs-verity since it depends on kernel support. */
|
||||||
private static final int FSVERITY_DISABLED = 0;
|
private static final int FSVERITY_DISABLED = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Experimental implementation targeting priv apps, with Android specific kernel patches to
|
|
||||||
* extend fs-verity.
|
|
||||||
*/
|
|
||||||
private static final int FSVERITY_LEGACY = 1;
|
|
||||||
|
|
||||||
/** Standard fs-verity. */
|
/** Standard fs-verity. */
|
||||||
private static final int FSVERITY_ENABLED = 2;
|
private static final int FSVERITY_ENABLED = 2;
|
||||||
|
|
||||||
@@ -607,10 +601,6 @@ public class PackageManagerServiceUtils {
|
|||||||
== FSVERITY_ENABLED;
|
== FSVERITY_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static boolean isLegacyApkVerityEnabled() {
|
|
||||||
return SystemProperties.getInt("ro.apk_verity.mode", FSVERITY_DISABLED) == FSVERITY_LEGACY;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns true to force apk verification if the package is considered privileged. */
|
/** Returns true to force apk verification if the package is considered privileged. */
|
||||||
static boolean isApkVerificationForced(@Nullable PackageSetting ps) {
|
static boolean isApkVerificationForced(@Nullable PackageSetting ps) {
|
||||||
// TODO(b/154310064): re-enable.
|
// TODO(b/154310064): re-enable.
|
||||||
|
|||||||
Reference in New Issue
Block a user