1 /*
2  * Copyright (C) 2011 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 
17 package com.android.server.pm;
18 
19 import android.content.pm.PackageManager;
20 import android.util.SparseBooleanArray;
21 
22 /**
23  * Tracks the package verification state for a particular package. Each package verification has a
24  * required verifier and zero or more sufficient verifiers. Only one of the sufficient verifier list
25  * must return affirmative to allow the package to be considered verified. If there are zero
26  * sufficient verifiers, then package verification is considered complete.
27  */
28 class PackageVerificationState {
29     private final VerifyingSession mVerifyingSession;
30 
31     private final SparseBooleanArray mSufficientVerifierUids;
32 
33     private final SparseBooleanArray mRequiredVerifierUids;
34     private final SparseBooleanArray mUnrespondedRequiredVerifierUids;
35 
36     private final SparseBooleanArray mExtendedTimeoutUids;
37 
38     private boolean mSufficientVerificationComplete;
39 
40     private boolean mSufficientVerificationPassed;
41 
42     private boolean mRequiredVerificationComplete;
43 
44     private boolean mRequiredVerificationPassed;
45 
46     private boolean mIntegrityVerificationComplete;
47 
48     /**
49      * Create a new package verification state where {@code requiredVerifierUid} is the user ID for
50      * the package that must reply affirmative before things can continue.
51      */
PackageVerificationState(VerifyingSession verifyingSession)52     PackageVerificationState(VerifyingSession verifyingSession) {
53         mVerifyingSession = verifyingSession;
54         mSufficientVerifierUids = new SparseBooleanArray();
55         mRequiredVerifierUids = new SparseBooleanArray();
56         mUnrespondedRequiredVerifierUids = new SparseBooleanArray();
57         mExtendedTimeoutUids = new SparseBooleanArray();
58         mRequiredVerificationComplete = false;
59         mRequiredVerificationPassed = true;
60     }
61 
getVerifyingSession()62     VerifyingSession getVerifyingSession() {
63         return mVerifyingSession;
64     }
65 
66     /** Add the user ID of the required package verifier. */
addRequiredVerifierUid(int uid)67     void addRequiredVerifierUid(int uid) {
68         mRequiredVerifierUids.put(uid, true);
69         mUnrespondedRequiredVerifierUids.put(uid, true);
70     }
71 
72     /** Returns true if the uid a required verifier. */
checkRequiredVerifierUid(int uid)73     boolean checkRequiredVerifierUid(int uid) {
74         return mRequiredVerifierUids.get(uid, false);
75     }
76 
77     /**
78      * Add a verifier which is added to our sufficient list.
79      *
80      * @param uid user ID of sufficient verifier
81      */
addSufficientVerifier(int uid)82     void addSufficientVerifier(int uid) {
83         mSufficientVerifierUids.put(uid, true);
84     }
85 
86     /** Returns true if the uid a sufficient verifier. */
checkSufficientVerifierUid(int uid)87     boolean checkSufficientVerifierUid(int uid) {
88         return mSufficientVerifierUids.get(uid, false);
89     }
90 
setVerifierResponseOnTimeout(int uid, int code)91     void setVerifierResponseOnTimeout(int uid, int code) {
92         if (!checkRequiredVerifierUid(uid)) {
93             return;
94         }
95 
96         // Timeout, not waiting for the sufficient verifiers anymore.
97         mSufficientVerifierUids.clear();
98 
99         // Only if unresponded.
100         if (mUnrespondedRequiredVerifierUids.get(uid, false)) {
101             setVerifierResponse(uid, code);
102         }
103     }
104 
105     /**
106      * Should be called when a verification is received from an agent so the state of the package
107      * verification can be tracked.
108      *
109      * @param uid user ID of the verifying agent
110      */
setVerifierResponse(int uid, int code)111     void setVerifierResponse(int uid, int code) {
112         if (mRequiredVerifierUids.get(uid)) {
113             switch (code) {
114                 case PackageManager.VERIFICATION_ALLOW_WITHOUT_SUFFICIENT:
115                     mSufficientVerifierUids.clear();
116                     // fall through
117                 case PackageManager.VERIFICATION_ALLOW:
118                     // Two possible options:
119                     // - verification result is true,
120                     // - another verifier set it to false.
121                     // In both cases we don't need to assign anything, just exit.
122                     break;
123                 default:
124                     mRequiredVerificationPassed = false;
125                     // Required verifier rejected, no need to wait for the rest.
126                     mUnrespondedRequiredVerifierUids.clear();
127                     mSufficientVerifierUids.clear();
128                     mExtendedTimeoutUids.clear();
129             }
130 
131             // Responded, no need to extend timeout.
132             mExtendedTimeoutUids.delete(uid);
133 
134             mUnrespondedRequiredVerifierUids.delete(uid);
135             if (mUnrespondedRequiredVerifierUids.size() == 0) {
136                 mRequiredVerificationComplete = true;
137             }
138         } else if (mSufficientVerifierUids.get(uid)) {
139             if (code == PackageManager.VERIFICATION_ALLOW) {
140                 mSufficientVerificationPassed = true;
141                 mSufficientVerificationComplete = true;
142             }
143 
144             mSufficientVerifierUids.delete(uid);
145             if (mSufficientVerifierUids.size() == 0) {
146                 mSufficientVerificationComplete = true;
147             }
148         }
149     }
150 
151     /**
152      * Mark the session as passed required verification.
153      */
passRequiredVerification()154     void passRequiredVerification() {
155         if (mUnrespondedRequiredVerifierUids.size() > 0) {
156             throw new RuntimeException("Required verifiers still present.");
157         }
158         mRequiredVerificationPassed = true;
159         mRequiredVerificationComplete = true;
160     }
161 
162     /**
163      * Returns whether verification is considered complete. This means that the required verifier
164      * and at least one of the sufficient verifiers has returned a positive verification.
165      *
166      * @return {@code true} when verification is considered complete
167      */
isVerificationComplete()168     boolean isVerificationComplete() {
169         if (!mRequiredVerificationComplete) {
170             return false;
171         }
172 
173         if (mSufficientVerifierUids.size() == 0) {
174             return true;
175         }
176 
177         return mSufficientVerificationComplete;
178     }
179 
180     /**
181      * Returns whether installation should be allowed. This should only be called after {@link
182      * #isVerificationComplete()} returns {@code true}.
183      *
184      * @return {@code true} if installation should be allowed
185      */
isInstallAllowed()186     boolean isInstallAllowed() {
187         if (!mRequiredVerificationComplete || !mRequiredVerificationPassed) {
188             return false;
189         }
190 
191         if (mSufficientVerificationComplete) {
192             return mSufficientVerificationPassed;
193         }
194 
195         return true;
196     }
197 
198     /** Extend the timeout for this Package to be verified. */
extendTimeout(int uid)199     boolean extendTimeout(int uid) {
200         if (!checkRequiredVerifierUid(uid) || timeoutExtended(uid)) {
201             return false;
202         }
203         mExtendedTimeoutUids.append(uid, true);
204         return true;
205     }
206 
207     /**
208      * Returns whether the timeout was extended for verification.
209      *
210      * @return {@code true} if a timeout was already extended.
211      */
timeoutExtended(int uid)212     boolean timeoutExtended(int uid) {
213         return mExtendedTimeoutUids.get(uid, false);
214     }
215 
setIntegrityVerificationResult(int code)216     void setIntegrityVerificationResult(int code) {
217         mIntegrityVerificationComplete = true;
218     }
219 
isIntegrityVerificationComplete()220     boolean isIntegrityVerificationComplete() {
221         return mIntegrityVerificationComplete;
222     }
223 
areAllVerificationsComplete()224     boolean areAllVerificationsComplete() {
225         return mIntegrityVerificationComplete && isVerificationComplete();
226     }
227 }
228