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

Commit f1cbd3e1 authored by Alex Buynytskyy's avatar Alex Buynytskyy
Browse files

Backend attestation support: API.

Bug: 160605420
Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest IncrementalServiceTest PackageManagerServiceTest ChecksumsTest
Change-Id: I5734e3dd0cc272cb95244182fee337f1c7564c79
parent f98870a5
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -12050,7 +12050,6 @@ package android.content.pm {
  public static class PackageInstaller.Session implements java.io.Closeable {
    method public void abandon();
    method @Deprecated public void addChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>) throws java.io.IOException;
    method public void addChildSessionId(int);
    method public void close();
    method public void commit(@NonNull android.content.IntentSender);
@@ -12064,6 +12063,7 @@ package android.content.pm {
    method @NonNull public java.io.OutputStream openWrite(@NonNull String, long, long) throws java.io.IOException;
    method public void removeChildSessionId(int);
    method public void removeSplit(@NonNull String) throws java.io.IOException;
    method @Deprecated public void setChecksums(@NonNull String, @NonNull java.util.List<android.content.pm.Checksum>, @Nullable byte[]) throws java.io.IOException;
    method public void setStagingProgress(float);
    method public void transfer(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
  }
+1 −1
Original line number Diff line number Diff line
@@ -35,7 +35,7 @@ interface IPackageInstallerSession {
    void write(String name, long offsetBytes, long lengthBytes, in ParcelFileDescriptor fd);
    void stageViaHardLink(String target);

    void addChecksums(String name, in Checksum[] checksums);
    void setChecksums(String name, in Checksum[] checksums, in byte[] signature);

    void removeSplit(String splitName);

+8 −4
Original line number Diff line number Diff line
@@ -1247,12 +1247,15 @@ public class PackageInstaller {
        }

        /**
         * Adds installer-provided checksums for the APK file in session.
         * Sets installer-provided checksums for the APK file in session.
         *
         * @param name      previously written as part of this session.
         *                  {@link #openWrite}
         * @param checksums installer intends to make available via
         *                  {@link PackageManager#requestChecksums}.
         * @param signature PKCS#7 detached signature bytes over serialized checksums to enable
         *                  fs-verity for the checksums or null if fs-verity should not be enabled.
         *                  @see <a href="https://www.kernel.org/doc/html/latest/filesystems/fsverity.html#built-in-signature-verification">fs-verity</a>
         * @throws SecurityException if called after the session has been
         *                           committed or abandoned.
         * @throws IllegalStateException if checksums for this file have already been added.
@@ -1262,13 +1265,14 @@ public class PackageInstaller {
         *              in {@link PackageManager#requestChecksums}.
         */
        @Deprecated
        public void addChecksums(@NonNull String name, @NonNull List<Checksum> checksums)
                throws IOException {
        public void setChecksums(@NonNull String name, @NonNull List<Checksum> checksums,
                @Nullable byte[] signature) throws IOException {
            Objects.requireNonNull(name);
            Objects.requireNonNull(checksums);

            try {
                mSession.addChecksums(name, checksums.toArray(new Checksum[checksums.size()]));
                mSession.setChecksums(name, checksums.toArray(new Checksum[checksums.size()]),
                        signature);
            } catch (RuntimeException e) {
                ExceptionUtils.maybeUnwrapIOException(e);
                throw e;
+102 −25
Original line number Diff line number Diff line
@@ -186,6 +186,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    static final String TAG_CHILD_SESSION = "childSession";
    static final String TAG_SESSION_FILE = "sessionFile";
    static final String TAG_SESSION_CHECKSUM = "sessionChecksum";
    static final String TAG_SESSION_CHECKSUM_SIGNATURE = "sessionChecksumSignature";
    private static final String TAG_GRANTED_RUNTIME_PERMISSION = "granted-runtime-permission";
    private static final String TAG_WHITELISTED_RESTRICTED_PERMISSION =
            "whitelisted-restricted-permission";
@@ -397,8 +398,26 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    @GuardedBy("mLock")
    private ArraySet<FileEntry> mFiles = new ArraySet<>();

    static class PerFileChecksum {
        private final Checksum[] mChecksums;
        private final byte[] mSignature;

        PerFileChecksum(Checksum[] checksums, byte[] signature) {
            mChecksums = checksums;
            mSignature = signature;
        }

        Checksum[] getChecksums() {
            return this.mChecksums;
        }

        byte[] getSignature() {
            return this.mSignature;
        }
    }

    @GuardedBy("mLock")
    private ArrayMap<String, Checksum[]> mChecksums = new ArrayMap<>();
    private ArrayMap<String, PerFileChecksum> mChecksums = new ArrayMap<>();

    @Nullable
    final StagedSession mStagedSession;
@@ -921,7 +940,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            int sessionId, int userId, int installerUid, @NonNull InstallSource installSource,
            SessionParams params, long createdMillis, long committedMillis,
            File stageDir, String stageCid, InstallationFile[] files,
            ArrayMap<String, List<Checksum>> checksums,
            ArrayMap<String, PerFileChecksum> checksums,
            boolean prepared, boolean committed, boolean destroyed, boolean sealed,
            @Nullable int[] childSessionIds, int parentSessionId, boolean isReady,
            boolean isFailed, boolean isApplied, int stagedSessionErrorCode,
@@ -967,11 +986,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        }

        if (checksums != null) {
            for (int i = 0, isize = checksums.size(); i < isize; ++i) {
                final String fileName = checksums.keyAt(i);
                final List<Checksum> fileChecksums = checksums.valueAt(i);
                mChecksums.put(fileName, fileChecksums.toArray(new Checksum[fileChecksums.size()]));
            }
            mChecksums.putAll(checksums);
        }

        if (!params.isMultiPackage && (stageDir == null) == (stageCid == null)) {
@@ -1253,7 +1268,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
    }

    @Override
    public void addChecksums(String name, @NonNull Checksum[] checksums) {
    public void setChecksums(String name, @NonNull Checksum[] checksums,
            @Nullable byte[] signature) {
        if (checksums.length == 0) {
            return;
        }
@@ -1269,6 +1285,17 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            throw new IllegalStateException("Can't obtain calling installer's package.");
        }

        if (signature != null && signature.length != 0) {
            final boolean standardMode = PackageManagerServiceUtils.isApkVerityEnabled();
            final boolean legacyMode = PackageManagerServiceUtils.isLegacyApkVerityEnabled();
            if (!standardMode || legacyMode) {
                Slog.e(TAG,
                        "Can't enforce checksum's signature: Apk-Verity is disabled or in legacy "
                                + "mode.");
                signature = null;
            }
        }

        synchronized (mLock) {
            assertCallerIsOwnerOrRootLocked();
            assertPreparedAndNotCommittedOrDestroyedLocked("addChecksums");
@@ -1277,7 +1304,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                throw new IllegalStateException("Duplicate checksums.");
            }

            mChecksums.put(name, checksums);
            mChecksums.put(name, new PerFileChecksum(checksums, signature));
        }
    }

@@ -3032,15 +3059,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        maybeStageFsveritySignatureLocked(dexMetadataFile, targetDexMetadataFile);
    }

    private void storeBytesToInstallationFile(final String localPath, final String absolutePath,
            final byte[] bytes) throws IOException {
        if (!isIncrementalInstallation() || mIncrementalFileStorages == null) {
            FileUtils.bytesToFile(absolutePath, bytes);
        } else {
            mIncrementalFileStorages.makeFile(localPath, bytes);
        }
    }

    @GuardedBy("mLock")
    private void maybeStageDigestsLocked(File origFile, File targetFile, String splitName)
            throws PackageManagerException {
        final Checksum[] checksums = mChecksums.get(origFile.getName());
        if (checksums == null) {
        final PerFileChecksum perFileChecksum = mChecksums.get(origFile.getName());
        if (perFileChecksum == null) {
            return;
        }
        mChecksums.remove(origFile.getName());

        final Checksum[] checksums = perFileChecksum.getChecksums();
        if (checksums.length == 0) {
            return;
        }
@@ -3048,14 +3085,24 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        final String targetDigestsPath = ApkChecksums.buildDigestsPathForApk(targetFile.getName());
        final File targetDigestsFile = new File(stageDir, targetDigestsPath);
        try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
            // Storing and staging checksums.
            ApkChecksums.writeChecksums(os, checksums);
            final byte[] checksumsBytes = os.toByteArray();
            storeBytesToInstallationFile(targetDigestsPath, targetDigestsFile.getAbsolutePath(),
                    os.toByteArray());
            stageFileLocked(targetDigestsFile, targetDigestsFile);

            if (!isIncrementalInstallation() || mIncrementalFileStorages == null) {
                FileUtils.bytesToFile(targetDigestsFile.getAbsolutePath(), checksumsBytes);
            } else {
                mIncrementalFileStorages.makeFile(targetDigestsPath, checksumsBytes);
            final byte[] signature = perFileChecksum.getSignature();
            if (signature == null || signature.length == 0) {
                return;
            }

            // Storing and staging signature.
            final String targetDigestsSignaturePath = VerityUtils.getFsveritySignatureFilePath(
                    targetDigestsPath);
            final File targetDigestsSignatureFile = new File(stageDir, targetDigestsSignaturePath);
            storeBytesToInstallationFile(targetDigestsSignaturePath,
                    targetDigestsSignatureFile.getAbsolutePath(), signature);
            stageFileLocked(targetDigestsSignatureFile, targetDigestsSignatureFile);
        } catch (CertificateException e) {
            throw new PackageManagerException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
                    "Failed to encode certificate for " + mPackageName, e);
@@ -3063,8 +3110,6 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                    "Failed to store digests for " + mPackageName, e);
        }

        stageFileLocked(targetDigestsFile, targetDigestsFile);
    }

    @GuardedBy("mLock")
@@ -4277,7 +4322,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {

            for (int i = 0, isize = mChecksums.size(); i < isize; ++i) {
                final String fileName = mChecksums.keyAt(i);
                final Checksum[] checksums = mChecksums.valueAt(i);
                final PerFileChecksum perFileChecksum = mChecksums.valueAt(i);
                final Checksum[] checksums = perFileChecksum.getChecksums();
                for (Checksum checksum : checksums) {
                    out.startTag(null, TAG_SESSION_CHECKSUM);
                    writeStringAttribute(out, ATTR_NAME, fileName);
@@ -4286,6 +4332,19 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                    out.endTag(null, TAG_SESSION_CHECKSUM);
                }
            }
            for (int i = 0, isize = mChecksums.size(); i < isize; ++i) {
                final String fileName = mChecksums.keyAt(i);
                final PerFileChecksum perFileChecksum = mChecksums.valueAt(i);
                final byte[] signature = perFileChecksum.getSignature();
                if (signature == null || signature.length == 0) {
                    continue;
                }
                out.startTag(null, TAG_SESSION_CHECKSUM_SIGNATURE);
                writeStringAttribute(out, ATTR_NAME, fileName);
                writeByteArrayAttribute(out, ATTR_SIGNATURE, signature);
                out.endTag(null, TAG_SESSION_CHECKSUM_SIGNATURE);
            }

        }

        out.endTag(null, TAG_SESSION);
@@ -4401,6 +4460,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
        List<Integer> childSessionIds = new ArrayList<>();
        List<InstallationFile> files = new ArrayList<>();
        ArrayMap<String, List<Checksum>> checksums = new ArrayMap<>();
        ArrayMap<String, byte[]> signatures = new ArrayMap<>();
        int outerDepth = in.getDepth();
        int type;
        while ((type = in.next()) != XmlPullParser.END_DOCUMENT
@@ -4443,6 +4503,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
                }
                fileChecksums.add(checksum);
            }
            if (TAG_SESSION_CHECKSUM_SIGNATURE.equals(in.getName())) {
                final String fileName = readStringAttribute(in, ATTR_NAME);
                final byte[] signature = readByteArrayAttribute(in, ATTR_SIGNATURE);
                signatures.put(fileName, signature);
            }
        }

        if (grantedRuntimePermissions.size() > 0) {
@@ -4471,13 +4536,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            fileArray = files.toArray(EMPTY_INSTALLATION_FILE_ARRAY);
        }

        ArrayMap<String, PerFileChecksum> checksumsMap = null;
        if (!checksums.isEmpty()) {
            checksumsMap = new ArrayMap<>(checksums.size());
            for (int i = 0, isize = checksums.size(); i < isize; ++i) {
                final String fileName = checksums.keyAt(i);
                final List<Checksum> perFileChecksum = checksums.valueAt(i);
                final byte[] perFileSignature = signatures.get(fileName);
                checksumsMap.put(fileName, new PerFileChecksum(
                        perFileChecksum.toArray(new Checksum[perFileChecksum.size()]),
                        perFileSignature));
            }
        }

        InstallSource installSource = InstallSource.create(installInitiatingPackageName,
                installOriginatingPackageName, installerPackageName, installerAttributionTag);
        return new PackageInstallerSession(callback, context, pm, sessionProvider,
                installerThread, stagingManager, sessionId, userId, installerUid,
                installSource, params, createdMillis, committedMillis, stageDir, stageCid,
                fileArray, checksums, prepared, committed, destroyed, sealed, childSessionIdsArray,
                parentSessionId, isReady, isFailed, isApplied, stagedSessionErrorCode,
                stagedSessionErrorMessage);
        return new PackageInstallerSession(callback, context, pm, sessionProvider, installerThread,
                stagingManager, sessionId, userId, installerUid, installSource, params,
                createdMillis, committedMillis, stageDir, stageCid, fileArray, checksumsMap,
                prepared, committed, destroyed, sealed, childSessionIdsArray, parentSessionId,
                isReady, isFailed, isApplied, stagedSessionErrorCode, stagedSessionErrorMessage);
    }
}