1 /*
2  * Copyright (C) 2018 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.uri;
18 
19 import android.annotation.Nullable;
20 import android.app.GrantedUriPermission;
21 import android.content.Intent;
22 import android.os.Binder;
23 import android.os.UserHandle;
24 import android.util.ArraySet;
25 import android.util.Log;
26 import android.util.Slog;
27 
28 import com.google.android.collect.Sets;
29 
30 import java.io.PrintWriter;
31 import java.util.Comparator;
32 
33 /**
34  * Description of a permission granted to an app to access a particular URI.
35  *
36  * CTS tests for this functionality can be run with "runtest cts-appsecurity".
37  *
38  * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/
39  *      src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
40  */
41 final class UriPermission {
42     private static final String TAG = "UriPermission";
43 
44     public static final int STRENGTH_NONE = 0;
45     public static final int STRENGTH_OWNED = 1;
46     public static final int STRENGTH_GLOBAL = 2;
47     public static final int STRENGTH_PERSISTABLE = 3;
48 
49     final int targetUserId;
50     final String sourcePkg;
51     final String targetPkg;
52 
53     /** Cached UID of {@link #targetPkg}; should not be persisted */
54     final int targetUid;
55 
56     final GrantUri uri;
57 
58     /**
59      * Allowed modes. All permission enforcement should use this field. Must
60      * always be a combination of {@link #ownedModeFlags},
61      * {@link #globalModeFlags}, {@link #persistableModeFlags}, and
62      * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by
63      * the owning class.
64      */
65     int modeFlags = 0;
66 
67     /** Allowed modes with active owner. */
68     int ownedModeFlags = 0;
69     /** Allowed modes without explicit owner. */
70     int globalModeFlags = 0;
71     /** Allowed modes that have been offered for possible persisting. */
72     int persistableModeFlags = 0;
73 
74     /** Allowed modes that should be persisted across device boots. */
75     int persistedModeFlags = 0;
76 
77     /**
78      * Timestamp when {@link #persistedModeFlags} was first defined in
79      * {@link System#currentTimeMillis()} time base.
80      */
81     long persistedCreateTime = INVALID_TIME;
82 
83     static final long INVALID_TIME = Long.MIN_VALUE;
84 
85     private ArraySet<UriPermissionOwner> mReadOwners;
86     private ArraySet<UriPermissionOwner> mWriteOwners;
87 
88     private String stringName;
89 
UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri)90     UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) {
91         this.targetUserId = UserHandle.getUserId(targetUid);
92         this.sourcePkg = sourcePkg;
93         this.targetPkg = targetPkg;
94         this.targetUid = targetUid;
95         this.uri = uri;
96     }
97 
updateModeFlags()98     private void updateModeFlags() {
99         final int oldModeFlags = modeFlags;
100         modeFlags = ownedModeFlags | globalModeFlags | persistedModeFlags;
101 
102         if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) {
103             Slog.d(TAG,
104                     "Permission for " + targetPkg + " to " + uri + " is changing from 0x"
105                             + Integer.toHexString(oldModeFlags) + " to 0x"
106                             + Integer.toHexString(modeFlags) + " via calling UID "
107                             + Binder.getCallingUid() + " PID " + Binder.getCallingPid(),
108                     new Throwable());
109         }
110     }
111 
112     /**
113      * Initialize persisted modes as read from file. This doesn't issue any
114      * global or owner grants.
115      */
initPersistedModes(int modeFlags, long createdTime)116     void initPersistedModes(int modeFlags, long createdTime) {
117         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
118                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
119 
120         persistableModeFlags = modeFlags;
121         persistedModeFlags = modeFlags;
122         persistedCreateTime = createdTime;
123 
124         updateModeFlags();
125     }
126 
grantModes(int modeFlags, @Nullable UriPermissionOwner owner)127     boolean grantModes(int modeFlags, @Nullable UriPermissionOwner owner) {
128         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
129         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
130                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
131 
132         if (persistable) {
133             persistableModeFlags |= modeFlags;
134         }
135 
136         if (owner == null) {
137             globalModeFlags |= modeFlags;
138         } else {
139             if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
140                 addReadOwner(owner);
141             }
142             if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
143                 addWriteOwner(owner);
144             }
145         }
146 
147         updateModeFlags();
148         return false;
149     }
150 
151     /**
152      * @return if mode changes should trigger persisting.
153      */
takePersistableModes(int modeFlags)154     boolean takePersistableModes(int modeFlags) {
155         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
156                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
157 
158         if ((modeFlags & persistableModeFlags) != modeFlags) {
159             Slog.w(TAG, "Requested flags 0x"
160                     + Integer.toHexString(modeFlags) + ", but only 0x"
161                     + Integer.toHexString(persistableModeFlags) + " are allowed");
162             return false;
163         }
164 
165         final int before = persistedModeFlags;
166         persistedModeFlags |= (persistableModeFlags & modeFlags);
167 
168         if (persistedModeFlags != 0) {
169             persistedCreateTime = System.currentTimeMillis();
170         }
171 
172         updateModeFlags();
173         return persistedModeFlags != before;
174     }
175 
releasePersistableModes(int modeFlags)176     boolean releasePersistableModes(int modeFlags) {
177         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
178                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
179 
180         final int before = persistedModeFlags;
181         persistedModeFlags &= ~modeFlags;
182 
183         if (persistedModeFlags == 0) {
184             persistedCreateTime = INVALID_TIME;
185         }
186 
187         updateModeFlags();
188         return persistedModeFlags != before;
189     }
190 
191     /**
192      * @return if mode changes should trigger persisting.
193      */
revokeModes(int modeFlags, boolean includingOwners)194     boolean revokeModes(int modeFlags, boolean includingOwners) {
195         final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0;
196         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
197                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
198 
199         final int before = persistedModeFlags;
200 
201         if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
202             if (persistable) {
203                 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
204                 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
205             }
206             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
207             if (mReadOwners != null && includingOwners) {
208                 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
209                 for (UriPermissionOwner r : mReadOwners) {
210                     if (r != null) {
211                         r.removeReadPermission(this);
212                     }
213                 }
214                 mReadOwners = null;
215             }
216         }
217         if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
218             if (persistable) {
219                 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
220                 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
221             }
222             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
223             if (mWriteOwners != null && includingOwners) {
224                 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
225                 for (UriPermissionOwner r : mWriteOwners) {
226                     if (r != null) {
227                         r.removeWritePermission(this);
228                     }
229                 }
230                 mWriteOwners = null;
231             }
232         }
233 
234         if (persistedModeFlags == 0) {
235             persistedCreateTime = INVALID_TIME;
236         }
237 
238         updateModeFlags();
239         return persistedModeFlags != before;
240     }
241 
242     /**
243      * Return strength of this permission grant for the given flags.
244      */
getStrength(int modeFlags)245     public int getStrength(int modeFlags) {
246         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
247                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
248         if ((persistableModeFlags & modeFlags) == modeFlags) {
249             return STRENGTH_PERSISTABLE;
250         } else if ((globalModeFlags & modeFlags) == modeFlags) {
251             return STRENGTH_GLOBAL;
252         } else if ((ownedModeFlags & modeFlags) == modeFlags) {
253             return STRENGTH_OWNED;
254         } else {
255             return STRENGTH_NONE;
256         }
257     }
258 
addReadOwner(UriPermissionOwner owner)259     private void addReadOwner(UriPermissionOwner owner) {
260         if (mReadOwners == null) {
261             mReadOwners = Sets.newArraySet();
262             ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
263             updateModeFlags();
264         }
265         if (mReadOwners.add(owner)) {
266             owner.addReadPermission(this);
267         }
268     }
269 
270     /**
271      * Remove given read owner, updating {@Link #modeFlags} as needed.
272      */
removeReadOwner(UriPermissionOwner owner)273     void removeReadOwner(UriPermissionOwner owner) {
274         if (mReadOwners == null || !mReadOwners.remove(owner)) {
275             Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
276             return;
277         }
278         if (mReadOwners.size() == 0) {
279             mReadOwners = null;
280             ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
281             updateModeFlags();
282         }
283     }
284 
addWriteOwner(UriPermissionOwner owner)285     private void addWriteOwner(UriPermissionOwner owner) {
286         if (mWriteOwners == null) {
287             mWriteOwners = Sets.newArraySet();
288             ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
289             updateModeFlags();
290         }
291         if (mWriteOwners.add(owner)) {
292             owner.addWritePermission(this);
293         }
294     }
295 
296     /**
297      * Remove given write owner, updating {@Link #modeFlags} as needed.
298      */
removeWriteOwner(UriPermissionOwner owner)299     void removeWriteOwner(UriPermissionOwner owner) {
300         if (mWriteOwners == null || !mWriteOwners.remove(owner)) {
301             Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
302             return;
303         }
304         if (mWriteOwners.size() == 0) {
305             mWriteOwners = null;
306             ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
307             updateModeFlags();
308         }
309     }
310 
311     @Override
toString()312     public String toString() {
313         if (stringName != null) {
314             return stringName;
315         }
316         StringBuilder sb = new StringBuilder(128);
317         sb.append("UriPermission{");
318         sb.append(Integer.toHexString(System.identityHashCode(this)));
319         sb.append(' ');
320         sb.append(uri);
321         sb.append('}');
322         return stringName = sb.toString();
323     }
324 
dump(PrintWriter pw, String prefix)325     void dump(PrintWriter pw, String prefix) {
326         pw.print(prefix);
327         pw.print("targetUserId=" + targetUserId);
328         pw.print(" sourcePkg=" + sourcePkg);
329         pw.println(" targetPkg=" + targetPkg);
330 
331         pw.print(prefix);
332         pw.print("mode=0x" + Integer.toHexString(modeFlags));
333         pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
334         pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
335         pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
336         pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
337         if (persistedCreateTime != INVALID_TIME) {
338             pw.print(" persistedCreate=" + persistedCreateTime);
339         }
340         pw.println();
341 
342         if (mReadOwners != null) {
343             pw.print(prefix);
344             pw.println("readOwners:");
345             for (UriPermissionOwner owner : mReadOwners) {
346                 pw.print(prefix);
347                 pw.println("  * " + owner);
348             }
349         }
350         if (mWriteOwners != null) {
351             pw.print(prefix);
352             pw.println("writeOwners:");
353             for (UriPermissionOwner owner : mWriteOwners) {
354                 pw.print(prefix);
355                 pw.println("  * " + owner);
356             }
357         }
358     }
359 
360     public static class PersistedTimeComparator implements Comparator<UriPermission> {
361         @Override
compare(UriPermission lhs, UriPermission rhs)362         public int compare(UriPermission lhs, UriPermission rhs) {
363             return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
364         }
365     }
366 
367     /**
368      * Snapshot of {@link UriPermission} with frozen
369      * {@link UriPermission#persistedModeFlags} state.
370      */
371     public static class Snapshot {
372         final int targetUserId;
373         final String sourcePkg;
374         final String targetPkg;
375         final GrantUri uri;
376         final int persistedModeFlags;
377         final long persistedCreateTime;
378 
Snapshot(UriPermission perm)379         private Snapshot(UriPermission perm) {
380             this.targetUserId = perm.targetUserId;
381             this.sourcePkg = perm.sourcePkg;
382             this.targetPkg = perm.targetPkg;
383             this.uri = perm.uri;
384             this.persistedModeFlags = perm.persistedModeFlags;
385             this.persistedCreateTime = perm.persistedCreateTime;
386         }
387     }
388 
snapshot()389     public Snapshot snapshot() {
390         return new Snapshot(this);
391     }
392 
buildPersistedPublicApiObject()393     public android.content.UriPermission buildPersistedPublicApiObject() {
394         return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
395     }
396 
buildGrantedUriPermission()397     public GrantedUriPermission buildGrantedUriPermission() {
398         return new GrantedUriPermission(uri.uri, targetPkg);
399     }
400 }
401