Loading services/core/java/com/android/server/pm/PackageManagerService.java +18 −8 Original line number Diff line number Diff line Loading @@ -16911,19 +16911,29 @@ public class PackageManagerService extends IPackageManager.Stub final String filePath = entry.getKey(); final String signaturePath = entry.getValue(); final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData( filePath, signaturePath, legacyMode); if (!legacyMode) { // fs-verity is optional for now. Only set up if signature is provided. if (new File(signaturePath).exists()) { try { VerityUtils.setUpFsverity(filePath, signaturePath); } catch (IOException | DigestException | NoSuchAlgorithmException | SecurityException e) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, "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 { mInstaller.installApkVerity(filePath, fd, result.getContentSize()); // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN. if (legacyMode) { final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath); mInstaller.assertFsverityRootHashMatches(filePath, rootHash); } } finally { IoUtils.closeQuietly(fd); } services/core/java/com/android/server/security/VerityUtils.java +88 −39 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; Loading @@ -59,6 +60,8 @@ abstract public class 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 int COMMON_LINUX_PAGE_SIZE_IN_BYTES = 4096; private static final boolean DEBUG = false; /** Returns true if the given file looks like containing an fs-verity signature. */ Loading @@ -71,6 +74,48 @@ abstract public class VerityUtils { return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION; } /** Generates Merkle tree and fs-verity metadata then enables fs-verity. */ public static void setUpFsverity(@NonNull String filePath, String signaturePath) throws IOException, DigestException, NoSuchAlgorithmException { final PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(Paths.get(signaturePath))); final byte[] expectedMeasurement = pkcs7.getContentInfo().getContentBytes(); if (DEBUG) { Slog.d(TAG, "Enabling fs-verity with signed fs-verity measurement " + bytesToString(expectedMeasurement)); Slog.d(TAG, "PKCS#7 info: " + pkcs7); } final TrackedBufferFactory bufferFactory = new TrackedBufferFactory(); final byte[] actualMeasurement = generateFsverityMetadata(filePath, signaturePath, bufferFactory); try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) { FileChannel ch = raf.getChannel(); ch.position(roundUpToNextMultiple(ch.size(), COMMON_LINUX_PAGE_SIZE_IN_BYTES)); ByteBuffer buffer = bufferFactory.getBuffer(); long offset = buffer.position(); long size = buffer.limit(); while (offset < size) { long s = ch.write(buffer); offset += s; size -= s; } } if (!Arrays.equals(expectedMeasurement, actualMeasurement)) { throw new SecurityException("fs-verity measurement mismatch: " + bytesToString(actualMeasurement) + " != " + bytesToString(expectedMeasurement)); } // This can fail if the public key is not already in .fs-verity kernel keyring. int errno = enableFsverityNative(filePath); if (errno != 0) { throw new IOException("Failed to enable fs-verity on " + filePath + ": " + Os.strerror(errno)); } } /** Returns whether the file has fs-verity enabled. */ public static boolean hasFsverity(@NonNull String filePath) { // NB: only measure but not check the actual measurement here. As long as this succeeds, Loading @@ -87,36 +132,18 @@ abstract public class VerityUtils { } /** * Generates Merkle tree and fs-verity metadata. * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped. * * @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, String signaturePath, boolean skipSigningBlock) { public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { if (DEBUG) { Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file " + signaturePath); Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath); } SharedMemory shm = null; try { 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; } } 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"); Loading @@ -124,8 +151,8 @@ abstract public class VerityUtils { return SetupResult.skipped(); } Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, signaturePath, signedVerityHash, skipSigningBlock); Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, signedVerityHash); shm = result.first; int contentSize = result.second; FileDescriptor rfd = shm.getFileDescriptor(); Loading Loading @@ -156,7 +183,7 @@ abstract public class VerityUtils { * {@see ApkSignatureVerifier#getVerityRootHash(String)}. */ public static byte[] getVerityRootHash(@NonNull String apkPath) throws IOException, SignatureNotFoundException, SecurityException { throws IOException, SignatureNotFoundException { return ApkSignatureVerifier.getVerityRootHash(apkPath); } Loading @@ -172,9 +199,8 @@ abstract public class VerityUtils { * includes 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 { @NonNull ByteBufferFactory trackedBufferFactory) throws IOException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree( file, trackedBufferFactory); Loading @@ -184,6 +210,7 @@ abstract public class VerityUtils { final byte[] measurement = generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath, buffer); buffer.flip(); return constructFsveritySignedDataNative(measurement); } } Loading Loading @@ -243,6 +270,7 @@ abstract public class VerityUtils { return md.digest(); } private static native int enableFsverityNative(@NonNull String filePath); private static native int measureFsverityNative(@NonNull String filePath); private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement); private static native byte[] constructFsverityDescriptorNative(long fileSize); Loading @@ -256,18 +284,13 @@ abstract public class VerityUtils { * 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, String signaturePath, @NonNull byte[] expectedRootHash, boolean skipSigningBlock) throws IOException, SecurityException, DigestException, NoSuchAlgorithmException, private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath, @NonNull byte[] expectedRootHash) throws IOException, DigestException, NoSuchAlgorithmException, SignatureNotFoundException { TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); byte[] generatedRootHash; if (skipSigningBlock) { generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); } else { generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory); } 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)) { Loading Loading @@ -345,7 +368,7 @@ abstract public class VerityUtils { private ByteBuffer mBuffer; @Override public ByteBuffer create(int capacity) throws SecurityException { 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 Loading Loading @@ -378,4 +401,30 @@ abstract public class VerityUtils { return mBuffer == null ? -1 : mBuffer.limit(); } } /** A {@code ByteBufferFactory} that tracks the {@code ByteBuffer} it creates. */ private static class TrackedBufferFactory implements ByteBufferFactory { private ByteBuffer mBuffer; @Override public ByteBuffer create(int capacity) { if (mBuffer != null) { throw new IllegalStateException("Multiple instantiation from this factory"); } mBuffer = ByteBuffer.allocate(capacity); return mBuffer; } public ByteBuffer getBuffer() { return mBuffer; } } /** Round up the number to the next multiple of the divisor. */ private static long roundUpToNextMultiple(long number, long divisor) { if (number > (Long.MAX_VALUE - divisor)) { throw new IllegalArgumentException("arithmetic overflow"); } return ((number + (divisor - 1)) / divisor) * divisor; } } services/core/jni/com_android_server_security_VerityUtils.cpp +23 −2 Original line number Diff line number Diff line Loading @@ -75,6 +75,23 @@ class JavaByteArrayHolder { jbyte* mElements; }; int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { #if HAS_FSVERITY const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); if (rfd.get() < 0) { return errno; } if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) { return errno; } return 0; #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return ENOSYS; #endif // HAS_FSVERITY } int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes); Loading @@ -82,14 +99,17 @@ int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { data->digest_size = kSha256Bytes; // the only input/output parameter const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY)); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); if (rfd.get() < 0) { return errno; } if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) { return errno; } return 0; #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return -1; return ENOSYS; #endif // HAS_FSVERITY } Loading Loading @@ -172,6 +192,7 @@ jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, } const JNINativeMethod sMethods[] = { { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity }, { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity }, { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData }, { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, Loading Loading
services/core/java/com/android/server/pm/PackageManagerService.java +18 −8 Original line number Diff line number Diff line Loading @@ -16911,19 +16911,29 @@ public class PackageManagerService extends IPackageManager.Stub final String filePath = entry.getKey(); final String signaturePath = entry.getValue(); final VerityUtils.SetupResult result = VerityUtils.generateApkVeritySetupData( filePath, signaturePath, legacyMode); if (!legacyMode) { // fs-verity is optional for now. Only set up if signature is provided. if (new File(signaturePath).exists()) { try { VerityUtils.setUpFsverity(filePath, signaturePath); } catch (IOException | DigestException | NoSuchAlgorithmException | SecurityException e) { throw new PrepareFailure(PackageManager.INSTALL_FAILED_BAD_SIGNATURE, "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 { mInstaller.installApkVerity(filePath, fd, result.getContentSize()); // In legacy mode, fs-verity can only be enabled by process with CAP_SYS_ADMIN. if (legacyMode) { final byte[] rootHash = VerityUtils.generateApkVerityRootHash(filePath); mInstaller.assertFsverityRootHashMatches(filePath, rootHash); } } finally { IoUtils.closeQuietly(fd); }
services/core/java/com/android/server/security/VerityUtils.java +88 −39 Original line number Diff line number Diff line Loading @@ -36,6 +36,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; Loading @@ -59,6 +60,8 @@ abstract public class 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 int COMMON_LINUX_PAGE_SIZE_IN_BYTES = 4096; private static final boolean DEBUG = false; /** Returns true if the given file looks like containing an fs-verity signature. */ Loading @@ -71,6 +74,48 @@ abstract public class VerityUtils { return filePath + FSVERITY_SIGNATURE_FILE_EXTENSION; } /** Generates Merkle tree and fs-verity metadata then enables fs-verity. */ public static void setUpFsverity(@NonNull String filePath, String signaturePath) throws IOException, DigestException, NoSuchAlgorithmException { final PKCS7 pkcs7 = new PKCS7(Files.readAllBytes(Paths.get(signaturePath))); final byte[] expectedMeasurement = pkcs7.getContentInfo().getContentBytes(); if (DEBUG) { Slog.d(TAG, "Enabling fs-verity with signed fs-verity measurement " + bytesToString(expectedMeasurement)); Slog.d(TAG, "PKCS#7 info: " + pkcs7); } final TrackedBufferFactory bufferFactory = new TrackedBufferFactory(); final byte[] actualMeasurement = generateFsverityMetadata(filePath, signaturePath, bufferFactory); try (RandomAccessFile raf = new RandomAccessFile(filePath, "rw")) { FileChannel ch = raf.getChannel(); ch.position(roundUpToNextMultiple(ch.size(), COMMON_LINUX_PAGE_SIZE_IN_BYTES)); ByteBuffer buffer = bufferFactory.getBuffer(); long offset = buffer.position(); long size = buffer.limit(); while (offset < size) { long s = ch.write(buffer); offset += s; size -= s; } } if (!Arrays.equals(expectedMeasurement, actualMeasurement)) { throw new SecurityException("fs-verity measurement mismatch: " + bytesToString(actualMeasurement) + " != " + bytesToString(expectedMeasurement)); } // This can fail if the public key is not already in .fs-verity kernel keyring. int errno = enableFsverityNative(filePath); if (errno != 0) { throw new IOException("Failed to enable fs-verity on " + filePath + ": " + Os.strerror(errno)); } } /** Returns whether the file has fs-verity enabled. */ public static boolean hasFsverity(@NonNull String filePath) { // NB: only measure but not check the actual measurement here. As long as this succeeds, Loading @@ -87,36 +132,18 @@ abstract public class VerityUtils { } /** * Generates Merkle tree and fs-verity metadata. * Generates legacy Merkle tree and fs-verity metadata with Signing Block skipped. * * @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, String signaturePath, boolean skipSigningBlock) { public static SetupResult generateApkVeritySetupData(@NonNull String apkPath) { if (DEBUG) { Slog.d(TAG, "Trying to install apk verity to " + apkPath + " with signature file " + signaturePath); Slog.d(TAG, "Trying to install legacy apk verity to " + apkPath); } SharedMemory shm = null; try { 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; } } 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"); Loading @@ -124,8 +151,8 @@ abstract public class VerityUtils { return SetupResult.skipped(); } Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, signaturePath, signedVerityHash, skipSigningBlock); Pair<SharedMemory, Integer> result = generateFsVerityIntoSharedMemory(apkPath, signedVerityHash); shm = result.first; int contentSize = result.second; FileDescriptor rfd = shm.getFileDescriptor(); Loading Loading @@ -156,7 +183,7 @@ abstract public class VerityUtils { * {@see ApkSignatureVerifier#getVerityRootHash(String)}. */ public static byte[] getVerityRootHash(@NonNull String apkPath) throws IOException, SignatureNotFoundException, SecurityException { throws IOException, SignatureNotFoundException { return ApkSignatureVerifier.getVerityRootHash(apkPath); } Loading @@ -172,9 +199,8 @@ abstract public class VerityUtils { * includes 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 { @NonNull ByteBufferFactory trackedBufferFactory) throws IOException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile file = new RandomAccessFile(filePath, "r")) { VerityBuilder.VerityResult result = VerityBuilder.generateFsVerityTree( file, trackedBufferFactory); Loading @@ -184,6 +210,7 @@ abstract public class VerityUtils { final byte[] measurement = generateFsverityDescriptorAndMeasurement(file, result.rootHash, signaturePath, buffer); buffer.flip(); return constructFsveritySignedDataNative(measurement); } } Loading Loading @@ -243,6 +270,7 @@ abstract public class VerityUtils { return md.digest(); } private static native int enableFsverityNative(@NonNull String filePath); private static native int measureFsverityNative(@NonNull String filePath); private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement); private static native byte[] constructFsverityDescriptorNative(long fileSize); Loading @@ -256,18 +284,13 @@ abstract public class VerityUtils { * 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, String signaturePath, @NonNull byte[] expectedRootHash, boolean skipSigningBlock) throws IOException, SecurityException, DigestException, NoSuchAlgorithmException, private static Pair<SharedMemory, Integer> generateFsVerityIntoSharedMemory(String apkPath, @NonNull byte[] expectedRootHash) throws IOException, DigestException, NoSuchAlgorithmException, SignatureNotFoundException { TrackedShmBufferFactory shmBufferFactory = new TrackedShmBufferFactory(); byte[] generatedRootHash; if (skipSigningBlock) { generatedRootHash = ApkSignatureVerifier.generateApkVerity(apkPath, shmBufferFactory); } else { generatedRootHash = generateFsverityMetadata(apkPath, signaturePath, shmBufferFactory); } 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)) { Loading Loading @@ -345,7 +368,7 @@ abstract public class VerityUtils { private ByteBuffer mBuffer; @Override public ByteBuffer create(int capacity) throws SecurityException { 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 Loading Loading @@ -378,4 +401,30 @@ abstract public class VerityUtils { return mBuffer == null ? -1 : mBuffer.limit(); } } /** A {@code ByteBufferFactory} that tracks the {@code ByteBuffer} it creates. */ private static class TrackedBufferFactory implements ByteBufferFactory { private ByteBuffer mBuffer; @Override public ByteBuffer create(int capacity) { if (mBuffer != null) { throw new IllegalStateException("Multiple instantiation from this factory"); } mBuffer = ByteBuffer.allocate(capacity); return mBuffer; } public ByteBuffer getBuffer() { return mBuffer; } } /** Round up the number to the next multiple of the divisor. */ private static long roundUpToNextMultiple(long number, long divisor) { if (number > (Long.MAX_VALUE - divisor)) { throw new IllegalArgumentException("arithmetic overflow"); } return ((number + (divisor - 1)) / divisor) * divisor; } }
services/core/jni/com_android_server_security_VerityUtils.cpp +23 −2 Original line number Diff line number Diff line Loading @@ -75,6 +75,23 @@ class JavaByteArrayHolder { jbyte* mElements; }; int enableFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { #if HAS_FSVERITY const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); if (rfd.get() < 0) { return errno; } if (ioctl(rfd.get(), FS_IOC_ENABLE_VERITY, nullptr) < 0) { return errno; } return 0; #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return ENOSYS; #endif // HAS_FSVERITY } int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { #if HAS_FSVERITY auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes); Loading @@ -82,14 +99,17 @@ int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) { data->digest_size = kSha256Bytes; // the only input/output parameter const char* path = env->GetStringUTFChars(filePath, nullptr); ::android::base::unique_fd rfd(open(path, O_RDONLY)); ::android::base::unique_fd rfd(open(path, O_RDONLY | O_CLOEXEC)); if (rfd.get() < 0) { return errno; } if (ioctl(rfd.get(), FS_IOC_MEASURE_VERITY, data) < 0) { return errno; } return 0; #else LOG_ALWAYS_FATAL("fs-verity is used while not enabled"); return -1; return ENOSYS; #endif // HAS_FSVERITY } Loading Loading @@ -172,6 +192,7 @@ jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */, } const JNINativeMethod sMethods[] = { { "enableFsverityNative", "(Ljava/lang/String;)I", (void *)enableFsverity }, { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity }, { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData }, { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor }, Loading