Loading services/core/java/com/android/server/pm/PackageManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -16004,7 +16004,8 @@ public class PackageManagerService extends IPackageManager.Stub } if (apkPath != null) { final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(apkPath); VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */, true /* skipSigningBlock */); if (result.isOk()) { if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath); FileDescriptor fd = result.getUnownedFileDescriptor(); services/core/java/com/android/server/security/VerityUtils.java +145 −15 Original line number Diff line number Diff line Loading @@ -26,42 +26,76 @@ import android.system.Os; import android.util.Pair; import android.util.Slog; import android.util.apk.ApkSignatureVerifier; import android.util.apk.ApkVerityBuilder; import android.util.apk.ByteBufferFactory; import android.util.apk.SignatureNotFoundException; import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import sun.security.pkcs.PKCS7; /** Provides fsverity related operations. */ abstract public class VerityUtils { private static final String TAG = "VerityUtils"; /** The maximum size of signature file. This is just to avoid potential abuse. */ private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192; private static final boolean DEBUG = false; /** * Generates Merkle tree and fsverity metadata. * Generates Merkle tree and fs-verity metadata. * * @return {@code SetupResult} that contains the {@code EsetupResultCode}, and when success, the * @return {@code SetupResult} that contains the result code, and when success, the * {@code FileDescriptor} to read all the data from. */ public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { if (DEBUG) Slog.d(TAG, "Trying to install apk verity to " + apkPath); public static SetupResult generateApkVeritySetupData(@NonNull String apkPath, String signaturePath, boolean skipSigningBlock) { if (DEBUG) { Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file " + signaturePath); } SharedMemory shm = null; try { byte[] signedRootHash = ApkSignatureVerifier.getVerityRootHash(apkPath); if (signedRootHash == null) { byte[] signedVerityHash; if (skipSigningBlock) { signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath); } else { Path path = Paths.get(signaturePath); if (Files.exists(path)) { // TODO(112037636): fail early if the signing key is not in .fs-verity keyring. PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path)); signedVerityHash = pkcs7.getContentInfo().getContentBytes(); if (DEBUG) { Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash)); } } else { signedVerityHash = null; } } if (signedVerityHash == null) { if (DEBUG) { Slog.d(TAG, "Skip verity tree generation since there is no root hash"); Slog.d(TAG, "Skip verity tree generation since there is no signed root hash"); } return SetupResult.skipped(); } Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath, signedRootHash); Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, signaturePath, signedVerityHash, skipSigningBlock); shm = result.first; int contentSize = result.second; FileDescriptor rfd = shm.getFileDescriptor(); Loading Loading @@ -96,23 +130,115 @@ abstract public class VerityUtils { return ApkSignatureVerifier.getVerityRootHash(apkPath); } /** * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and * extensions, including a PKCS#7 signature provided in {@code signaturePath}. * * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code * ByteBuffer}. The data will be used outside this method via the factory itself. * * @return fs-verity measurement of {@code filePath}, which is a SHA-256 of fs-verity descriptor * and authenticated extensions. */ private static byte[] generateFsverityMetadata(String filePath, String signaturePath, @NonNull TrackedShmBufferFactory trackedBufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateFsVerityTree( file, trackedBufferFactory); ByteBuffer buffer = result.verityData; buffer.position(result.merkleTreeSize); return generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath, buffer); } } /** * Generates fs-verity descriptor including the extensions to the {@code output} and returns the * fs-verity measurement. * * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated * extensions. */ private static byte[] generateFsverityDescriptorAndMeasurement( @NonNull RandomAccessFile file, @NonNull byte[] rootHash, @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output) throws IOException, NoSuchAlgorithmException, DigestException { final short kRootHashExtensionId = 1; final short kPkcs7SignatureExtensionId = 3; final int origPosition = output.position(); // For generating fs-verity file measurement, which consists of the descriptor and // authenticated extensions (but not unauthenticated extensions and the footer). MessageDigest md = MessageDigest.getInstance("SHA-256"); // 1. Generate fs-verity descriptor. final byte[] desc = constructFsverityDescriptorNative(file.length()); output.put(desc); md.update(desc); // 2. Generate authenticated extensions. final byte[] authExt = constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length); output.put(authExt); output.put(rootHash); md.update(authExt); md.update(rootHash); // 3. Generate unauthenticated extensions. ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); output.putShort((short) 1); // number of unauthenticated extensions below output.position(output.position() + 6); // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be // done by the caller if needed). Path path = Paths.get(pkcs7SignaturePath); if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) { throw new IllegalArgumentException("Signature size is unexpectedly large: " + pkcs7SignaturePath); } final byte[] pkcs7Signature = Files.readAllBytes(path); output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId, pkcs7Signature.length)); output.put(pkcs7Signature); // 4. Generate the footer. output.put(constructFsverityFooterNative(output.position() - origPosition)); return md.digest(); } private static native byte[] constructFsverityDescriptorNative(long fileSize); private static native byte[] constructFsverityExtensionNative(short extensionId, int extensionDataSize); private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead); /** * 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> generateApkVerityIntoSharedMemory( String apkPath, byte[] expectedRootHash) private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory( String apkPath, String signaturePath, @NonNull byte[] expectedRootHash, boolean skipSigningBlock) throws IOException, SecurityException, DigestException, NoSuchAlgorithmException, SignatureNotFoundException { TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); byte[] generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); byte[] generatedRootHash; if (skipSigningBlock) { generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); } else { generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, 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("Locally generated verity root hash does not match"); throw new SecurityException("verity hash mismatch: " + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash)); } int contentSize = shmBufferFactory.getBufferLimit(); Loading @@ -126,11 +252,15 @@ abstract public class VerityUtils { return Pair.create(shm, contentSize); } private static String bytesToString(byte[] bytes) { return HexEncoding.encodeToString(bytes); } public static class SetupResult { /** Result code if verity is set up correctly. */ private static final int RESULT_OK = 1; /** Result code if the apk does not contain a verity root hash. */ /** Result code if signature is not provided. */ private static final int RESULT_SKIPPED = 2; /** Result code if the setup failed. */ Loading services/core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ cc_library_static { "com_android_server_locksettings_SyntheticPasswordManager.cpp", "com_android_server_net_NetworkStatsService.cpp", "com_android_server_power_PowerManagerService.cpp", "com_android_server_security_VerityUtils.cpp", "com_android_server_SerialService.cpp", "com_android_server_storage_AppFuseBridge.cpp", "com_android_server_SystemServer.cpp", Loading services/core/jni/com_android_server_security_VerityUtils.cpp 0 → 100644 +137 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VerityUtils" #include <nativehelper/JNIHelp.h> #include "jni.h" #include <utils/Log.h> #include <string.h> // TODO(112037636): Always include once fsverity.h is upstreamed and backported. #define HAS_FSVERITY 0 #if HAS_FSVERITY #include <linux/fsverity.h> #endif namespace android { namespace { class JavaByteArrayHolder { public: static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) { return new JavaByteArrayHolder(env, size); } jbyte* getRaw() { return mElements; } jbyteArray release() { mEnv->ReleaseByteArrayElements(mBytes, mElements, 0); mElements = nullptr; return mBytes; } private: JavaByteArrayHolder(JNIEnv* env, jsize size) { mEnv = env; mBytes = mEnv->NewByteArray(size); mElements = mEnv->GetByteArrayElements(mBytes, nullptr); memset(mElements, 0, size); } virtual ~JavaByteArrayHolder() { LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released"); } JNIEnv* mEnv; jbyteArray mBytes; jbyte* mElements; }; jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor)); fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw()); memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic)); desc->major_version = 1; desc->minor_version = 0; desc->log_data_blocksize = 12; desc->log_tree_blocksize = 12; desc->data_algorithm = FS_VERITY_ALG_SHA256; desc->tree_algorithm = FS_VERITY_ALG_SHA256; desc->flags = 0; desc->orig_file_size = fileSize; desc->auth_ext_count = 1; return raii->release(); #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return 0; #endif // HAS_FSVERITY } jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId, jint extensionDataSize) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension)); fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw()); ext->length = sizeof(fsverity_extension) + extensionDataSize; ext->type = extensionId; return raii->release(); #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return 0; #endif // HAS_FSVERITY } jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, jint offsetToDescriptorHead) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer)); fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw()); footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer); memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic)); return raii->release(); #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return 0; #endif // HAS_FSVERITY } const JNINativeMethod sMethods[] = { { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension }, { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter }, }; } // namespace int register_android_server_security_VerityUtils(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods)); } } // namespace android services/core/jni/onload.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_server_GraphicsStatsService(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); int register_android_server_security_VerityUtils(JNIEnv* env); }; using namespace android; Loading Loading @@ -101,5 +102,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); register_android_server_net_NetworkStatsService(env); register_android_server_security_VerityUtils(env); return JNI_VERSION_1_4; } Loading
services/core/java/com/android/server/pm/PackageManagerService.java +2 −1 Original line number Diff line number Diff line Loading @@ -16004,7 +16004,8 @@ public class PackageManagerService extends IPackageManager.Stub } if (apkPath != null) { final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData(apkPath); VerityUtils.generateApkVeritySetupData(apkPath, null /* signaturePath */, true /* skipSigningBlock */); if (result.isOk()) { if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath); FileDescriptor fd = result.getUnownedFileDescriptor();
services/core/java/com/android/server/security/VerityUtils.java +145 −15 Original line number Diff line number Diff line Loading @@ -26,42 +26,76 @@ import android.system.Os; import android.util.Pair; import android.util.Slog; import android.util.apk.ApkSignatureVerifier; import android.util.apk.ApkVerityBuilder; import android.util.apk.ByteBufferFactory; import android.util.apk.SignatureNotFoundException; import libcore.util.HexEncoding; import java.io.FileDescriptor; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.security.DigestException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; import sun.security.pkcs.PKCS7; /** Provides fsverity related operations. */ abstract public class VerityUtils { private static final String TAG = "VerityUtils"; /** The maximum size of signature file. This is just to avoid potential abuse. */ private static final int MAX_SIGNATURE_FILE_SIZE_BYTES = 8192; private static final boolean DEBUG = false; /** * Generates Merkle tree and fsverity metadata. * Generates Merkle tree and fs-verity metadata. * * @return {@code SetupResult} that contains the {@code EsetupResultCode}, and when success, the * @return {@code SetupResult} that contains the result code, and when success, the * {@code FileDescriptor} to read all the data from. */ public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { if (DEBUG) Slog.d(TAG, "Trying to install apk verity to " + apkPath); public static SetupResult generateApkVeritySetupData(@NonNull String apkPath, String signaturePath, boolean skipSigningBlock) { if (DEBUG) { Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file " + signaturePath); } SharedMemory shm = null; try { byte[] signedRootHash = ApkSignatureVerifier.getVerityRootHash(apkPath); if (signedRootHash == null) { byte[] signedVerityHash; if (skipSigningBlock) { signedVerityHash = ApkSignatureVerifier.getVerityRootHash(apkPath); } else { Path path = Paths.get(signaturePath); if (Files.exists(path)) { // TODO(112037636): fail early if the signing key is not in .fs-verity keyring. PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(path)); signedVerityHash = pkcs7.getContentInfo().getContentBytes(); if (DEBUG) { Slog.d(TAG, "fs-verity measurement = " + bytesToString(signedVerityHash)); } } else { signedVerityHash = null; } } if (signedVerityHash == null) { if (DEBUG) { Slog.d(TAG, "Skip verity tree generation since there is no root hash"); Slog.d(TAG, "Skip verity tree generation since there is no signed root hash"); } return SetupResult.skipped(); } Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath, signedRootHash); Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, signaturePath, signedVerityHash, skipSigningBlock); shm = result.first; int contentSize = result.second; FileDescriptor rfd = shm.getFileDescriptor(); Loading Loading @@ -96,23 +130,115 @@ abstract public class VerityUtils { return ApkSignatureVerifier.getVerityRootHash(apkPath); } /** * Generates fs-verity metadata for {@code filePath} in the buffer created by {@code * trackedBufferFactory}. The metadata contains the Merkle tree, fs-verity descriptor and * extensions, including a PKCS#7 signature provided in {@code signaturePath}. * * <p>It is worthy to note that {@code trackedBufferFactory} generates a "tracked" {@code * ByteBuffer}. The data will be used outside this method via the factory itself. * * @return fs-verity measurement of {@code filePath}, which is a SHA-256 of fs-verity descriptor * and authenticated extensions. */ private static byte[] generateFsverityMetadata(String filePath, String signaturePath, @NonNull TrackedShmBufferFactory trackedBufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateFsVerityTree( file, trackedBufferFactory); ByteBuffer buffer = result.verityData; buffer.position(result.merkleTreeSize); return generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath, buffer); } } /** * Generates fs-verity descriptor including the extensions to the {@code output} and returns the * fs-verity measurement. * * @return fs-verity measurement, which is a SHA-256 of fs-verity descriptor and authenticated * extensions. */ private static byte[] generateFsverityDescriptorAndMeasurement( @NonNull RandomAccessFile file, @NonNull byte[] rootHash, @NonNull String pkcs7SignaturePath, @NonNull ByteBuffer output) throws IOException, NoSuchAlgorithmException, DigestException { final short kRootHashExtensionId = 1; final short kPkcs7SignatureExtensionId = 3; final int origPosition = output.position(); // For generating fs-verity file measurement, which consists of the descriptor and // authenticated extensions (but not unauthenticated extensions and the footer). MessageDigest md = MessageDigest.getInstance("SHA-256"); // 1. Generate fs-verity descriptor. final byte[] desc = constructFsverityDescriptorNative(file.length()); output.put(desc); md.update(desc); // 2. Generate authenticated extensions. final byte[] authExt = constructFsverityExtensionNative(kRootHashExtensionId, rootHash.length); output.put(authExt); output.put(rootHash); md.update(authExt); md.update(rootHash); // 3. Generate unauthenticated extensions. ByteBuffer header = ByteBuffer.allocate(8).order(ByteOrder.LITTLE_ENDIAN); output.putShort((short) 1); // number of unauthenticated extensions below output.position(output.position() + 6); // Generate PKCS#7 extension. NB: We do not verify agaist trusted certificate (should be // done by the caller if needed). Path path = Paths.get(pkcs7SignaturePath); if (Files.size(path) > MAX_SIGNATURE_FILE_SIZE_BYTES) { throw new IllegalArgumentException("Signature size is unexpectedly large: " + pkcs7SignaturePath); } final byte[] pkcs7Signature = Files.readAllBytes(path); output.put(constructFsverityExtensionNative(kPkcs7SignatureExtensionId, pkcs7Signature.length)); output.put(pkcs7Signature); // 4. Generate the footer. output.put(constructFsverityFooterNative(output.position() - origPosition)); return md.digest(); } private static native byte[] constructFsverityDescriptorNative(long fileSize); private static native byte[] constructFsverityExtensionNative(short extensionId, int extensionDataSize); private static native byte[] constructFsverityFooterNative(int offsetToDescriptorHead); /** * 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> generateApkVerityIntoSharedMemory( String apkPath, byte[] expectedRootHash) private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory( String apkPath, String signaturePath, @NonNull byte[] expectedRootHash, boolean skipSigningBlock) throws IOException, SecurityException, DigestException, NoSuchAlgorithmException, SignatureNotFoundException { TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); byte[] generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); byte[] generatedRootHash; if (skipSigningBlock) { generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); } else { generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, 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("Locally generated verity root hash does not match"); throw new SecurityException("verity hash mismatch: " + bytesToString(generatedRootHash) + " != " + bytesToString(expectedRootHash)); } int contentSize = shmBufferFactory.getBufferLimit(); Loading @@ -126,11 +252,15 @@ abstract public class VerityUtils { return Pair.create(shm, contentSize); } private static String bytesToString(byte[] bytes) { return HexEncoding.encodeToString(bytes); } public static class SetupResult { /** Result code if verity is set up correctly. */ private static final int RESULT_OK = 1; /** Result code if the apk does not contain a verity root hash. */ /** Result code if signature is not provided. */ private static final int RESULT_SKIPPED = 2; /** Result code if the setup failed. */ Loading
services/core/jni/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ cc_library_static { "com_android_server_locksettings_SyntheticPasswordManager.cpp", "com_android_server_net_NetworkStatsService.cpp", "com_android_server_power_PowerManagerService.cpp", "com_android_server_security_VerityUtils.cpp", "com_android_server_SerialService.cpp", "com_android_server_storage_AppFuseBridge.cpp", "com_android_server_SystemServer.cpp", Loading
services/core/jni/com_android_server_security_VerityUtils.cpp 0 → 100644 +137 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define LOG_TAG "VerityUtils" #include <nativehelper/JNIHelp.h> #include "jni.h" #include <utils/Log.h> #include <string.h> // TODO(112037636): Always include once fsverity.h is upstreamed and backported. #define HAS_FSVERITY 0 #if HAS_FSVERITY #include <linux/fsverity.h> #endif namespace android { namespace { class JavaByteArrayHolder { public: static JavaByteArrayHolder* newArray(JNIEnv* env, jsize size) { return new JavaByteArrayHolder(env, size); } jbyte* getRaw() { return mElements; } jbyteArray release() { mEnv->ReleaseByteArrayElements(mBytes, mElements, 0); mElements = nullptr; return mBytes; } private: JavaByteArrayHolder(JNIEnv* env, jsize size) { mEnv = env; mBytes = mEnv->NewByteArray(size); mElements = mEnv->GetByteArrayElements(mBytes, nullptr); memset(mElements, 0, size); } virtual ~JavaByteArrayHolder() { LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released"); } JNIEnv* mEnv; jbyteArray mBytes; jbyte* mElements; }; jbyteArray constructFsverityDescriptor(JNIEnv* env, jobject /* clazz */, jlong fileSize) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_descriptor)); fsverity_descriptor* desc = reinterpret_cast<fsverity_descriptor*>(raii->getRaw()); memcpy(desc->magic, FS_VERITY_MAGIC, sizeof(desc->magic)); desc->major_version = 1; desc->minor_version = 0; desc->log_data_blocksize = 12; desc->log_tree_blocksize = 12; desc->data_algorithm = FS_VERITY_ALG_SHA256; desc->tree_algorithm = FS_VERITY_ALG_SHA256; desc->flags = 0; desc->orig_file_size = fileSize; desc->auth_ext_count = 1; return raii->release(); #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return 0; #endif // HAS_FSVERITY } jbyteArray constructFsverityExtension(JNIEnv* env, jobject /* clazz */, jshort extensionId, jint extensionDataSize) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_extension)); fsverity_extension* ext = reinterpret_cast<fsverity_extension*>(raii->getRaw()); ext->length = sizeof(fsverity_extension) + extensionDataSize; ext->type = extensionId; return raii->release(); #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return 0; #endif // HAS_FSVERITY } jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, jint offsetToDescriptorHead) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_footer)); fsverity_footer* footer = reinterpret_cast<fsverity_footer*>(raii->getRaw()); footer->desc_reverse_offset = offsetToDescriptorHead + sizeof(fsverity_footer); memcpy(footer->magic, FS_VERITY_MAGIC, sizeof(footer->magic)); return raii->release(); #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return 0; #endif // HAS_FSVERITY } const JNINativeMethod sMethods[] = { { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension }, { "constructFsverityFooterNative", "(I)[B", (void *)constructFsverityFooter }, }; } // namespace int register_android_server_security_VerityUtils(JNIEnv* env) { return jniRegisterNativeMethods(env, "com/android/server/security/VerityUtils", sMethods, NELEM(sMethods)); } } // namespace android
services/core/jni/onload.cpp +2 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,7 @@ int register_android_server_SyntheticPasswordManager(JNIEnv* env); int register_android_server_GraphicsStatsService(JNIEnv* env); int register_android_hardware_display_DisplayViewport(JNIEnv* env); int register_android_server_net_NetworkStatsService(JNIEnv* env); int register_android_server_security_VerityUtils(JNIEnv* env); }; using namespace android; Loading Loading @@ -101,5 +102,6 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) register_android_server_GraphicsStatsService(env); register_android_hardware_display_DisplayViewport(env); register_android_server_net_NetworkStatsService(env); register_android_server_security_VerityUtils(env); return JNI_VERSION_1_4; }