blob: 07eacbfd87dd180f9c224f72bdf7842d2d0273be [file] [log] [blame]
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +01001/*
2 * Copyright (C) 2019 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server.integrity.engine;
18
Song Pan75147d52019-11-19 00:57:46 +000019import android.content.integrity.AppInstallMetadata;
Song Pane24b80a2019-12-30 15:35:10 +000020import android.content.integrity.AtomicFormula;
21import android.content.integrity.CompoundFormula;
22import android.content.integrity.Formula;
Song Pan75147d52019-11-19 00:57:46 +000023import android.content.integrity.Rule;
Song Pan6e3677c2019-10-29 14:19:26 +000024import android.util.Slog;
Song Pan75147d52019-11-19 00:57:46 +000025
Song Pane24b80a2019-12-30 15:35:10 +000026import com.android.internal.annotations.VisibleForTesting;
Song Pan6e3677c2019-10-29 14:19:26 +000027import com.android.server.integrity.IntegrityFileManager;
Khaled Abdelmohsenaba57d62019-10-08 13:40:38 +010028import com.android.server.integrity.model.IntegrityCheckResult;
Khaled Abdelmohsen31012692019-10-02 17:54:47 +010029
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010030import java.util.ArrayList;
Song Pane24b80a2019-12-30 15:35:10 +000031import java.util.Arrays;
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010032import java.util.List;
Song Panf17fd092019-11-29 13:00:50 +000033import java.util.Map;
Song Pane24b80a2019-12-30 15:35:10 +000034import java.util.Optional;
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010035
36/**
37 * The engine used to evaluate rules against app installs.
38 *
Song Pan75147d52019-11-19 00:57:46 +000039 * <p>Every app install is evaluated against rules (pushed by the verifier) by the evaluation engine
40 * to allow/block that install.
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010041 */
Song Pan6e3677c2019-10-29 14:19:26 +000042public class RuleEvaluationEngine {
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010043 private static final String TAG = "RuleEvaluation";
44
45 // The engine for loading rules, retrieving metadata for app installs, and evaluating app
46 // installs against rules.
47 private static RuleEvaluationEngine sRuleEvaluationEngine;
48
Song Pan6e3677c2019-10-29 14:19:26 +000049 private final IntegrityFileManager mIntegrityFileManager;
50
Song Pane24b80a2019-12-30 15:35:10 +000051 @VisibleForTesting
52 RuleEvaluationEngine(IntegrityFileManager integrityFileManager) {
Song Pan6e3677c2019-10-29 14:19:26 +000053 mIntegrityFileManager = integrityFileManager;
54 }
55
Song Pan75147d52019-11-19 00:57:46 +000056 /** Provide a singleton instance of the rule evaluation engine. */
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010057 public static synchronized RuleEvaluationEngine getRuleEvaluationEngine() {
58 if (sRuleEvaluationEngine == null) {
Song Pan6e3677c2019-10-29 14:19:26 +000059 return new RuleEvaluationEngine(IntegrityFileManager.getInstance());
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +010060 }
61 return sRuleEvaluationEngine;
62 }
Khaled Abdelmohsenaba57d62019-10-08 13:40:38 +010063
64 /**
65 * Load, and match the list of rules against an app install metadata.
66 *
67 * @param appInstallMetadata Metadata of the app to be installed, and to evaluate the rules
Song Pan75147d52019-11-19 00:57:46 +000068 * against.
Song Pan097f65d2019-11-10 18:02:52 +000069 * @return result of the integrity check
Khaled Abdelmohsenaba57d62019-10-08 13:40:38 +010070 */
Song Panf17fd092019-11-29 13:00:50 +000071 public IntegrityCheckResult evaluate(
72 AppInstallMetadata appInstallMetadata, Map<String, String> allowedInstallers) {
Khaled Abdelmohsenaba57d62019-10-08 13:40:38 +010073 List<Rule> rules = loadRules(appInstallMetadata);
Song Pane24b80a2019-12-30 15:35:10 +000074 allowedInstallersRule(allowedInstallers).ifPresent(rules::add);
Song Pan097f65d2019-11-10 18:02:52 +000075 return RuleEvaluator.evaluateRules(rules, appInstallMetadata);
Khaled Abdelmohsenaba57d62019-10-08 13:40:38 +010076 }
77
78 private List<Rule> loadRules(AppInstallMetadata appInstallMetadata) {
Song Pan6e3677c2019-10-29 14:19:26 +000079 try {
80 return mIntegrityFileManager.readRules(appInstallMetadata);
81 } catch (Exception e) {
82 Slog.e(TAG, "Error loading rules.", e);
83 return new ArrayList<>();
84 }
Khaled Abdelmohsenaba57d62019-10-08 13:40:38 +010085 }
Song Pane24b80a2019-12-30 15:35:10 +000086
87 private static Optional<Rule> allowedInstallersRule(Map<String, String> allowedInstallers) {
88 if (allowedInstallers.isEmpty()) {
89 return Optional.empty();
90 }
91
92 List<Formula> formulas = new ArrayList<>(allowedInstallers.size());
93 allowedInstallers.forEach(
94 (installer, cert) -> {
95 formulas.add(allowedInstallerFormula(installer, cert));
96 });
97
98 // We need this special case since OR-formulas require at least two operands.
99 Formula allInstallersFormula =
100 formulas.size() == 1
101 ? formulas.get(0)
102 : new CompoundFormula(CompoundFormula.OR, formulas);
103
104 return Optional.of(
105 new Rule(
106 new CompoundFormula(
107 CompoundFormula.NOT, Arrays.asList(allInstallersFormula)),
108 Rule.DENY));
109 }
110
111 private static Formula allowedInstallerFormula(String installer, String cert) {
112 return new CompoundFormula(
113 CompoundFormula.AND,
114 Arrays.asList(
115 new AtomicFormula.StringAtomicFormula(
116 AtomicFormula.INSTALLER_NAME,
117 installer,
118 /* isHashedValue= */ false),
119 new AtomicFormula.StringAtomicFormula(
120 AtomicFormula.INSTALLER_CERTIFICATE,
121 cert,
122 /* isHashedValue= */ false)));
123 }
Khaled Abdelmohsen3a7a43f2019-10-02 11:38:22 +0100124}