diff options
30 files changed, 343 insertions, 141 deletions
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl index 85b5eff46efa..02b27a8800b6 100644 --- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl +++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl @@ -28,4 +28,5 @@ interface OverlayablePolicy { const int SIGNATURE = 0x00000010; const int ODM_PARTITION = 0x00000020; const int OEM_PARTITION = 0x00000040; + const int ACTOR_SIGNATURE = 0x00000080; } diff --git a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h index 9f9b836e31d5..4973b7638d10 100644 --- a/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h +++ b/cmds/idmap2/libidmap2_policies/include/idmap2/Policies.h @@ -29,6 +29,7 @@ using PolicyFlags = android::ResTable_overlayable_policy_header::PolicyFlags; namespace android::idmap2::policy { +constexpr const char* kPolicyActor = "actor"; constexpr const char* kPolicyOdm = "odm"; constexpr const char* kPolicyOem = "oem"; constexpr const char* kPolicyProduct = "product"; @@ -37,8 +38,9 @@ constexpr const char* kPolicySignature = "signature"; constexpr const char* kPolicySystem = "system"; constexpr const char* kPolicyVendor = "vendor"; -inline static const std::array<std::pair<StringPiece, PolicyFlags>, 7> kPolicyStringToFlag = { - std::pair{kPolicyOdm, PolicyFlags::ODM_PARTITION}, +inline static const std::array<std::pair<StringPiece, PolicyFlags>, 8> kPolicyStringToFlag = { + std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE}, + {kPolicyOdm, PolicyFlags::ODM_PARTITION}, {kPolicyOem, PolicyFlags::OEM_PARTITION}, {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION}, {kPolicyPublic, PolicyFlags::PUBLIC}, diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp index 76c6eaf75adc..87da36c01192 100644 --- a/cmds/idmap2/tests/IdmapTests.cpp +++ b/cmds/idmap2/tests/IdmapTests.cpp @@ -279,17 +279,25 @@ TEST(IdmapTests, CreateIdmapDataFromApkAssetsSharedLibOverlay) { const auto& target_entries = data->GetTargetEntries(); ASSERT_EQ(target_entries.size(), 4U); - ASSERT_TARGET_ENTRY(target_entries[0], 0x7f010000, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00010000); - ASSERT_TARGET_ENTRY(target_entries[1], 0x7f02000c, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020000); - ASSERT_TARGET_ENTRY(target_entries[2], 0x7f02000e, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020001); - ASSERT_TARGET_ENTRY(target_entries[3], 0x7f02000f, Res_value::TYPE_DYNAMIC_REFERENCE, 0x00020002); + ASSERT_TARGET_ENTRY(target_entries[0], R::target::integer::int1, + Res_value::TYPE_DYNAMIC_REFERENCE, R::overlay_shared::integer::int1); + ASSERT_TARGET_ENTRY(target_entries[1], R::target::string::str1, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay_shared::string::str1); + ASSERT_TARGET_ENTRY(target_entries[2], R::target::string::str3, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay_shared::string::str3); + ASSERT_TARGET_ENTRY(target_entries[3], R::target::string::str4, Res_value::TYPE_DYNAMIC_REFERENCE, + R::overlay_shared::string::str4); const auto& overlay_entries = data->GetOverlayEntries(); ASSERT_EQ(target_entries.size(), 4U); - ASSERT_OVERLAY_ENTRY(overlay_entries[0], 0x00010000, 0x7f010000); - ASSERT_OVERLAY_ENTRY(overlay_entries[1], 0x00020000, 0x7f02000c); - ASSERT_OVERLAY_ENTRY(overlay_entries[2], 0x00020001, 0x7f02000e); - ASSERT_OVERLAY_ENTRY(overlay_entries[3], 0x00020002, 0x7f02000f); + ASSERT_OVERLAY_ENTRY(overlay_entries[0], R::overlay_shared::integer::int1, + R::target::integer::int1); + ASSERT_OVERLAY_ENTRY(overlay_entries[1], R::overlay_shared::string::str1, + R::target::string::str1); + ASSERT_OVERLAY_ENTRY(overlay_entries[2], R::overlay_shared::string::str3, + R::target::string::str3); + ASSERT_OVERLAY_ENTRY(overlay_entries[3], R::overlay_shared::string::str4, + R::target::string::str4); } TEST(IdmapTests, CreateIdmapDataDoNotRewriteNonOverlayResourceId) { diff --git a/cmds/idmap2/tests/PoliciesTests.cpp b/cmds/idmap2/tests/PoliciesTests.cpp index 4b395c7912d1..1b2775939886 100644 --- a/cmds/idmap2/tests/PoliciesTests.cpp +++ b/cmds/idmap2/tests/PoliciesTests.cpp @@ -67,6 +67,14 @@ TEST(PoliciesTests, PoliciesToBitmaskResults) { const auto bitmask10 = PoliciesToBitmaskResult({"system "}); ASSERT_FALSE(bitmask10); + + const auto bitmask11 = PoliciesToBitmaskResult({"signature"}); + ASSERT_TRUE(bitmask11); + ASSERT_EQ(*bitmask11, PolicyFlags::SIGNATURE); + + const auto bitmask12 = PoliciesToBitmaskResult({"actor"}); + ASSERT_TRUE(bitmask12); + ASSERT_EQ(*bitmask12, PolicyFlags::ACTOR_SIGNATURE); } TEST(PoliciesTests, BitmaskToPolicies) { @@ -91,6 +99,14 @@ TEST(PoliciesTests, BitmaskToPolicies) { ASSERT_EQ(policies3[3], "public"); ASSERT_EQ(policies3[4], "system"); ASSERT_EQ(policies3[5], "vendor"); + + const auto policies4 = BitmaskToPolicies(PolicyFlags::SIGNATURE); + ASSERT_EQ(1, policies4.size()); + ASSERT_EQ(policies4[0], "signature"); + + const auto policies5 = BitmaskToPolicies(PolicyFlags::ACTOR_SIGNATURE); + ASSERT_EQ(1, policies5.size()); + ASSERT_EQ(policies5[0], "actor"); } } // namespace android::idmap2 diff --git a/cmds/idmap2/tests/R.h b/cmds/idmap2/tests/R.h index b2a589144c77..aed263a49aa3 100644 --- a/cmds/idmap2/tests/R.h +++ b/cmds/idmap2/tests/R.h @@ -40,16 +40,17 @@ namespace R::target { namespace string { constexpr ResourceId not_overlayable = 0x7f020003; constexpr ResourceId other = 0x7f020004; - constexpr ResourceId policy_odm = 0x7f020005; - constexpr ResourceId policy_oem = 0x7f020006; - constexpr ResourceId policy_product = 0x7f020007; - constexpr ResourceId policy_public = 0x7f020008; - constexpr ResourceId policy_signature = 0x7f020009; - constexpr ResourceId policy_system = 0x7f02000a; - constexpr ResourceId policy_system_vendor = 0x7f02000b; - constexpr ResourceId str1 = 0x7f02000c; - constexpr ResourceId str3 = 0x7f02000e; - constexpr ResourceId str4 = 0x7f02000f; + 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; namespace literal { inline const std::string str1 = hexify(R::target::string::str1); @@ -70,6 +71,17 @@ namespace R::overlay { } } +namespace R::overlay_shared { + namespace integer { + constexpr ResourceId int1 = 0x00010000; + } + namespace string { + constexpr ResourceId str1 = 0x00020000; + constexpr ResourceId str3 = 0x00020001; + constexpr ResourceId str4 = 0x00020002; + } +} + namespace R::system_overlay::string { constexpr ResourceId policy_public = 0x7f010000; constexpr ResourceId policy_system = 0x7f010001; @@ -79,13 +91,14 @@ namespace R::system_overlay::string { namespace R::system_overlay_invalid::string { constexpr ResourceId not_overlayable = 0x7f010000; constexpr ResourceId other = 0x7f010001; - constexpr ResourceId policy_odm = 0x7f010002; - constexpr ResourceId policy_oem = 0x7f010003; - constexpr ResourceId policy_product = 0x7f010004; - constexpr ResourceId policy_public = 0x7f010005; - constexpr ResourceId policy_signature = 0x7f010006; - constexpr ResourceId policy_system = 0x7f010007; - constexpr ResourceId policy_system_vendor = 0x7f010008; + 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; }; // clang-format on diff --git a/cmds/idmap2/tests/ResourceMappingTests.cpp b/cmds/idmap2/tests/ResourceMappingTests.cpp index 8d0e6609ac40..de039f440e33 100644 --- a/cmds/idmap2/tests/ResourceMappingTests.cpp +++ b/cmds/idmap2/tests/ResourceMappingTests.cpp @@ -237,12 +237,15 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(res.GetTargetToOverlayMap().size(), 9U); + ASSERT_EQ(res.GetTargetToOverlayMap().size(), 10U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::other, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_actor, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_odm, false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_oem, Res_value::TYPE_REFERENCE, @@ -306,12 +309,15 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { ASSERT_TRUE(resources) << resources.GetErrorMessage(); auto& res = *resources; - ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 9U); + ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 10U); ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::not_overlayable, false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::other, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::other, false /* rewrite */)); + ASSERT_RESULT(MappingExists(res, R::target::string::policy_actor, Res_value::TYPE_REFERENCE, + R::system_overlay_invalid::string::policy_actor, + false /* rewrite */)); ASSERT_RESULT(MappingExists(res, R::target::string::policy_odm, Res_value::TYPE_REFERENCE, R::system_overlay_invalid::string::policy_odm, false /* rewrite */)); diff --git a/cmds/idmap2/tests/TestConstants.h b/cmds/idmap2/tests/TestConstants.h index c874dc93ce79..6bc924e5ac3c 100644 --- a/cmds/idmap2/tests/TestConstants.h +++ b/cmds/idmap2/tests/TestConstants.h @@ -19,8 +19,8 @@ namespace android::idmap2::TestConstants { -constexpr const auto TARGET_CRC = 0x76a20829; -constexpr const auto TARGET_CRC_STRING = "76a20829"; +constexpr const auto TARGET_CRC = 0x41c60c8c; +constexpr const auto TARGET_CRC_STRING = "41c60c8c"; constexpr const auto OVERLAY_CRC = 0xc054fb26; constexpr const auto OVERLAY_CRC_STRING = "c054fb26"; 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 9ebfae41e4c5..7119d8283061 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 @@ -25,6 +25,7 @@ <string name="policy_signature">policy_signature</string> <string name="policy_odm">policy_odm</string> <string name="policy_oem">policy_oem</string> + <string name="policy_actor">policy_actor</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 1456e749e796..bd990983693c 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/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml index 8389f5635e15..ad4cd4882632 100644 --- a/cmds/idmap2/tests/data/target/res/values/overlayable.xml +++ b/cmds/idmap2/tests/data/target/res/values/overlayable.xml @@ -41,6 +41,10 @@ <item type="string" name="policy_oem" /> </policy> + <policy type="actor"> + <item type="string" name="policy_actor" /> + </policy> + <!-- Resources publicly overlayable --> <policy type="public"> <item type="string" name="policy_public" /> @@ -63,4 +67,4 @@ <item type="string" name="other" /> </policy> </overlayable> -</resources>
\ No newline at end of file +</resources> diff --git a/cmds/idmap2/tests/data/target/res/values/values.xml b/cmds/idmap2/tests/data/target/res/values/values.xml index a892c98f0fbb..5230e25e626b 100644 --- a/cmds/idmap2/tests/data/target/res/values/values.xml +++ b/cmds/idmap2/tests/data/target/res/values/values.xml @@ -36,6 +36,7 @@ <string name="policy_signature">policy_signature</string> <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="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 2eb7c477c3b4..58504a74a83a 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 251cf46f969d..c80e5eb65ff2 100644 --- a/cmds/idmap2/tests/data/target/target.apk +++ b/cmds/idmap2/tests/data/target/target.apk diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java index 55a6cab2f2d5..62815ddcfc19 100644 --- a/core/java/android/content/om/OverlayInfo.java +++ b/core/java/android/content/om/OverlayInfo.java @@ -138,6 +138,7 @@ public final class OverlayInfo implements Parcelable { * * @hide */ + @NonNull public final String packageName; /** @@ -145,6 +146,7 @@ public final class OverlayInfo implements Parcelable { * * @hide */ + @NonNull public final String targetPackageName; /** @@ -165,6 +167,7 @@ public final class OverlayInfo implements Parcelable { * Full path to the base APK for this overlay package * @hide */ + @NonNull public final String baseCodePath; /** @@ -292,6 +295,7 @@ public final class OverlayInfo implements Parcelable { return targetOverlayableName; } + @SuppressWarnings("ConstantConditions") private void ensureValidState() { if (packageName == null) { throw new IllegalArgumentException("packageName must not be null"); diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index d15a3a27cbb1..2bfc7fc38d1c 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1682,7 +1682,6 @@ struct ResTable_overlayable_policy_header * Flags for a bitmask for all possible overlayable policy options. * * Any changes to this set should also update aidl/android/os/OverlayablePolicy.aidl - * and proto/OverlayablePolicy.proto. */ enum PolicyFlags : uint32_t { // Base @@ -1703,8 +1702,8 @@ struct ResTable_overlayable_policy_header // partition before an upgrade to overlay these resources. PRODUCT_PARTITION = 0x00000008, - // The overlay must be signed with the same signature as the actor of the target resource, - // which can be separate or the same as the target package with the resource. + // The overlay must be signed with the same signature as the package containing the target + // resource SIGNATURE = 0x00000010, // The overlay must reside of the odm partition or must have existed on the odm @@ -1714,6 +1713,10 @@ struct ResTable_overlayable_policy_header // The overlay must reside of the oem partition or must have existed on the oem // partition before an upgrade to overlay these resources. OEM_PARTITION = 0x00000040, + + // The overlay must be signed with the same signature as the actor declared for the target + // resource + ACTOR_SIGNATURE = 0x00000080, }; using PolicyBitmask = uint32_t; diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 48a1afd2be59..7c9be2dfacd6 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -21,6 +21,7 @@ import static com.android.server.om.OverlayManagerService.TAG; import android.annotation.NonNull; import android.content.om.OverlayInfo; +import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.os.Build.VERSION_CODES; @@ -29,9 +30,8 @@ import android.os.SystemProperties; import android.os.UserHandle; import android.util.Slog; -import com.android.server.om.OverlayManagerServiceImpl.PackageManagerHelper; - import java.io.File; +import java.io.IOException; /** * Handle the creation and deletion of idmap files. @@ -55,11 +55,11 @@ class IdmapManager { VENDOR_IS_Q_OR_LATER = isQOrLater; } - private final PackageManagerHelper mPackageManager; + private final OverlayableInfoCallback mOverlayableCallback; private final IdmapDaemon mIdmapDaemon; - IdmapManager(final PackageManagerHelper packageManager) { - mPackageManager = packageManager; + IdmapManager(final OverlayableInfoCallback verifyCallback) { + mOverlayableCallback = verifyCallback; mIdmapDaemon = IdmapDaemon.getInstance(); } @@ -151,11 +151,16 @@ class IdmapManager { int fulfilledPolicies = OverlayablePolicy.PUBLIC; // Overlay matches target signature - if (mPackageManager.signaturesMatching(targetPackage.packageName, + if (mOverlayableCallback.signaturesMatching(targetPackage.packageName, overlayPackage.packageName, userId)) { fulfilledPolicies |= OverlayablePolicy.SIGNATURE; } + // Overlay matches actor signature + if (matchesActorSignature(targetPackage, overlayPackage, userId)) { + fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE; + } + // Vendor partition (/vendor) if (ai.isVendor()) { return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION; @@ -184,4 +189,26 @@ class IdmapManager { return fulfilledPolicies; } + + private boolean matchesActorSignature(@NonNull PackageInfo targetPackage, + @NonNull PackageInfo overlayPackage, int userId) { + String targetOverlayableName = overlayPackage.targetOverlayableName; + if (targetOverlayableName != null) { + try { + OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget( + targetPackage.packageName, targetOverlayableName, userId); + if (overlayableInfo != null) { + String actorPackageName = OverlayActorEnforcer.getPackageNameForActor( + overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first; + if (mOverlayableCallback.signaturesMatching(actorPackageName, + overlayPackage.packageName, userId)) { + return true; + } + } + } catch (IOException ignored) { + } + } + + return false; + } } diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index 4c85603a719c..40efb7cd96d7 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -17,7 +17,6 @@ package com.android.server.om; import android.annotation.NonNull; -import android.annotation.Nullable; import android.content.om.OverlayInfo; import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; @@ -46,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 VerifyCallback mVerifyCallback; + private final OverlayableInfoCallback mOverlayableCallback; /** * @return nullable actor result with {@link ActorState} failure status @@ -80,8 +79,8 @@ public class OverlayActorEnforcer { return Pair.create(packageName, ActorState.ALLOWED); } - public OverlayActorEnforcer(@NonNull VerifyCallback verifyCallback) { - mVerifyCallback = verifyCallback; + public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) { + mOverlayableCallback = overlayableCallback; } void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName, @@ -117,7 +116,7 @@ public class OverlayActorEnforcer { return ActorState.ALLOWED; } - String[] callingPackageNames = mVerifyCallback.getPackagesForUid(callingUid); + String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid); if (ArrayUtils.isEmpty(callingPackageNames)) { return ActorState.NO_PACKAGES_FOR_UID; } @@ -132,12 +131,12 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(targetOverlayableName)) { try { - if (mVerifyCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { + if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { return ActorState.MISSING_TARGET_OVERLAYABLE_NAME; } else { // If there's no overlayable defined, fallback to the legacy permission check try { - mVerifyCallback.enforcePermission( + mOverlayableCallback.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -153,7 +152,7 @@ public class OverlayActorEnforcer { OverlayableInfo targetOverlayable; try { - targetOverlayable = mVerifyCallback.getOverlayableForTarget(targetPackageName, + targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName, targetOverlayableName, userId); } catch (IOException e) { return ActorState.UNABLE_TO_GET_TARGET; @@ -167,7 +166,7 @@ public class OverlayActorEnforcer { if (TextUtils.isEmpty(actor)) { // If there's no actor defined, fallback to the legacy permission check try { - mVerifyCallback.enforcePermission( + mOverlayableCallback.enforcePermission( android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); // If the previous method didn't throw, check passed @@ -177,7 +176,7 @@ public class OverlayActorEnforcer { } } - Map<String, Map<String, String>> namedActors = mVerifyCallback.getNamedActors(); + Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors(); Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors); ActorState actorUriState = actorUriPair.second; if (actorUriState != ActorState.ALLOWED) { @@ -185,7 +184,7 @@ public class OverlayActorEnforcer { } String packageName = actorUriPair.first; - PackageInfo packageInfo = mVerifyCallback.getPackageInfo(packageName, userId); + PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId); if (packageInfo == null) { return ActorState.MISSING_APP_INFO; } @@ -211,7 +210,7 @@ public class OverlayActorEnforcer { * For easier logging/debugging, a set of all possible failure/success states when running * enforcement. */ - enum ActorState { + public enum ActorState { ALLOWED, INVALID_ACTOR, MISSING_NAMESPACE, @@ -228,53 +227,4 @@ public class OverlayActorEnforcer { UNABLE_TO_GET_TARGET, MISSING_LEGACY_PERMISSION } - - /** - * Delegate to the system for querying information about packages. - */ - public interface VerifyCallback { - - /** - * 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, - @Nullable String targetOverlayableName, int userId) - throws IOException; - - /** - * @see android.content.pm.PackageManager#getPackagesForUid(int) - */ - @Nullable - String[] getPackagesForUid(int uid); - - /** - * @param userId user to filter package visibility by - * @see android.content.pm.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 RemoteException, IOException; - - /** - * @throws SecurityException containing message if the caller doesn't have the given - * permission - */ - void enforcePermission(String permission, String message) throws SecurityException; - } } diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index f22128533ac2..c81f7cd4a8b4 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -226,7 +226,7 @@ public final class OverlayManagerService extends SystemService { private final AtomicFile mSettingsFile; - private final PackageManagerHelper mPackageManager; + private final PackageManagerHelperImpl mPackageManager; private final UserManagerService mUserManager; @@ -244,7 +244,7 @@ public final class OverlayManagerService extends SystemService { traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService"); mSettingsFile = new AtomicFile( new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays"); - mPackageManager = new PackageManagerHelper(context); + mPackageManager = new PackageManagerHelperImpl(context); mUserManager = UserManagerService.getInstance(); IdmapManager im = new IdmapManager(mPackageManager); mSettings = new OverlayManagerSettings(); @@ -1053,14 +1053,8 @@ public final class OverlayManagerService extends SystemService { } } - /** - * Delegate for {@link android.content.pm.PackageManager} and {@link PackageManagerInternal} - * functionality, separated for easy testing. - * - * @hide - */ - public static final class PackageManagerHelper implements - OverlayManagerServiceImpl.PackageManagerHelper, OverlayActorEnforcer.VerifyCallback { + private static final class PackageManagerHelperImpl implements PackageManagerHelper, + OverlayableInfoCallback { private final Context mContext; private final IPackageManager mPackageManager; @@ -1073,7 +1067,7 @@ public final class OverlayManagerService extends SystemService { // behind until all pending intents have been processed. private final SparseArray<HashMap<String, PackageInfo>> mCache = new SparseArray<>(); - PackageManagerHelper(Context context) { + PackageManagerHelperImpl(Context context) { mContext = context; mPackageManager = getPackageManager(); mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class); @@ -1132,7 +1126,7 @@ public final class OverlayManagerService extends SystemService { @Nullable @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, - @Nullable String targetOverlayableName, int userId) + @NonNull String targetOverlayableName, int userId) throws IOException { PackageInfo packageInfo = getPackageInfo(packageName, userId); if (packageInfo == null) { diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index 2493057e0121..5734271ecb83 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -18,7 +18,6 @@ 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_ENABLED_IMMUTABLE; import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; import static android.content.om.OverlayInfo.STATE_NO_IDMAP; import static android.content.om.OverlayInfo.STATE_OVERLAY_IS_BEING_REPLACED; @@ -806,11 +805,4 @@ final class OverlayManagerServiceImpl { **/ void onOverlaysChanged(@NonNull String targetPackage, int userId); } - - interface PackageManagerHelper { - PackageInfo getPackageInfo(@NonNull String packageName, int userId); - boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2, - int userId); - List<PackageInfo> getOverlayPackages(int userId); - } } diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java new file mode 100644 index 000000000000..6b818849c257 --- /dev/null +++ b/services/core/java/com/android/server/om/OverlayableInfoCallback.java @@ -0,0 +1,85 @@ +/* + * 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 android.os.RemoteException; + +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 RemoteException, 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 new file mode 100644 index 000000000000..ec9c5e64e390 --- /dev/null +++ b/services/core/java/com/android/server/om/PackageManagerHelper.java @@ -0,0 +1,36 @@ +/* + * 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.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; + +import java.util.List; + +/** + * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality, + * separated for easy testing. + * + * @hide + */ +interface PackageManagerHelper { + PackageInfo getPackageInfo(@NonNull String packageName, int userId); + boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); + List<PackageInfo> getOverlayPackages(int userId); +} 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 233e16c297a3..e08eea298aaf 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt +++ b/services/tests/servicestests/src/com/android/server/om/OverlayActorEnforcerTests.kt @@ -24,6 +24,7 @@ import android.os.Process import org.junit.Rule import org.junit.Test import org.junit.rules.ExpectedException +import java.lang.UnsupportedOperationException class OverlayActorEnforcerTests { companion object { @@ -159,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") - ) : OverlayActorEnforcer.VerifyCallback { + ) : OverlayableInfoCallback { override fun getNamedActors() = if (isActor) { mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME)) @@ -169,7 +170,7 @@ class OverlayActorEnforcerTests { override fun getOverlayableForTarget( packageName: String, - targetOverlayableName: String?, + targetOverlayableName: String, userId: Int ) = overlayableInfo @@ -193,5 +194,9 @@ class OverlayActorEnforcerTests { throw SecurityException() } } + + override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean { + throw UnsupportedOperationException() + } } } 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 a428a97e51cd..cd7343235750 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -24,30 +24,16 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; -import android.annotation.NonNull; import android.content.om.OverlayInfo; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.util.ArraySet; import androidx.test.runner.AndroidJUnit4; -import com.android.internal.content.om.OverlayConfig; - -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.Set; @RunWith(AndroidJUnit4.class) public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTestsBase { 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 a753aac39c48..820e61cb0a08 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -23,10 +23,13 @@ import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.content.om.OverlayInfo; import android.content.om.OverlayInfo.State; +import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.util.ArraySet; +import androidx.annotation.Nullable; + import com.android.internal.content.om.OverlayConfig; import org.junit.Before; @@ -35,6 +38,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -281,8 +285,8 @@ class OverlayManagerServiceImplTestsBase { } } - static final class DummyPackageManagerHelper implements - OverlayManagerServiceImpl.PackageManagerHelper { + static final class DummyPackageManagerHelper implements PackageManagerHelper, + OverlayableInfoCallback { private final DummyDeviceState mState; private DummyPackageManagerHelper(DummyDeviceState state) { @@ -320,6 +324,35 @@ class OverlayManagerServiceImplTestsBase { .map(p -> getPackageInfo(p.packageName, p.userId)) .collect(Collectors.toList()); } + + @Nullable + @Override + public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, + @NonNull String targetOverlayableName, int userId) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public String[] getPackagesForUid(int uid) { + throw new UnsupportedOperationException(); + } + + @NonNull + @Override + public Map<String, Map<String, String>> getNamedActors() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) { + throw new UnsupportedOperationException(); + } + + @Override + public void enforcePermission(String permission, String message) throws SecurityException { + throw new UnsupportedOperationException(); + } } static class DummyIdmapManager extends IdmapManager { diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 77e7fc55a229..9b70079a98c9 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -1007,6 +1007,9 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { <policy type="oem"> <item type="string" name="buz" /> </policy> + <policy type="actor"> + <item type="string" name="actor" /> + </policy> </overlayable>)"; ASSERT_TRUE(TestParse(input)); @@ -1065,6 +1068,14 @@ TEST_F(ResourceParserTest, ParseOverlayablePolicy) { result_overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::OEM_PARTITION)); + + search_result = table_.FindResource(test::ParseNameOrDie("string/actor")); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(result_overlayable_item.overlayable->name, Eq("Name")); + EXPECT_THAT(result_overlayable_item.policies, Eq(PolicyFlags::ACTOR_SIGNATURE)); } TEST_F(ResourceParserTest, ParseOverlayableNoPolicyError) { diff --git a/tools/aapt2/Resources.proto b/tools/aapt2/Resources.proto index 8a2f5afa7255..ab9ce66b0ae3 100644 --- a/tools/aapt2/Resources.proto +++ b/tools/aapt2/Resources.proto @@ -167,6 +167,7 @@ message OverlayableItem { SIGNATURE = 5; ODM = 6; OEM = 7; + ACTOR = 8; } // 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 e1e0f17c8dbb..59627ce579af 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -775,6 +775,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { std::string name_three = "com.app.test:integer/overlayable_three"; OverlayableItem overlayable_item_three(group_one); overlayable_item_three.policies |= PolicyFlags::SIGNATURE; + overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() @@ -828,7 +829,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { result_overlayable = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); - EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE); + EXPECT_EQ(result_overlayable.policies, PolicyFlags::SIGNATURE + | PolicyFlags::ACTOR_SIGNATURE); } TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { diff --git a/tools/aapt2/format/proto/ProtoDeserialize.cpp b/tools/aapt2/format/proto/ProtoDeserialize.cpp index db8e093594a0..2fd01d7f3dee 100644 --- a/tools/aapt2/format/proto/ProtoDeserialize.cpp +++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp @@ -401,6 +401,9 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable, case pb::OverlayableItem::OEM: out_overlayable->policies |= PolicyFlags::OEM_PARTITION; break; + case pb::OverlayableItem::ACTOR: + out_overlayable->policies |= PolicyFlags::ACTOR_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 6bc4524d3d5c..ba6df22af9d3 100644 --- a/tools/aapt2/format/proto/ProtoSerialize.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize.cpp @@ -322,6 +322,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item if (overlayable_item.policies & PolicyFlags::OEM_PARTITION) { pb_overlayable_item->add_policy(pb::OverlayableItem::OEM); } + if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { + pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); + } if (source_pool != nullptr) { SerializeSourceToPb(overlayable_item.source, source_pool, diff --git a/tools/aapt2/format/proto/ProtoSerialize_test.cpp b/tools/aapt2/format/proto/ProtoSerialize_test.cpp index cdc86597b2f3..1a7de6dc1c48 100644 --- a/tools/aapt2/format/proto/ProtoSerialize_test.cpp +++ b/tools/aapt2/format/proto/ProtoSerialize_test.cpp @@ -536,6 +536,11 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { overlayable_item_boz.policies |= PolicyFlags::ODM_PARTITION; overlayable_item_boz.policies |= PolicyFlags::OEM_PARTITION; + OverlayableItem overlayable_item_actor_config(std::make_shared<Overlayable>( + "ActorConfig", "overlay://theme")); + overlayable_item_actor_config.policies |= PolicyFlags::SIGNATURE; + overlayable_item_actor_config.policies |= PolicyFlags::ACTOR_SIGNATURE; + OverlayableItem overlayable_item_biz(std::make_shared<Overlayable>( "Other", "overlay://customization")); overlayable_item_biz.comment ="comment"; @@ -548,6 +553,7 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { .SetOverlayable("com.app.a:bool/baz", overlayable_item_baz) .SetOverlayable("com.app.a:bool/boz", overlayable_item_boz) .SetOverlayable("com.app.a:bool/biz", overlayable_item_biz) + .SetOverlayable("com.app.a:bool/actor_config", overlayable_item_actor_config) .AddValue("com.app.a:bool/fiz", ResourceUtils::TryParseBool("true")) .Build(); @@ -597,6 +603,15 @@ TEST(ProtoSerializeTest, SerializeAndDeserializeOverlayable) { | PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION)); + search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/actor_config")); + ASSERT_TRUE(search_result); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + overlayable_item = search_result.value().entry->overlayable_item.value(); + EXPECT_THAT(overlayable_item.overlayable->name, Eq("ActorConfig")); + EXPECT_THAT(overlayable_item.overlayable->actor, Eq("overlay://theme")); + EXPECT_THAT(overlayable_item.policies, Eq(PolicyFlags::SIGNATURE + | PolicyFlags::ACTOR_SIGNATURE)); + search_result = new_table.FindResource(test::ParseNameOrDie("com.app.a:bool/biz")); ASSERT_TRUE(search_result); ASSERT_TRUE(search_result.value().entry->overlayable_item); |