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
diff --git a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
index 02b27a8..403d8c5 100644
--- a/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
+++ b/cmds/idmap2/idmap2d/aidl/android/os/OverlayablePolicy.aidl
@@ -29,4 +29,5 @@
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 34589a1..fd8b4eb 100644
--- a/cmds/idmap2/libidmap2/ResourceMapping.cpp
+++ b/cmds/idmap2/libidmap2/ResourceMapping.cpp
@@ -61,10 +61,13 @@
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 5bd353a..8046319 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* 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 aed263a..89b4346 100644
--- a/cmds/idmap2/tests/R.h
+++ b/cmds/idmap2/tests/R.h
@@ -41,16 +41,17 @@
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 @@
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 de039f4..3ec6ac2 100644
--- a/cmds/idmap2/tests/ResourceMappingTests.cpp
+++ b/cmds/idmap2/tests/ResourceMappingTests.cpp
@@ -237,7 +237,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
};
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 6bc924e..641a7a8 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
index 7c25985..dab25b1 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name-static.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
index c75f3e1..c8b95c2 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-no-name.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-shared.apk b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
index 93dcc82..0a8b737 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-shared.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-shared.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
index 5b8a6e4..fd41182 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-1.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
index 698a1fd..b24765f 100644
--- a/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay-static-2.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/overlay/overlay.apk b/cmds/idmap2/tests/data/overlay/overlay.apk
index 1db303f..870575e 100644
--- a/cmds/idmap2/tests/data/overlay/overlay.apk
+++ b/cmds/idmap2/tests/data/overlay/overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
index 51e19de..e0fd204 100644
--- a/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
+++ b/cmds/idmap2/tests/data/signature-overlay/signature-overlay.apk
Binary files differ
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 7119d82..ebaf49c 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
index bd99098..a63daf8 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
Binary files differ
diff --git a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
index a0fba43..90d2803 100644
--- a/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
+++ b/cmds/idmap2/tests/data/system-overlay/system-overlay.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/res/values/overlayable.xml b/cmds/idmap2/tests/data/target/res/values/overlayable.xml
index ad4cd48..57e6c43 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 5230e25..00909a9 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
index 58504a7..cc3491d 100644
--- a/cmds/idmap2/tests/data/target/target-no-overlayable.apk
+++ b/cmds/idmap2/tests/data/target/target-no-overlayable.apk
Binary files differ
diff --git a/cmds/idmap2/tests/data/target/target.apk b/cmds/idmap2/tests/data/target/target.apk
index c80e5eb..4a58c5e 100644
--- a/cmds/idmap2/tests/data/target/target.apk
+++ b/cmds/idmap2/tests/data/target/target.apk
Binary files differ
diff --git a/core/java/com/android/server/SystemConfig.java b/core/java/com/android/server/SystemConfig.java
index ea390cd..4fc66bc 100644
--- a/core/java/com/android/server/SystemConfig.java
+++ b/core/java/com/android/server/SystemConfig.java
@@ -19,6 +19,7 @@
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 @@
*/
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 @@
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 @@
}
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 e351a46..e10a7f3 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -1717,6 +1717,10 @@
// 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 b241bd1..ad1986a 100644
--- a/services/core/java/android/content/pm/PackageManagerInternal.java
+++ b/services/core/java/android/content/pm/PackageManagerInternal.java
@@ -69,6 +69,7 @@
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 d6b1b27..cb6e960 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.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 @@
}
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 @@
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 @@
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 @@
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 2bc3499..8c03c6c 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 @@
// 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
}
- 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 @@
}
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 3968153..0f8c9c7 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 @@
}
}
- 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 @@
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 5066ecd..0000000
--- 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 ec9c5e6..b1a8b4e 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 @@
* @hide
*/
interface PackageManagerHelper {
- PackageInfo getPackageInfo(@NonNull String packageName, int userId);
- boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId);
+ /**
+ * @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);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4f0c707..fddd46a 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.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 @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 @@
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 @@
mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
+ mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
mResolveComponentName = testParams.resolveComponentName;
mPackages.putAll(testParams.packages);
@@ -3373,6 +3377,7 @@
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 @@
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 @@
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 @@
}
// 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 @@
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 @@
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 03f4708..de0e4b5 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 @@
}
/**
+ * 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 e08eea2..0839273 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 @@
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 @@
}
}
+ 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 b7692f9..e281f2b 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 @@
@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 @@
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 @@
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 f4c5506..c1d862a 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 @@
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 @@
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 @@
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 733310b..2faf29f 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.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 @@
private DummyPackageManagerHelper mPackageManager;
private DummyIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig;
+ private String mConfigSignaturePackageName;
@Before
public void setUp() {
@@ -83,6 +85,18 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
}
}
- static final class DummyPackageManagerHelper implements PackageManagerHelper,
- OverlayableInfoCallback {
+ final class DummyPackageManagerHelper implements PackageManagerHelper {
private final DummyDeviceState mState;
private DummyPackageManagerHelper(DummyDeviceState state) {
@@ -343,6 +373,11 @@
.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 ab9ce66..b1e1a77 100644
--- a/tools/aapt2/Resources.proto
+++ b/tools/aapt2/Resources.proto
@@ -168,6 +168,7 @@
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 59627ce..6932baf 100644
--- a/tools/aapt2/format/binary/TableFlattener_test.cpp
+++ b/tools/aapt2/format/binary/TableFlattener_test.cpp
@@ -776,6 +776,7 @@
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 @@
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 2fd01d7..7eb8ebd 100644
--- a/tools/aapt2/format/proto/ProtoDeserialize.cpp
+++ b/tools/aapt2/format/proto/ProtoDeserialize.cpp
@@ -404,6 +404,9 @@
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 ba6df22..831229f 100644
--- a/tools/aapt2/format/proto/ProtoSerialize.cpp
+++ b/tools/aapt2/format/proto/ProtoSerialize.cpp
@@ -325,6 +325,9 @@
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,