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

Commit 0b4f8443 authored by Todd Kennedy's avatar Todd Kennedy Committed by android-build-merger
Browse files

Merge "Restrict updates of system packages" into nyc-dev am: 4e4fca43 am: 728b0978

am: c5f564a0

* commit 'c5f564a0':
  Restrict updates of system packages

Change-Id: I06d7729ddc9ee2fb485ab3a9af88e3a7d26b5718
parents bd53930c c5f564a0
Loading
Loading
Loading
Loading
+28 −2
Original line number Diff line number Diff line
@@ -159,6 +159,7 @@ public class PackageParser {
    private static final String TAG_SUPPORTS_INPUT = "supports-input";
    private static final String TAG_EAT_COMMENT = "eat-comment";
    private static final String TAG_PACKAGE = "package";
    private static final String TAG_RESTRICT_UPDATE = "restrict-update";

    // These are the tags supported by child packages
    private static final Set<String> CHILD_PACKAGE_TAGS = new ArraySet<>();
@@ -1639,9 +1640,9 @@ public class PackageParser {
    /**
     * This is the common parsing routing for handling parent and child
     * packages in a base APK. The difference between parent and child
     * parsing is that some targs are not supported by child packages as
     * parsing is that some tags are not supported by child packages as
     * well as some manifest attributes are ignored. The implementation
     * assumes the calling code already handled the manifest tag if needed
     * assumes the calling code has already handled the manifest tag if needed
     * (this applies to the parent only).
     *
     * @param pkg The package which to populate
@@ -2089,6 +2090,29 @@ public class PackageParser {
                    // If parsing a child failed the error is already set
                    return null;
                }

            } else if (tagName.equals(TAG_RESTRICT_UPDATE)) {
                if ((flags & PARSE_IS_SYSTEM_DIR) != 0) {
                    sa = res.obtainAttributes(parser,
                            com.android.internal.R.styleable.AndroidManifestRestrictUpdate);
                    final String hash = sa.getNonConfigurationString(
                            com.android.internal.R.styleable.AndroidManifestRestrictUpdate_hash, 0);
                    sa.recycle();

                    pkg.restrictUpdateHash = null;
                    if (hash != null) {
                        final int hashLength = hash.length();
                        final byte[] hashBytes = new byte[hashLength / 2];
                        for (int i = 0; i < hashLength; i += 2){
                            hashBytes[i/2] = (byte) ((Character.digit(hash.charAt(i), 16) << 4)
                                    + Character.digit(hash.charAt(i + 1), 16));
                        }
                        pkg.restrictUpdateHash = hashBytes;
                    }
                }

                XmlUtils.skipCurrentTag(parser);

            } else if (RIGID_PARSER) {
                outError[0] = "Bad element under <manifest>: "
                    + parser.getName();
@@ -4822,6 +4846,8 @@ public class PackageParser {
         */
        public boolean use32bitAbi;

        public byte[] restrictUpdateHash;

        public Package(String packageName) {
            this.packageName = packageName;
            applicationInfo.packageName = packageName;
+10 −0
Original line number Diff line number Diff line
@@ -2291,4 +2291,14 @@
        <attr name="minimalHeight" format="dimension" />
    </declare-styleable>

    <!-- <code>restrict-update</code> tag restricts system apps from being updated unless the
        SHA-512 hash equals the specified value.
        @hide -->
    <declare-styleable name="AndroidManifestRestrictUpdate" parent="AndroidManifest">
        <!-- The SHA-512 hash of the only APK that can be used to update a package.
             <p>NOTE: This is only applicable to system packages.
             @hide -->
        <attr name="hash" format="string" />
    </declare-styleable>

</resources>
+1 −0
Original line number Diff line number Diff line
@@ -2715,6 +2715,7 @@
    <public type="attr" name="contentInsetEndWithActions" />
    <public type="attr" name="numberPickerStyle" />
    <public type="attr" name="enableVrMode" />
    <public type="attr" name="hash" />

    <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
    <public type="style" name="Widget.Material.SeekBar.Discrete" />
+35 −0
Original line number Diff line number Diff line
@@ -266,6 +266,7 @@ import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
@@ -274,6 +275,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
@@ -13838,6 +13840,13 @@ public class PackageManagerService extends IPackageManager.Stub {
        return false;
    }
    private static void updateDigest(MessageDigest digest, File file) throws IOException {
        try (DigestInputStream digestStream =
                new DigestInputStream(new FileInputStream(file), digest)) {
            while (digestStream.read() != -1) {} // nothing to do; just plow through the file
        }
    }
    private void replacePackageLIF(PackageParser.Package pkg, final int policyFlags, int scanFlags,
            UserHandle user, String installerPackageName, PackageInstalledInfo res) {
        final boolean isEphemeral = (policyFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
@@ -13892,6 +13901,32 @@ public class PackageManagerService extends IPackageManager.Stub {
                }
            }
            // don't allow a system upgrade unless the upgrade hash matches
            if (oldPackage.restrictUpdateHash != null && oldPackage.isSystemApp()) {
                byte[] digestBytes = null;
                try {
                    final MessageDigest digest = MessageDigest.getInstance("SHA-512");
                    updateDigest(digest, new File(pkg.baseCodePath));
                    if (!ArrayUtils.isEmpty(pkg.splitCodePaths)) {
                        for (String path : pkg.splitCodePaths) {
                            updateDigest(digest, new File(path));
                        }
                    }
                    digestBytes = digest.digest();
                } catch (NoSuchAlgorithmException | IOException e) {
                    res.setError(INSTALL_FAILED_INVALID_APK,
                            "Could not compute hash: " + pkgName);
                    return;
                }
                if (!Arrays.equals(oldPackage.restrictUpdateHash, digestBytes)) {
                    res.setError(INSTALL_FAILED_INVALID_APK,
                            "New package fails restrict-update check: " + pkgName);
                    return;
                }
                // retain upgrade restriction
                pkg.restrictUpdateHash = oldPackage.restrictUpdateHash;
            }
            // Check for shared user id changes
            String invalidPackageName =
                    getParentOrChildPackageChangedSharedUser(oldPackage, pkg);