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