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

Commit f720a9d9 authored by Todd Kennedy's avatar Todd Kennedy
Browse files

Always perform has code check

Move code checking from the package parser and into the block
where we implement policy.

Bug: 28132476
Change-Id: Ie5cacacbf80289ff8d85acc5b57e58ea7216859c
parent b05e4851
Loading
Loading
Loading
Loading
+4 −27
Original line number Diff line number Diff line
@@ -131,12 +131,6 @@ public class PackageParser {
    /** File name in an APK for the Android manifest. */
    private static final String ANDROID_MANIFEST_FILENAME = "AndroidManifest.xml";

    /**
     * File name in an APK for bytecode.  There may be additional bytecode files
     * but this one is always required for an APK that has code.
     */
    private static final String BYTECODE_FILENAME = "classes.dex";

    /** Path prefix for apps on expanded storage */
    private static final String MNT_EXPAND = "/mnt/expand/";

@@ -1137,13 +1131,11 @@ public class PackageParser {

        Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
        try {
            collectCertificates(
                    pkg, new File(pkg.baseCodePath), pkg.applicationInfo.flags, parseFlags);
            collectCertificates(pkg, new File(pkg.baseCodePath), parseFlags);

            if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
                for (int i = 0; i < pkg.splitCodePaths.length; i++) {
                    collectCertificates(
                            pkg, new File(pkg.splitCodePaths[i]), pkg.splitFlags[i], parseFlags);
                    collectCertificates(pkg, new File(pkg.splitCodePaths[i]), parseFlags);
                }
            }
        } finally {
@@ -1151,10 +1143,8 @@ public class PackageParser {
        }
    }

    private static void collectCertificates(Package pkg, File apkFile, int apkFlags, int parseFlags)
    private static void collectCertificates(Package pkg, File apkFile, int parseFlags)
            throws PackageParserException {
        final boolean hasCode = (apkFlags & ApplicationInfo.FLAG_HAS_CODE) != 0;
        final boolean requireCode = ((parseFlags & PARSE_ENFORCE_CODE) != 0) && hasCode;
        final String apkPath = apkFile.getAbsolutePath();

        // Try to verify the APK using APK Signature Scheme v2.
@@ -1202,7 +1192,6 @@ public class PackageParser {
            }
        }

        boolean codeFound = false;
        StrictJarFile jarFile = null;
        try {
            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
@@ -1226,10 +1215,6 @@ public class PackageParser {

            // Optimization: early termination when APK already verified
            if (verified) {
                if ((requireCode) && (jarFile.findEntry(BYTECODE_FILENAME) == null)) {
                    throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                            "Package " + apkPath + " code is missing");
                }
                return;
            }

@@ -1249,19 +1234,11 @@ public class PackageParser {
                    final String entryName = entry.getName();
                    if (entryName.startsWith("META-INF/")) continue;
                    if (entryName.equals(ANDROID_MANIFEST_FILENAME)) continue;
                    if (entryName.equals(BYTECODE_FILENAME)) {
                        codeFound = true;
                    }

                    toVerify.add(entry);
                }
            }

            if (!codeFound && requireCode) {
                throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
                        "Package " + apkPath + " code is missing");
            }

            // Verify that entries are signed consistently with the first entry
            // we encountered. Note that for splits, certificates may have
            // already been populated during an earlier parse of a base APK.
@@ -1349,7 +1326,7 @@ public class PackageParser {
                final Package tempPkg = new Package(null);
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectCertificates");
                try {
                    collectCertificates(tempPkg, apkFile, 0 /*apkFlags*/, 0 /*flags*/);
                    collectCertificates(tempPkg, apkFile, 0 /*parseFlags*/);
                } finally {
                    Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                }
+51 −0
Original line number Diff line number Diff line
@@ -216,6 +216,7 @@ import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
import android.util.Xml;
import android.util.jar.StrictJarFile;
import android.view.Display;
import com.android.internal.R;
@@ -7643,6 +7644,52 @@ public class PackageManagerService extends IPackageManager.Stub {
        }
    }
    /**
     * Returns {@code true} if the given file contains code. Otherwise {@code false}.
     */
    private static boolean apkHasCode(String fileName) {
        StrictJarFile jarFile = null;
        try {
            jarFile = new StrictJarFile(fileName,
                    false /*verify*/, false /*signatureSchemeRollbackProtectionsEnforced*/);
            return jarFile.findEntry("classes.dex") != null;
        } catch (IOException ignore) {
        } finally {
            try {
                jarFile.close();
            } catch (IOException ignore) {}
        }
        return false;
    }
    /**
     * Enforces code policy for the package. This ensures that if an APK has
     * declared hasCode="true" in its manifest that the APK actually contains
     * code.
     *
     * @throws PackageManagerException If bytecode could not be found when it should exist
     */
    private static void enforceCodePolicy(PackageParser.Package pkg)
            throws PackageManagerException {
        final boolean shouldHaveCode =
                (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
        if (shouldHaveCode && !apkHasCode(pkg.baseCodePath)) {
            throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                    "Package " + pkg.baseCodePath + " code is missing");
        }
        if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
            for (int i = 0; i < pkg.splitCodePaths.length; i++) {
                final boolean splitShouldHaveCode =
                        (pkg.splitFlags[i] & ApplicationInfo.FLAG_HAS_CODE) != 0;
                if (splitShouldHaveCode && !apkHasCode(pkg.splitCodePaths[i])) {
                    throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
                            "Package " + pkg.splitCodePaths[i] + " code is missing");
                }
            }
        }
    }
    private PackageParser.Package scanPackageDirtyLI(PackageParser.Package pkg,
            final int policyFlags, final int scanFlags, long currentTime, UserHandle user)
            throws PackageManagerException {
@@ -7687,6 +7734,10 @@ public class PackageManagerService extends IPackageManager.Stub {
            pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
        }
        if ((policyFlags & PackageParser.PARSE_ENFORCE_CODE) != 0) {
            enforceCodePolicy(pkg);
        }
        if (mCustomResolverComponentName != null &&
                mCustomResolverComponentName.getPackageName().equals(pkg.packageName)) {
            setUpCustomResolverActivity(pkg);