Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fcff8dd1 authored by Victor Hsieh's avatar Victor Hsieh
Browse files

Provide a way to query fs-verity status

Test: in-development feature works
Bug: 112037636
Change-Id: I58068d7df3f36e911d70f538506bea3d3147c118
parent 9df31e55
Loading
Loading
Loading
Loading
+19 −5
Original line number Diff line number Diff line
@@ -16,13 +16,11 @@

package com.android.server.security;

import static android.system.OsConstants.PROT_READ;
import static android.system.OsConstants.PROT_WRITE;

import android.annotation.NonNull;
import android.os.SharedMemory;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
import android.util.Pair;
import android.util.Slog;
import android.util.apk.ApkSignatureVerifier;
@@ -56,6 +54,21 @@ abstract public class VerityUtils {

    private static final boolean DEBUG = false;

    /** 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,
        // the file is on readable if the measurement can be verified against a trusted key, and
        // this is good enough for installed apps.
        int errno = measureFsverityNative(filePath);
        if (errno != 0) {
            if (errno != OsConstants.ENODATA) {
                Slog.e(TAG, "Failed to measure fs-verity, errno " + errno + ": " + filePath);
            }
            return false;
        }
        return true;
    }

    /**
     * Generates Merkle tree and fs-verity metadata.
     *
@@ -213,6 +226,7 @@ abstract public class VerityUtils {
        return md.digest();
    }

    private static native int measureFsverityNative(@NonNull String filePath);
    private static native byte[] constructFsveritySignedDataNative(@NonNull byte[] measurement);
    private static native byte[] constructFsverityDescriptorNative(long fileSize);
    private static native byte[] constructFsverityExtensionNative(short extensionId,
@@ -249,7 +263,7 @@ abstract public class VerityUtils {
        if (shm == null) {
            throw new IllegalStateException("Failed to generate verity tree into shared memory");
        }
        if (!shm.setProtect(PROT_READ)) {
        if (!shm.setProtect(OsConstants.PROT_READ)) {
            throw new SecurityException("Failed to set up shared memory correctly");
        }
        return Pair.create(shm, contentSize);
@@ -323,7 +337,7 @@ abstract public class VerityUtils {
                    throw new IllegalStateException("Multiple instantiation from this factory");
                }
                mShm = SharedMemory.create("apkverity", capacity);
                if (!mShm.setProtect(PROT_READ | PROT_WRITE)) {
                if (!mShm.setProtect(OsConstants.PROT_READ | OsConstants.PROT_WRITE)) {
                    throw new SecurityException("Failed to set protection");
                }
                mBuffer = mShm.mapReadWrite();
+28 −1
Original line number Diff line number Diff line
@@ -20,13 +20,22 @@
#include "jni.h"
#include <utils/Log.h>

#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>

#include <android-base/unique_fd.h>

// TODO(112037636): Always include once fsverity.h is upstreamed and backported.
#define HAS_FSVERITY 0

#if HAS_FSVERITY
#include <linux/fsverity.h>

const int kSha256Bytes = 32;
#endif

namespace android {
@@ -66,9 +75,26 @@ class JavaByteArrayHolder {
    jbyte* mElements;
};

int measureFsverity(JNIEnv* env, jobject /* clazz */, jstring filePath) {
#if HAS_FSVERITY
    auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest) + kSha256Bytes);
    fsverity_digest* data = reinterpret_cast<fsverity_digest*>(raii->getRaw());
    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));
    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;
#endif  // HAS_FSVERITY
}

jbyteArray constructFsveritySignedData(JNIEnv* env, jobject /* clazz */, jbyteArray digest) {
#if HAS_FSVERITY
    const int kSha256Bytes = 32;
    auto raii = JavaByteArrayHolder::newArray(env, sizeof(fsverity_digest_disk) + kSha256Bytes);
    fsverity_digest_disk* data = reinterpret_cast<fsverity_digest_disk*>(raii->getRaw());

@@ -146,6 +172,7 @@ jbyteArray constructFsverityFooter(JNIEnv* env, jobject /* clazz */,
}

const JNINativeMethod sMethods[] = {
    { "measureFsverityNative", "(Ljava/lang/String;)I", (void *)measureFsverity },
    { "constructFsveritySignedDataNative", "([B)[B", (void *)constructFsveritySignedData },
    { "constructFsverityDescriptorNative", "(J)[B", (void *)constructFsverityDescriptor },
    { "constructFsverityExtensionNative", "(SI)[B", (void *)constructFsverityExtension },