Two API changes:
1. Add a new formula type "INSTALLER_ALLOWD_BY_MANIFEST" that evaluates to true when installer is specified in the manifest. This CL only adds this class without actually removing the part where we propagate allowed installers. That will be changed in a new CL. 2. Change the AppIntegrityComponent API so that it is type-safe. Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/integrity Test: atest frameworks/base/core/tests/coretests/src/android/content/integrity Bug: 148780440, 147835536 Change-Id: Icfb996b2f6de241d9790a423dd01992edaf35117
This commit is contained in:
@@ -1922,18 +1922,22 @@ package android.content.integrity {
|
||||
public abstract class IntegrityFormula {
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula all(@NonNull android.content.integrity.IntegrityFormula...);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula any(@NonNull android.content.integrity.IntegrityFormula...);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula equalTo(@NonNull String);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula equalTo(boolean);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula equalTo(long);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula greaterThan(long);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula greaterThanOrEquals(long);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula not(@NonNull android.content.integrity.IntegrityFormula);
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula APP_CERTIFICATE;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_CERTIFICATE;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_NAME;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula PACKAGE_NAME;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula PRE_INSTALLED;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula VERSION_CODE;
|
||||
}
|
||||
|
||||
public static final class IntegrityFormula.Application {
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula isPreInstalled();
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula versionCodeEquals(@NonNull long);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula versionCodeGreaterThan(@NonNull long);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula versionCodeGreaterThanOrEqualTo(@NonNull long);
|
||||
}
|
||||
|
||||
public static final class IntegrityFormula.Installer {
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula notAllowedByManifest();
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
|
||||
}
|
||||
|
||||
public final class Rule implements android.os.Parcelable {
|
||||
|
||||
@@ -812,18 +812,22 @@ package android.content.integrity {
|
||||
public abstract class IntegrityFormula {
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula all(@NonNull android.content.integrity.IntegrityFormula...);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula any(@NonNull android.content.integrity.IntegrityFormula...);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula equalTo(@NonNull String);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula equalTo(boolean);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula equalTo(long);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula greaterThan(long);
|
||||
method @NonNull public android.content.integrity.IntegrityFormula greaterThanOrEquals(long);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula not(@NonNull android.content.integrity.IntegrityFormula);
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula APP_CERTIFICATE;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_CERTIFICATE;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula INSTALLER_NAME;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula PACKAGE_NAME;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula PRE_INSTALLED;
|
||||
field @NonNull public static final android.content.integrity.IntegrityFormula VERSION_CODE;
|
||||
}
|
||||
|
||||
public static final class IntegrityFormula.Application {
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula isPreInstalled();
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula versionCodeEquals(@NonNull long);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula versionCodeGreaterThan(@NonNull long);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula versionCodeGreaterThanOrEqualTo(@NonNull long);
|
||||
}
|
||||
|
||||
public static final class IntegrityFormula.Installer {
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula certificatesContain(@NonNull String);
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula notAllowedByManifest();
|
||||
method @NonNull public static android.content.integrity.IntegrityFormula packageNameEquals(@NonNull String);
|
||||
}
|
||||
|
||||
public final class Rule implements android.os.Parcelable {
|
||||
|
||||
@@ -18,7 +18,9 @@ package android.content.integrity;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
@@ -40,6 +42,7 @@ public final class AppInstallMetadata {
|
||||
private final List<String> mInstallerCertificates;
|
||||
private final long mVersionCode;
|
||||
private final boolean mIsPreInstalled;
|
||||
private final Map<String, String> mAllowedInstallersAndCertificates;
|
||||
|
||||
private AppInstallMetadata(Builder builder) {
|
||||
this.mPackageName = builder.mPackageName;
|
||||
@@ -48,6 +51,7 @@ public final class AppInstallMetadata {
|
||||
this.mInstallerCertificates = builder.mInstallerCertificates;
|
||||
this.mVersionCode = builder.mVersionCode;
|
||||
this.mIsPreInstalled = builder.mIsPreInstalled;
|
||||
this.mAllowedInstallersAndCertificates = builder.mAllowedInstallersAndCertificates;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -80,6 +84,13 @@ public final class AppInstallMetadata {
|
||||
return mIsPreInstalled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the allowed installers and their corresponding cert.
|
||||
*/
|
||||
public Map<String, String> getAllowedInstallersAndCertificates() {
|
||||
return mAllowedInstallersAndCertificates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
@@ -101,6 +112,23 @@ public final class AppInstallMetadata {
|
||||
private List<String> mInstallerCertificates;
|
||||
private long mVersionCode;
|
||||
private boolean mIsPreInstalled;
|
||||
private Map<String, String> mAllowedInstallersAndCertificates;
|
||||
|
||||
public Builder() {
|
||||
mAllowedInstallersAndCertificates = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add allowed installers and cert.
|
||||
*
|
||||
* @see AppInstallMetadata#getAllowedInstallersAndCertificates()
|
||||
*/
|
||||
@NonNull
|
||||
public Builder setAllowedInstallersAndCert(
|
||||
@NonNull Map<String, String> allowedInstallersAndCertificates) {
|
||||
this.mAllowedInstallersAndCertificates = allowedInstallersAndCertificates;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set package name of the app to be installed.
|
||||
|
||||
@@ -55,14 +55,12 @@ public abstract class AtomicFormula extends IntegrityFormula {
|
||||
PRE_INSTALLED,
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Key {
|
||||
}
|
||||
public @interface Key {}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(value = {EQ, GT, GTE})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface Operator {
|
||||
}
|
||||
public @interface Operator {}
|
||||
|
||||
/**
|
||||
* Package name of the app.
|
||||
@@ -354,7 +352,8 @@ public abstract class AtomicFormula extends IntegrityFormula {
|
||||
"Key %s cannot be used with StringAtomicFormula", keyToString(key)));
|
||||
mValue = hashValue(key, value);
|
||||
mIsHashedValue =
|
||||
key == APP_CERTIFICATE || key == INSTALLER_CERTIFICATE
|
||||
key == APP_CERTIFICATE
|
||||
|| key == INSTALLER_CERTIFICATE
|
||||
? true
|
||||
: !mValue.equals(value);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 android.content.integrity;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* An atomic formula that evaluates to true if the installer of the current install is specified in
|
||||
* the "allowed installer" field in the android manifest. Note that an empty "allowed installer" by
|
||||
* default means containing all possible installers.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class InstallerAllowedByManifestFormula extends IntegrityFormula {
|
||||
|
||||
@Override
|
||||
public int getTag() {
|
||||
return IntegrityFormula.INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(AppInstallMetadata appInstallMetadata) {
|
||||
Map<String, String> allowedInstallersAndCertificates =
|
||||
appInstallMetadata.getAllowedInstallersAndCertificates();
|
||||
return allowedInstallersAndCertificates.isEmpty()
|
||||
|| installerInAllowedInstallersFromManifest(
|
||||
appInstallMetadata, allowedInstallersAndCertificates);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAppCertificateFormula() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInstallerFormula() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean installerInAllowedInstallersFromManifest(
|
||||
AppInstallMetadata appInstallMetadata,
|
||||
Map<String, String> allowedInstallersAndCertificates) {
|
||||
return allowedInstallersAndCertificates.containsKey(appInstallMetadata.getInstallerName())
|
||||
&& appInstallMetadata.getInstallerCertificates()
|
||||
.contains(
|
||||
allowedInstallersAndCertificates
|
||||
.get(appInstallMetadata.getInstallerName()));
|
||||
}
|
||||
}
|
||||
@@ -42,66 +42,88 @@ import java.util.Arrays;
|
||||
@VisibleForTesting
|
||||
public abstract class IntegrityFormula {
|
||||
|
||||
/**
|
||||
* A static formula base for package name formulas.
|
||||
*
|
||||
* This formulation is incomplete and should always be used with {@code equals} formulation.
|
||||
* Evaluates to false when used directly and cannot be written as a parcel.
|
||||
*/
|
||||
@NonNull
|
||||
public static final IntegrityFormula PACKAGE_NAME =
|
||||
new StringAtomicFormula(AtomicFormula.PACKAGE_NAME);
|
||||
/** Factory class for creating integrity formulas based on the app being installed. */
|
||||
public static final class Application {
|
||||
/** Returns an integrity formula that checks the equality to a package name. */
|
||||
@NonNull
|
||||
public static IntegrityFormula packageNameEquals(@NonNull String packageName) {
|
||||
return new StringAtomicFormula(AtomicFormula.PACKAGE_NAME, packageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static formula base for app certificate formulas.
|
||||
*
|
||||
* This formulation is incomplete and should always be used with {@code equals} formulation.
|
||||
* Evaluates to false when used directly and cannot be written as a parcel.
|
||||
*/
|
||||
@NonNull
|
||||
public static final IntegrityFormula APP_CERTIFICATE =
|
||||
new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE);
|
||||
/**
|
||||
* Returns an integrity formula that checks if the app certificates contain {@code
|
||||
* appCertificate}.
|
||||
*/
|
||||
@NonNull
|
||||
public static IntegrityFormula certificatesContain(@NonNull String appCertificate) {
|
||||
return new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE, appCertificate);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static formula base for installer name formulas.
|
||||
*
|
||||
* This formulation is incomplete and should always be used with {@code equals} formulation.
|
||||
* Evaluates to false when used directly and cannot be written as a parcel.
|
||||
*/
|
||||
@NonNull
|
||||
public static final IntegrityFormula INSTALLER_NAME =
|
||||
new StringAtomicFormula(AtomicFormula.INSTALLER_NAME);
|
||||
/** Returns an integrity formula that checks the equality to a version code. */
|
||||
@NonNull
|
||||
public static IntegrityFormula versionCodeEquals(@NonNull long versionCode) {
|
||||
return new LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.EQ, versionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static formula base for installer certificate formulas.
|
||||
*
|
||||
* This formulation is incomplete and should always be used with {@code equals} formulation.
|
||||
* Evaluates to false when used directly and cannot be written as a parcel.
|
||||
*/
|
||||
@NonNull
|
||||
public static final IntegrityFormula INSTALLER_CERTIFICATE =
|
||||
new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE);
|
||||
/**
|
||||
* Returns an integrity formula that checks the app's version code is greater than the
|
||||
* provided value.
|
||||
*/
|
||||
@NonNull
|
||||
public static IntegrityFormula versionCodeGreaterThan(@NonNull long versionCode) {
|
||||
return new LongAtomicFormula(AtomicFormula.VERSION_CODE, AtomicFormula.GT, versionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static formula base for version code name formulas.
|
||||
*
|
||||
* This formulation is incomplete and should always be used with {@code equals},
|
||||
* {@code greaterThan} and {@code greaterThanEquals} formulation. Evaluates to false when used
|
||||
* directly and cannot be written as a parcel.
|
||||
*/
|
||||
@NonNull
|
||||
public static final IntegrityFormula VERSION_CODE =
|
||||
new LongAtomicFormula(AtomicFormula.VERSION_CODE);
|
||||
/**
|
||||
* Returns an integrity formula that checks the app's version code is greater than or equal
|
||||
* to the provided value.
|
||||
*/
|
||||
@NonNull
|
||||
public static IntegrityFormula versionCodeGreaterThanOrEqualTo(@NonNull long versionCode) {
|
||||
return new LongAtomicFormula(
|
||||
AtomicFormula.VERSION_CODE, AtomicFormula.GTE, versionCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* A static formula base for pre-installed status formulas.
|
||||
*
|
||||
* This formulation is incomplete and should always be used with {@code equals} formulation.
|
||||
* Evaluates to false when used directly and cannot be written as a parcel.
|
||||
*/
|
||||
@NonNull
|
||||
public static final IntegrityFormula PRE_INSTALLED =
|
||||
new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED);
|
||||
/** Returns an integrity formula that is valid when app is pre-installed. */
|
||||
@NonNull
|
||||
public static IntegrityFormula isPreInstalled() {
|
||||
return new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED, true);
|
||||
}
|
||||
|
||||
private Application() {
|
||||
}
|
||||
}
|
||||
|
||||
/** Factory class for creating integrity formulas based on installer. */
|
||||
public static final class Installer {
|
||||
/** Returns an integrity formula that checks the equality to an installer name. */
|
||||
@NonNull
|
||||
public static IntegrityFormula packageNameEquals(@NonNull String installerName) {
|
||||
return new StringAtomicFormula(AtomicFormula.INSTALLER_NAME, installerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* An static formula that evaluates to true if the installer is NOT allowed according to the
|
||||
* "allowed installer" field in the android manifest.
|
||||
*/
|
||||
@NonNull
|
||||
public static IntegrityFormula notAllowedByManifest() {
|
||||
return not(new InstallerAllowedByManifestFormula());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integrity formula that checks if the installer certificates contain {@code
|
||||
* installerCertificate}.
|
||||
*/
|
||||
@NonNull
|
||||
public static IntegrityFormula certificatesContain(@NonNull String installerCertificate) {
|
||||
return new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE,
|
||||
installerCertificate);
|
||||
}
|
||||
|
||||
private Installer() {
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@IntDef(
|
||||
@@ -109,10 +131,12 @@ public abstract class IntegrityFormula {
|
||||
COMPOUND_FORMULA_TAG,
|
||||
STRING_ATOMIC_FORMULA_TAG,
|
||||
LONG_ATOMIC_FORMULA_TAG,
|
||||
BOOLEAN_ATOMIC_FORMULA_TAG
|
||||
BOOLEAN_ATOMIC_FORMULA_TAG,
|
||||
INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@interface Tag {}
|
||||
@interface Tag {
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static final int COMPOUND_FORMULA_TAG = 0;
|
||||
@@ -122,6 +146,8 @@ public abstract class IntegrityFormula {
|
||||
public static final int LONG_ATOMIC_FORMULA_TAG = 2;
|
||||
/** @hide */
|
||||
public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3;
|
||||
/** @hide */
|
||||
public static final int INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG = 4;
|
||||
|
||||
/**
|
||||
* Returns the tag that identifies the current class.
|
||||
@@ -135,14 +161,14 @@ public abstract class IntegrityFormula {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract @Tag boolean matches(AppInstallMetadata appInstallMetadata);
|
||||
public abstract boolean matches(AppInstallMetadata appInstallMetadata);
|
||||
|
||||
/**
|
||||
* Returns true when the formula (or one of its atomic formulas) has app certificate as key.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract @Tag boolean isAppCertificateFormula();
|
||||
public abstract boolean isAppCertificateFormula();
|
||||
|
||||
/**
|
||||
* Returns true when the formula (or one of its atomic formulas) has installer package name
|
||||
@@ -150,7 +176,7 @@ public abstract class IntegrityFormula {
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public abstract @Tag boolean isInstallerFormula();
|
||||
public abstract boolean isInstallerFormula();
|
||||
|
||||
/**
|
||||
* Write an {@link IntegrityFormula} to {@link android.os.Parcel}.
|
||||
@@ -159,7 +185,6 @@ public abstract class IntegrityFormula {
|
||||
* {@link Parcelable}.
|
||||
*
|
||||
* @throws IllegalArgumentException if {@link IntegrityFormula} is not a recognized subclass
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static void writeToParcel(
|
||||
@@ -194,70 +219,6 @@ public abstract class IntegrityFormula {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integrity formula that evaluates to true when value of the key matches to the
|
||||
* provided string value.
|
||||
*
|
||||
* <p>The value will be hashed with SHA256 and the hex digest will be computed; for
|
||||
* all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value is less than
|
||||
* 32 characters.
|
||||
*
|
||||
* <p>Throws an {@link IllegalArgumentException} if the key is not string typed.
|
||||
*/
|
||||
@NonNull
|
||||
public IntegrityFormula equalTo(@NonNull String value) {
|
||||
AtomicFormula baseFormula = (AtomicFormula) this;
|
||||
return new AtomicFormula.StringAtomicFormula(baseFormula.getKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an integrity formula that evaluates to true when the boolean value of the key matches
|
||||
* the provided boolean value. It can only be used with the boolean comparison keys.
|
||||
*
|
||||
* <p>Throws an {@link IllegalArgumentException} if the key is not boolean typed.
|
||||
*/
|
||||
@NonNull
|
||||
public IntegrityFormula equalTo(boolean value) {
|
||||
AtomicFormula baseFormula = (AtomicFormula) this;
|
||||
return new AtomicFormula.BooleanAtomicFormula(baseFormula.getKey(), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formula that evaluates to true when the value of the key in the package being
|
||||
* installed is equal to {@code value}.
|
||||
*
|
||||
* <p>Throws an {@link IllegalArgumentException} if the key is not long typed.
|
||||
*/
|
||||
@NonNull
|
||||
public IntegrityFormula equalTo(long value) {
|
||||
AtomicFormula baseFormula = (AtomicFormula) this;
|
||||
return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.EQ, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formula that evaluates to true when the value of the key in the package being
|
||||
* installed is greater than {@code value}.
|
||||
*
|
||||
* <p>Throws an {@link IllegalArgumentException} if the key is not long typed.
|
||||
*/
|
||||
@NonNull
|
||||
public IntegrityFormula greaterThan(long value) {
|
||||
AtomicFormula baseFormula = (AtomicFormula) this;
|
||||
return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GT, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formula that evaluates to true when the value of the key in the package being
|
||||
* installed is greater than or equals to the {@code value}.
|
||||
*
|
||||
* <p>Throws an {@link IllegalArgumentException} if the key is not long typed.
|
||||
*/
|
||||
@NonNull
|
||||
public IntegrityFormula greaterThanOrEquals(long value) {
|
||||
AtomicFormula baseFormula = (AtomicFormula) this;
|
||||
return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GTE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formula that evaluates to true when any formula in {@code formulae} evaluates to
|
||||
* true.
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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 android.content.integrity;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
public class InstallerAllowedByManifestFormulaTest {
|
||||
|
||||
private static final InstallerAllowedByManifestFormula
|
||||
FORMULA = new InstallerAllowedByManifestFormula();
|
||||
|
||||
@Test
|
||||
public void testFormulaMatches_installerAndCertBothInManifest() {
|
||||
AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
|
||||
.setInstallerName("installer1")
|
||||
.setInstallerCertificates(Arrays.asList("installer_cert1", "random_cert"))
|
||||
.setAllowedInstallersAndCert(ImmutableMap.of(
|
||||
"installer1", "installer_cert1",
|
||||
"installer2", "installer_cert2"
|
||||
)).build();
|
||||
|
||||
assertThat(FORMULA.matches(appInstallMetadata)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormulaMatches_installerAndCertDoesNotMatchInManifest() {
|
||||
AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
|
||||
.setInstallerName("installer1")
|
||||
.setInstallerCertificates(Arrays.asList("installer_cert1", "random_cert"))
|
||||
.setAllowedInstallersAndCert(ImmutableMap.of(
|
||||
"installer1", "installer_cert2",
|
||||
"installer2", "installer_cert1"
|
||||
)).build();
|
||||
|
||||
assertThat(FORMULA.matches(appInstallMetadata)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormulaMatches_installerNotInManifest() {
|
||||
AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
|
||||
.setInstallerName("installer3")
|
||||
.setInstallerCertificates(Arrays.asList("installer_cert1", "random_cert"))
|
||||
.setAllowedInstallersAndCert(ImmutableMap.of(
|
||||
"installer1", "installer_cert2",
|
||||
"installer2", "installer_cert1"
|
||||
)).build();
|
||||
|
||||
assertThat(FORMULA.matches(appInstallMetadata)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormulaMatches_certificateNotInManifest() {
|
||||
AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
|
||||
.setInstallerName("installer1")
|
||||
.setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert"))
|
||||
.setAllowedInstallersAndCert(ImmutableMap.of(
|
||||
"installer1", "installer_cert2",
|
||||
"installer2", "installer_cert1"
|
||||
)).build();
|
||||
|
||||
assertThat(FORMULA.matches(appInstallMetadata)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormulaMatches_emptyManifest() {
|
||||
AppInstallMetadata appInstallMetadata = getAppInstallMetadataBuilder()
|
||||
.setInstallerName("installer1")
|
||||
.setInstallerCertificates(Arrays.asList("installer_cert3", "random_cert"))
|
||||
.setAllowedInstallersAndCert(ImmutableMap.of()).build();
|
||||
|
||||
assertThat(FORMULA.matches(appInstallMetadata)).isTrue();
|
||||
}
|
||||
|
||||
/** Returns a builder with all fields filled with some dummy data. */
|
||||
private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
|
||||
return new AppInstallMetadata.Builder()
|
||||
.setPackageName("abc")
|
||||
.setAppCertificates(Collections.emptyList())
|
||||
.setInstallerCertificates(Collections.emptyList())
|
||||
.setInstallerName("abc")
|
||||
.setVersionCode(-1)
|
||||
.setIsPreInstalled(true);
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,6 @@ import static android.content.integrity.IntegrityFormula.COMPOUND_FORMULA_TAG;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import static org.testng.Assert.assertThrows;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
@@ -32,8 +30,7 @@ public class IntegrityFormulaTest {
|
||||
@Test
|
||||
public void createEqualsFormula_packageName() {
|
||||
String packageName = "com.test.app";
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.PACKAGE_NAME.equalTo(packageName);
|
||||
IntegrityFormula formula = IntegrityFormula.Application.packageNameEquals(packageName);
|
||||
|
||||
AtomicFormula.StringAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.StringAtomicFormula) formula;
|
||||
@@ -46,8 +43,7 @@ public class IntegrityFormulaTest {
|
||||
@Test
|
||||
public void createEqualsFormula_appCertificate() {
|
||||
String appCertificate = "com.test.app";
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.APP_CERTIFICATE.equalTo(appCertificate);
|
||||
IntegrityFormula formula = IntegrityFormula.Application.certificatesContain(appCertificate);
|
||||
|
||||
AtomicFormula.StringAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.StringAtomicFormula) formula;
|
||||
@@ -60,8 +56,7 @@ public class IntegrityFormulaTest {
|
||||
@Test
|
||||
public void createEqualsFormula_installerName() {
|
||||
String installerName = "com.test.app";
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.INSTALLER_NAME.equalTo(installerName);
|
||||
IntegrityFormula formula = IntegrityFormula.Installer.packageNameEquals(installerName);
|
||||
|
||||
AtomicFormula.StringAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.StringAtomicFormula) formula;
|
||||
@@ -75,7 +70,7 @@ public class IntegrityFormulaTest {
|
||||
public void createEqualsFormula_installerCertificate() {
|
||||
String installerCertificate = "com.test.app";
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.INSTALLER_CERTIFICATE.equalTo(installerCertificate);
|
||||
IntegrityFormula.Installer.certificatesContain(installerCertificate);
|
||||
|
||||
AtomicFormula.StringAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.StringAtomicFormula) formula;
|
||||
@@ -88,8 +83,7 @@ public class IntegrityFormulaTest {
|
||||
@Test
|
||||
public void createEqualsFormula_versionCode() {
|
||||
int versionCode = 12;
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.VERSION_CODE.equalTo(versionCode);
|
||||
IntegrityFormula formula = IntegrityFormula.Application.versionCodeEquals(versionCode);
|
||||
|
||||
AtomicFormula.LongAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.LongAtomicFormula) formula;
|
||||
@@ -99,25 +93,10 @@ public class IntegrityFormulaTest {
|
||||
assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.EQ);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createEqualsFormula_invalidKeyTypeForStringParameter() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> IntegrityFormula.PRE_INSTALLED.equalTo("wrongString"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createEqualsFormula_invalidKeyTypeForLongParameter() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> IntegrityFormula.PACKAGE_NAME.equalTo(12));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createGreaterThanFormula_versionCode() {
|
||||
int versionCode = 12;
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.VERSION_CODE.greaterThan(versionCode);
|
||||
IntegrityFormula formula = IntegrityFormula.Application.versionCodeGreaterThan(versionCode);
|
||||
|
||||
AtomicFormula.LongAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.LongAtomicFormula) formula;
|
||||
@@ -127,18 +106,11 @@ public class IntegrityFormulaTest {
|
||||
assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.GT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createGreaterThanFormula_invalidKeyTypeForLongParameter() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> IntegrityFormula.PACKAGE_NAME.greaterThan(12));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createGreaterThanOrEqualsToFormula_versionCode() {
|
||||
int versionCode = 12;
|
||||
IntegrityFormula formula =
|
||||
IntegrityFormula.VERSION_CODE.greaterThanOrEquals(versionCode);
|
||||
IntegrityFormula formula = IntegrityFormula.Application.versionCodeGreaterThanOrEqualTo(
|
||||
versionCode);
|
||||
|
||||
AtomicFormula.LongAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.LongAtomicFormula) formula;
|
||||
@@ -148,16 +120,9 @@ public class IntegrityFormulaTest {
|
||||
assertThat(stringAtomicFormula.getOperator()).isEqualTo(AtomicFormula.GTE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createGreaterThanOrEqualsToFormula_invalidKeyTypeForLongParameter() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> IntegrityFormula.PACKAGE_NAME.greaterThanOrEquals(12));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIsTrueFormula_preInstalled() {
|
||||
IntegrityFormula formula = IntegrityFormula.PRE_INSTALLED.equalTo(true);
|
||||
IntegrityFormula formula = IntegrityFormula.Application.isPreInstalled();
|
||||
|
||||
AtomicFormula.BooleanAtomicFormula stringAtomicFormula =
|
||||
(AtomicFormula.BooleanAtomicFormula) formula;
|
||||
@@ -166,21 +131,13 @@ public class IntegrityFormulaTest {
|
||||
assertThat(stringAtomicFormula.getValue()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createIsTrueFormula_invalidKeyTypeForBoolParameter() {
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> IntegrityFormula.PACKAGE_NAME.equalTo(true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createAllFormula() {
|
||||
String packageName = "com.test.package";
|
||||
String certificateName = "certificate";
|
||||
IntegrityFormula formula1 =
|
||||
IntegrityFormula.PACKAGE_NAME.equalTo(packageName);
|
||||
IntegrityFormula formula2 =
|
||||
IntegrityFormula.APP_CERTIFICATE.equalTo(certificateName);
|
||||
IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName);
|
||||
IntegrityFormula formula2 = IntegrityFormula.Application.certificatesContain(
|
||||
certificateName);
|
||||
|
||||
IntegrityFormula compoundFormula = IntegrityFormula.all(formula1, formula2);
|
||||
|
||||
@@ -191,10 +148,9 @@ public class IntegrityFormulaTest {
|
||||
public void createAnyFormula() {
|
||||
String packageName = "com.test.package";
|
||||
String certificateName = "certificate";
|
||||
IntegrityFormula formula1 =
|
||||
IntegrityFormula.PACKAGE_NAME.equalTo(packageName);
|
||||
IntegrityFormula formula2 =
|
||||
IntegrityFormula.APP_CERTIFICATE.equalTo(certificateName);
|
||||
IntegrityFormula formula1 = IntegrityFormula.Application.packageNameEquals(packageName);
|
||||
IntegrityFormula formula2 = IntegrityFormula.Application.certificatesContain(
|
||||
certificateName);
|
||||
|
||||
IntegrityFormula compoundFormula = IntegrityFormula.any(formula1, formula2);
|
||||
|
||||
@@ -206,8 +162,7 @@ public class IntegrityFormulaTest {
|
||||
String packageName = "com.test.package";
|
||||
|
||||
IntegrityFormula compoundFormula =
|
||||
IntegrityFormula.not(
|
||||
IntegrityFormula.PACKAGE_NAME.equalTo(packageName));
|
||||
IntegrityFormula.not(IntegrityFormula.Application.packageNameEquals(packageName));
|
||||
|
||||
assertThat(compoundFormula.getTag()).isEqualTo(COMPOUND_FORMULA_TAG);
|
||||
}
|
||||
|
||||
@@ -29,13 +29,14 @@ public final class ComponentBitSize {
|
||||
public static final int KEY_BITS = 4;
|
||||
public static final int OPERATOR_BITS = 3;
|
||||
public static final int CONNECTOR_BITS = 2;
|
||||
public static final int SEPARATOR_BITS = 2;
|
||||
public static final int SEPARATOR_BITS = 3;
|
||||
public static final int VALUE_SIZE_BITS = 8;
|
||||
public static final int IS_HASHED_BITS = 1;
|
||||
|
||||
public static final int ATOMIC_FORMULA_START = 0;
|
||||
public static final int COMPOUND_FORMULA_START = 1;
|
||||
public static final int COMPOUND_FORMULA_END = 2;
|
||||
public static final int INSTALLER_ALLOWED_BY_MANIFEST_START = 3;
|
||||
|
||||
public static final int DEFAULT_FORMAT_VERSION = 1;
|
||||
public static final int SIGNAL_BIT = 1;
|
||||
|
||||
@@ -23,6 +23,7 @@ import static com.android.server.integrity.model.ComponentBitSize.COMPOUND_FORMU
|
||||
import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.INSTALLER_ALLOWED_BY_MANIFEST_START;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.IS_HASHED_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
|
||||
@@ -35,6 +36,7 @@ import static com.android.server.integrity.parser.BinaryFileOperations.getString
|
||||
|
||||
import android.content.integrity.AtomicFormula;
|
||||
import android.content.integrity.CompoundFormula;
|
||||
import android.content.integrity.InstallerAllowedByManifestFormula;
|
||||
import android.content.integrity.IntegrityFormula;
|
||||
import android.content.integrity.Rule;
|
||||
|
||||
@@ -140,6 +142,8 @@ public class RuleBinaryParser implements RuleParser {
|
||||
return parseCompoundFormula(bitInputStream);
|
||||
case COMPOUND_FORMULA_END:
|
||||
return null;
|
||||
case INSTALLER_ALLOWED_BY_MANIFEST_START:
|
||||
return new InstallerAllowedByManifestFormula();
|
||||
default:
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Unknown formula separator: %s", separator));
|
||||
|
||||
@@ -23,6 +23,7 @@ import static com.android.server.integrity.model.ComponentBitSize.CONNECTOR_BITS
|
||||
import static com.android.server.integrity.model.ComponentBitSize.DEFAULT_FORMAT_VERSION;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.EFFECT_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.FORMAT_VERSION_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.INSTALLER_ALLOWED_BY_MANIFEST_START;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.KEY_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.OPERATOR_BITS;
|
||||
import static com.android.server.integrity.model.ComponentBitSize.SEPARATOR_BITS;
|
||||
@@ -36,6 +37,7 @@ import static com.android.server.integrity.serializer.RuleIndexingDetails.PACKAG
|
||||
|
||||
import android.content.integrity.AtomicFormula;
|
||||
import android.content.integrity.CompoundFormula;
|
||||
import android.content.integrity.InstallerAllowedByManifestFormula;
|
||||
import android.content.integrity.IntegrityFormula;
|
||||
import android.content.integrity.IntegrityUtils;
|
||||
import android.content.integrity.Rule;
|
||||
@@ -202,6 +204,8 @@ public class RuleBinarySerializer implements RuleSerializer {
|
||||
serializeAtomicFormula((AtomicFormula) formula, bitOutputStream);
|
||||
} else if (formula instanceof CompoundFormula) {
|
||||
serializeCompoundFormula((CompoundFormula) formula, bitOutputStream);
|
||||
} else if (formula instanceof InstallerAllowedByManifestFormula) {
|
||||
bitOutputStream.setNext(SEPARATOR_BITS, INSTALLER_ALLOWED_BY_MANIFEST_START);
|
||||
} else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Invalid formula type: %s", formula.getClass()));
|
||||
|
||||
@@ -84,6 +84,7 @@ class RuleIndexingDetailsIdentifier {
|
||||
return getIndexingDetailsForStringAtomicFormula(
|
||||
(AtomicFormula.StringAtomicFormula) formula);
|
||||
case IntegrityFormula.LONG_ATOMIC_FORMULA_TAG:
|
||||
case IntegrityFormula.INSTALLER_ALLOWED_BY_MANIFEST_FORMULA_TAG:
|
||||
case IntegrityFormula.BOOLEAN_ATOMIC_FORMULA_TAG:
|
||||
// Package name and app certificate related formulas are string atomic formulas.
|
||||
return new RuleIndexingDetails(NOT_INDEXED);
|
||||
|
||||
@@ -211,7 +211,8 @@ public class AppIntegrityManagerServiceImplTest {
|
||||
IntentSender mockReceiver = mock(IntentSender.class);
|
||||
List<Rule> rules =
|
||||
Arrays.asList(
|
||||
new Rule(IntegrityFormula.PACKAGE_NAME.equalTo(PACKAGE_NAME), Rule.DENY));
|
||||
new Rule(IntegrityFormula.Application.packageNameEquals(PACKAGE_NAME),
|
||||
Rule.DENY));
|
||||
|
||||
mService.updateRuleSet(VERSION, new ParceledListSlice<>(rules), mockReceiver);
|
||||
runJobInHandler();
|
||||
@@ -230,7 +231,8 @@ public class AppIntegrityManagerServiceImplTest {
|
||||
IntentSender mockReceiver = mock(IntentSender.class);
|
||||
List<Rule> rules =
|
||||
Arrays.asList(
|
||||
new Rule(IntegrityFormula.PACKAGE_NAME.equalTo(PACKAGE_NAME), Rule.DENY));
|
||||
new Rule(IntegrityFormula.Application.packageNameEquals(PACKAGE_NAME),
|
||||
Rule.DENY));
|
||||
|
||||
mService.updateRuleSet(VERSION, new ParceledListSlice<>(rules), mockReceiver);
|
||||
runJobInHandler();
|
||||
@@ -390,7 +392,7 @@ public class AppIntegrityManagerServiceImplTest {
|
||||
public void getCurrentRules() throws Exception {
|
||||
whitelistUsAsRuleProvider();
|
||||
makeUsSystemApp();
|
||||
Rule rule = new Rule(IntegrityFormula.PACKAGE_NAME.equalTo("package"), Rule.DENY);
|
||||
Rule rule = new Rule(IntegrityFormula.Application.packageNameEquals("package"), Rule.DENY);
|
||||
when(mIntegrityFileManager.readRules(any())).thenReturn(Arrays.asList(rule));
|
||||
|
||||
assertThat(mService.getCurrentRules().getList()).containsExactly(rule);
|
||||
|
||||
@@ -58,7 +58,7 @@ public class RuleBinaryParserTest {
|
||||
getBits(COMPOUND_FORMULA_END, SEPARATOR_BITS);
|
||||
private static final String ATOMIC_FORMULA_START_BITS =
|
||||
getBits(ATOMIC_FORMULA_START, SEPARATOR_BITS);
|
||||
private static final int INVALID_FORMULA_SEPARATOR_VALUE = 3;
|
||||
private static final int INVALID_FORMULA_SEPARATOR_VALUE = (1 << SEPARATOR_BITS) - 1;
|
||||
private static final String INVALID_FORMULA_SEPARATOR_BITS =
|
||||
getBits(INVALID_FORMULA_SEPARATOR_VALUE, SEPARATOR_BITS);
|
||||
|
||||
|
||||
@@ -112,6 +112,7 @@ public class RuleIndexingDetailsIdentifierTest {
|
||||
ATOMIC_FORMULA_WITH_VERSION_CODE,
|
||||
ATOMIC_FORMULA_WITH_ISPREINSTALLED)),
|
||||
Rule.DENY);
|
||||
public static final int INVALID_FORMULA_TAG = -1;
|
||||
|
||||
@Test
|
||||
public void getIndexType_nullRule() {
|
||||
@@ -290,7 +291,7 @@ public class RuleIndexingDetailsIdentifierTest {
|
||||
return new AtomicFormula(0) {
|
||||
@Override
|
||||
public int getTag() {
|
||||
return 4;
|
||||
return INVALID_FORMULA_TAG;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user