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