Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 69741ced authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Remove RuleEvaluationEngine from AppIntegrityManagerService." into main

parents 4da89c03 1e6126f6
Loading
Loading
Loading
Loading
+1 −6
Original line number Diff line number Diff line
@@ -63,7 +63,6 @@ import com.android.internal.pm.parsing.PackageParser2;
import com.android.internal.pm.pkg.parsing.ParsingPackageUtils;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.integrity.engine.RuleEvaluationEngine;
import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.integrity.model.RuleMetadata;
import com.android.server.pm.PackageManagerServiceUtils;
@@ -130,7 +129,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
    private final Handler mHandler;
    private final PackageManagerInternal mPackageManagerInternal;
    private final Supplier<PackageParser2> mParserSupplier;
    private final RuleEvaluationEngine mEvaluationEngine;
    private final IntegrityFileManager mIntegrityFileManager;

    /** Create an instance of {@link AppIntegrityManagerServiceImpl}. */
@@ -142,7 +140,6 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
                context,
                LocalServices.getService(PackageManagerInternal.class),
                PackageParserUtils::forParsingFileWithDefaults,
                RuleEvaluationEngine.getRuleEvaluationEngine(),
                IntegrityFileManager.getInstance(),
                handlerThread.getThreadHandler());
    }
@@ -152,13 +149,11 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
            Context context,
            PackageManagerInternal packageManagerInternal,
            Supplier<PackageParser2> parserSupplier,
            RuleEvaluationEngine evaluationEngine,
            IntegrityFileManager integrityFileManager,
            Handler handler) {
        mContext = context;
        mPackageManagerInternal = packageManagerInternal;
        mParserSupplier = parserSupplier;
        mEvaluationEngine = evaluationEngine;
        mIntegrityFileManager = integrityFileManager;
        mHandler = handler;

@@ -330,7 +325,7 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub {
                                + " installers "
                                + allowedInstallers);
            }
            IntegrityCheckResult result = mEvaluationEngine.evaluate(appInstallMetadata);
            IntegrityCheckResult result = IntegrityCheckResult.allow();
            if (!result.getMatchedRules().isEmpty() || DEBUG_INTEGRITY_COMPONENT) {
                Slog.i(
                        TAG,
+0 −85
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.integrity.engine;

import android.content.integrity.AppInstallMetadata;
import android.content.integrity.Rule;
import android.util.Slog;

import com.android.internal.annotations.VisibleForTesting;
import com.android.server.integrity.IntegrityFileManager;
import com.android.server.integrity.model.IntegrityCheckResult;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * The engine used to evaluate rules against app installs.
 *
 * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine
 * to allow/block that install.
 */
public class RuleEvaluationEngine {
    private static final String TAG = "RuleEvaluation";

    // The engine for loading rules, retrieving metadata for app installs, and evaluating app
    // installs against rules.
    private static RuleEvaluationEngine sRuleEvaluationEngine;

    private final IntegrityFileManager mIntegrityFileManager;

    @VisibleForTesting
    RuleEvaluationEngine(IntegrityFileManager integrityFileManager) {
        mIntegrityFileManager = integrityFileManager;
    }

    /** Provide a singleton instance of the rule evaluation engine. */
    public static synchronized RuleEvaluationEngine getRuleEvaluationEngine() {
        if (sRuleEvaluationEngine == null) {
            return new RuleEvaluationEngine(IntegrityFileManager.getInstance());
        }
        return sRuleEvaluationEngine;
    }

    /**
     * Load, and match the list of rules against an app install metadata.
     *
     * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
     *                           against.
     * @return result of the integrity check
     */
    public IntegrityCheckResult evaluate(
            AppInstallMetadata appInstallMetadata) {
        List<Rule> rules = loadRules(appInstallMetadata);
        return IntegrityCheckResult.allow();
    }

    private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
        if (!mIntegrityFileManager.initialized()) {
            Slog.w(TAG, "Integrity rule files are not available.");
            return Collections.emptyList();
        }

        try {
            return mIntegrityFileManager.readRules(appInstallMetadata);
        } catch (Exception e) {
            Slog.e(TAG, "Error loading rules.", e);
            return new ArrayList<>();
        }
    }
}
+0 −118
Original line number Diff line number Diff line
@@ -69,7 +69,6 @@ import androidx.test.InstrumentationRegistry;
import com.android.internal.R;
import com.android.internal.pm.parsing.PackageParser2;
import com.android.server.compat.PlatformCompat;
import com.android.server.integrity.engine.RuleEvaluationEngine;
import com.android.server.integrity.model.IntegrityCheckResult;
import com.android.server.pm.parsing.TestPackageParser2;
import com.android.server.testutils.TestUtils;
@@ -138,7 +137,6 @@ public class AppIntegrityManagerServiceImplTest {
    @Mock PlatformCompat mPlatformCompat;
    @Mock Context mMockContext;
    @Mock Resources mMockResources;
    @Mock RuleEvaluationEngine mRuleEvaluationEngine;
    @Mock IntegrityFileManager mIntegrityFileManager;
    @Mock Handler mHandler;

@@ -176,7 +174,6 @@ public class AppIntegrityManagerServiceImplTest {
                        mMockContext,
                        mPackageManagerInternal,
                        mParserSupplier,
                        mRuleEvaluationEngine,
                        mIntegrityFileManager,
                        mHandler);

@@ -306,91 +303,6 @@ public class AppIntegrityManagerServiceImplTest {
        assertEquals(PACKAGE_MIME_TYPE, intentFilterCaptor.getValue().getDataType(0));
    }

    @Test
    public void handleBroadcast_correctArgs() throws Exception {
        allowlistUsAsRuleProvider();
        makeUsSystemApp();
        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        verify(mMockContext)
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        Intent intent = makeVerificationIntent();
        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();

        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
                ArgumentCaptor.forClass(AppInstallMetadata.class);
        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
        assertEquals(PACKAGE_NAME, appInstallMetadata.getPackageName());
        assertThat(appInstallMetadata.getAppCertificates()).containsExactly(APP_CERT);
        assertEquals(INSTALLER_SHA256, appInstallMetadata.getInstallerName());
        // we cannot check installer cert because it seems to be device specific.
        assertEquals(VERSION_CODE, appInstallMetadata.getVersionCode());
        assertFalse(appInstallMetadata.isPreInstalled());
        // Asserting source stamp not present.
        assertFalse(appInstallMetadata.isStampPresent());
        assertFalse(appInstallMetadata.isStampVerified());
        assertFalse(appInstallMetadata.isStampTrusted());
        assertNull(appInstallMetadata.getStampCertificateHash());
        // These are hardcoded in the test apk android manifest
        Map<String, String> allowedInstallers =
                appInstallMetadata.getAllowedInstallersAndCertificates();
        assertEquals(2, allowedInstallers.size());
        assertEquals(PLAY_STORE_CERT, allowedInstallers.get(PLAY_STORE_PKG));
        assertEquals(INSTALLER_CERTIFICATE_NOT_EVALUATED, allowedInstallers.get(ADB_INSTALLER));
    }

    @Test
    public void handleBroadcast_correctArgs_multipleCerts() throws Exception {
        allowlistUsAsRuleProvider();
        makeUsSystemApp();
        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        verify(mMockContext)
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        Intent intent = makeVerificationIntent();
        intent.setDataAndType(Uri.fromFile(mTestApkTwoCerts), PACKAGE_MIME_TYPE);
        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();

        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
                ArgumentCaptor.forClass(AppInstallMetadata.class);
        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
        assertThat(appInstallMetadata.getAppCertificates())
                .containsExactly(DUMMY_APP_TWO_CERTS_CERT_1, DUMMY_APP_TWO_CERTS_CERT_2);
    }

    @Test
    public void handleBroadcast_correctArgs_sourceStamp() throws Exception {
        allowlistUsAsRuleProvider();
        makeUsSystemApp();
        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        verify(mMockContext)
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        Intent intent = makeVerificationIntent();
        intent.setDataAndType(Uri.fromFile(mTestApkSourceStamp), PACKAGE_MIME_TYPE);
        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();

        ArgumentCaptor<AppInstallMetadata> metadataCaptor =
                ArgumentCaptor.forClass(AppInstallMetadata.class);
        verify(mRuleEvaluationEngine).evaluate(metadataCaptor.capture());
        AppInstallMetadata appInstallMetadata = metadataCaptor.getValue();
        assertTrue(appInstallMetadata.isStampPresent());
        assertTrue(appInstallMetadata.isStampVerified());
        assertTrue(appInstallMetadata.isStampTrusted());
        assertEquals(SOURCE_STAMP_CERTIFICATE_HASH, appInstallMetadata.getStampCertificateHash());
    }

    @Test
    public void handleBroadcast_allow() throws Exception {
        allowlistUsAsRuleProvider();
@@ -400,7 +312,6 @@ public class AppIntegrityManagerServiceImplTest {
        verify(mMockContext)
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        Intent intent = makeVerificationIntent();
        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();
@@ -410,32 +321,6 @@ public class AppIntegrityManagerServiceImplTest {
                        1, PackageManagerInternal.INTEGRITY_VERIFICATION_ALLOW);
    }

    @Test
    public void handleBroadcast_reject() throws Exception {
        allowlistUsAsRuleProvider();
        makeUsSystemApp();
        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
                ArgumentCaptor.forClass(BroadcastReceiver.class);
        verify(mMockContext)
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        when(mRuleEvaluationEngine.evaluate(any()))
                .thenReturn(
                        IntegrityCheckResult.deny(
                                Arrays.asList(
                                        new Rule(
                                                new AtomicFormula.BooleanAtomicFormula(
                                                        AtomicFormula.PRE_INSTALLED, false),
                                                Rule.DENY))));
        Intent intent = makeVerificationIntent();

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();

        verify(mPackageManagerInternal)
                .setIntegrityVerificationResult(
                        1, PackageManagerInternal.INTEGRITY_VERIFICATION_REJECT);
    }

    @Test
    public void handleBroadcast_notInitialized() throws Exception {
        allowlistUsAsRuleProvider();
@@ -446,7 +331,6 @@ public class AppIntegrityManagerServiceImplTest {
        verify(mMockContext)
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        Intent intent = makeVerificationIntent();
        when(mRuleEvaluationEngine.evaluate(any())).thenReturn(IntegrityCheckResult.allow());

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();
@@ -467,8 +351,6 @@ public class AppIntegrityManagerServiceImplTest {
        verify(mMockContext, atLeastOnce())
                .registerReceiver(broadcastReceiverCaptor.capture(), any(), any(), any());
        Intent intent = makeVerificationIntent(TEST_FRAMEWORK_PACKAGE);
        when(mRuleEvaluationEngine.evaluate(any()))
                .thenReturn(IntegrityCheckResult.deny(/* rule= */ null));

        broadcastReceiverCaptor.getValue().onReceive(mMockContext, intent);
        runJobInHandler();
+0 −192
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 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.integrity.engine;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;

import android.content.integrity.AppInstallMetadata;
import android.content.integrity.IntegrityFormula;
import android.content.integrity.Rule;

import com.android.server.integrity.IntegrityFileManager;
import com.android.server.integrity.model.IntegrityCheckResult;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

@RunWith(JUnit4.class)
public class RuleEvaluationEngineTest {

    private static final String INSTALLER_1 = "installer1";
    private static final String INSTALLER_1_CERT = "installer1_cert";
    private static final String INSTALLER_2 = "installer2";
    private static final String INSTALLER_2_CERT = "installer2_cert";

    private static final String RANDOM_INSTALLER = "random";
    private static final String RANDOM_INSTALLER_CERT = "random_cert";

    @Mock
    private IntegrityFileManager mIntegrityFileManager;

    private RuleEvaluationEngine mEngine;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        mEngine = new RuleEvaluationEngine(mIntegrityFileManager);

        when(mIntegrityFileManager.readRules(any())).thenReturn(Collections.singletonList(new Rule(
                IntegrityFormula.Installer.notAllowedByManifest(), Rule.DENY)));

        when(mIntegrityFileManager.initialized()).thenReturn(true);
    }

    @Test
    public void testAllowedInstallers_empty() {
        AppInstallMetadata appInstallMetadata1 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_1)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .build();
        AppInstallMetadata appInstallMetadata2 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_2)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                        .build();
        AppInstallMetadata appInstallMetadata3 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(RANDOM_INSTALLER)
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .build();

        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
    }

    @Test
    public void testAllowedInstallers_oneElement() {
        Map<String, String> allowedInstallers =
                Collections.singletonMap(INSTALLER_1, INSTALLER_1_CERT);

        AppInstallMetadata appInstallMetadata1 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_1)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);

        AppInstallMetadata appInstallMetadata2 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(RANDOM_INSTALLER)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);

        AppInstallMetadata appInstallMetadata3 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_1)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);

        AppInstallMetadata appInstallMetadata4 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_1)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(RANDOM_INSTALLER_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
    }

    @Test
    public void testAllowedInstallers_multipleElement() {
        Map<String, String> allowedInstallers = new HashMap<>(2);
        allowedInstallers.put(INSTALLER_1, INSTALLER_1_CERT);
        allowedInstallers.put(INSTALLER_2, INSTALLER_2_CERT);

        AppInstallMetadata appInstallMetadata1 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_1)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata1).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);

        AppInstallMetadata appInstallMetadata2 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_2)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata2).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);

        AppInstallMetadata appInstallMetadata3 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_1)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_2_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata3).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);

        AppInstallMetadata appInstallMetadata4 =
                getAppInstallMetadataBuilder()
                        .setInstallerName(INSTALLER_2)
                        .setAllowedInstallersAndCert(allowedInstallers)
                        .setInstallerCertificates(Collections.singletonList(INSTALLER_1_CERT))
                        .build();
        assertThat(mEngine.evaluate(appInstallMetadata4).getEffect())
                .isEqualTo(IntegrityCheckResult.Effect.ALLOW);
    }

    /** Returns a builder with all fields filled with some placeholder data. */
    private AppInstallMetadata.Builder getAppInstallMetadataBuilder() {
        return new AppInstallMetadata.Builder()
                .setPackageName("abc")
                .setAppCertificates(Collections.singletonList("abc"))
                .setAppCertificateLineage(Collections.singletonList("abc"))
                .setInstallerCertificates(Collections.singletonList("abc"))
                .setInstallerName("abc")
                .setVersionCode(-1)
                .setIsPreInstalled(true);
    }
}