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