Merge "Allow revoked capabilities to be restored in sharedUserId lineage" into tm-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
80af2faccf
@@ -112,6 +112,29 @@ public final class SigningDetails implements Parcelable {
|
|||||||
int AUTH = 16;
|
int AUTH = 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@IntDef(value = {CapabilityMergeRule.MERGE_SELF_CAPABILITY,
|
||||||
|
CapabilityMergeRule.MERGE_OTHER_CAPABILITY,
|
||||||
|
CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY})
|
||||||
|
public @interface CapabilityMergeRule {
|
||||||
|
/**
|
||||||
|
* When capabilities are different for a common signer in the lineage, use the capabilities
|
||||||
|
* from this instance.
|
||||||
|
*/
|
||||||
|
int MERGE_SELF_CAPABILITY = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When capabilities are different for a common signer in the lineage, use the capabilites
|
||||||
|
* from the other instance.
|
||||||
|
*/
|
||||||
|
int MERGE_OTHER_CAPABILITY = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When capabilities are different for a common signer in the lineage, use the most
|
||||||
|
* restrictive between the two signers.
|
||||||
|
*/
|
||||||
|
int MERGE_RESTRICTED_CAPABILITY = 2;
|
||||||
|
}
|
||||||
|
|
||||||
/** A representation of unknown signing details. Use instead of null. */
|
/** A representation of unknown signing details. Use instead of null. */
|
||||||
public static final SigningDetails UNKNOWN = new SigningDetails(/* signatures */ null,
|
public static final SigningDetails UNKNOWN = new SigningDetails(/* signatures */ null,
|
||||||
SignatureSchemeVersion.UNKNOWN, /* keys */ null, /* pastSigningCertificates */ null);
|
SignatureSchemeVersion.UNKNOWN, /* keys */ null, /* pastSigningCertificates */ null);
|
||||||
@@ -164,30 +187,60 @@ public final class SigningDetails implements Parcelable {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the signing lineage of this instance with the lineage in the provided {@code
|
* Merges the signing lineage of this instance with the lineage in the provided {@code
|
||||||
* otherSigningDetails} when one has the same or an ancestor signer of the other.
|
* otherSigningDetails} using {@link CapabilityMergeRule#MERGE_OTHER_CAPABILITY} as the merge
|
||||||
|
* rule.
|
||||||
|
*
|
||||||
|
* @param otherSigningDetails the {@code SigningDetails} with which to merge
|
||||||
|
* @return Merged {@code SigningDetails} instance when one has the same or an ancestor signer
|
||||||
|
* of the other. If neither instance has a lineage, or if neither has the same or an
|
||||||
|
* ancestor signer then this instance is returned.
|
||||||
|
* @see #mergeLineageWith(SigningDetails, int)
|
||||||
|
*/
|
||||||
|
public @NonNull SigningDetails mergeLineageWith(@NonNull SigningDetails otherSigningDetails) {
|
||||||
|
return mergeLineageWith(otherSigningDetails, CapabilityMergeRule.MERGE_OTHER_CAPABILITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Merges the signing lineage of this instance with the lineage in the provided {@code
|
||||||
|
* otherSigningDetails} when one has the same or an ancestor signer of the other using the
|
||||||
|
* provided {@code mergeRule} to handle differences in capabilities for shared signers.
|
||||||
*
|
*
|
||||||
* <p>Merging two signing lineages will result in a new {@code SigningDetails} instance
|
* <p>Merging two signing lineages will result in a new {@code SigningDetails} instance
|
||||||
* containing the longest common lineage with the most restrictive capabilities. If the two
|
* containing the longest common lineage with differences in capabilities for shared signers
|
||||||
* lineages contain the same signers with the same capabilities then the instance on which
|
* resolved using the provided {@code mergeRule}. If the two lineages contain the same signers
|
||||||
* this was invoked is returned without any changes. Similarly if neither instance has a
|
* with the same capabilities then the instance on which this was invoked is returned without
|
||||||
* lineage, or if neither has the same or an ancestor signer then this instance is returned.
|
* any changes. Similarly if neither instance has a lineage, or if neither has the same or an
|
||||||
|
* ancestor signer then this instance is returned.
|
||||||
*
|
*
|
||||||
* Following are some example results of this method for lineages with signers A, B, C, D:
|
* Following are some example results of this method for lineages with signers A, B, C, D:
|
||||||
* - lineage B merged with lineage A -> B returns lineage A -> B.
|
* <ul>
|
||||||
* - lineage A -> B merged with lineage B -> C returns lineage A -> B -> C
|
* <li>lineage B merged with lineage A -> B returns lineage A -> B.
|
||||||
* - lineage A -> B with the {@code PERMISSION} capability revoked for A merged with
|
* <li>lineage A -> B merged with lineage B -> C returns lineage A -> B -> C
|
||||||
* lineage A -> B with the {@code SHARED_USER_ID} capability revoked for A returns
|
* <li>lineage A -> B with the {@code PERMISSION} capability revoked for A merged with
|
||||||
* lineage A -> B with both capabilities revoked for A.
|
* lineage A -> B with the {@code SHARED_USER_ID} capability revoked for A returns the
|
||||||
* - lineage A -> B -> C merged with lineage A -> B -> D would return the original lineage
|
* following based on the {@code mergeRule}:
|
||||||
* A -> B -> C since the current signer of both instances is not the same or in the
|
* <ul>
|
||||||
* lineage of the other.
|
* <li>{@code MERGE_SELF_CAPABILITY} - lineage A -> B with {@code PERMISSION} revoked
|
||||||
|
* for A.
|
||||||
|
* <li>{@code MERGE_OTHER_CAPABILITY} - lineage A -> B with {@code SHARED_USER_ID}
|
||||||
|
* revoked for A.
|
||||||
|
* <li>{@code MERGE_RESTRICTED_CAPABILITY} - lineage A -> B with {@code PERMISSION} and
|
||||||
|
* {@code SHARED_USER_ID} revoked for A.
|
||||||
|
* </ul>
|
||||||
|
* <li>lineage A -> B -> C merged with lineage A -> B -> D would return the original lineage
|
||||||
|
* A -> B -> C since the current signer of both instances is not the same or in the
|
||||||
|
* lineage of the other.
|
||||||
|
* </ul>
|
||||||
*
|
*
|
||||||
* @param otherSigningDetails The {@code SigningDetails} you would like to merge with.
|
* @param otherSigningDetails the {@code SigningDetails} with which to merge
|
||||||
|
* @param mergeRule the {@link CapabilityMergeRule} to use when resolving differences in
|
||||||
|
* capabilities for shared signers
|
||||||
* @return Merged {@code SigningDetails} instance when one has the same or an ancestor signer
|
* @return Merged {@code SigningDetails} instance when one has the same or an ancestor signer
|
||||||
* of the other. If neither instance has a lineage, or if neither has the same or an
|
* of the other. If neither instance has a lineage, or if neither has the same or an
|
||||||
* ancestor signer then this instance is returned.
|
* ancestor signer then this instance is returned.
|
||||||
*/
|
*/
|
||||||
public @NonNull SigningDetails mergeLineageWith(@NonNull SigningDetails otherSigningDetails) {
|
public @NonNull SigningDetails mergeLineageWith(@NonNull SigningDetails otherSigningDetails,
|
||||||
|
@CapabilityMergeRule int mergeRule) {
|
||||||
if (!hasPastSigningCertificates()) {
|
if (!hasPastSigningCertificates()) {
|
||||||
return otherSigningDetails.hasPastSigningCertificates()
|
return otherSigningDetails.hasPastSigningCertificates()
|
||||||
&& otherSigningDetails.hasAncestorOrSelf(this) ? otherSigningDetails : this;
|
&& otherSigningDetails.hasAncestorOrSelf(this) ? otherSigningDetails : this;
|
||||||
@@ -201,19 +254,43 @@ public final class SigningDetails implements Parcelable {
|
|||||||
if (descendantSigningDetails == null) {
|
if (descendantSigningDetails == null) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
return descendantSigningDetails == this ? mergeLineageWithAncestorOrSelf(
|
SigningDetails mergedDetails = this;
|
||||||
otherSigningDetails) : otherSigningDetails.mergeLineageWithAncestorOrSelf(this);
|
if (descendantSigningDetails == this) {
|
||||||
|
// If this instance is the descendant then the merge will also be invoked against this
|
||||||
|
// instance and the provided mergeRule can be used as is.
|
||||||
|
mergedDetails = mergeLineageWithAncestorOrSelf(otherSigningDetails, mergeRule);
|
||||||
|
} else {
|
||||||
|
// If the provided instance is the descendant then the merge will be invoked against the
|
||||||
|
// other instance and a self or other merge rule will need to be flipped.
|
||||||
|
switch (mergeRule) {
|
||||||
|
case CapabilityMergeRule.MERGE_SELF_CAPABILITY:
|
||||||
|
mergedDetails = otherSigningDetails.mergeLineageWithAncestorOrSelf(this,
|
||||||
|
CapabilityMergeRule.MERGE_OTHER_CAPABILITY);
|
||||||
|
break;
|
||||||
|
case CapabilityMergeRule.MERGE_OTHER_CAPABILITY:
|
||||||
|
mergedDetails = otherSigningDetails.mergeLineageWithAncestorOrSelf(this,
|
||||||
|
CapabilityMergeRule.MERGE_SELF_CAPABILITY);
|
||||||
|
break;
|
||||||
|
case CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY:
|
||||||
|
mergedDetails = otherSigningDetails.mergeLineageWithAncestorOrSelf(this,
|
||||||
|
mergeRule);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mergedDetails;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges the signing lineage of this instance with the lineage of the ancestor (or same)
|
* Merges the signing lineage of this instance with the lineage of the ancestor (or same)
|
||||||
* signer in the provided {@code otherSigningDetails}.
|
* signer in the provided {@code otherSigningDetails}.
|
||||||
*
|
*
|
||||||
* @param otherSigningDetails The {@code SigningDetails} you would like to merge with.
|
* @param otherSigningDetails the {@code SigningDetails} with which to merge
|
||||||
|
* @param mergeRule the {@link CapabilityMergeRule} to use when resolving differences in
|
||||||
|
* capabilities for shared signers
|
||||||
* @return Merged {@code SigningDetails} instance.
|
* @return Merged {@code SigningDetails} instance.
|
||||||
*/
|
*/
|
||||||
private @NonNull SigningDetails mergeLineageWithAncestorOrSelf(
|
private @NonNull SigningDetails mergeLineageWithAncestorOrSelf(
|
||||||
@NonNull SigningDetails otherSigningDetails) {
|
@NonNull SigningDetails otherSigningDetails, @CapabilityMergeRule int mergeRule) {
|
||||||
// This method should only be called with instances that contain lineages.
|
// This method should only be called with instances that contain lineages.
|
||||||
int index = mPastSigningCertificates.length - 1;
|
int index = mPastSigningCertificates.length - 1;
|
||||||
int otherIndex = otherSigningDetails.mPastSigningCertificates.length - 1;
|
int otherIndex = otherSigningDetails.mPastSigningCertificates.length - 1;
|
||||||
@@ -236,16 +313,26 @@ public final class SigningDetails implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
// Add the common signer to the merged lineage with the most restrictive
|
// Add the common signer to the merged lineage and resolve any differences in
|
||||||
// capabilities of the two lineages.
|
// capabilites with the merge rule.
|
||||||
Signature signature = mPastSigningCertificates[index--];
|
Signature signature = mPastSigningCertificates[index--];
|
||||||
Signature ancestorSignature =
|
Signature ancestorSignature =
|
||||||
otherSigningDetails.mPastSigningCertificates[otherIndex--];
|
otherSigningDetails.mPastSigningCertificates[otherIndex--];
|
||||||
Signature mergedSignature = new Signature(signature);
|
Signature mergedSignature = new Signature(signature);
|
||||||
int mergedCapabilities = signature.getFlags() & ancestorSignature.getFlags();
|
if (signature.getFlags() != ancestorSignature.getFlags()) {
|
||||||
if (signature.getFlags() != mergedCapabilities) {
|
|
||||||
capabilitiesModified = true;
|
capabilitiesModified = true;
|
||||||
mergedSignature.setFlags(mergedCapabilities);
|
switch (mergeRule) {
|
||||||
|
case CapabilityMergeRule.MERGE_SELF_CAPABILITY:
|
||||||
|
mergedSignature.setFlags(signature.getFlags());
|
||||||
|
break;
|
||||||
|
case CapabilityMergeRule.MERGE_OTHER_CAPABILITY:
|
||||||
|
mergedSignature.setFlags(ancestorSignature.getFlags());
|
||||||
|
break;
|
||||||
|
case CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY:
|
||||||
|
mergedSignature.setFlags(
|
||||||
|
signature.getFlags() & ancestorSignature.getFlags());
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
mergedSignatures.add(mergedSignature);
|
mergedSignatures.add(mergedSignature);
|
||||||
} while (index >= 0 && otherIndex >= 0 && mPastSigningCertificates[index].equals(
|
} while (index >= 0 && otherIndex >= 0 && mPastSigningCertificates[index].equals(
|
||||||
@@ -858,7 +945,7 @@ public final class SigningDetails implements Parcelable {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Code below generated by codegen v1.0.22.
|
// Code below generated by codegen v1.0.23.
|
||||||
//
|
//
|
||||||
// DO NOT MODIFY!
|
// DO NOT MODIFY!
|
||||||
// CHECKSTYLE:OFF Generated code
|
// CHECKSTYLE:OFF Generated code
|
||||||
@@ -914,10 +1001,10 @@ public final class SigningDetails implements Parcelable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DataClass.Generated(
|
@DataClass.Generated(
|
||||||
time = 1616984092921L,
|
time = 1650058974710L,
|
||||||
codegenVersion = "1.0.22",
|
codegenVersion = "1.0.23",
|
||||||
sourceFile = "frameworks/base/core/java/android/content/pm/SigningDetails.java",
|
sourceFile = "frameworks/base/core/java/android/content/pm/SigningDetails.java",
|
||||||
inputSignatures = "private static final java.lang.String TAG\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mSignatures\nprivate final @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate final @android.annotation.Nullable android.util.ArraySet<java.security.PublicKey> mPublicKeys\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\nprivate static final int PAST_CERT_EXISTS\npublic static final android.content.pm.SigningDetails UNKNOWN\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.SigningDetails> CREATOR\npublic @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWith(android.content.pm.SigningDetails)\nprivate @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWithAncestorOrSelf(android.content.pm.SigningDetails)\npublic boolean hasCommonAncestor(android.content.pm.SigningDetails)\npublic boolean hasAncestorOrSelfWithDigest(java.util.Set<java.lang.String>)\nprivate @android.annotation.Nullable android.content.pm.SigningDetails getDescendantOrSelf(android.content.pm.SigningDetails)\npublic boolean hasSignatures()\npublic boolean hasPastSigningCertificates()\npublic boolean hasAncestorOrSelf(android.content.pm.SigningDetails)\npublic boolean hasAncestor(android.content.pm.SigningDetails)\npublic boolean hasCommonSignerWithCapability(android.content.pm.SigningDetails,int)\npublic boolean checkCapability(android.content.pm.SigningDetails,int)\npublic boolean checkCapabilityRecover(android.content.pm.SigningDetails,int)\npublic boolean hasCertificate(android.content.pm.Signature)\npublic boolean hasCertificate(android.content.pm.Signature,int)\npublic boolean hasCertificate(byte[])\nprivate boolean hasCertificateInternal(android.content.pm.Signature,int)\npublic boolean checkCapability(java.lang.String,int)\npublic boolean hasSha256Certificate(byte[])\npublic boolean hasSha256Certificate(byte[],int)\nprivate boolean hasSha256CertificateInternal(byte[],int)\npublic boolean signaturesMatchExactly(android.content.pm.SigningDetails)\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override int hashCode()\npublic static android.util.ArraySet<java.security.PublicKey> toSigningKeys(android.content.pm.Signature[])\nclass SigningDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.NonNull android.content.pm.Signature[] mSignatures\nprivate @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\npublic android.content.pm.SigningDetails.Builder setSignatures(android.content.pm.Signature[])\npublic android.content.pm.SigningDetails.Builder setSignatureSchemeVersion(int)\npublic android.content.pm.SigningDetails.Builder setPastSigningCertificates(android.content.pm.Signature[])\nprivate void checkInvariants()\npublic android.content.pm.SigningDetails build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false, genParcelable=true, genAidl=false)")
|
inputSignatures = "private static final java.lang.String TAG\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mSignatures\nprivate final @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate final @android.annotation.Nullable android.util.ArraySet<java.security.PublicKey> mPublicKeys\nprivate final @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\nprivate static final int PAST_CERT_EXISTS\npublic static final android.content.pm.SigningDetails UNKNOWN\npublic static final @android.annotation.NonNull android.os.Parcelable.Creator<android.content.pm.SigningDetails> CREATOR\npublic @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWith(android.content.pm.SigningDetails)\npublic @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWith(android.content.pm.SigningDetails,int)\nprivate @android.annotation.NonNull android.content.pm.SigningDetails mergeLineageWithAncestorOrSelf(android.content.pm.SigningDetails,int)\npublic boolean hasCommonAncestor(android.content.pm.SigningDetails)\npublic boolean hasAncestorOrSelfWithDigest(java.util.Set<java.lang.String>)\nprivate @android.annotation.Nullable android.content.pm.SigningDetails getDescendantOrSelf(android.content.pm.SigningDetails)\npublic boolean hasSignatures()\npublic boolean hasPastSigningCertificates()\npublic boolean hasAncestorOrSelf(android.content.pm.SigningDetails)\npublic boolean hasAncestor(android.content.pm.SigningDetails)\npublic boolean hasCommonSignerWithCapability(android.content.pm.SigningDetails,int)\npublic boolean checkCapability(android.content.pm.SigningDetails,int)\npublic boolean checkCapabilityRecover(android.content.pm.SigningDetails,int)\npublic boolean hasCertificate(android.content.pm.Signature)\npublic boolean hasCertificate(android.content.pm.Signature,int)\npublic boolean hasCertificate(byte[])\nprivate boolean hasCertificateInternal(android.content.pm.Signature,int)\npublic boolean checkCapability(java.lang.String,int)\npublic boolean hasSha256Certificate(byte[])\npublic boolean hasSha256Certificate(byte[],int)\nprivate boolean hasSha256CertificateInternal(byte[],int)\npublic boolean signaturesMatchExactly(android.content.pm.SigningDetails)\npublic @java.lang.Override int describeContents()\npublic @java.lang.Override void writeToParcel(android.os.Parcel,int)\npublic @java.lang.Override boolean equals(java.lang.Object)\npublic @java.lang.Override int hashCode()\npublic static android.util.ArraySet<java.security.PublicKey> toSigningKeys(android.content.pm.Signature[])\nclass SigningDetails extends java.lang.Object implements [android.os.Parcelable]\nprivate @android.annotation.NonNull android.content.pm.Signature[] mSignatures\nprivate @android.content.pm.SigningDetails.SignatureSchemeVersion int mSignatureSchemeVersion\nprivate @android.annotation.Nullable android.content.pm.Signature[] mPastSigningCertificates\npublic android.content.pm.SigningDetails.Builder setSignatures(android.content.pm.Signature[])\npublic android.content.pm.SigningDetails.Builder setSignatureSchemeVersion(int)\npublic android.content.pm.SigningDetails.Builder setPastSigningCertificates(android.content.pm.Signature[])\nprivate void checkInvariants()\npublic android.content.pm.SigningDetails build()\nclass Builder extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false, genParcelable=true, genAidl=false)")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
private void __metadata() {}
|
private void __metadata() {}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@
|
|||||||
*/
|
*/
|
||||||
package android.content.pm;
|
package android.content.pm;
|
||||||
|
|
||||||
|
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_OTHER_CAPABILITY;
|
||||||
|
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
|
||||||
|
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_SELF_CAPABILITY;
|
||||||
import static android.content.pm.SigningDetails.CertCapabilities.AUTH;
|
import static android.content.pm.SigningDetails.CertCapabilities.AUTH;
|
||||||
import static android.content.pm.SigningDetails.CertCapabilities.INSTALLED_DATA;
|
import static android.content.pm.SigningDetails.CertCapabilities.INSTALLED_DATA;
|
||||||
import static android.content.pm.SigningDetails.CertCapabilities.PERMISSION;
|
import static android.content.pm.SigningDetails.CertCapabilities.PERMISSION;
|
||||||
@@ -45,6 +48,7 @@ import java.util.Set;
|
|||||||
public class SigningDetailsTest {
|
public class SigningDetailsTest {
|
||||||
private static final int DEFAULT_CAPABILITIES =
|
private static final int DEFAULT_CAPABILITIES =
|
||||||
INSTALLED_DATA | SHARED_USER_ID | PERMISSION | AUTH;
|
INSTALLED_DATA | SHARED_USER_ID | PERMISSION | AUTH;
|
||||||
|
private static final int CURRENT_SIGNER_CAPABILITIES = DEFAULT_CAPABILITIES | ROLLBACK;
|
||||||
|
|
||||||
// Some of the tests in this class require valid certificate encodings from which to pull the
|
// Some of the tests in this class require valid certificate encodings from which to pull the
|
||||||
// public key for the SigningDetails; the following are all DER encoded EC X.509 certificates.
|
// public key for the SigningDetails; the following are all DER encoded EC X.509 certificates.
|
||||||
@@ -368,10 +372,10 @@ public class SigningDetailsTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mergeLineageWith_sameLineageDifferentCaps_returnsLineageWithModifiedCaps()
|
public void mergeLineageWith_sameLineageDifferentCaps_returnsLineageWithProvidedCaps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// This test verifies when two lineages consist of the same signers but have different
|
// This test verifies when two lineages consist of the same signers but have different
|
||||||
// capabilities the more restrictive capabilities are returned.
|
// capabilities, the capabilities of the provided lineage are returned.
|
||||||
SigningDetails defaultCapabilitiesDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
|
SigningDetails defaultCapabilitiesDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
|
||||||
SECOND_SIGNATURE, THIRD_SIGNATURE);
|
SECOND_SIGNATURE, THIRD_SIGNATURE);
|
||||||
SigningDetails modifiedCapabilitiesDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails modifiedCapabilitiesDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
@@ -384,68 +388,135 @@ public class SigningDetailsTest {
|
|||||||
defaultCapabilitiesDetails);
|
defaultCapabilitiesDetails);
|
||||||
|
|
||||||
assertEquals(modifiedCapabilitiesDetails, result1);
|
assertEquals(modifiedCapabilitiesDetails, result1);
|
||||||
assertTrue(result2 == modifiedCapabilitiesDetails);
|
assertEquals(defaultCapabilitiesDetails, result2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void
|
||||||
|
mergeLineageWith_sameLineageDifferentCapsRestrictedRule_returnsLineageWithModifiedCaps()
|
||||||
|
throws Exception {
|
||||||
|
// This test verifies when two lineages consist of the same signers but have different
|
||||||
|
// capabilities, and the restricted merge rule is used, the more restrictive capabilities
|
||||||
|
// are returned.
|
||||||
|
SigningDetails defaultCapabilitiesDetails = createSigningDetailsWithLineage(FIRST_SIGNATURE,
|
||||||
|
SECOND_SIGNATURE, THIRD_SIGNATURE);
|
||||||
|
SigningDetails modifiedCapabilitiesDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
|
||||||
|
new int[]{INSTALLED_DATA, INSTALLED_DATA, INSTALLED_DATA});
|
||||||
|
|
||||||
|
SigningDetails result1 = defaultCapabilitiesDetails.mergeLineageWith(
|
||||||
|
modifiedCapabilitiesDetails, MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
SigningDetails result2 = modifiedCapabilitiesDetails.mergeLineageWith(
|
||||||
|
defaultCapabilitiesDetails, MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
|
||||||
|
assertEquals(modifiedCapabilitiesDetails, result1);
|
||||||
|
assertEquals(modifiedCapabilitiesDetails, result2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mergeLineageWith_overlappingLineageDiffCaps_returnsFullLineageWithModifiedCaps()
|
public void mergeLineageWith_overlappingLineageDiffCaps_returnsFullLineageWithModifiedCaps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// This test verifies the following scenario:
|
// This test verifies the merge of two lineages with overlapping signers and modified caps
|
||||||
// - First lineage has signers A -> B with modified capabilities for A and B
|
// returns the full lineage with expected capabilities based on the provided merge rule.
|
||||||
// - Second lineage has signers B -> C with modified capabilities for B and C
|
|
||||||
// The merged lineage should be A -> B -> C with the most restrictive capabilities for B
|
|
||||||
// since it is in both lineages.
|
|
||||||
int[] firstCapabilities =
|
int[] firstCapabilities =
|
||||||
new int[]{INSTALLED_DATA | AUTH, INSTALLED_DATA | SHARED_USER_ID | PERMISSION};
|
new int[]{INSTALLED_DATA | AUTH, INSTALLED_DATA | SHARED_USER_ID | PERMISSION};
|
||||||
int[] secondCapabilities = new int[]{INSTALLED_DATA | SHARED_USER_ID | AUTH,
|
int[] secondCapabilities = new int[]{INSTALLED_DATA | SHARED_USER_ID | AUTH,
|
||||||
INSTALLED_DATA | SHARED_USER_ID | AUTH};
|
INSTALLED_DATA | SHARED_USER_ID | AUTH};
|
||||||
int[] expectedCapabilities =
|
int[] expectedRestrictedCapabilities =
|
||||||
new int[]{firstCapabilities[0], firstCapabilities[1] & secondCapabilities[0],
|
new int[]{firstCapabilities[0], firstCapabilities[1] & secondCapabilities[0],
|
||||||
secondCapabilities[1]};
|
secondCapabilities[1]};
|
||||||
|
int[] expectedCapabilities1 =
|
||||||
|
new int[]{firstCapabilities[0], secondCapabilities[0], secondCapabilities[1]};
|
||||||
|
int[] expectedCapabilities2 =
|
||||||
|
new int[]{firstCapabilities[0], firstCapabilities[1], secondCapabilities[1]};
|
||||||
SigningDetails firstDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails firstDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, firstCapabilities);
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, firstCapabilities);
|
||||||
SigningDetails secondDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails secondDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
new String[]{SECOND_SIGNATURE, THIRD_SIGNATURE}, secondCapabilities);
|
new String[]{SECOND_SIGNATURE, THIRD_SIGNATURE}, secondCapabilities);
|
||||||
SigningDetails expectedDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails expectedRestrictedDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
|
||||||
expectedCapabilities);
|
expectedRestrictedCapabilities);
|
||||||
|
SigningDetails expectedDetails1 = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
|
||||||
|
expectedCapabilities1);
|
||||||
|
SigningDetails expectedDetails2 = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE},
|
||||||
|
expectedCapabilities2);
|
||||||
|
|
||||||
SigningDetails result1 = firstDetails.mergeLineageWith(secondDetails);
|
SigningDetails result1 = firstDetails.mergeLineageWith(secondDetails,
|
||||||
SigningDetails result2 = secondDetails.mergeLineageWith(firstDetails);
|
MERGE_OTHER_CAPABILITY);
|
||||||
|
SigningDetails result2 = secondDetails.mergeLineageWith(firstDetails,
|
||||||
|
MERGE_SELF_CAPABILITY);
|
||||||
|
SigningDetails result3 = firstDetails.mergeLineageWith(secondDetails,
|
||||||
|
MERGE_SELF_CAPABILITY);
|
||||||
|
SigningDetails result4 = secondDetails.mergeLineageWith(firstDetails,
|
||||||
|
MERGE_OTHER_CAPABILITY);
|
||||||
|
SigningDetails result5 = firstDetails.mergeLineageWith(secondDetails,
|
||||||
|
MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
SigningDetails result6 = secondDetails.mergeLineageWith(firstDetails,
|
||||||
|
MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
|
||||||
assertEquals(expectedDetails, result1);
|
assertEquals(expectedDetails1, result1);
|
||||||
assertEquals(expectedDetails, result2);
|
assertEquals(expectedDetails1, result2);
|
||||||
|
assertEquals(expectedDetails2, result3);
|
||||||
|
assertEquals(expectedDetails2, result4);
|
||||||
|
assertEquals(expectedRestrictedDetails, result5);
|
||||||
|
assertEquals(expectedRestrictedDetails, result6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void mergeLineageWith_subLineageModifiedCaps_returnsFullLineageWithModifiedCaps()
|
public void mergeLineageWith_subLineageModifiedCaps_returnsFullLineageWithModifiedCaps()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
// This test verifies the following scenario:
|
// This test verifies the merge of a full lineage and a subset of that lineage with
|
||||||
// - First lineage has signers B -> C with modified capabilities
|
// modified caps returns the full lineage with expected capabilities based on the
|
||||||
// - Second lineage has signers A -> B -> C -> D with modified capabilities
|
// provided merge rule.
|
||||||
// The merged lineage should be A -> B -> C -> D with the most restrictive capabilities for
|
|
||||||
// B and C since they are in both lineages.
|
|
||||||
int[] subCapabilities = new int[]{INSTALLED_DATA | SHARED_USER_ID | PERMISSION,
|
int[] subCapabilities = new int[]{INSTALLED_DATA | SHARED_USER_ID | PERMISSION,
|
||||||
DEFAULT_CAPABILITIES | ROLLBACK};
|
DEFAULT_CAPABILITIES | ROLLBACK};
|
||||||
int[] fullCapabilities =
|
int[] fullCapabilities =
|
||||||
new int[]{0, SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES};
|
new int[]{0, SHARED_USER_ID, DEFAULT_CAPABILITIES, DEFAULT_CAPABILITIES};
|
||||||
int[] expectedCapabilities =
|
int[] expectedRestrictedCapabilities =
|
||||||
new int[]{fullCapabilities[0], subCapabilities[0] & fullCapabilities[1],
|
new int[]{fullCapabilities[0], subCapabilities[0] & fullCapabilities[1],
|
||||||
subCapabilities[1] & fullCapabilities[2], fullCapabilities[3]};
|
subCapabilities[1] & fullCapabilities[2], fullCapabilities[3]};
|
||||||
|
int[] expectedCapabilities1 =
|
||||||
|
new int[]{fullCapabilities[0], fullCapabilities[1], fullCapabilities[2],
|
||||||
|
fullCapabilities[3]};
|
||||||
|
int[] expectedCapabilities2 =
|
||||||
|
new int[]{fullCapabilities[0], subCapabilities[0], subCapabilities[1],
|
||||||
|
fullCapabilities[3]};
|
||||||
SigningDetails subLineageDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails subLineageDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
new String[]{SECOND_SIGNATURE, THIRD_SIGNATURE}, subCapabilities);
|
new String[]{SECOND_SIGNATURE, THIRD_SIGNATURE}, subCapabilities);
|
||||||
SigningDetails fullLineageDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails fullLineageDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE},
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE},
|
||||||
fullCapabilities);
|
fullCapabilities);
|
||||||
SigningDetails expectedDetails = createSigningDetailsWithLineageAndCapabilities(
|
SigningDetails expectedRestrictedDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE},
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE},
|
||||||
expectedCapabilities);
|
expectedRestrictedCapabilities);
|
||||||
|
SigningDetails expectedDetails1 = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE},
|
||||||
|
expectedCapabilities1);
|
||||||
|
SigningDetails expectedDetails2 = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE, THIRD_SIGNATURE, FOURTH_SIGNATURE},
|
||||||
|
expectedCapabilities2);
|
||||||
|
|
||||||
SigningDetails result1 = subLineageDetails.mergeLineageWith(fullLineageDetails);
|
SigningDetails result1 = subLineageDetails.mergeLineageWith(fullLineageDetails,
|
||||||
SigningDetails result2 = fullLineageDetails.mergeLineageWith(subLineageDetails);
|
MERGE_OTHER_CAPABILITY);
|
||||||
|
SigningDetails result2 = fullLineageDetails.mergeLineageWith(subLineageDetails,
|
||||||
|
MERGE_SELF_CAPABILITY);
|
||||||
|
SigningDetails result3 = subLineageDetails.mergeLineageWith(fullLineageDetails,
|
||||||
|
MERGE_SELF_CAPABILITY);
|
||||||
|
SigningDetails result4 = fullLineageDetails.mergeLineageWith(subLineageDetails,
|
||||||
|
MERGE_OTHER_CAPABILITY);
|
||||||
|
SigningDetails result5 = subLineageDetails.mergeLineageWith(fullLineageDetails,
|
||||||
|
MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
SigningDetails result6 = fullLineageDetails.mergeLineageWith(subLineageDetails,
|
||||||
|
MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
|
||||||
assertEquals(expectedDetails, result1);
|
assertEquals(expectedDetails1, result1);
|
||||||
assertEquals(expectedDetails, result2);
|
assertEquals(expectedDetails1, result2);
|
||||||
|
assertEquals(expectedDetails2, result3);
|
||||||
|
assertEquals(expectedDetails2, result4);
|
||||||
|
assertEquals(expectedRestrictedDetails, result5);
|
||||||
|
assertEquals(expectedRestrictedDetails, result6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -465,6 +536,39 @@ public class SigningDetailsTest {
|
|||||||
assertTrue(result2 == secondLineageDetails);
|
assertTrue(result2 == secondLineageDetails);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void mergeLineageWith_modifiedCaps_returnsCapsFromProvidedLineage()
|
||||||
|
throws Exception {
|
||||||
|
// By default, when merging two lineage instances, the initial instance should represent a
|
||||||
|
// shared lineage while the provided lineage represents that of a newly installed / updated
|
||||||
|
// package. The shared lineage should contain any previous capability modifications from
|
||||||
|
// the default while the provided lineage has an opportunity to modify what was previously
|
||||||
|
// set. Initially, the most restrictive capabilities were always retained by the returned
|
||||||
|
// lineage, so apps had no mechanism to roll back a restriction to a previous signer. To
|
||||||
|
// allow this, a merge rule can be specified to indicate how differences in capabilities
|
||||||
|
// in common signers should be handled with the default using the capabilities from the
|
||||||
|
// provided lineage.
|
||||||
|
int[] firstCapabilities = new int[]{INSTALLED_DATA | PERMISSION | AUTH,
|
||||||
|
CURRENT_SIGNER_CAPABILITIES};
|
||||||
|
int[] secondCapabilities =
|
||||||
|
new int[]{DEFAULT_CAPABILITIES, CURRENT_SIGNER_CAPABILITIES};
|
||||||
|
SigningDetails firstDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, firstCapabilities);
|
||||||
|
SigningDetails secondDetails = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, secondCapabilities);
|
||||||
|
// By default, the resulting capabilities should be that of the provided lineage.
|
||||||
|
SigningDetails expectedDetails1 = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, secondCapabilities);
|
||||||
|
SigningDetails expectedDetails2 = createSigningDetailsWithLineageAndCapabilities(
|
||||||
|
new String[]{FIRST_SIGNATURE, SECOND_SIGNATURE}, firstCapabilities);
|
||||||
|
|
||||||
|
SigningDetails result1 = firstDetails.mergeLineageWith(secondDetails);
|
||||||
|
SigningDetails result2 = secondDetails.mergeLineageWith(firstDetails);
|
||||||
|
|
||||||
|
assertEquals(expectedDetails1, result1);
|
||||||
|
assertEquals(expectedDetails2, result2);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void hasCommonAncestor_noLineageSameSingleSigner_returnsTrue() throws Exception {
|
public void hasCommonAncestor_noLineageSameSingleSigner_returnsTrue() throws Exception {
|
||||||
// If neither SigningDetails have a lineage but they have the same single signer then
|
// If neither SigningDetails have a lineage but they have the same single signer then
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ package com.android.server.pm;
|
|||||||
|
|
||||||
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
|
||||||
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
|
||||||
|
import static android.content.pm.SigningDetails.CapabilityMergeRule.MERGE_RESTRICTED_CAPABILITY;
|
||||||
|
|
||||||
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
|
import static com.android.server.pm.PackageManagerService.SCAN_BOOTING;
|
||||||
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
|
import static com.android.server.pm.PackageManagerService.SCAN_DONT_KILL_APP;
|
||||||
@@ -176,6 +177,19 @@ final class ReconcilePackageUtils {
|
|||||||
SigningDetails mergedDetails = sharedSigningDetails.mergeLineageWith(
|
SigningDetails mergedDetails = sharedSigningDetails.mergeLineageWith(
|
||||||
signingDetails);
|
signingDetails);
|
||||||
if (mergedDetails != sharedSigningDetails) {
|
if (mergedDetails != sharedSigningDetails) {
|
||||||
|
// Use the restricted merge rule with the signing lineages from the
|
||||||
|
// other packages in the sharedUserId to ensure if any revoke a
|
||||||
|
// capability from a previous signer then this is reflected in the
|
||||||
|
// shared lineage.
|
||||||
|
for (AndroidPackage androidPackage : sharedUserSetting.getPackages()) {
|
||||||
|
if (androidPackage.getPackageName() != null
|
||||||
|
&& !androidPackage.getPackageName().equals(
|
||||||
|
parsedPackage.getPackageName())) {
|
||||||
|
mergedDetails = mergedDetails.mergeLineageWith(
|
||||||
|
androidPackage.getSigningDetails(),
|
||||||
|
MERGE_RESTRICTED_CAPABILITY);
|
||||||
|
}
|
||||||
|
}
|
||||||
sharedUserSetting.signatures.mSigningDetails =
|
sharedUserSetting.signatures.mSigningDetails =
|
||||||
mergedDetails;
|
mergedDetails;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user