1 /*
2  * Copyright (C) 2020 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 static com.android.server.uri.UriGrantsMockContext.FLAG_PERSISTABLE;
20 import static com.android.server.uri.UriGrantsMockContext.FLAG_PREFIX;
21 import static com.android.server.uri.UriGrantsMockContext.FLAG_READ;
22 import static com.android.server.uri.UriGrantsMockContext.PKG_CAMERA;
23 import static com.android.server.uri.UriGrantsMockContext.PKG_COMPLEX;
24 import static com.android.server.uri.UriGrantsMockContext.PKG_FORCE;
25 import static com.android.server.uri.UriGrantsMockContext.PKG_SOCIAL;
26 import static com.android.server.uri.UriGrantsMockContext.UID_PRIMARY_CAMERA;
27 import static com.android.server.uri.UriGrantsMockContext.UID_PRIMARY_COMPLEX;
28 import static com.android.server.uri.UriGrantsMockContext.UID_PRIMARY_FORCE;
29 import static com.android.server.uri.UriGrantsMockContext.UID_PRIMARY_PRIVATE;
30 import static com.android.server.uri.UriGrantsMockContext.UID_PRIMARY_PUBLIC;
31 import static com.android.server.uri.UriGrantsMockContext.UID_PRIMARY_SOCIAL;
32 import static com.android.server.uri.UriGrantsMockContext.UID_SECONDARY_CAMERA;
33 import static com.android.server.uri.UriGrantsMockContext.UID_SECONDARY_SOCIAL;
34 import static com.android.server.uri.UriGrantsMockContext.URI_FORCE;
35 import static com.android.server.uri.UriGrantsMockContext.URI_PHOTO_1;
36 import static com.android.server.uri.UriGrantsMockContext.URI_PRIVATE;
37 import static com.android.server.uri.UriGrantsMockContext.URI_PUBLIC;
38 import static com.android.server.uri.UriGrantsMockContext.USER_PRIMARY;
39 import static com.android.server.uri.UriGrantsMockContext.USER_SECONDARY;
40 
41 import static org.junit.Assert.assertEquals;
42 import static org.junit.Assert.assertFalse;
43 import static org.junit.Assert.assertNull;
44 import static org.junit.Assert.assertTrue;
45 import static org.junit.Assert.fail;
46 import static org.mockito.ArgumentMatchers.any;
47 import static org.mockito.ArgumentMatchers.anyBoolean;
48 import static org.mockito.ArgumentMatchers.anyInt;
49 import static org.mockito.ArgumentMatchers.eq;
50 import static org.mockito.ArgumentMatchers.isNull;
51 import static org.mockito.Mockito.never;
52 import static org.mockito.Mockito.verify;
53 
54 import android.content.ClipData;
55 import android.content.Intent;
56 import android.content.pm.ProviderInfo;
57 import android.net.Uri;
58 import android.os.Process;
59 import android.os.UserHandle;
60 import android.util.ArraySet;
61 
62 import androidx.test.InstrumentationRegistry;
63 
64 import org.junit.Before;
65 import org.junit.Test;
66 
67 import java.util.Arrays;
68 import java.util.Set;
69 
70 public class UriGrantsManagerServiceTest {
71     private UriGrantsMockContext mContext;
72     private UriGrantsManagerInternal mService;
73 
74     // we expect the following only during grant if a grant is expected
verifyNoVisibilityGrant()75     private void verifyNoVisibilityGrant() {
76         verify(mContext.mPmInternal, never()).grantImplicitAccess(
77                 anyInt(), any(), anyInt(), anyInt(), anyBoolean(), anyBoolean());
78     }
79 
80     @Before
setUp()81     public void setUp() throws Exception {
82         mContext = new UriGrantsMockContext(InstrumentationRegistry.getContext());
83         mService = UriGrantsManagerService.createForTest(mContext.getFilesDir()).getLocalService();
84     }
85 
86     /**
87      * Verify that a camera sharing a normally-private photo with a social media
88      * app in the same user issues a grant.
89      */
90     @Test
testNeeded_normal_sameUser()91     public void testNeeded_normal_sameUser() {
92         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
93         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
94 
95         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
96                 intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
97         assertEquals(PKG_SOCIAL, needed.targetPkg);
98         assertEquals(UID_PRIMARY_SOCIAL, needed.targetUid);
99         assertEquals(FLAG_READ, needed.flags);
100         assertEquals(asSet(expectedGrant), needed.uris);
101         verifyNoVisibilityGrant();
102     }
103 
104     /**
105      * Verify that a camera sharing a normally-private photo with a social media
106      * app in a different user issues a grant.
107      */
108     @Test
testNeeded_normal_differentUser()109     public void testNeeded_normal_differentUser() {
110         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
111         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
112 
113         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
114                 intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
115         assertEquals(PKG_SOCIAL, needed.targetPkg);
116         assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
117         assertEquals(FLAG_READ, needed.flags);
118         assertEquals(asSet(expectedGrant), needed.uris);
119         verifyNoVisibilityGrant();
120     }
121 
122     /**
123      * No need to issue grants for public authorities.
124      */
125     @Test
testNeeded_public()126     public void testNeeded_public() {
127         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PUBLIC).addFlags(FLAG_READ);
128         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
129                 intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_PRIMARY);
130         assertNull(needed);
131         verify(mContext.mPmInternal).grantImplicitAccess(eq(USER_PRIMARY), isNull(), eq(
132                 UserHandle.getAppId(UID_PRIMARY_SOCIAL)), eq(UID_PRIMARY_PUBLIC), eq(false));
133     }
134 
135     /**
136      * But we're willing to issue grants to public authorities when crossing
137      * user boundaries.
138      */
139     @Test
testNeeded_public_differentUser()140     public void testNeeded_public_differentUser() {
141         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PUBLIC).addFlags(FLAG_READ);
142         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PUBLIC, FLAG_READ);
143 
144         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
145                 intent, UID_PRIMARY_PUBLIC, PKG_SOCIAL, USER_SECONDARY);
146         assertEquals(PKG_SOCIAL, needed.targetPkg);
147         assertEquals(UID_SECONDARY_SOCIAL, needed.targetUid);
148         assertEquals(FLAG_READ, needed.flags);
149         assertEquals(asSet(expectedGrant), needed.uris);
150         verifyNoVisibilityGrant();
151     }
152 
153     /**
154      * Refuse to issue grants for private authorities.
155      */
156     @Test
testNeeded_private()157     public void testNeeded_private() {
158         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PRIVATE).addFlags(FLAG_READ);
159         try {
160             mService.checkGrantUriPermissionFromIntent(
161                     intent, UID_PRIMARY_PRIVATE, PKG_SOCIAL, USER_PRIMARY);
162             fail();
163         } catch (SecurityException expected) {
164         }
165     }
166 
167     /**
168      * Verify that {@link ProviderInfo#forceUriPermissions} forces permission
169      * grants, even when receiver already holds permission.
170      */
171     @Test
testNeeded_force()172     public void testNeeded_force() {
173         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_FORCE)
174                 .addFlags(FLAG_READ);
175         final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
176                 intent, UID_PRIMARY_FORCE, PKG_FORCE, USER_PRIMARY);
177         assertEquals(asSet(new GrantUri(USER_PRIMARY, URI_FORCE, 0)), needed.uris);
178     }
179 
180     /**
181      * Verify that we can't grant permissions to top level of a provider with
182      * complex permission model.
183      */
184     @Test
testNeeded_complex_top()185     public void testNeeded_complex_top() {
186         final Uri uri = Uri.parse("content://" + PKG_COMPLEX + "/");
187         {
188             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
189                     .addFlags(FLAG_READ | Intent.FLAG_ACTIVITY_CLEAR_TASK);
190             assertNull(mService.checkGrantUriPermissionFromIntent(
191                     intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY));
192         }
193         {
194             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
195                     .addFlags(FLAG_READ | FLAG_PREFIX);
196             try {
197                 mService.checkGrantUriPermissionFromIntent(
198                         intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
199                 fail();
200             } catch (SecurityException expected) {
201             }
202         }
203         {
204             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
205                     .addFlags(FLAG_READ | FLAG_PERSISTABLE);
206             try {
207                 mService.checkGrantUriPermissionFromIntent(
208                         intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
209                 fail();
210             } catch (SecurityException expected) {
211             }
212         }
213     }
214 
215     /**
216      * Verify that we allow special cross-user grants to top level of a provider
217      * that normally wouldn't allow it. Only basic permission modes are allowed;
218      * advanced modes throw.
219      */
220     @Test
testNeeded_complex_top_differentUser()221     public void testNeeded_complex_top_differentUser() {
222         final Uri uri = Uri.parse("content://" + PKG_COMPLEX + "/");
223         {
224             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
225                     .addFlags(FLAG_READ);
226             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
227                     intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
228             assertEquals(FLAG_READ, needed.flags);
229         }
230         {
231             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
232                     .addFlags(FLAG_READ | FLAG_PREFIX);
233             try {
234                 mService.checkGrantUriPermissionFromIntent(
235                         intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
236                 fail();
237             } catch (SecurityException expected) {
238             }
239         }
240         {
241             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
242                     .addFlags(FLAG_READ | FLAG_PERSISTABLE);
243             try {
244                 mService.checkGrantUriPermissionFromIntent(
245                         intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_SECONDARY);
246                 fail();
247             } catch (SecurityException expected) {
248             }
249         }
250     }
251 
252     /**
253      * Verify that we can grant permissions to middle level of a provider with
254      * complex permission model.
255      */
256     @Test
testNeeded_complex_middle()257     public void testNeeded_complex_middle() {
258         final Uri uri = Uri.parse("content://" + PKG_COMPLEX + "/secure/12");
259         {
260             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
261                     .addFlags(FLAG_READ);
262             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
263                     intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
264             assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
265         }
266         {
267             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
268                     .addFlags(FLAG_READ | FLAG_PREFIX);
269             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
270                     intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
271             assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, FLAG_PREFIX)), needed.uris);
272         }
273         {
274             final Intent intent = new Intent(Intent.ACTION_VIEW, uri)
275                     .addFlags(FLAG_READ | FLAG_PERSISTABLE);
276             final NeededUriGrants needed = mService.checkGrantUriPermissionFromIntent(
277                     intent, UID_PRIMARY_COMPLEX, PKG_SOCIAL, USER_PRIMARY);
278             assertEquals(asSet(new GrantUri(USER_PRIMARY, uri, 0)), needed.uris);
279         }
280     }
281 
282     /**
283      * Verify that when we try sending a list of mixed items that the actual
284      * grants are verified based on the capabilities of the caller.
285      */
286     @Test
testNeeded_mixedPersistable()287     public void testNeeded_mixedPersistable() {
288         final ClipData clip = ClipData.newRawUri("test", URI_PHOTO_1);
289         clip.addItem(new ClipData.Item(URI_PUBLIC));
290 
291         final Intent intent = new Intent(Intent.ACTION_VIEW);
292         intent.addFlags(FLAG_READ | FLAG_PERSISTABLE);
293         intent.setClipData(clip);
294 
295         {
296             // The camera package shouldn't be able to see other packages or their providers,
297             // so make sure the grant only succeeds for the camera's URIs.
298             final NeededUriGrants nug = mService.checkGrantUriPermissionFromIntent(
299                     intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY);
300             if (nug != null && nug.uris != null) {
301                 for (GrantUri gu : nug.uris) {
302                     if (!gu.uri.getAuthority().equals(PKG_CAMERA)) {
303                         fail();
304                     }
305                 }
306             }
307         }
308         {
309             // The camera package shouldn't be able to see other packages or their providers,
310             // so make sure the grant only succeeds for the camera's URIs.
311             final NeededUriGrants nug = mService.checkGrantUriPermissionFromIntent(
312                     intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_SECONDARY);
313             if (nug != null && nug.uris != null) {
314                 for (GrantUri gu : nug.uris) {
315                     if (!gu.uri.getAuthority().equals(PKG_CAMERA)) {
316                         fail();
317                     }
318                 }
319             }
320         }
321     }
322 
323     /**
324      * Verify that two overlapping owners require separate grants and that they
325      * don't interfere with each other.
326      */
327     @Test
testGrant_overlap()328     public void testGrant_overlap() {
329         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
330 
331         final UriPermissionOwner activity = new UriPermissionOwner(mService, "activity");
332         final UriPermissionOwner service = new UriPermissionOwner(mService, "service");
333 
334         final GrantUri expectedGrant = new GrantUri(USER_PRIMARY, URI_PHOTO_1, FLAG_READ);
335 
336         // Grant read via activity and write via service
337         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
338                 intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), activity);
339         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
340                 intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), service);
341 
342         // Verify that everything is good with the world
343         assertTrue(mService.checkUriPermission(expectedGrant, UID_PRIMARY_SOCIAL, FLAG_READ));
344 
345         // Finish activity; service should hold permission
346         activity.removeUriPermissions();
347         assertTrue(mService.checkUriPermission(expectedGrant, UID_PRIMARY_SOCIAL, FLAG_READ));
348 
349         // And finishing service should wrap things up
350         service.removeUriPermissions();
351         assertFalse(mService.checkUriPermission(expectedGrant, UID_PRIMARY_SOCIAL, FLAG_READ));
352     }
353 
354     @Test
testCheckAuthorityGrants()355     public void testCheckAuthorityGrants() {
356         final Intent intent = new Intent(Intent.ACTION_VIEW, URI_PHOTO_1).addFlags(FLAG_READ);
357         final UriPermissionOwner owner = new UriPermissionOwner(mService, "primary");
358 
359         final ProviderInfo cameraInfo = mContext.mPmInternal.resolveContentProvider(
360                 PKG_CAMERA, 0, USER_PRIMARY, Process.SYSTEM_UID);
361 
362         // By default no social can see any camera
363         assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
364                 cameraInfo, USER_PRIMARY, true));
365         assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
366                 cameraInfo, USER_SECONDARY, true));
367         assertFalse(mService.checkAuthorityGrants(UID_SECONDARY_SOCIAL,
368                 cameraInfo, USER_PRIMARY, true));
369         assertFalse(mService.checkAuthorityGrants(UID_SECONDARY_SOCIAL,
370                 cameraInfo, USER_SECONDARY, true));
371 
372         // Granting primary camera to primary social
373         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
374                 intent, UID_PRIMARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
375         assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
376                 cameraInfo, USER_PRIMARY, true));
377         assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
378                 cameraInfo, USER_SECONDARY, true));
379         assertFalse(mService.checkAuthorityGrants(UID_SECONDARY_SOCIAL,
380                 cameraInfo, USER_PRIMARY, true));
381         assertFalse(mService.checkAuthorityGrants(UID_SECONDARY_SOCIAL,
382                 cameraInfo, USER_SECONDARY, true));
383 
384         // Granting secondary camera to primary social
385         mService.grantUriPermissionUncheckedFromIntent(mService.checkGrantUriPermissionFromIntent(
386                 intent, UID_SECONDARY_CAMERA, PKG_SOCIAL, USER_PRIMARY), owner);
387         assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
388                 cameraInfo, USER_PRIMARY, true));
389         assertTrue(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
390                 cameraInfo, USER_SECONDARY, true));
391         assertFalse(mService.checkAuthorityGrants(UID_SECONDARY_SOCIAL,
392                 cameraInfo, USER_PRIMARY, true));
393         assertFalse(mService.checkAuthorityGrants(UID_SECONDARY_SOCIAL,
394                 cameraInfo, USER_SECONDARY, true));
395 
396         // And releasing the grant means we lose access
397         owner.removeUriPermissions();
398         assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
399                 cameraInfo, USER_PRIMARY, true));
400         assertFalse(mService.checkAuthorityGrants(UID_PRIMARY_SOCIAL,
401                 cameraInfo, USER_SECONDARY, true));
402     }
403 
asSet(T... values)404     private static <T> Set<T> asSet(T... values) {
405         return new ArraySet<T>(Arrays.asList(values));
406     }
407 }
408