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

Commit 01a0288c authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Fix fs-verity per fs-verity spec change" into pi-dev

parents ae202c6f cccad197
Loading
Loading
Loading
Loading
+35 −25
Original line number Diff line number Diff line
@@ -72,22 +72,31 @@ abstract class ApkVerityBuilder {
                signatureInfo.centralDirOffset - signatureInfo.apkSigningBlockOffset;
        long dataSize = apk.length() - signingBlockSize;
        int[] levelOffset = calculateVerityLevelOffset(dataSize);
        int merkleTreeSize = levelOffset[levelOffset.length - 1];

        ByteBuffer output = bufferFactory.create(
                CHUNK_SIZE_BYTES +  // fsverity header + extensions + padding
                levelOffset[levelOffset.length - 1]);  // Merkle tree size
                merkleTreeSize
                + CHUNK_SIZE_BYTES);  // maximum size of fsverity metadata
        output.order(ByteOrder.LITTLE_ENDIAN);

        ByteBuffer header = slice(output, 0, FSVERITY_HEADER_SIZE_BYTES);
        ByteBuffer extensions = slice(output, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES);
        ByteBuffer tree = slice(output, CHUNK_SIZE_BYTES, output.limit());
        ByteBuffer tree = slice(output, 0, merkleTreeSize);
        ByteBuffer header = slice(output, merkleTreeSize,
                merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES);
        ByteBuffer extensions = slice(output, merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES,
                merkleTreeSize + CHUNK_SIZE_BYTES);
        byte[] apkDigestBytes = new byte[DIGEST_SIZE_BYTES];
        ByteBuffer apkDigest = ByteBuffer.wrap(apkDigestBytes);
        apkDigest.order(ByteOrder.LITTLE_ENDIAN);

        // NB: Buffer limit is set inside once finished.
        calculateFsveritySignatureInternal(apk, signatureInfo, tree, apkDigest, header, extensions);

        output.rewind();
        // Put the reverse offset to fs-verity header at the end.
        output.position(merkleTreeSize + FSVERITY_HEADER_SIZE_BYTES + extensions.limit());
        output.putInt(FSVERITY_HEADER_SIZE_BYTES + extensions.limit()
                + 4);  // size of this integer right before EOF
        output.flip();

        return new ApkVerityResult(output, apkDigestBytes);
    }

@@ -101,7 +110,8 @@ abstract class ApkVerityBuilder {
        ByteBuffer verityBlock = ByteBuffer.allocate(CHUNK_SIZE_BYTES)
                .order(ByteOrder.LITTLE_ENDIAN);
        ByteBuffer header = slice(verityBlock, 0, FSVERITY_HEADER_SIZE_BYTES);
        ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES, CHUNK_SIZE_BYTES);
        ByteBuffer extensions = slice(verityBlock, FSVERITY_HEADER_SIZE_BYTES,
                CHUNK_SIZE_BYTES - FSVERITY_HEADER_SIZE_BYTES);

        calculateFsveritySignatureInternal(apk, signatureInfo, null, null, header, extensions);

@@ -328,10 +338,10 @@ abstract class ApkVerityBuilder {
        buffer.put((byte) 12);              // log2(block-size): log2(4096)
        buffer.put((byte) 7);               // log2(leaves-per-node): log2(4096 / 32)

        buffer.putShort((short) 1);         // meta algorithm, SHA256_MODE == 1
        buffer.putShort((short) 1);         // data algorithm, SHA256_MODE == 1
        buffer.putShort((short) 1);         // meta algorithm, SHA256 == 1
        buffer.putShort((short) 1);         // data algorithm, SHA256 == 1

        buffer.putInt(0x0);                 // flags
        buffer.putInt(0);                   // flags
        buffer.putInt(0);                   // reserved

        buffer.putLong(fileSize);           // original file size
@@ -362,12 +372,11 @@ abstract class ApkVerityBuilder {
        //
        // struct fsverity_extension_patch {
        //   __le64 offset;
        //   u8 length;
        //   u8 reserved[7];
        //   u8 databytes[];
        // };

        final int kSizeOfFsverityExtensionHeader = 8;
        final int kExtensionSizeAlignment = 8;

        {
            // struct fsverity_extension #1
@@ -385,23 +394,24 @@ abstract class ApkVerityBuilder {

        {
            // struct fsverity_extension #2
            final int kSizeOfFsverityPatchExtension =
                    8 +  // offset size
                    1 +  // size of length from offset (up to 255)
                    7 +  // reserved
                    ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;
            final int kPadding = (int) divideRoundup(kSizeOfFsverityPatchExtension % 8, 8);
            final int kTotalSize = kSizeOfFsverityExtensionHeader
                    + 8 // offset size
                    + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE;

            buffer.putShort((short)  // total size of extension, padded to 64-bit alignment
                    (kSizeOfFsverityExtensionHeader + kSizeOfFsverityPatchExtension + kPadding));
            buffer.putShort((short) kTotalSize);
            buffer.put((byte) 1);    // ID of patch extension
            skip(buffer, 5);         // reserved

            // struct fsverity_extension_patch
            buffer.putLong(eocdOffset);                                 // offset
            buffer.put((byte) ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_SIZE);  // length
            skip(buffer, 7);                                            // reserved
            buffer.putLong(eocdOffset + ZIP_EOCD_CENTRAL_DIR_OFFSET_FIELD_OFFSET);  // offset
            buffer.putInt(Math.toIntExact(signingBlockOffset));  // databytes

            // The extension needs to be 0-padded at the end, since the length may not be multiple
            // of 8.
            int kPadding = kExtensionSizeAlignment - kTotalSize % kExtensionSizeAlignment;
            if (kPadding == kExtensionSizeAlignment) {
                kPadding = 0;
            }
            skip(buffer, kPadding);                              // padding
        }

+2 −2
Original line number Diff line number Diff line
@@ -484,11 +484,11 @@ public class Installer extends SystemService {
        }
    }

    public void installApkVerity(String filePath, FileDescriptor verityInput)
    public void installApkVerity(String filePath, FileDescriptor verityInput, int contentSize)
            throws InstallerException {
        if (!checkBeforeRemote()) return;
        try {
            mInstalld.installApkVerity(filePath, verityInput);
            mInstalld.installApkVerity(filePath, verityInput, contentSize);
        } catch (Exception e) {
            throw InstallerException.from(e);
        }
+5 −2
Original line number Diff line number Diff line
@@ -17322,8 +17322,11 @@ public class PackageManagerService extends IPackageManager.Stub
                    if (Build.IS_DEBUGGABLE) Slog.i(TAG, "Enabling apk verity to " + apkPath);
                    FileDescriptor fd = result.getUnownedFileDescriptor();
                    try {
                        mInstaller.installApkVerity(apkPath, fd);
                    } catch (InstallerException e) {
                        final byte[] signedRootHash = VerityUtils.generateFsverityRootHash(apkPath);
                        mInstaller.installApkVerity(apkPath, fd, result.getContentSize());
                        mInstaller.assertFsverityRootHashMatches(apkPath, signedRootHash);
                    } catch (InstallerException | IOException | DigestException |
                             NoSuchAlgorithmException e) {
                        res.setError(INSTALL_FAILED_INTERNAL_ERROR,
                                "Failed to set up verity: " + e);
                        return;
+36 −11
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.system.Os;
import android.util.apk.ApkSignatureVerifier;
import android.util.apk.ByteBufferFactory;
import android.util.apk.SignatureNotFoundException;
import android.util.Pair;
import android.util.Slog;

import java.io.FileDescriptor;
@@ -59,12 +60,15 @@ abstract public class VerityUtils {
                return SetupResult.skipped();
            }

            shm = generateApkVerityIntoSharedMemory(apkPath, signedRootHash);
            Pair<SharedMemory, Integer> result = generateApkVerityIntoSharedMemory(apkPath,
                    signedRootHash);
            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));
            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);
@@ -85,10 +89,20 @@ abstract public class VerityUtils {
    }

    /**
     * Returns a {@code SharedMemory} that contains Merkle tree and fsverity headers for the given
     * apk, in the form that can immediately be used for fsverity setup.
     * {@see ApkSignatureVerifier#getVerityRootHash(String)}.
     */
    private static SharedMemory generateApkVerityIntoSharedMemory(
    public static byte[] getVerityRootHash(@NonNull String apkPath)
            throws IOException, SignatureNotFoundException, SecurityException {
        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> generateApkVerityIntoSharedMemory(
            String apkPath, byte[] expectedRootHash)
            throws IOException, SecurityException, DigestException, NoSuchAlgorithmException,
                   SignatureNotFoundException {
@@ -101,6 +115,7 @@ abstract public class VerityUtils {
            throw new SecurityException("Locally generated verity root hash does not match");
        }

        int contentSize = shmBufferFactory.getBufferLimit();
        SharedMemory shm = shmBufferFactory.releaseSharedMemory();
        if (shm == null) {
            throw new IllegalStateException("Failed to generate verity tree into shared memory");
@@ -108,7 +123,7 @@ abstract public class VerityUtils {
        if (!shm.setProtect(PROT_READ)) {
            throw new SecurityException("Failed to set up shared memory correctly");
        }
        return shm;
        return Pair.create(shm, contentSize);
    }

    public static class SetupResult {
@@ -123,22 +138,24 @@ abstract public class VerityUtils {

        private final int mCode;
        private final FileDescriptor mFileDescriptor;
        private final int mContentSize;

        public static SetupResult ok(@NonNull FileDescriptor fileDescriptor) {
            return new SetupResult(RESULT_OK, fileDescriptor);
        public static SetupResult ok(@NonNull FileDescriptor fileDescriptor, int contentSize) {
            return new SetupResult(RESULT_OK, fileDescriptor, contentSize);
        }

        public static SetupResult skipped() {
            return new SetupResult(RESULT_SKIPPED, null);
            return new SetupResult(RESULT_SKIPPED, null, -1);
        }

        public static SetupResult failed() {
            return new SetupResult(RESULT_FAILED, null);
            return new SetupResult(RESULT_FAILED, null, -1);
        }

        private SetupResult(int code, FileDescriptor fileDescriptor) {
        private SetupResult(int code, FileDescriptor fileDescriptor, int contentSize) {
            this.mCode = code;
            this.mFileDescriptor = fileDescriptor;
            this.mContentSize = contentSize;
        }

        public boolean isFailed() {
@@ -152,6 +169,10 @@ abstract public class VerityUtils {
        public @NonNull FileDescriptor getUnownedFileDescriptor() {
            return mFileDescriptor;
        }

        public int getContentSize() {
            return mContentSize;
        }
    }

    /** A {@code ByteBufferFactory} that creates a shared memory backed {@code ByteBuffer}. */
@@ -188,5 +209,9 @@ abstract public class VerityUtils {
            mShm = null;
            return tmp;
        }

        public int getBufferLimit() {
            return mBuffer == null ? -1 : mBuffer.limit();
        }
    }
}