OMS: Add config_signature policy handling am: 0f942f99ca

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1453997

Change-Id: I779b6c73a37b0ccd42afa1b899a2b6e4a3c17f92
This commit is contained in:
Zoran Jovanovic
2020-10-19 18:28:24 +00:00
committed by Automerger Merge Worker
38 changed files with 415 additions and 175 deletions

View File

@@ -29,4 +29,5 @@ interface OverlayablePolicy {
const int ODM_PARTITION = 0x00000020; const int ODM_PARTITION = 0x00000020;
const int OEM_PARTITION = 0x00000040; const int OEM_PARTITION = 0x00000040;
const int ACTOR_SIGNATURE = 0x00000080; const int ACTOR_SIGNATURE = 0x00000080;
const int CONFIG_SIGNATURE = 0x0000100;
} }

View File

@@ -61,10 +61,13 @@ Result<Unit> CheckOverlayable(const LoadedPackage& target_package,
const ResourceId& target_resource) { const ResourceId& target_resource) {
static constexpr const PolicyBitmask sDefaultPolicies = static constexpr const PolicyBitmask sDefaultPolicies =
PolicyFlags::ODM_PARTITION | PolicyFlags::OEM_PARTITION | PolicyFlags::SYSTEM_PARTITION | 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 // 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()) { if (!target_package.DefinesOverlayable()) {
return (sDefaultPolicies & fulfilled_policies) != 0 return (sDefaultPolicies & fulfilled_policies) != 0
? Result<Unit>({}) ? Result<Unit>({})

View File

@@ -37,16 +37,18 @@ constexpr const char* kPolicyOdm = "odm";
constexpr const char* kPolicyOem = "oem"; constexpr const char* kPolicyOem = "oem";
constexpr const char* kPolicyProduct = "product"; constexpr const char* kPolicyProduct = "product";
constexpr const char* kPolicyPublic = "public"; constexpr const char* kPolicyPublic = "public";
constexpr const char* kPolicyConfigSignature = "config_signature";
constexpr const char* kPolicySignature = "signature"; constexpr const char* kPolicySignature = "signature";
constexpr const char* kPolicySystem = "system"; constexpr const char* kPolicySystem = "system";
constexpr const char* kPolicyVendor = "vendor"; 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}, std::pair{kPolicyActor, PolicyFlags::ACTOR_SIGNATURE},
{kPolicyOdm, PolicyFlags::ODM_PARTITION}, {kPolicyOdm, PolicyFlags::ODM_PARTITION},
{kPolicyOem, PolicyFlags::OEM_PARTITION}, {kPolicyOem, PolicyFlags::OEM_PARTITION},
{kPolicyProduct, PolicyFlags::PRODUCT_PARTITION}, {kPolicyProduct, PolicyFlags::PRODUCT_PARTITION},
{kPolicyPublic, PolicyFlags::PUBLIC}, {kPolicyPublic, PolicyFlags::PUBLIC},
{kPolicyConfigSignature, PolicyFlags::CONFIG_SIGNATURE},
{kPolicySignature, PolicyFlags::SIGNATURE}, {kPolicySignature, PolicyFlags::SIGNATURE},
{kPolicySystem, PolicyFlags::SYSTEM_PARTITION}, {kPolicySystem, PolicyFlags::SYSTEM_PARTITION},
{kPolicyVendor, PolicyFlags::VENDOR_PARTITION}, {kPolicyVendor, PolicyFlags::VENDOR_PARTITION},

View File

@@ -41,16 +41,17 @@ namespace R::target {
constexpr ResourceId not_overlayable = 0x7f020003; constexpr ResourceId not_overlayable = 0x7f020003;
constexpr ResourceId other = 0x7f020004; constexpr ResourceId other = 0x7f020004;
constexpr ResourceId policy_actor = 0x7f020005; constexpr ResourceId policy_actor = 0x7f020005;
constexpr ResourceId policy_odm = 0x7f020006; constexpr ResourceId policy_config_signature = 0x7f020006;
constexpr ResourceId policy_oem = 0x7f020007; constexpr ResourceId policy_odm = 0x7f020007;
constexpr ResourceId policy_product = 0x7f020008; constexpr ResourceId policy_oem = 0x7f020008;
constexpr ResourceId policy_public = 0x7f020009; constexpr ResourceId policy_product = 0x7f020009;
constexpr ResourceId policy_signature = 0x7f02000a; constexpr ResourceId policy_public = 0x7f02000a;
constexpr ResourceId policy_system = 0x7f02000b; constexpr ResourceId policy_signature = 0x7f02000b;
constexpr ResourceId policy_system_vendor = 0x7f02000c; constexpr ResourceId policy_system = 0x7f02000c;
constexpr ResourceId str1 = 0x7f02000d; constexpr ResourceId policy_system_vendor = 0x7f02000d;
constexpr ResourceId str3 = 0x7f02000f; constexpr ResourceId str1 = 0x7f02000e;
constexpr ResourceId str4 = 0x7f020010; constexpr ResourceId str3 = 0x7f020010;
constexpr ResourceId str4 = 0x7f020011;
namespace literal { namespace literal {
inline const std::string str1 = hexify(R::target::string::str1); inline const std::string str1 = hexify(R::target::string::str1);
@@ -92,14 +93,15 @@ namespace R::system_overlay_invalid::string {
constexpr ResourceId not_overlayable = 0x7f010000; constexpr ResourceId not_overlayable = 0x7f010000;
constexpr ResourceId other = 0x7f010001; constexpr ResourceId other = 0x7f010001;
constexpr ResourceId policy_actor = 0x7f010002; constexpr ResourceId policy_actor = 0x7f010002;
constexpr ResourceId policy_odm = 0x7f010003; constexpr ResourceId policy_config_signature = 0x7f010003;
constexpr ResourceId policy_oem = 0x7f010004; constexpr ResourceId policy_odm = 0x7f010004;
constexpr ResourceId policy_product = 0x7f010005; constexpr ResourceId policy_oem = 0x7f010005;
constexpr ResourceId policy_public = 0x7f010006; constexpr ResourceId policy_product = 0x7f010006;
constexpr ResourceId policy_signature = 0x7f010007; constexpr ResourceId policy_public = 0x7f010007;
constexpr ResourceId policy_system = 0x7f010008; constexpr ResourceId policy_signature = 0x7f010008;
constexpr ResourceId policy_system_vendor = 0x7f010009; constexpr ResourceId policy_system = 0x7f010009;
}; constexpr ResourceId policy_system_vendor = 0x7f01000a;
}
// clang-format on // clang-format on
} // namespace android::idmap2 } // namespace android::idmap2

View File

@@ -237,7 +237,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore
ASSERT_TRUE(resources) << resources.GetErrorMessage(); ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources; 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, ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::not_overlayable, R::system_overlay_invalid::string::not_overlayable,
false /* rewrite */)); false /* rewrite */));
@@ -256,6 +256,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsPolicySystemPublicInvalidIgnore
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_public, R::system_overlay_invalid::string::policy_public,
false /* rewrite */)); 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, ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_signature, R::system_overlay_invalid::string::policy_signature,
false /* rewrite */)); false /* rewrite */));
@@ -298,8 +302,9 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPoliciesPublicFail) {
ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U); ASSERT_EQ(resources->GetTargetToOverlayMap().size(), 0U);
} }
// Overlays that are pre-installed or are signed with the same signature as the target can overlay // Overlays that are pre-installed or are signed with the same signature as the target or are signed
// packages that have not defined overlayable resources. // with the same signature as the reference package can overlay packages that have not defined
// overlayable resources.
TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) { TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void { auto CheckEntries = [&](const PolicyBitmask& fulfilled_policies) -> void {
auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk", auto resources = TestGetResourceMapping("/target/target-no-overlayable.apk",
@@ -309,7 +314,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
ASSERT_TRUE(resources) << resources.GetErrorMessage(); ASSERT_TRUE(resources) << resources.GetErrorMessage();
auto& res = *resources; 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, ASSERT_RESULT(MappingExists(res, R::target::string::not_overlayable, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::not_overlayable, R::system_overlay_invalid::string::not_overlayable,
false /* rewrite */)); false /* rewrite */));
@@ -330,6 +335,10 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE, ASSERT_RESULT(MappingExists(res, R::target::string::policy_public, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_public, R::system_overlay_invalid::string::policy_public,
false /* rewrite */)); 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, ASSERT_RESULT(MappingExists(res, R::target::string::policy_signature, Res_value::TYPE_REFERENCE,
R::system_overlay_invalid::string::policy_signature, R::system_overlay_invalid::string::policy_signature,
false /* rewrite */)); false /* rewrite */));
@@ -342,6 +351,7 @@ TEST(ResourceMappingTests, ResourcesFromApkAssetsDefaultPolicies) {
}; };
CheckEntries(PolicyFlags::SIGNATURE); CheckEntries(PolicyFlags::SIGNATURE);
CheckEntries(PolicyFlags::CONFIG_SIGNATURE);
CheckEntries(PolicyFlags::PRODUCT_PARTITION); CheckEntries(PolicyFlags::PRODUCT_PARTITION);
CheckEntries(PolicyFlags::SYSTEM_PARTITION); CheckEntries(PolicyFlags::SYSTEM_PARTITION);
CheckEntries(PolicyFlags::VENDOR_PARTITION); CheckEntries(PolicyFlags::VENDOR_PARTITION);

View File

@@ -19,11 +19,11 @@
namespace android::idmap2::TestConstants { namespace android::idmap2::TestConstants {
constexpr const auto TARGET_CRC = 0x41c60c8c; constexpr const auto TARGET_CRC = 0x7c2d4719;
constexpr const auto TARGET_CRC_STRING = "41c60c8c"; constexpr const auto TARGET_CRC_STRING = "7c2d4719";
constexpr const auto OVERLAY_CRC = 0xc054fb26; constexpr const auto OVERLAY_CRC = 0x5afff726;
constexpr const auto OVERLAY_CRC_STRING = "c054fb26"; constexpr const auto OVERLAY_CRC_STRING = "5afff726";
} // namespace android::idmap2::TestConstants } // namespace android::idmap2::TestConstants

View File

@@ -26,6 +26,7 @@
<string name="policy_odm">policy_odm</string> <string name="policy_odm">policy_odm</string>
<string name="policy_oem">policy_oem</string> <string name="policy_oem">policy_oem</string>
<string name="policy_actor">policy_actor</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. --> <!-- Requests to overlay a resource that is not declared as overlayable. -->
<string name="not_overlayable">not_overlayable</string> <string name="not_overlayable">not_overlayable</string>

View File

@@ -45,6 +45,10 @@
<item type="string" name="policy_actor" /> <item type="string" name="policy_actor" />
</policy> </policy>
<policy type="config_signature">
<item type="string" name="policy_config_signature"/>
</policy>
<!-- Resources publicly overlayable --> <!-- Resources publicly overlayable -->
<policy type="public"> <policy type="public">
<item type="string" name="policy_public" /> <item type="string" name="policy_public" />

View File

@@ -37,6 +37,7 @@
<string name="policy_system">policy_system</string> <string name="policy_system">policy_system</string>
<string name="policy_system_vendor">policy_system_vendor</string> <string name="policy_system_vendor">policy_system_vendor</string>
<string name="policy_actor">policy_actor</string> <string name="policy_actor">policy_actor</string>
<string name="policy_config_signature">policy_config_signature</string>
<string name="other">other</string> <string name="other">other</string>
</resources> </resources>

View File

@@ -19,6 +19,7 @@ package com.android.server;
import static com.android.internal.util.ArrayUtils.appendInt; import static com.android.internal.util.ArrayUtils.appendInt;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.ActivityManager; import android.app.ActivityManager;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.pm.FeatureInfo; import android.content.pm.FeatureInfo;
@@ -238,6 +239,14 @@ public class SystemConfig {
*/ */
private Map<String, Map<String, String>> mNamedActors = null; 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() { public static SystemConfig getInstance() {
if (!isSystemProcess()) { if (!isSystemProcess()) {
Slog.wtf(TAG, "SystemConfig is being accessed by a process other than " Slog.wtf(TAG, "SystemConfig is being accessed by a process other than "
@@ -433,6 +442,12 @@ public class SystemConfig {
return mNamedActors != null ? mNamedActors : Collections.emptyMap(); 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. * Only use for testing. Do NOT use in production code.
* @param readPermissions false to create an empty SystemConfig; true to read the permissions. * @param readPermissions false to create an empty SystemConfig; true to read the permissions.
@@ -1151,6 +1166,27 @@ public class SystemConfig {
} }
XmlUtils.skipCurrentTag(parser); XmlUtils.skipCurrentTag(parser);
} break; } 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": { case "rollback-whitelisted-app": {
String pkgname = parser.getAttributeValue(null, "package"); String pkgname = parser.getAttributeValue(null, "package");
if (pkgname == null) { if (pkgname == null) {

View File

@@ -1717,6 +1717,10 @@ struct ResTable_overlayable_policy_header
// The overlay must be signed with the same signature as the actor declared for the target // The overlay must be signed with the same signature as the actor declared for the target
// resource // resource
ACTOR_SIGNATURE = 0x00000080, 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; using PolicyBitmask = uint32_t;

View File

@@ -69,6 +69,7 @@ public abstract class PackageManagerInternal {
public static final int PACKAGE_WIFI = 13; public static final int PACKAGE_WIFI = 13;
public static final int PACKAGE_COMPANION = 14; public static final int PACKAGE_COMPANION = 14;
public static final int PACKAGE_RETAIL_DEMO = 15; public static final int PACKAGE_RETAIL_DEMO = 15;
public static final int PACKAGE_OVERLAY_CONFIG_SIGNATURE = 16;
@IntDef(flag = true, prefix = "RESOLVE_", value = { @IntDef(flag = true, prefix = "RESOLVE_", value = {
RESOLVE_NON_BROWSER_ONLY, RESOLVE_NON_BROWSER_ONLY,

View File

@@ -27,6 +27,7 @@ import android.content.pm.PackageInfo;
import android.os.Build.VERSION_CODES; import android.os.Build.VERSION_CODES;
import android.os.OverlayablePolicy; import android.os.OverlayablePolicy;
import android.os.SystemProperties; import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.Slog; import android.util.Slog;
import java.io.IOException; import java.io.IOException;
@@ -53,11 +54,20 @@ final class IdmapManager {
} }
private final IdmapDaemon mIdmapDaemon; 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; mIdmapDaemon = idmapDaemon;
mConfigSignaturePackage = packageManager.getConfigSignaturePackage();
} }
/** /**
@@ -139,7 +149,7 @@ final class IdmapManager {
int fulfilledPolicies = OverlayablePolicy.PUBLIC; int fulfilledPolicies = OverlayablePolicy.PUBLIC;
// Overlay matches target signature // Overlay matches target signature
if (mOverlayableCallback.signaturesMatching(targetPackage.packageName, if (mPackageManager.signaturesMatching(targetPackage.packageName,
overlayPackage.packageName, userId)) { overlayPackage.packageName, userId)) {
fulfilledPolicies |= OverlayablePolicy.SIGNATURE; fulfilledPolicies |= OverlayablePolicy.SIGNATURE;
} }
@@ -149,6 +159,16 @@ final class IdmapManager {
fulfilledPolicies |= OverlayablePolicy.ACTOR_SIGNATURE; 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) // Vendor partition (/vendor)
if (ai.isVendor()) { if (ai.isVendor()) {
return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION; return fulfilledPolicies | OverlayablePolicy.VENDOR_PARTITION;
@@ -183,12 +203,12 @@ final class IdmapManager {
String targetOverlayableName = overlayPackage.targetOverlayableName; String targetOverlayableName = overlayPackage.targetOverlayableName;
if (targetOverlayableName != null) { if (targetOverlayableName != null) {
try { try {
OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget( OverlayableInfo overlayableInfo = mPackageManager.getOverlayableForTarget(
targetPackage.packageName, targetOverlayableName, userId); targetPackage.packageName, targetOverlayableName, userId);
if (overlayableInfo != null && overlayableInfo.actor != null) { if (overlayableInfo != null && overlayableInfo.actor != null) {
String actorPackageName = OverlayActorEnforcer.getPackageNameForActor( String actorPackageName = OverlayActorEnforcer.getPackageNameForActor(
overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first; overlayableInfo.actor, mPackageManager.getNamedActors()).first;
if (mOverlayableCallback.signaturesMatching(actorPackageName, if (mPackageManager.signaturesMatching(actorPackageName,
overlayPackage.packageName, userId)) { overlayPackage.packageName, userId)) {
return true; return true;
} }

View File

@@ -45,7 +45,7 @@ public class OverlayActorEnforcer {
// By default, the reason is not logged to prevent leaks of why it failed // By default, the reason is not logged to prevent leaks of why it failed
private static final boolean DEBUG_REASON = false; private static final boolean DEBUG_REASON = false;
private final OverlayableInfoCallback mOverlayableCallback; private final PackageManagerHelper mPackageManager;
/** /**
* @return nullable actor result with {@link ActorState} failure status * @return nullable actor result with {@link ActorState} failure status
@@ -79,8 +79,8 @@ public class OverlayActorEnforcer {
return Pair.create(packageName, ActorState.ALLOWED); return Pair.create(packageName, ActorState.ALLOWED);
} }
public OverlayActorEnforcer(@NonNull OverlayableInfoCallback overlayableCallback) { public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) {
mOverlayableCallback = overlayableCallback; mPackageManager = packageManager;
} }
void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName, void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName,
@@ -110,7 +110,7 @@ public class OverlayActorEnforcer {
return ActorState.ALLOWED; return ActorState.ALLOWED;
} }
String[] callingPackageNames = mOverlayableCallback.getPackagesForUid(callingUid); String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid);
if (ArrayUtils.isEmpty(callingPackageNames)) { if (ArrayUtils.isEmpty(callingPackageNames)) {
return ActorState.NO_PACKAGES_FOR_UID; return ActorState.NO_PACKAGES_FOR_UID;
} }
@@ -125,12 +125,12 @@ public class OverlayActorEnforcer {
if (TextUtils.isEmpty(targetOverlayableName)) { if (TextUtils.isEmpty(targetOverlayableName)) {
try { try {
if (mOverlayableCallback.doesTargetDefineOverlayable(targetPackageName, userId)) { if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) {
return ActorState.MISSING_TARGET_OVERLAYABLE_NAME; return ActorState.MISSING_TARGET_OVERLAYABLE_NAME;
} else { } else {
// If there's no overlayable defined, fallback to the legacy permission check // If there's no overlayable defined, fallback to the legacy permission check
try { try {
mOverlayableCallback.enforcePermission( mPackageManager.enforcePermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
// If the previous method didn't throw, check passed // If the previous method didn't throw, check passed
@@ -146,7 +146,7 @@ public class OverlayActorEnforcer {
OverlayableInfo targetOverlayable; OverlayableInfo targetOverlayable;
try { try {
targetOverlayable = mOverlayableCallback.getOverlayableForTarget(targetPackageName, targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName,
targetOverlayableName, userId); targetOverlayableName, userId);
} catch (IOException e) { } catch (IOException e) {
return ActorState.UNABLE_TO_GET_TARGET; return ActorState.UNABLE_TO_GET_TARGET;
@@ -160,7 +160,7 @@ public class OverlayActorEnforcer {
if (TextUtils.isEmpty(actor)) { if (TextUtils.isEmpty(actor)) {
// If there's no actor defined, fallback to the legacy permission check // If there's no actor defined, fallback to the legacy permission check
try { try {
mOverlayableCallback.enforcePermission( mPackageManager.enforcePermission(
android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName);
// If the previous method didn't throw, check passed // If the previous method didn't throw, check passed
@@ -170,7 +170,7 @@ public class OverlayActorEnforcer {
} }
} }
Map<String, Map<String, String>> namedActors = mOverlayableCallback.getNamedActors(); Map<String, Map<String, String>> namedActors = mPackageManager.getNamedActors();
Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors); Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors);
ActorState actorUriState = actorUriPair.second; ActorState actorUriState = actorUriPair.second;
if (actorUriState != ActorState.ALLOWED) { if (actorUriState != ActorState.ALLOWED) {
@@ -178,7 +178,7 @@ public class OverlayActorEnforcer {
} }
String packageName = actorUriPair.first; String packageName = actorUriPair.first;
PackageInfo packageInfo = mOverlayableCallback.getPackageInfo(packageName, userId); PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, userId);
if (packageInfo == null) { if (packageInfo == null) {
return ActorState.MISSING_APP_INFO; return ActorState.MISSING_APP_INFO;
} }

View File

@@ -1053,8 +1053,7 @@ public final class OverlayManagerService extends SystemService {
} }
} }
private static final class PackageManagerHelperImpl implements PackageManagerHelper, private static final class PackageManagerHelperImpl implements PackageManagerHelper {
OverlayableInfoCallback {
private final Context mContext; private final Context mContext;
private final IPackageManager mPackageManager; private final IPackageManager mPackageManager;
@@ -1127,6 +1126,14 @@ public final class OverlayManagerService extends SystemService {
return overlays; 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 @Nullable
@Override @Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,

View File

@@ -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);
}

View File

@@ -17,11 +17,17 @@
package com.android.server.om; package com.android.server.om;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.om.OverlayableInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManagerInternal;
import com.android.server.pm.PackageManagerServiceUtils;
import java.io.IOException;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality, * Delegate for {@link PackageManager} and {@link PackageManagerInternal} functionality,
@@ -30,7 +36,65 @@ import java.util.List;
* @hide * @hide
*/ */
interface PackageManagerHelper { 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); 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);
} }

View File

@@ -120,6 +120,7 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet;
import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter; 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.compareSignatures;
import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists; import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists;
import static com.android.server.pm.PackageManagerServiceUtils.decompressFile; import static com.android.server.pm.PackageManagerServiceUtils.decompressFile;
@@ -1114,6 +1115,7 @@ public class PackageManagerService extends IPackageManager.Stub
public @Nullable String storageManagerPackage; public @Nullable String storageManagerPackage;
public @Nullable String defaultTextClassifierPackage; public @Nullable String defaultTextClassifierPackage;
public @Nullable String systemTextClassifierPackage; public @Nullable String systemTextClassifierPackage;
public @Nullable String overlayConfigSignaturePackage;
public ViewCompiler viewCompiler; public ViewCompiler viewCompiler;
public @Nullable String wellbeingPackage; public @Nullable String wellbeingPackage;
public @Nullable String retailDemoPackage; public @Nullable String retailDemoPackage;
@@ -1646,6 +1648,7 @@ public class PackageManagerService extends IPackageManager.Stub
final @Nullable String mServicesExtensionPackageName; final @Nullable String mServicesExtensionPackageName;
final @Nullable String mSharedSystemSharedLibraryPackageName; final @Nullable String mSharedSystemSharedLibraryPackageName;
final @Nullable String mRetailDemoPackage; final @Nullable String mRetailDemoPackage;
final @Nullable String mOverlayConfigSignaturePackage;
private final PackageUsage mPackageUsage = new PackageUsage(); private final PackageUsage mPackageUsage = new PackageUsage();
private final CompilerStats mCompilerStats = new CompilerStats(); private final CompilerStats mCompilerStats = new CompilerStats();
@@ -2808,6 +2811,7 @@ public class PackageManagerService extends IPackageManager.Stub
mIncidentReportApproverPackage = testParams.incidentReportApproverPackage; mIncidentReportApproverPackage = testParams.incidentReportApproverPackage;
mServicesExtensionPackageName = testParams.servicesExtensionPackageName; mServicesExtensionPackageName = testParams.servicesExtensionPackageName;
mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName; mSharedSystemSharedLibraryPackageName = testParams.sharedSystemSharedLibraryPackageName;
mOverlayConfigSignaturePackage = testParams.overlayConfigSignaturePackage;
mResolveComponentName = testParams.resolveComponentName; mResolveComponentName = testParams.resolveComponentName;
mPackages.putAll(testParams.packages); mPackages.putAll(testParams.packages);
@@ -3373,6 +3377,7 @@ public class PackageManagerService extends IPackageManager.Stub
mAppPredictionServicePackage = getAppPredictionServicePackageName(); mAppPredictionServicePackage = getAppPredictionServicePackageName();
mIncidentReportApproverPackage = getIncidentReportApproverPackageName(); mIncidentReportApproverPackage = getIncidentReportApproverPackageName();
mRetailDemoPackage = getRetailDemoPackageName(); mRetailDemoPackage = getRetailDemoPackageName();
mOverlayConfigSignaturePackage = getOverlayConfigSignaturePackageName();
// Now that we know all of the shared libraries, update all clients to have // Now that we know all of the shared libraries, update all clients to have
// the correct library paths. // the correct library paths.
@@ -12100,12 +12105,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) { if (sharedUserSetting != null && sharedUserSetting.isPrivileged()) {
// Exempt SharedUsers signed with the platform key. // Exempt SharedUsers signed with the platform key.
PackageSetting platformPkgSetting = mSettings.mPackages.get("android"); PackageSetting platformPkgSetting = mSettings.mPackages.get("android");
if ((platformPkgSetting.signatures.mSigningDetails if (!comparePackageSignatures(platformPkgSetting,
!= PackageParser.SigningDetails.UNKNOWN) pkg.getSigningDetails().signatures)) {
&& (compareSignatures(
platformPkgSetting.signatures.mSigningDetails.signatures,
pkg.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH)) {
throw new PackageManagerException("Apps that share a user with a " + throw new PackageManagerException("Apps that share a user with a " +
"privileged app must themselves be marked as privileged. " + "privileged app must themselves be marked as privileged. " +
pkg.getPackageName() + " shares privileged user " + pkg.getPackageName() + " shares privileged user " +
@@ -12152,12 +12153,8 @@ public class PackageManagerService extends IPackageManager.Stub
if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) { if (pkg.getTargetSdkVersion() < Build.VERSION_CODES.Q) {
final PackageSetting platformPkgSetting = final PackageSetting platformPkgSetting =
mSettings.getPackageLPr("android"); mSettings.getPackageLPr("android");
if ((platformPkgSetting.signatures.mSigningDetails if (!comparePackageSignatures(platformPkgSetting,
!= PackageParser.SigningDetails.UNKNOWN) pkg.getSigningDetails().signatures)) {
&& (compareSignatures(
platformPkgSetting.signatures.mSigningDetails.signatures,
pkg.getSigningDetails().signatures)
!= PackageManager.SIGNATURE_MATCH)) {
throw new PackageManagerException("Overlay " throw new PackageManagerException("Overlay "
+ pkg.getPackageName() + pkg.getPackageName()
+ " must target Q or later, " + " must target Q or later, "
@@ -12166,24 +12163,35 @@ public class PackageManagerService extends IPackageManager.Stub
} }
// A non-preloaded overlay package, without <overlay android:targetName>, will // 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 // only be used if it is signed with the same certificate as its target OR if
// target is already installed, check this here to augment the last line of // it is signed with the same certificate as a reference package declared
// defence which is OMS. // 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) { if (pkg.getOverlayTargetName() == null) {
final PackageSetting targetPkgSetting = final PackageSetting targetPkgSetting =
mSettings.getPackageLPr(pkg.getOverlayTarget()); mSettings.getPackageLPr(pkg.getOverlayTarget());
if (targetPkgSetting != null) { if (targetPkgSetting != null) {
if ((targetPkgSetting.signatures.mSigningDetails if (!comparePackageSignatures(targetPkgSetting,
!= PackageParser.SigningDetails.UNKNOWN) pkg.getSigningDetails().signatures)) {
&& (compareSignatures( // check reference signature
targetPkgSetting.signatures.mSigningDetails.signatures, if (mOverlayConfigSignaturePackage == null) {
pkg.getSigningDetails().signatures) throw new PackageManagerException("Overlay "
!= PackageManager.SIGNATURE_MATCH)) { + pkg.getPackageName() + " and target "
throw new PackageManagerException("Overlay " + pkg.getOverlayTarget() + " signed with"
+ pkg.getPackageName() + " and target " + " different certificates, and the overlay lacks"
+ pkg.getOverlayTarget() + " signed with" + " <overlay android:targetName>");
+ " 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>");
}
} }
} }
} }
@@ -20716,6 +20724,11 @@ public class PackageManagerService extends IPackageManager.Stub
return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName()); return ensureSystemPackageName(contentCaptureServiceComponentName.getPackageName());
} }
public String getOverlayConfigSignaturePackageName() {
return ensureSystemPackageName(SystemConfig.getInstance()
.getOverlayConfigSignaturePackage());
}
@Nullable @Nullable
private String getRetailDemoPackageName() { private String getRetailDemoPackageName() {
final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage); final String predefinedPkgName = mContext.getString(R.string.config_retailDemoPackage);
@@ -24232,6 +24245,8 @@ public class PackageManagerService extends IPackageManager.Stub
return TextUtils.isEmpty(mRetailDemoPackage) return TextUtils.isEmpty(mRetailDemoPackage)
? ArrayUtils.emptyArray(String.class) ? ArrayUtils.emptyArray(String.class)
: new String[] {mRetailDemoPackage}; : new String[] {mRetailDemoPackage};
case PackageManagerInternal.PACKAGE_OVERLAY_CONFIG_SIGNATURE:
return filterOnlySystemPackages(getOverlayConfigSignaturePackageName());
default: default:
return ArrayUtils.emptyArray(String.class); return ArrayUtils.emptyArray(String.class);
} }

View File

@@ -487,6 +487,18 @@ public class PackageManagerServiceUtils {
return PackageManager.SIGNATURE_NO_MATCH; return PackageManager.SIGNATURE_NO_MATCH;
} }
/**
* 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 * Used for backward compatibility to make sure any packages with
* certificate chains get upgraded to the new style. {@code existingSigs} * certificate chains get upgraded to the new style. {@code existingSigs}

View File

@@ -160,7 +160,7 @@ class OverlayActorEnforcerTests {
private val hasPermission: Boolean = false, private val hasPermission: Boolean = false,
private val overlayableInfo: OverlayableInfo? = null, private val overlayableInfo: OverlayableInfo? = null,
private vararg val packageNames: String = arrayOf("com.test.actor.one") private vararg val packageNames: String = arrayOf("com.test.actor.one")
) : OverlayableInfoCallback { ) : PackageManagerHelper {
override fun getNamedActors() = if (isActor) { override fun getNamedActors() = if (isActor) {
mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME)) mapOf(NAMESPACE to mapOf(ACTOR_NAME to ACTOR_PKG_NAME))
@@ -195,6 +195,14 @@ class OverlayActorEnforcerTests {
} }
} }
override fun getConfigSignaturePackage(): String {
throw UnsupportedOperationException()
}
override fun getOverlayPackages(userId: Int): MutableList<PackageInfo> {
throw UnsupportedOperationException()
}
override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean { override fun signaturesMatching(pkgName1: String, pkgName2: String, userId: Int): Boolean {
throw UnsupportedOperationException() throw UnsupportedOperationException()
} }

View File

@@ -44,9 +44,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
@Test @Test
public void testUpdateOverlaysForUser() { public void testUpdateOverlaysForUser() {
final OverlayManagerServiceImpl impl = getImpl(); final OverlayManagerServiceImpl impl = getImpl();
addSystemPackage(target(TARGET), USER); addPackage(target(TARGET), USER);
addSystemPackage(target("some.other.target"), USER);; addPackage(target("some.other.target"), USER);
addSystemPackage(overlay(OVERLAY, TARGET), USER); addPackage(overlay(OVERLAY, TARGET), USER);
// do nothing, expect no change // do nothing, expect no change
final List<String> a = impl.updateOverlaysForUser(USER); final List<String> a = impl.updateOverlaysForUser(USER);
@@ -54,7 +54,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
assertTrue(a.contains(TARGET)); assertTrue(a.contains(TARGET));
// upgrade overlay, keep target // upgrade overlay, keep target
addSystemPackage(overlay(OVERLAY, TARGET), USER); addPackage(overlay(OVERLAY, TARGET), USER);
final List<String> b = impl.updateOverlaysForUser(USER); final List<String> b = impl.updateOverlaysForUser(USER);
assertEquals(1, b.size()); assertEquals(1, b.size());
@@ -66,7 +66,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI
assertTrue(c.contains(TARGET)); assertTrue(c.contains(TARGET));
// upgrade overlay, switch to new 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); final List<String> d = impl.updateOverlaysForUser(USER);
assertEquals(2, d.size()); assertEquals(2, d.size());
assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target"))); assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));

View File

@@ -19,6 +19,7 @@ package com.android.server.om;
import static android.content.om.OverlayInfo.STATE_DISABLED; import static android.content.om.OverlayInfo.STATE_DISABLED;
import static android.content.om.OverlayInfo.STATE_ENABLED; import static android.content.om.OverlayInfo.STATE_ENABLED;
import static android.content.om.OverlayInfo.STATE_MISSING_TARGET; 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.assertEquals;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
@@ -49,6 +50,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
private static final String OVERLAY3 = OVERLAY + "3"; private static final String OVERLAY3 = OVERLAY + "3";
private static final int USER3 = USER2 + 1; 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 @Test
public void testGetOverlayInfo() { public void testGetOverlayInfo() {
installNewPackage(overlay(OVERLAY, TARGET), USER); installNewPackage(overlay(OVERLAY, TARGET), USER);
@@ -204,4 +209,87 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes
impl.setEnabled(OVERLAY, true, USER); impl.setEnabled(OVERLAY, true, USER);
assertEquals(0, listener.count); 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);
}
} }

View File

@@ -27,6 +27,7 @@ import android.content.om.OverlayInfo.State;
import android.content.om.OverlayableInfo; import android.content.om.OverlayableInfo;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
import android.text.TextUtils;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
@@ -52,6 +53,7 @@ class OverlayManagerServiceImplTestsBase {
private DummyPackageManagerHelper mPackageManager; private DummyPackageManagerHelper mPackageManager;
private DummyIdmapDaemon mIdmapDaemon; private DummyIdmapDaemon mIdmapDaemon;
private OverlayConfig mOverlayConfig; private OverlayConfig mOverlayConfig;
private String mConfigSignaturePackageName;
@Before @Before
public void setUp() { public void setUp() {
@@ -83,6 +85,18 @@ class OverlayManagerServiceImplTestsBase {
return mListener; 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) { void assertState(@State int expected, final String overlayPackageName, int userId) {
final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId); final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId);
if (info == null) { if (info == null) {
@@ -102,9 +116,14 @@ class OverlayManagerServiceImplTestsBase {
assertEquals(expected, actual); assertEquals(expected, actual);
} }
DummyDeviceState.PackageBuilder app(String packageName) {
return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
null /* targetOverlayableName */, "data");
}
DummyDeviceState.PackageBuilder target(String packageName) { DummyDeviceState.PackageBuilder target(String packageName) {
return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */, return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */,
null /* targetOverlayableName */); null /* targetOverlayableName */, "");
} }
DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) { DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) {
@@ -114,10 +133,10 @@ class OverlayManagerServiceImplTestsBase {
DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName, DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName,
String targetOverlayableName) { String targetOverlayableName) {
return new DummyDeviceState.PackageBuilder(packageName, targetPackageName, 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); mState.add(pkg, userId);
} }
@@ -242,15 +261,17 @@ class OverlayManagerServiceImplTestsBase {
private String packageName; private String packageName;
private String targetPackage; private String targetPackage;
private String certificate = "[default]"; private String certificate = "[default]";
private String partition;
private int version = 0; private int version = 0;
private ArrayList<String> overlayableNames = new ArrayList<>(); private ArrayList<String> overlayableNames = new ArrayList<>();
private String targetOverlayableName; private String targetOverlayableName;
private PackageBuilder(String packageName, String targetPackage, private PackageBuilder(String packageName, String targetPackage,
String targetOverlayableName) { String targetOverlayableName, String partition) {
this.packageName = packageName; this.packageName = packageName;
this.targetPackage = targetPackage; this.targetPackage = targetPackage;
this.targetOverlayableName = targetOverlayableName; this.targetOverlayableName = targetOverlayableName;
this.partition = partition;
} }
PackageBuilder setCertificate(String certificate) { PackageBuilder setCertificate(String certificate) {
@@ -269,9 +290,19 @@ class OverlayManagerServiceImplTestsBase {
} }
Package build() { Package build() {
final String apkPath = String.format("%s/%s/base.apk", String path = "";
targetPackage == null ? "/system/app/:" : "/vendor/overlay/:", if (TextUtils.isEmpty(partition)) {
packageName); 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, final Package newPackage = new Package(packageName, targetPackage,
targetOverlayableName, version, apkPath, certificate); targetOverlayableName, version, apkPath, certificate);
newPackage.overlayableNames.addAll(overlayableNames); newPackage.overlayableNames.addAll(overlayableNames);
@@ -302,8 +333,7 @@ class OverlayManagerServiceImplTestsBase {
} }
} }
static final class DummyPackageManagerHelper implements PackageManagerHelper, final class DummyPackageManagerHelper implements PackageManagerHelper {
OverlayableInfoCallback {
private final DummyDeviceState mState; private final DummyDeviceState mState;
private DummyPackageManagerHelper(DummyDeviceState state) { private DummyPackageManagerHelper(DummyDeviceState state) {
@@ -343,6 +373,11 @@ class OverlayManagerServiceImplTestsBase {
.collect(Collectors.toList()); .collect(Collectors.toList());
} }
@Override
public @NonNull String getConfigSignaturePackage() {
return mConfigSignaturePackageName;
}
@Nullable @Nullable
@Override @Override
public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, public OverlayableInfo getOverlayableForTarget(@NonNull String packageName,

View File

@@ -168,6 +168,7 @@ message OverlayableItem {
ODM = 6; ODM = 6;
OEM = 7; OEM = 7;
ACTOR = 8; ACTOR = 8;
CONFIG_SIGNATURE = 9;
} }
// The location of the <item> declaration in source. // The location of the <item> declaration in source.

View File

@@ -776,6 +776,7 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
OverlayableItem overlayable_item_three(group_one); OverlayableItem overlayable_item_three(group_one);
overlayable_item_three.policies |= PolicyFlags::SIGNATURE; overlayable_item_three.policies |= PolicyFlags::SIGNATURE;
overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE; overlayable_item_three.policies |= PolicyFlags::ACTOR_SIGNATURE;
overlayable_item_three.policies |= PolicyFlags::CONFIG_SIGNATURE;
std::unique_ptr<ResourceTable> table = std::unique_ptr<ResourceTable> table =
test::ResourceTableBuilder() test::ResourceTableBuilder()
@@ -830,7 +831,8 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) {
EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); EXPECT_EQ(result_overlayable.overlayable->name, "OtherName");
EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); 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); | PolicyFlags::ACTOR_SIGNATURE
| PolicyFlags::CONFIG_SIGNATURE);
} }
TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) { TEST_F(TableFlattenerTest, FlattenOverlayableNoPolicyFails) {

View File

@@ -404,6 +404,9 @@ bool DeserializeOverlayableItemFromPb(const pb::OverlayableItem& pb_overlayable,
case pb::OverlayableItem::ACTOR: case pb::OverlayableItem::ACTOR:
out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE; out_overlayable->policies |= PolicyFlags::ACTOR_SIGNATURE;
break; break;
case pb::OverlayableItem::CONFIG_SIGNATURE:
out_overlayable->policies |= PolicyFlags::CONFIG_SIGNATURE;
break;
default: default:
*out_error = "unknown overlayable policy"; *out_error = "unknown overlayable policy";
return false; return false;

View File

@@ -325,6 +325,9 @@ static void SerializeOverlayableItemToPb(const OverlayableItem& overlayable_item
if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) { if (overlayable_item.policies & PolicyFlags::ACTOR_SIGNATURE) {
pb_overlayable_item->add_policy(pb::OverlayableItem::ACTOR); 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) { if (source_pool != nullptr) {
SerializeSourceToPb(overlayable_item.source, source_pool, SerializeSourceToPb(overlayable_item.source, source_pool,