• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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                     r.removeWritePermission(this);
227                 }
228                 mWriteOwners = null;
229             }
230         }
231 
232         if (persistedModeFlags == 0) {
233             persistedCreateTime = INVALID_TIME;
234         }
235 
236         updateModeFlags();
237         return persistedModeFlags != before;
238     }
239 
240     /**
241      * Return strength of this permission grant for the given flags.
242      */
getStrength(int modeFlags)243     public int getStrength(int modeFlags) {
244         modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION
245                 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
246         if ((persistableModeFlags & modeFlags) == modeFlags) {
247             return STRENGTH_PERSISTABLE;
248         } else if ((globalModeFlags & modeFlags) == modeFlags) {
249             return STRENGTH_GLOBAL;
250         } else if ((ownedModeFlags & modeFlags) == modeFlags) {
251             return STRENGTH_OWNED;
252         } else {
253             return STRENGTH_NONE;
254         }
255     }
256 
addReadOwner(UriPermissionOwner owner)257     private void addReadOwner(UriPermissionOwner owner) {
258         if (mReadOwners == null) {
259             mReadOwners = Sets.newArraySet();
260             ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
261             updateModeFlags();
262         }
263         if (mReadOwners.add(owner)) {
264             owner.addReadPermission(this);
265         }
266     }
267 
268     /**
269      * Remove given read owner, updating {@Link #modeFlags} as needed.
270      */
removeReadOwner(UriPermissionOwner owner)271     void removeReadOwner(UriPermissionOwner owner) {
272         if (!mReadOwners.remove(owner)) {
273             Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this);
274         }
275         if (mReadOwners.size() == 0) {
276             mReadOwners = null;
277             ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
278             updateModeFlags();
279         }
280     }
281 
addWriteOwner(UriPermissionOwner owner)282     private void addWriteOwner(UriPermissionOwner owner) {
283         if (mWriteOwners == null) {
284             mWriteOwners = Sets.newArraySet();
285             ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
286             updateModeFlags();
287         }
288         if (mWriteOwners.add(owner)) {
289             owner.addWritePermission(this);
290         }
291     }
292 
293     /**
294      * Remove given write owner, updating {@Link #modeFlags} as needed.
295      */
removeWriteOwner(UriPermissionOwner owner)296     void removeWriteOwner(UriPermissionOwner owner) {
297         if (!mWriteOwners.remove(owner)) {
298             Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this);
299         }
300         if (mWriteOwners.size() == 0) {
301             mWriteOwners = null;
302             ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
303             updateModeFlags();
304         }
305     }
306 
307     @Override
toString()308     public String toString() {
309         if (stringName != null) {
310             return stringName;
311         }
312         StringBuilder sb = new StringBuilder(128);
313         sb.append("UriPermission{");
314         sb.append(Integer.toHexString(System.identityHashCode(this)));
315         sb.append(' ');
316         sb.append(uri);
317         sb.append('}');
318         return stringName = sb.toString();
319     }
320 
dump(PrintWriter pw, String prefix)321     void dump(PrintWriter pw, String prefix) {
322         pw.print(prefix);
323         pw.print("targetUserId=" + targetUserId);
324         pw.print(" sourcePkg=" + sourcePkg);
325         pw.println(" targetPkg=" + targetPkg);
326 
327         pw.print(prefix);
328         pw.print("mode=0x" + Integer.toHexString(modeFlags));
329         pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
330         pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
331         pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
332         pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
333         if (persistedCreateTime != INVALID_TIME) {
334             pw.print(" persistedCreate=" + persistedCreateTime);
335         }
336         pw.println();
337 
338         if (mReadOwners != null) {
339             pw.print(prefix);
340             pw.println("readOwners:");
341             for (UriPermissionOwner owner : mReadOwners) {
342                 pw.print(prefix);
343                 pw.println("  * " + owner);
344             }
345         }
346         if (mWriteOwners != null) {
347             pw.print(prefix);
348             pw.println("writeOwners:");
349             for (UriPermissionOwner owner : mReadOwners) {
350                 pw.print(prefix);
351                 pw.println("  * " + owner);
352             }
353         }
354     }
355 
356     public static class PersistedTimeComparator implements Comparator<UriPermission> {
357         @Override
compare(UriPermission lhs, UriPermission rhs)358         public int compare(UriPermission lhs, UriPermission rhs) {
359             return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
360         }
361     }
362 
363     /**
364      * Snapshot of {@link UriPermission} with frozen
365      * {@link UriPermission#persistedModeFlags} state.
366      */
367     public static class Snapshot {
368         final int targetUserId;
369         final String sourcePkg;
370         final String targetPkg;
371         final GrantUri uri;
372         final int persistedModeFlags;
373         final long persistedCreateTime;
374 
Snapshot(UriPermission perm)375         private Snapshot(UriPermission perm) {
376             this.targetUserId = perm.targetUserId;
377             this.sourcePkg = perm.sourcePkg;
378             this.targetPkg = perm.targetPkg;
379             this.uri = perm.uri;
380             this.persistedModeFlags = perm.persistedModeFlags;
381             this.persistedCreateTime = perm.persistedCreateTime;
382         }
383     }
384 
snapshot()385     public Snapshot snapshot() {
386         return new Snapshot(this);
387     }
388 
buildPersistedPublicApiObject()389     public android.content.UriPermission buildPersistedPublicApiObject() {
390         return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime);
391     }
392 
buildGrantedUriPermission()393     public GrantedUriPermission buildGrantedUriPermission() {
394         return new GrantedUriPermission(uri.uri, targetPkg);
395     }
396 }
397