diff options
author | Zoran Jovanovic <zoran.jovanovic@sony.com> | 2020-06-09 18:51:57 +0200 |
---|---|---|
committer | Ryan Mitchell <rtmitchell@google.com> | 2020-10-14 14:52:46 -0700 |
commit | 0f942f99cac4f5f61b40847d20ecb3a94c96c843 (patch) | |
tree | f68594004b3a5e8ea8999ff76b059fd1432dbda8 | |
parent | 82cb76f90827c2925ae267f04f395a4e142f6a85 (diff) |
OMS: Add config_signature policy handling
Alongside SIGNATURE and ACTOR_SIGNATURE policies, add CONFIG_SIGNATURE
policy to overlayable that overlay fulfills if it is signed with the
same certificate as the reference package whose package name is
declared in 'config-signature' tag of SystemConfig and is vetted by
OMS that it's a system pre-installed package.
BUG: 158726924
TEST: regular aapt2, idmap2, OMS tests
Merged-In: I645ee72271496008742886274be0d63a2985201b
Change-Id: I645ee72271496008742886274be0d63a2985201b
38 files changed, 414 insertions, 174 deletions
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl index 02b27a8800b6..403d8c55de16 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl @@ -29,4 +29,5 @@ interface OverlayablePolicy { const int ODM_PARTITION = 0x00000020; const int OEM_PARTITION = 0x00000040; const int ACTOR_SIGNATURE = 0x00000080; + const int CONFIG_SIGNATURE = 0x0000100; } diff --git a/cmds/idmap2/libidmap2/ResourceMapping.cpp b/cmds/idmap2/libidmap2/ResourceMapping.cpp index 34589a1c39dc..fd8b4eb86b4a 100644 --- a/cmds/idmap2/libidmap2/ResourceMapping.cpp +++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp @@ -61,10 +61,13 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package, const ResourceId& target_resource) { static constexpr const PolicyBitmask sDefaultPolicies = PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION | - PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE; + PolicyFlags::VENDOR_PARTITION | PolicyFlags::PRODUCT_PARTITION | PolicyFlags::SIGNATURE | + PolicyFlags::CONFIG_SIGNATURE; // If the resource does not have an overlayable definition, allow the resource to be overlaid if - // the overlay is preinstalled or signed with the same signature as the target. + // the overlay is preinstalled, signed with the same signature as the target or signed with the + // same signature as reference package defined in SystemConfig under 'overlay-config-signature' + // tag. if (!target_package.DefinesOverlayable()) { return (sDefaultPolicies & fulfilled_policies) != 0 ? Result<Unit>({}) diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h index 5bd353af4ad3..804631982490 100644 --- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h +++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h @@ -37,16 +37,18 @@ constexpr const char* kPolicyOdm = "odm"; constexpr const char* kPolicyOem = "oem"; constexpr const char* kPolicyProduct = "product"; constexpr const char* kPolicyPublic = "public"; +constexpr const char* kPolicyConfigSignature = "config_signature"; constexpr const char* kPolicySignature = "signature"; constexpr const char* kPolicySystem = "system"; constexpr const char* kPolicyVendor = "vendor"; -inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = { +inline static const std::array<std::pair<StringPiece, PolicyFlags>, 9> kPolicyStringToFlag = { std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE}, {kPolicyOdm, PolicyFlags::ODM_PARTITION}, {kPolicyOem, PolicyFlags::OEM_PARTITION}, {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION}, {kPolicyPublic, PolicyFlags::PUBLIC}, + {kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE}, {kPolicySignature, PolicyFlags::SIGNATURE}, {kPolicySystem, PolicyFlags::SYSTEM_PARTITION}, {kPolicyVendor, PolicyFlags::VENDOR_PARTITION}, diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h index aed263a49aa3..89b43466ba5e 100644 --- a/cmds/idmap2/tests/R.h +++ b/cmds/idmap2/tests/R.h @@ -41,16 +41,17 @@ namespace R::target { constexpr ResourceId not_overlayable = 0x7f020003; constexpr ResourceId other = 0x7f020004; constexpr ResourceId policy_actor = 0x7f020005; - constexpr ResourceId policy_odm = 0x7f020006; - constexpr ResourceId policy_oem = 0x7f020007; - constexpr ResourceId policy_product = 0x7f020008; - constexpr ResourceId policy_public = 0x7f020009; - constexpr ResourceId policy_signature = 0x7f02000a; - constexpr ResourceId policy_system = 0x7f02000b; - constexpr ResourceId policy_system_vendor = 0x7f02000c; - constexpr ResourceId str1 = 0x7f02000d; - constexpr ResourceId str3 = 0x7f02000f; - constexpr ResourceId str4 = 0x7f020010; + constexpr ResourceId policy_config_signature = 0x7f020006; + constexpr ResourceId policy_odm = 0x7f020007; + constexpr ResourceId policy_oem = 0x7f020008; + constexpr ResourceId policy_product = 0x7f020009; + constexpr ResourceId policy_public = 0x7f02000a; + constexpr ResourceId policy_signature = 0x7f02000b; + constexpr ResourceId policy_system = 0x7f02000c; + constexpr ResourceId policy_system_vendor = 0x7f02000d; + constexpr ResourceId str1 = 0x7f02000e; + constexpr ResourceId str3 = 0x7f020010; + constexpr ResourceId str4 = 0x7f020011; namespace literal { inline const std::string str1 = hexify(R::target::string::str1); @@ -92,14 +93,15 @@ namespace R::system_overlay_invalid::string { constexpr ResourceId not_overlayable = 0x7f010000; constexpr ResourceId other = 0x7f010001; constexpr ResourceId policy_actor = 0x7f010002; - constexpr ResourceId policy_odm = 0x7f010003; - constexpr ResourceId policy_oem = 0x7f010004; - constexpr ResourceId policy_product = 0x7f010005; - constexpr ResourceId policy_public = 0x7f010006; - constexpr ResourceId policy_signature = 0x7f010007; - constexpr ResourceId policy_system = 0x7f010008; - constexpr ResourceId policy_system_vendor = 0x7f010009; -}; + constexpr ResourceId policy_config_signature = 0x7f010003; + constexpr ResourceId policy_odm = 0x7f010004; + constexpr ResourceId policy_oem = 0x7f010005; + constexpr ResourceId policy_product = 0x7f010006; + constexpr ResourceId policy_public = 0x7f010007; + constexpr ResourceId policy_signature = 0x7f010008; + constexpr ResourceId policy_system = 0x7f010009; + constexpr ResourceId policy_system_vendor = 0x7f01000a; +} // clang-format on } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index de039f440e33..3ec6ac24b238 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -237,7 +237,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U); + ASSERT_EQ(res.GetTargetToOverlayMap().size(), 11U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); @@ -256,6 +256,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature, + Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_config_signature, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_signature, false /* rewrite */)); @@ -298,8 +302,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) { ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U); } -// Overlays that are pre-installed or are signed with the same signature as the target can overlay -// packages that have not defined overlayable resources. +// Overlays that are pre-installed or are signed with the same signature as the target or are signed +// with the same signature as the reference package can overlay packages that have not defined +// overlayable resources. TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void { auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", @@ -309,7 +314,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U); + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 11U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); @@ -330,6 +335,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_public, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_config_signature, + Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_config_signature, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_signature, false /* rewrite */)); @@ -342,6 +351,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { }; CheckEntries(PolicyFlags::SIGNATURE); + CheckEntries(PolicyFlags::CONFIG_SIGNATURE); CheckEntries(PolicyFlags::PRODUCT_PARTITION); CheckEntries(PolicyFlags::SYSTEM_PARTITION); CheckEntries(PolicyFlags::VENDOR_PARTITION); diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h index 6bc924e5ac3c..641a7a8d45aa 100644 --- a/cmds/idmap2/tests/TestConstants.h +++ b/cmds/idmap2/tests/TestConstants.h @@ -19,11 +19,11 @@ namespace android::idmap2::TestConstants { -constexpr const auto TARGET_CRC = 0x41c60c8c; -constexpr const auto TARGET_CRC_STRING = "41c60c8c"; +constexpr const auto TARGET_CRC = 0x7c2d4719; +constexpr const auto TARGET_CRC_STRING = "7c2d4719"; -constexpr const auto OVERLAY_CRC = 0xc054fb26; -constexpr const auto OVERLAY_CRC_STRING = "c054fb26"; +constexpr const auto OVERLAY_CRC = 0x5afff726; +constexpr const auto OVERLAY_CRC_STRING = "5afff726"; } // namespace android::idmap2::TestConstants diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk Binary files differindex 7c25985e5a61..dab25b1f8131 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk Binary files differindex c75f3e1dbddf..c8b95c2601ad 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk Binary files differindex 93dcc82f9358..0a8b7372172e 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-shared.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk Binary files differindex 5b8a6e4a90ed..fd41182f8493 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk Binary files differindex 698a1fd6e702..b24765fc666a 100644 --- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk +++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk Binary files differindex 1db303ff05b5..870575efa10c 100644 --- a/cmds/idmap2/tests/data/overlay/overlay.apk +++ b/cmds/idmap2/tests/data/overlay/overlay.apk diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk Binary files differindex 51e19de082ed..e0fd20499671 100644 --- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk +++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml index 7119d8283061..ebaf49c34762 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml +++ b/cmds/idmap2/tests/data/system-overlay-invalid/res/values/values.xml @@ -26,6 +26,7 @@ <string name="policy_odm">policy_odm</string> <string name="policy_oem">policy_oem</string> <string name="policy_actor">policy_actor</string> + <string name="policy_config_signature">policy_config_signature</string> <!-- Requests to overlay a resource that is not declared as overlayable. --> <string name="not_overlayable">not_overlayable</string> diff --git a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk Binary files differindex bd990983693c..a63daf86caf5 100644 --- a/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk +++ b/cmds/idmap2/tests/data/system-overlay-invalid/system-overlay-invalid.apk diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk Binary files differindex a0fba4378b57..90d2803a1eca 100644 --- a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk +++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml index ad4cd4882632..57e6c439c23c 100644 --- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml +++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml @@ -45,6 +45,10 @@ <item type="string" name="policy_actor" /> </policy> + <policy type="config_signature"> + <item type="string" name="policy_config_signature"/> + </policy> + <!-- Resources publicly overlayable --> <policy type="public"> <item type="string" name="policy_public" /> diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml index 5230e25e626b..00909a9e481c 100644 --- a/cmds/idmap2/tests/data/target/res/values/values.xml +++ b/cmds/idmap2/tests/data/target/res/values/values.xml @@ -37,6 +37,7 @@ <string name="policy_system">policy_system</string> <string name="policy_system_vendor">policy_system_vendor</string> <string name="policy_actor">policy_actor</string> + <string name="policy_config_signature">policy_config_signature</string> <string name="other">other</string> </resources> diff --git a/cmds/idmap2/tests/data/target/target-no-overlayable.apk b/cmds/idmap2/tests/data/target/target-no-overlayable.apk Binary files differindex 58504a74a83a..cc3491de894d 100644 --- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk +++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk Binary files differindex c80e5eb65ff2..4a58c5e28f49 100644 --- a/cmds/idmap2/tests/data/target/target.apk +++ b/cmds/idmap2/tests/data/target/target.apk diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java index ea390cd71e31..4fc66bc802f3 100644 --- a/core/java/com/android/server/SystemConfig.java +++ b/core/java/com/android/server/SystemConfig.java @@ -19,6 +19,7 @@ package com.android.server; import static com.android.internal.util.ArrayUtils.appendInt; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.content.ComponentName; import android.content.pm.FeatureInfo; @@ -238,6 +239,14 @@ public class SystemConfig { */ private Map<String, Map<String, String>> mNamedActors = null; + // Package name of the package pre-installed on a read-only + // partition that is used to verify if an overlay package fulfills + // the 'config_signature' policy by comparing their signatures: + // if the overlay package is signed with the same certificate as + // the package declared in 'config-signature' tag, then the + // overlay package fulfills the 'config_signature' policy. + private String mOverlayConfigSignaturePackage; + public static SystemConfig getInstance() { if (!isSystemProcess()) { Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " @@ -433,6 +442,12 @@ public class SystemConfig { return mNamedActors != null ? mNamedActors : Collections.emptyMap(); } + @Nullable + public String getOverlayConfigSignaturePackage() { + return TextUtils.isEmpty(mOverlayConfigSignaturePackage) + ? null : mOverlayConfigSignaturePackage; + } + /** * Only use for testing. Do NOT use in production code. * @param readPermissions false to create an empty SystemConfig; true to read the permissions. @@ -1151,6 +1166,27 @@ public class SystemConfig { } XmlUtils.skipCurrentTag(parser); } break; + case "overlay-config-signature": { + if (allowAll) { + String pkgName = parser.getAttributeValue(null, "package"); + if (pkgName == null) { + Slog.w(TAG, "<" + name + "> without package in " + permFile + + " at " + parser.getPositionDescription()); + } else { + if (TextUtils.isEmpty(mOverlayConfigSignaturePackage)) { + mOverlayConfigSignaturePackage = pkgName.intern(); + } else { + throw new IllegalStateException("Reference signature package " + + "defined as both " + + mOverlayConfigSignaturePackage + + " and " + pkgName); + } + } + } else { + logNotAllowedInPartition(name, permFile, parser); + } + XmlUtils.skipCurrentTag(parser); + } break; case "rollback-whitelisted-app": { String pkgname = parser.getAttributeValue(null, "package"); if (pkgname == null) { diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index e351a46d633a..e10a7f3f5c61 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1717,6 +1717,10 @@ struct ResTable_overlayable_policy_header // The overlay must be signed with the same signature as the actor declared for the target // resource ACTOR_SIGNATURE = 0x00000080, + + // The overlay must be signed with the same signature as the reference package declared + // in the SystemConfig + CONFIG_SIGNATURE = 0x00000100, }; using PolicyBitmask = uint32_t; diff --git a/services/core/java/android/content/pm/PackageManagerInternal.java b/services/core/java/android/content/pm/PackageManagerInternal.java index b241bd16d3ee..ad1986a6669f 100644 --- a/services/core/java/android/content/pm/PackageManagerInternal.java +++ b/services/core/java/android/content/pm/PackageManagerInternal.java @@ -69,6 +69,7 @@ public abstract class PackageManagerInternal { public static final int PACKAGE_WIFI = 13; public static final int PACKAGE_COMPANION = 14; public static final int PACKAGE_RETAIL_DEMO = 15; + public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 16; @IntDef(flag = true, prefix = "RESOLVE_", value = { RESOLVE_NON_BROWSER_ONLY, diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index d6b1b27360ca..cb6e960b721d 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -27,6 +27,7 @@ import android.content.pm.PackageInfo; import android.os.Build.VERSION_CODES; import android.os.OverlayablePolicy; import android.os.SystemProperties; +import android.text.TextUtils; import android.util.Slog; import java.io.IOException; @@ -53,11 +54,20 @@ final class IdmapManager { } private final IdmapDaemon mIdmapDaemon; - private final OverlayableInfoCallback mOverlayableCallback; + private final PackageManagerHelper mPackageManager; - IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) { - mOverlayableCallback = verifyCallback; + /** + * Package name of the reference package defined in 'config-signature' tag of + * SystemConfig or empty String if tag not defined. This package is vetted on scan by + * PackageManagerService that it's a system package and is used to check if overlay matches + * its signature in order to fulfill the config_signature policy. + */ + private final String mConfigSignaturePackage; + + IdmapManager(final IdmapDaemon idmapDaemon, final PackageManagerHelper packageManager) { + mPackageManager = packageManager; mIdmapDaemon = idmapDaemon; + mConfigSignaturePackage = packageManager.getConfigSignaturePackage(); } /** @@ -139,7 +149,7 @@ final class IdmapManager { int fulfilledPolicies = OverlayablePolicy.PUBLIC; // Overlay matches target signature - if (mOverlayableCallback.signaturesMatching(targetPackage.packageName, + if (mPackageManager.signaturesMatching(targetPackage.packageName, overlayPackage.packageName, userId)) { fulfilledPolicies |= OverlayablePolicy.SIGNATURE; } @@ -149,6 +159,16 @@ final class IdmapManager { fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE; } + // If SystemConfig defines 'config-signature' package, given that + // this package is vetted by OverlayManagerService that it's a + // preinstalled package, check if overlay matches its signature. + if (!TextUtils.isEmpty(mConfigSignaturePackage) + && mPackageManager.signaturesMatching(mConfigSignaturePackage, + overlayPackage.packageName, + userId)) { + fulfilledPolicies |= OverlayablePolicy.CONFIG_SIGNATURE; + } + // Vendor partition (/vendor) if (ai.isVendor()) { return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION; @@ -183,12 +203,12 @@ final class IdmapManager { String targetOverlayableName = overlayPackage.targetOverlayableName; if (targetOverlayableName != null) { try { - OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget( + OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget( targetPackage.packageName, targetOverlayableName, userId); if (overlayableInfo != null && overlayableInfo.actor != null) { String actorPackageName = OverlayActorEnforcer.getPackageNameForActor( - overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first; - if (mOverlayableCallback.signaturesMatching(actorPackageName, + overlayableInfo.actor, mPackageManager.getNamedActors()).first; + if (mPackageManager.signaturesMatching(actorPackageName, overlayPackage.packageName, userId)) { return true; } diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index 2bc34998785b..8c03c6ce3092 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -45,7 +45,7 @@ public class OverlayActorEnforcer { // By default, the reason is not logged to prevent leaks of why it failed private static final boolean DEBUG_REASON = false; - private final OverlayableInfoCallback mOverlayableCallback; + private final PackageManagerHelper mPackageManager; /** * @return nullable actor result with {@link ActorState} failure status @@ -79,8 +79,8 @@ public class OverlayActorEnforcer { return Pair.create(packageName, ActorState.ALLOWED); } - public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) { - mOverlayableCallback = overlayableCallback; + public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) { + mPackageManager = packageManager; } void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName, @@ -110,7 +110,7 @@ public class OverlayActorEnforcer { return ActorState.ALLOWED; } - String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid); + String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid); if (ArrayUtils.isEmpty(callingPackageNames)) { return ActorState.NO_PACKAGES_FOR_UID; } @@ -125,12 +125,12 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(targetOverlayableName)) { try { - if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { + if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) { return ActorState.MISSING_TARGET_OVERLAYABLE_NAME; } else { // If there's no overlayable defined, fallback to the legacy permission check try { - mOverlayableCallback.enforcePermission( + mPackageManager.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -146,7 +146,7 @@ public class OverlayActorEnforcer { OverlayableInfo targetOverlayable; try { - targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName, + targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName, targetOverlayableName, userId); } catch (IOException e) { return ActorState.UNABLE_TO_GET_TARGET; @@ -160,7 +160,7 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(actor)) { // If there's no actor defined, fallback to the legacy permission check try { - mOverlayableCallback.enforcePermission( + mPackageManager.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -170,7 +170,7 @@ public class OverlayActorEnforcer { } } - Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors(); + Map<String, Map<String, String>> namedActors = mPackageManager.getNamedActors(); Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors); ActorState actorUriState = actorUriPair.second; if (actorUriState != ActorState.ALLOWED) { @@ -178,7 +178,7 @@ public class OverlayActorEnforcer { } String packageName = actorUriPair.first; - PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId); + PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, userId); if (packageInfo == null) { return ActorState.MISSING_APP_INFO; } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 396815399874..0f8c9c789a3f 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -1053,8 +1053,7 @@ public final class OverlayManagerService extends SystemService { } } - private static final class PackageManagerHelperImpl implements PackageManagerHelper, - OverlayableInfoCallback { + private static final class PackageManagerHelperImpl implements PackageManagerHelper { private final Context mContext; private final IPackageManager mPackageManager; @@ -1127,6 +1126,14 @@ public final class OverlayManagerService extends SystemService { return overlays; } + @Override + public String getConfigSignaturePackage() { + final String[] pkgs = mPackageManagerInternal.getKnownPackageNames( + PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE, + UserHandle.USER_SYSTEM); + return (pkgs.length == 0) ? null : pkgs[0]; + } + @Nullable @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java deleted file mode 100644 index 5066ecdd6316..000000000000 --- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.om; - - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.content.om.OverlayableInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; - -import com.android.server.pm.PackageManagerServiceUtils; - -import java.io.IOException; -import java.util.Map; - -/** - * Delegate to the system for querying information about overlayables and packages. - */ -public interface OverlayableInfoCallback { - - /** - * Read from the APK and AndroidManifest of a package to return the overlayable defined for - * a given name. - * - * @throws IOException if the target can't be read - */ - @Nullable - OverlayableInfo getOverlayableForTarget(@NonNull String packageName, - @NonNull String targetOverlayableName, int userId) - throws IOException; - - /** - * @see PackageManager#getPackagesForUid(int) - */ - @Nullable - String[] getPackagesForUid(int uid); - - /** - * @param userId user to filter package visibility by - * @see PackageManager#getPackageInfo(String, int) - */ - @Nullable - PackageInfo getPackageInfo(@NonNull String packageName, int userId); - - /** - * @return map of system pre-defined, uniquely named actors; keys are namespace, - * value maps actor name to package name - */ - @NonNull - Map<String, Map<String, String>> getNamedActors(); - - /** - * @return true if the target package has declared an overlayable - */ - boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException; - - /** - * @throws SecurityException containing message if the caller doesn't have the given - * permission - */ - void enforcePermission(String permission, String message) throws SecurityException; - - /** - * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages - * in the system returns {@link PackageManager#SIGNATURE_MATCH} - */ - boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); -} diff --git a/services/core/java/com/android/server/om/PackageManagerHelper.java b/services/core/java/com/android/server/om/PackageManagerHelper.java index ec9c5e64e390..b1a8b4ee4d9f 100644 --- a/services/core/java/com/android/server/om/PackageManagerHelper.java +++ b/services/core/java/com/android/server/om/PackageManagerHelper.java @@ -17,11 +17,17 @@ package com.android.server.om; import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.om.OverlayableInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; +import com.android.server.pm.PackageManagerServiceUtils; + +import java.io.IOException; import java.util.List; +import java.util.Map; /** * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality, @@ -30,7 +36,65 @@ import java.util.List; * @hide */ interface PackageManagerHelper { + /** + * @return true if the target package has declared an overlayable + */ + boolean doesTargetDefineOverlayable(String targetPackageName, int userId) throws IOException; + + /** + * @throws SecurityException containing message if the caller doesn't have the given + * permission + */ + void enforcePermission(String permission, String message) throws SecurityException; + + /** + * Returns the package name of the reference package defined in 'overlay-config-signature' tag + * of SystemConfig. This package is vetted on scan by PackageManagerService that it's a system + * package and is used to check if overlay matches its signature in order to fulfill the + * config_signature policy. + */ + @Nullable + String getConfigSignaturePackage(); + + /** + * @return map of system pre-defined, uniquely named actors; keys are namespace, + * value maps actor name to package name + */ + @NonNull + Map<String, Map<String, String>> getNamedActors(); + + /** + * @see PackageManagerInternal#getOverlayPackages(int) + */ + List<PackageInfo> getOverlayPackages(int userId); + + /** + * Read from the APK and AndroidManifest of a package to return the overlayable defined for + * a given name. + * + * @throws IOException if the target can't be read + */ + @Nullable + OverlayableInfo getOverlayableForTarget(@NonNull String packageName, + @NonNull String targetOverlayableName, int userId) + throws IOException; + + /** + * @see PackageManager#getPackagesForUid(int) + */ + @Nullable + String[] getPackagesForUid(int uid); + + /** + * @param userId user to filter package visibility by + * @see PackageManager#getPackageInfo(String, int) + */ + @Nullable PackageInfo getPackageInfo(@NonNull String packageName, int userId); + + /** + * @return true if {@link PackageManagerServiceUtils#compareSignatures} run on both packages + * in the system returns {@link PackageManager#SIGNATURE_MATCH} + */ boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); - List<PackageInfo> getOverlayPackages(int userId); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4f0c707a1dae..fddd46a9c026 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -120,6 +120,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter; +import static com.android.server.pm.PackageManagerServiceUtils.comparePackageSignatures; import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures; import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists; import static com.android.server.pm.PackageManagerServiceUtils.decompressFile; @@ -1114,6 +1115,7 @@ public class PackageManagerService extends IPackageManager.Stub public @Nullable String storageManagerPackage; public @Nullable String defaultTextClassifierPackage; public @Nullable String systemTextClassifierPackage; + public @Nullable String overlayConfigSignaturePackage; public ViewCompiler viewCompiler; public @Nullable String wellbeingPackage; public @Nullable String retailDemoPackage; @@ -1646,6 +1648,7 @@ public class PackageManagerService extends IPackageManager.Stub final @Nullable String mServicesExtensionPackageName; final @Nullable String mSharedSystemSharedLibraryPackageName; final @Nullable String mRetailDemoPackage; + final @Nullable String mOverlayConfigSignaturePackage; private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); @@ -2808,6 +2811,7 @@ public class PackageManagerService extends IPackageManager.Stub mIncidentReportApproverPackage = testParams.incidentReportApproverPackage; mServicesExtensionPackageName = testParams.servicesExtensionPackageName; mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName; + mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage; mResolveComponentName = testParams.resolveComponentName; mPackages.putAll(testParams.packages); @@ -3373,6 +3377,7 @@ public class PackageManagerService extends IPackageManager.Stub mAppPredictionServicePackage = getAppPredictionServicePackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); mRetailDemoPackage = getRetailDemoPackageName(); + mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName(); // Now that we know all of the shared libraries, update all clients to have // the correct library paths. @@ -12096,12 +12101,8 @@ public class PackageManagerService extends IPackageManager.Stub if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { // Exempt SharedUsers signed with the platform key. PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); - if ((platformPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.getSigningDetails().signatures) - != PackageManager.SIGNATURE_MATCH)) { + if (!comparePackageSignatures(platformPkgSetting, + pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Apps that share a user with a " + "privileged app must themselves be marked as privileged. " + pkg.getPackageName() + " shares privileged user " + @@ -12148,12 +12149,8 @@ public class PackageManagerService extends IPackageManager.Stub if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { final PackageSetting platformPkgSetting = mSettings.getPackageLPr("android"); - if ((platformPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - platformPkgSetting.signatures.mSigningDetails.signatures, - pkg.getSigningDetails().signatures) - != PackageManager.SIGNATURE_MATCH)) { + if (!comparePackageSignatures(platformPkgSetting, + pkg.getSigningDetails().signatures)) { throw new PackageManagerException("Overlay " + pkg.getPackageName() + " must target Q or later, " @@ -12162,24 +12159,35 @@ public class PackageManagerService extends IPackageManager.Stub } // A non-preloaded overlay package, without <overlay android:targetName>, will - // only be used if it is signed with the same certificate as its target. If the - // target is already installed, check this here to augment the last line of - // defence which is OMS. + // only be used if it is signed with the same certificate as its target OR if + // it is signed with the same certificate as a reference package declared + // in 'config-signature' tag of SystemConfig. + // If the target is already installed or 'config-signature' tag in SystemConfig + // is set, check this here to augment the last line of defence which is OMS. if (pkg.getOverlayTargetName() == null) { final PackageSetting targetPkgSetting = mSettings.getPackageLPr(pkg.getOverlayTarget()); if (targetPkgSetting != null) { - if ((targetPkgSetting.signatures.mSigningDetails - != PackageParser.SigningDetails.UNKNOWN) - && (compareSignatures( - targetPkgSetting.signatures.mSigningDetails.signatures, - pkg.getSigningDetails().signatures) - != PackageManager.SIGNATURE_MATCH)) { - throw new PackageManagerException("Overlay " - + pkg.getPackageName() + " and target " - + pkg.getOverlayTarget() + " signed with" - + " different certificates, and the overlay lacks" - + " <overlay android:targetName>"); + if (!comparePackageSignatures(targetPkgSetting, + pkg.getSigningDetails().signatures)) { + // check reference signature + if (mOverlayConfigSignaturePackage == null) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " and target " + + pkg.getOverlayTarget() + " signed with" + + " different certificates, and the overlay lacks" + + " <overlay android:targetName>"); + } + final PackageSetting refPkgSetting = + mSettings.getPackageLPr(mOverlayConfigSignaturePackage); + if (!comparePackageSignatures(refPkgSetting, + pkg.getSigningDetails().signatures)) { + throw new PackageManagerException("Overlay " + + pkg.getPackageName() + " signed with a different " + + "certificate than both the reference package and " + + "target " + pkg.getOverlayTarget() + ", and the " + + "overlay lacks <overlay android:targetName>"); + } } } } @@ -20712,6 +20720,11 @@ public class PackageManagerService extends IPackageManager.Stub return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName()); } + public String getOverlayConfigSignaturePackageName() { + return ensureSystemPackageName(SystemConfig.getInstance() + .getOverlayConfigSignaturePackage()); + } + @Nullable private String getRetailDemoPackageName() { final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage); @@ -24228,6 +24241,8 @@ public class PackageManagerService extends IPackageManager.Stub return TextUtils.isEmpty(mRetailDemoPackage) ? ArrayUtils.emptyArray(String.class) : new String[] {mRetailDemoPackage}; + case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE: + return filterOnlySystemPackages(getOverlayConfigSignaturePackageName()); default: return ArrayUtils.emptyArray(String.class); } diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java index 03f4708c09c4..de0e4b53adab 100644 --- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java +++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java @@ -488,6 +488,18 @@ public class PackageManagerServiceUtils { } /** + * Returns true if the signature set of the package is identical to the specified signature + * set or if the signing details of the package are unknown. + */ + public static boolean comparePackageSignatures(PackageSetting pkgSetting, + Signature[] signatures) { + return pkgSetting.signatures.mSigningDetails + == PackageParser.SigningDetails.UNKNOWN + || compareSignatures(pkgSetting.signatures.mSigningDetails.signatures, signatures) + == PackageManager.SIGNATURE_MATCH; + } + + /** * Used for backward compatibility to make sure any packages with * certificate chains get upgraded to the new style. {@code existingSigs} * will be in the old format (since they were stored on disk from before the diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt index e08eea298aaf..08392737350a 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt +++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt @@ -160,7 +160,7 @@ class OverlayActorEnforcerTests { private val hasPermission: Boolean = false, private val overlayableInfo: OverlayableInfo? = null, private vararg val packageNames: String = arrayOf("com.test.actor.one") - ) : OverlayableInfoCallback { + ) : PackageManagerHelper { override fun getNamedActors() = if (isActor) { mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME)) @@ -195,6 +195,14 @@ class OverlayActorEnforcerTests { } } + override fun getConfigSignaturePackage(): String { + throw UnsupportedOperationException() + } + + override fun getOverlayPackages(userId: Int): MutableList<PackageInfo> { + throw UnsupportedOperationException() + } + override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean { throw UnsupportedOperationException() } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java index b7692f912e39..e281f2b206f5 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java @@ -44,9 +44,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testUpdateOverlaysForUser() { final OverlayManagerServiceImpl impl = getImpl(); - addSystemPackage(target(TARGET), USER); - addSystemPackage(target("some.other.target"), USER);; - addSystemPackage(overlay(OVERLAY, TARGET), USER); + addPackage(target(TARGET), USER); + addPackage(target("some.other.target"), USER); + addPackage(overlay(OVERLAY, TARGET), USER); // do nothing, expect no change final List<String> a = impl.updateOverlaysForUser(USER); @@ -54,7 +54,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI assertTrue(a.contains(TARGET)); // upgrade overlay, keep target - addSystemPackage(overlay(OVERLAY, TARGET), USER); + addPackage(overlay(OVERLAY, TARGET), USER); final List<String> b = impl.updateOverlaysForUser(USER); assertEquals(1, b.size()); @@ -66,7 +66,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI assertTrue(c.contains(TARGET)); // upgrade overlay, switch to new target - addSystemPackage(overlay(OVERLAY, "some.other.target"), USER); + addPackage(overlay(OVERLAY, "some.other.target"), USER); final List<String> d = impl.updateOverlaysForUser(USER); assertEquals(2, d.size()); assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target"))); diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index f4c5506c7001..c1d862ab2ad4 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -19,6 +19,7 @@ package com.android.server.om; import static android.content.om.OverlayInfo.STATE_DISABLED; import static android.content.om.OverlayInfo.STATE_ENABLED; import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; +import static android.os.OverlayablePolicy.CONFIG_SIGNATURE; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -49,6 +50,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes private static final String OVERLAY3 = OVERLAY + "3"; private static final int USER3 = USER2 + 1; + private static final String CONFIG_SIGNATURE_REFERENCE_PKG = "com.dummy.ref"; + private static final String CERT_CONFIG_OK = "config_certificate_ok"; + private static final String CERT_CONFIG_NOK = "config_certificate_nok"; + @Test public void testGetOverlayInfo() { installNewPackage(overlay(OVERLAY, TARGET), USER); @@ -204,4 +209,87 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes impl.setEnabled(OVERLAY, true, USER); assertEquals(0, listener.count); } + + @Test + public void testConfigSignaturePolicyOk() { + setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); + reinitializeImpl(); + + addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_OK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == CONFIG_SIGNATURE); + } + + @Test + public void testConfigSignaturePolicyCertNok() { + setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); + reinitializeImpl(); + + addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } + + @Test + public void testConfigSignaturePolicyNoConfig() { + addPackage(target(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } + + @Test + public void testConfigSignaturePolicyNoRefPkg() { + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } + + @Test + public void testConfigSignaturePolicyRefPkgNotSystem() { + setConfigSignaturePackageName(CONFIG_SIGNATURE_REFERENCE_PKG); + reinitializeImpl(); + + addPackage(app(CONFIG_SIGNATURE_REFERENCE_PKG).setCertificate(CERT_CONFIG_OK), USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET).setCertificate(CERT_CONFIG_NOK), USER); + + final DummyIdmapDaemon idmapd = getIdmapd(); + final DummyDeviceState state = getState(); + String overlayPath = state.select(OVERLAY, USER).apkPath; + assertTrue(idmapd.idmapExists(overlayPath, USER)); + + DummyIdmapDaemon.IdmapHeader idmap = idmapd.getIdmap(overlayPath); + assertTrue((CONFIG_SIGNATURE & idmap.policies) == 0); + } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index 733310b2508a..2faf29f45375 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -27,6 +27,7 @@ import android.content.om.OverlayInfo.State; import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -52,6 +53,7 @@ class OverlayManagerServiceImplTestsBase { private DummyPackageManagerHelper mPackageManager; private DummyIdmapDaemon mIdmapDaemon; private OverlayConfig mOverlayConfig; + private String mConfigSignaturePackageName; @Before public void setUp() { @@ -83,6 +85,18 @@ class OverlayManagerServiceImplTestsBase { return mListener; } + DummyIdmapDaemon getIdmapd() { + return mIdmapDaemon; + } + + DummyDeviceState getState() { + return mState; + } + + void setConfigSignaturePackageName(String packageName) { + mConfigSignaturePackageName = packageName; + } + void assertState(@State int expected, final String overlayPackageName, int userId) { final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId); if (info == null) { @@ -102,9 +116,14 @@ class OverlayManagerServiceImplTestsBase { assertEquals(expected, actual); } + DummyDeviceState.PackageBuilder app(String packageName) { + return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */, + null /* targetOverlayableName */, "data"); + } + DummyDeviceState.PackageBuilder target(String packageName) { return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */, - null /* targetOverlayableName */); + null /* targetOverlayableName */, ""); } DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) { @@ -114,10 +133,10 @@ class OverlayManagerServiceImplTestsBase { DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName, String targetOverlayableName) { return new DummyDeviceState.PackageBuilder(packageName, targetPackageName, - targetOverlayableName); + targetOverlayableName, ""); } - void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) { + void addPackage(DummyDeviceState.PackageBuilder pkg, int userId) { mState.add(pkg, userId); } @@ -242,15 +261,17 @@ class OverlayManagerServiceImplTestsBase { private String packageName; private String targetPackage; private String certificate = "[default]"; + private String partition; private int version = 0; private ArrayList<String> overlayableNames = new ArrayList<>(); private String targetOverlayableName; private PackageBuilder(String packageName, String targetPackage, - String targetOverlayableName) { + String targetOverlayableName, String partition) { this.packageName = packageName; this.targetPackage = targetPackage; this.targetOverlayableName = targetOverlayableName; + this.partition = partition; } PackageBuilder setCertificate(String certificate) { @@ -269,9 +290,19 @@ class OverlayManagerServiceImplTestsBase { } Package build() { - final String apkPath = String.format("%s/%s/base.apk", - targetPackage == null ? "/system/app/:" : "/vendor/overlay/:", - packageName); + String path = ""; + if (TextUtils.isEmpty(partition)) { + if (targetPackage == null) { + path = "/system/app"; + } else { + path = "/vendor/overlay"; + } + } else { + String type = targetPackage == null ? "app" : "overlay"; + path = String.format("%s/%s", partition, type); + } + + final String apkPath = String.format("%s/%s/base.apk", path, packageName); final Package newPackage = new Package(packageName, targetPackage, targetOverlayableName, version, apkPath, certificate); newPackage.overlayableNames.addAll(overlayableNames); @@ -302,8 +333,7 @@ class OverlayManagerServiceImplTestsBase { } } - static final class DummyPackageManagerHelper implements PackageManagerHelper, - OverlayableInfoCallback { + final class DummyPackageManagerHelper implements PackageManagerHelper { private final DummyDeviceState mState; private DummyPackageManagerHelper(DummyDeviceState state) { @@ -343,6 +373,11 @@ class OverlayManagerServiceImplTestsBase { .collect(Collectors.toList()); } + @Override + public @NonNull String getConfigSignaturePackage() { + return mConfigSignaturePackageName; + } + @Nullable @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index ab9ce66b0ae3..b1e1a77e1224 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -168,6 +168,7 @@ message OverlayableItem { ODM = 6; OEM = 7; ACTOR = 8; + CONFIG_SIGNATURE = 9; } // The location of the <item> declaration in source. diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index 59627ce579af..6932baf76c75 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -776,6 +776,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { OverlayableItem overlayable_item_three(group_one); overlayable_item_three.policies |= PolicyFlags::SIGNATURE; overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; + overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -830,7 +831,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE - | PolicyFlags::ACTOR_SIGNATURE); + | PolicyFlags::ACTOR_SIGNATURE + | PolicyFlags::CONFIG_SIGNATURE); } TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index 2fd01d7f3dee..7eb8ebd9a043 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -404,6 +404,9 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, case pb::OverlayableItem::ACTOR: out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE; break; + case pb::OverlayableItem::CONFIG_SIGNATURE: + out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE; + break; default: *out_error = "unknown overlayable policy"; return false; diff --git a/tools/aapt2/format/proto/ProtoSerialize.cpp b/tools/aapt2/format/proto/ProtoSerialize.cpp index ba6df22af9d3..831229ffa383 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -325,6 +325,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); } + if (overlayable_item.policies & PolicyFlags::CONFIG_SIGNATURE) { + pb_overlayable_item->add_policy(pb::OverlayableItem::CONFIG_SIGNATURE); + } if (source_pool != nullptr) { SerializeSourceToPb(overlayable_item.source, source_pool, |