Loading core/java/android/content/pm/PackageParser.java +28 −2 Original line number Diff line number Diff line Loading @@ -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<>(); Loading Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -4822,6 +4846,8 @@ public class PackageParser { */ public boolean use32bitAbi; public byte[] restrictUpdateHash; public Package(String packageName) { this.packageName = packageName; applicationInfo.packageName = packageName; Loading core/res/res/values/attrs_manifest.xml +10 −0 Original line number Diff line number Diff line Loading @@ -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> core/res/res/values/public.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading services/core/java/com/android/server/pm/PackageManagerService.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading
core/java/android/content/pm/PackageParser.java +28 −2 Original line number Diff line number Diff line Loading @@ -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<>(); Loading Loading @@ -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 Loading Loading @@ -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(); Loading Loading @@ -4822,6 +4846,8 @@ public class PackageParser { */ public boolean use32bitAbi; public byte[] restrictUpdateHash; public Package(String packageName) { this.packageName = packageName; applicationInfo.packageName = packageName; Loading
core/res/res/values/attrs_manifest.xml +10 −0 Original line number Diff line number Diff line Loading @@ -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>
core/res/res/values/public.xml +1 −0 Original line number Diff line number Diff line Loading @@ -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" /> Loading
services/core/java/com/android/server/pm/PackageManagerService.java +35 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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);