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                     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