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