• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.net.Uri;
21 import android.os.UserHandle;
22 import android.util.Log;
23 
24 import com.google.android.collect.Sets;
25 
26 import java.io.PrintWriter;
27 import java.util.Comparator;
28 import java.util.HashSet;
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 userHandle;
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 Uri 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 explicit 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     /** Allowed modes that should be persisted across device boots. */
71     int persistedModeFlags = 0;
72 
73     /**
74      * Timestamp when {@link #persistedModeFlags} was first defined in
75      * {@link System#currentTimeMillis()} time base.
76      */
77     long persistedCreateTime = INVALID_TIME;
78 
79     private static final long INVALID_TIME = Long.MIN_VALUE;
80 
81     private HashSet<UriPermissionOwner> mReadOwners;
82     private HashSet<UriPermissionOwner> mWriteOwners;
83 
84     private String stringName;
85 
UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri)86     UriPermission(String sourcePkg, String targetPkg, int targetUid, Uri uri) {
87         this.userHandle = UserHandle.getUserId(targetUid);
88         this.sourcePkg = sourcePkg;
89         this.targetPkg = targetPkg;
90         this.targetUid = targetUid;
91         this.uri = uri;
92     }
93 
updateModeFlags()94     private void updateModeFlags() {
95         modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags;
96     }
97 
98     /**
99      * Initialize persisted modes as read from file. This doesn't issue any
100      * global or owner grants.
101      */
initPersistedModes(int modeFlags, long createdTime)102     void initPersistedModes(int modeFlags, long createdTime) {
103         persistableModeFlags = modeFlags;
104         persistedModeFlags = modeFlags;
105         persistedCreateTime = createdTime;
106 
107         updateModeFlags();
108     }
109 
grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner)110     void grantModes(int modeFlags, boolean persistable, UriPermissionOwner owner) {
111         if (persistable) {
112             persistableModeFlags |= modeFlags;
113         }
114 
115         if (owner == null) {
116             globalModeFlags |= modeFlags;
117         } else {
118             if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
119                 addReadOwner(owner);
120             }
121             if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
122                 addWriteOwner(owner);
123             }
124         }
125 
126         updateModeFlags();
127     }
128 
129     /**
130      * @return if mode changes should trigger persisting.
131      */
takePersistableModes(int modeFlags)132     boolean takePersistableModes(int modeFlags) {
133         if ((modeFlags & persistableModeFlags) != modeFlags) {
134             throw new SecurityException("Requested flags 0x"
135                     + Integer.toHexString(modeFlags) + ", but only 0x"
136                     + Integer.toHexString(persistableModeFlags) + " are allowed");
137         }
138 
139         final int before = persistedModeFlags;
140         persistedModeFlags |= (persistableModeFlags & modeFlags);
141 
142         if (persistedModeFlags != 0) {
143             persistedCreateTime = System.currentTimeMillis();
144         }
145 
146         updateModeFlags();
147         return persistedModeFlags != before;
148     }
149 
releasePersistableModes(int modeFlags)150     boolean releasePersistableModes(int modeFlags) {
151         final int before = persistedModeFlags;
152 
153         persistableModeFlags &= ~modeFlags;
154         persistedModeFlags &= ~modeFlags;
155 
156         if (persistedModeFlags == 0) {
157             persistedCreateTime = INVALID_TIME;
158         }
159 
160         updateModeFlags();
161         return persistedModeFlags != before;
162     }
163 
164     /**
165      * @return if mode changes should trigger persisting.
166      */
clearModes(int modeFlags, boolean persistable)167     boolean clearModes(int modeFlags, boolean persistable) {
168         final int before = persistedModeFlags;
169 
170         if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
171             if (persistable) {
172                 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
173                 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
174             }
175             globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
176             if (mReadOwners != null) {
177                 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
178                 for (UriPermissionOwner r : mReadOwners) {
179                     r.removeReadPermission(this);
180                 }
181                 mReadOwners = null;
182             }
183         }
184         if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
185             if (persistable) {
186                 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
187                 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
188             }
189             globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
190             if (mWriteOwners != null) {
191                 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
192                 for (UriPermissionOwner r : mWriteOwners) {
193                     r.removeWritePermission(this);
194                 }
195                 mWriteOwners = null;
196             }
197         }
198 
199         if (persistedModeFlags == 0) {
200             persistedCreateTime = INVALID_TIME;
201         }
202 
203         updateModeFlags();
204         return persistedModeFlags != before;
205     }
206 
207     /**
208      * Return strength of this permission grant for the given flags.
209      */
getStrength(int modeFlags)210     public int getStrength(int modeFlags) {
211         if ((persistableModeFlags & modeFlags) == modeFlags) {
212             return STRENGTH_PERSISTABLE;
213         } else if ((globalModeFlags & modeFlags) == modeFlags) {
214             return STRENGTH_GLOBAL;
215         } else if ((ownedModeFlags & modeFlags) == modeFlags) {
216             return STRENGTH_OWNED;
217         } else {
218             return STRENGTH_NONE;
219         }
220     }
221 
addReadOwner(UriPermissionOwner owner)222     private void addReadOwner(UriPermissionOwner owner) {
223         if (mReadOwners == null) {
224             mReadOwners = Sets.newHashSet();
225             ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;
226             updateModeFlags();
227         }
228         if (mReadOwners.add(owner)) {
229             owner.addReadPermission(this);
230         }
231     }
232 
233     /**
234      * Remove given read owner, updating {@Link #modeFlags} as needed.
235      */
removeReadOwner(UriPermissionOwner owner)236     void removeReadOwner(UriPermissionOwner owner) {
237         if (!mReadOwners.remove(owner)) {
238             Log.wtf(TAG, "Unknown read owner " + owner + " in " + this);
239         }
240         if (mReadOwners.size() == 0) {
241             mReadOwners = null;
242             ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION;
243             updateModeFlags();
244         }
245     }
246 
addWriteOwner(UriPermissionOwner owner)247     private void addWriteOwner(UriPermissionOwner owner) {
248         if (mWriteOwners == null) {
249             mWriteOwners = Sets.newHashSet();
250             ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
251             updateModeFlags();
252         }
253         if (mWriteOwners.add(owner)) {
254             owner.addWritePermission(this);
255         }
256     }
257 
258     /**
259      * Remove given write owner, updating {@Link #modeFlags} as needed.
260      */
removeWriteOwner(UriPermissionOwner owner)261     void removeWriteOwner(UriPermissionOwner owner) {
262         if (!mWriteOwners.remove(owner)) {
263             Log.wtf(TAG, "Unknown write owner " + owner + " in " + this);
264         }
265         if (mWriteOwners.size() == 0) {
266             mWriteOwners = null;
267             ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
268             updateModeFlags();
269         }
270     }
271 
272     @Override
toString()273     public String toString() {
274         if (stringName != null) {
275             return stringName;
276         }
277         StringBuilder sb = new StringBuilder(128);
278         sb.append("UriPermission{");
279         sb.append(Integer.toHexString(System.identityHashCode(this)));
280         sb.append(' ');
281         sb.append(uri);
282         sb.append('}');
283         return stringName = sb.toString();
284     }
285 
dump(PrintWriter pw, String prefix)286     void dump(PrintWriter pw, String prefix) {
287         pw.print(prefix);
288         pw.print("userHandle=" + userHandle);
289         pw.print(" sourcePkg=" + sourcePkg);
290         pw.println(" targetPkg=" + targetPkg);
291 
292         pw.print(prefix);
293         pw.print("mode=0x" + Integer.toHexString(modeFlags));
294         pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags));
295         pw.print(" global=0x" + Integer.toHexString(globalModeFlags));
296         pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags));
297         pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags));
298         if (persistedCreateTime != INVALID_TIME) {
299             pw.print(" persistedCreate=" + persistedCreateTime);
300         }
301         pw.println();
302 
303         if (mReadOwners != null) {
304             pw.print(prefix);
305             pw.println("readOwners:");
306             for (UriPermissionOwner owner : mReadOwners) {
307                 pw.print(prefix);
308                 pw.println("  * " + owner);
309             }
310         }
311         if (mWriteOwners != null) {
312             pw.print(prefix);
313             pw.println("writeOwners:");
314             for (UriPermissionOwner owner : mReadOwners) {
315                 pw.print(prefix);
316                 pw.println("  * " + owner);
317             }
318         }
319     }
320 
321     public static class PersistedTimeComparator implements Comparator<UriPermission> {
322         @Override
compare(UriPermission lhs, UriPermission rhs)323         public int compare(UriPermission lhs, UriPermission rhs) {
324             return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime);
325         }
326     }
327 
328     /**
329      * Snapshot of {@link UriPermission} with frozen
330      * {@link UriPermission#persistedModeFlags} state.
331      */
332     public static class Snapshot {
333         final int userHandle;
334         final String sourcePkg;
335         final String targetPkg;
336         final Uri uri;
337         final int persistedModeFlags;
338         final long persistedCreateTime;
339 
Snapshot(UriPermission perm)340         private Snapshot(UriPermission perm) {
341             this.userHandle = perm.userHandle;
342             this.sourcePkg = perm.sourcePkg;
343             this.targetPkg = perm.targetPkg;
344             this.uri = perm.uri;
345             this.persistedModeFlags = perm.persistedModeFlags;
346             this.persistedCreateTime = perm.persistedCreateTime;
347         }
348     }
349 
snapshot()350     public Snapshot snapshot() {
351         return new Snapshot(this);
352     }
353 
buildPersistedPublicApiObject()354     public android.content.UriPermission buildPersistedPublicApiObject() {
355         return new android.content.UriPermission(uri, persistedModeFlags, persistedCreateTime);
356     }
357 }
358