1 /* 2 * Copyright (C) 2009 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.cts.usespermissiondiffcertapp; 18 19 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertContentUriAllowed; 20 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertContentUriNotAllowed; 21 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingContentUriAllowed; 22 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertReadingContentUriNotAllowed; 23 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingContentUriAllowed; 24 import static com.android.cts.usespermissiondiffcertapp.Asserts.assertWritingContentUriNotAllowed; 25 26 import static junit.framework.Assert.assertEquals; 27 28 import android.content.Context; 29 import android.content.Intent; 30 import android.net.Uri; 31 import android.provider.CalendarContract; 32 import android.provider.ContactsContract; 33 34 import androidx.test.InstrumentationRegistry; 35 import androidx.test.runner.AndroidJUnit4; 36 37 import org.junit.Test; 38 import org.junit.runner.RunWith; 39 40 /** 41 * Tests that signature-enforced permissions cannot be accessed by apps signed 42 * with different certs than app that declares the permission. 43 * 44 * Accesses app cts/tests/appsecurity-tests/test-apps/PermissionDeclareApp/... 45 */ 46 @RunWith(AndroidJUnit4.class) 47 public class AccessPermissionWithDiffSigTest { getContext()48 private static Context getContext() { 49 return InstrumentationRegistry.getTargetContext(); 50 } 51 52 static final Uri PERM_URI = Uri.parse("content://ctspermissionwithsignature"); 53 static final Uri PERM_URI_GRANTING = Uri.parse("content://ctspermissionwithsignaturegranting"); 54 static final Uri PERM_URI_PATH = Uri.parse("content://ctspermissionwithsignaturepath"); 55 static final Uri PERM_URI_PATH_RESTRICTING = Uri.parse( 56 "content://ctspermissionwithsignaturepathrestricting"); 57 static final Uri PRIV_URI = Uri.parse("content://ctsprivateprovider"); 58 static final Uri PRIV_URI_GRANTING = Uri.parse("content://ctsprivateprovidergranting"); 59 static final String EXPECTED_MIME_TYPE = "got/theMIME"; 60 61 static final Uri AMBIGUOUS_URI_COMPAT = Uri.parse("content://ctsambiguousprovidercompat"); 62 static final String EXPECTED_MIME_TYPE_AMBIGUOUS = "got/theUnspecifiedMIME"; 63 static final Uri AMBIGUOUS_URI = Uri.parse("content://ctsambiguousprovider"); 64 65 static final Uri[] GRANTABLE = new Uri[] { 66 Uri.withAppendedPath(PERM_URI_GRANTING, "foo"), 67 Uri.withAppendedPath(PERM_URI_PATH, "foo"), 68 Uri.withAppendedPath(PRIV_URI_GRANTING, "foo"), 69 }; 70 71 static final Uri[] NOT_GRANTABLE = new Uri[] { 72 Uri.withAppendedPath(PERM_URI, "bar"), 73 Uri.withAppendedPath(PERM_URI_GRANTING, "bar"), 74 Uri.withAppendedPath(PERM_URI_PATH, "bar"), 75 Uri.withAppendedPath(PRIV_URI, "bar"), 76 Uri.withAppendedPath(PRIV_URI_GRANTING, "bar"), 77 Uri.withAppendedPath(AMBIGUOUS_URI, "bar"), 78 CalendarContract.CONTENT_URI, 79 ContactsContract.AUTHORITY_URI, 80 }; 81 82 static final int[] GRANTABLE_MODES = new int[] { 83 Intent.FLAG_GRANT_READ_URI_PERMISSION, 84 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 85 }; 86 87 static final int[] NOT_GRANTABLE_MODES = new int[] { 88 Intent.FLAG_GRANT_READ_URI_PERMISSION, 89 Intent.FLAG_GRANT_WRITE_URI_PERMISSION, 90 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, 91 Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, 92 Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, 93 Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, 94 }; 95 96 /** 97 * Test that the ctspermissionwithsignature content provider cannot be read, 98 * since this app lacks the required certs 99 */ 100 @Test testReadProviderWithDiff()101 public void testReadProviderWithDiff() { 102 assertReadingContentUriNotAllowed(PERM_URI, null); 103 } 104 105 /** 106 * Test that the ctspermissionwithsignature content provider cannot be written, 107 * since this app lacks the required certs 108 */ 109 @Test testWriteProviderWithDiff()110 public void testWriteProviderWithDiff() { 111 assertWritingContentUriNotAllowed(PERM_URI, null); 112 } 113 114 /** 115 * Test that the ctsprivateprovider content provider cannot be read, 116 * since it is not exported from its app. 117 */ 118 @Test testReadProviderWhenPrivate()119 public void testReadProviderWhenPrivate() { 120 assertReadingContentUriNotAllowed(PRIV_URI, "shouldn't read private provider"); 121 } 122 123 /** 124 * Test that the ctsambiguousprovider content provider cannot be read, 125 * since it doesn't have an "exported=" line. 126 */ 127 @Test testReadProviderWhenAmbiguous()128 public void testReadProviderWhenAmbiguous() { 129 assertReadingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't read ambiguous provider"); 130 } 131 132 /** 133 * Old App Compatibility Test 134 * 135 * Test that the ctsambiguousprovidercompat content provider can be read for older 136 * API versions, because it didn't specify either exported=true or exported=false. 137 */ 138 @Test testReadProviderWhenAmbiguousCompat()139 public void testReadProviderWhenAmbiguousCompat() { 140 assertReadingContentUriAllowed(AMBIGUOUS_URI_COMPAT); 141 } 142 143 /** 144 * Old App Compatibility Test 145 * 146 * Test that the ctsambiguousprovidercompat content provider can be written for older 147 * API versions, because it didn't specify either exported=true or exported=false. 148 */ 149 @Test testWriteProviderWhenAmbiguousCompat()150 public void testWriteProviderWhenAmbiguousCompat() { 151 assertWritingContentUriAllowed(AMBIGUOUS_URI_COMPAT); 152 } 153 154 /** 155 * Test that the ctsprivateprovider content provider cannot be written, 156 * since it is not exported from its app. 157 */ 158 @Test testWriteProviderWhenPrivate()159 public void testWriteProviderWhenPrivate() { 160 assertWritingContentUriNotAllowed(PRIV_URI, "shouldn't write private provider"); 161 } 162 163 /** 164 * Test that the ctsambiguousprovider content provider cannot be written, 165 * since it doesn't have an exported= line. 166 */ 167 @Test testWriteProviderWhenAmbiguous()168 public void testWriteProviderWhenAmbiguous() { 169 assertWritingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't write ambiguous provider"); 170 } 171 172 /** 173 * Verify that we can access paths outside the {@code path-permission} 174 * protections, which should only rely on {@code provider} permissions. 175 */ 176 @Test testRestrictingProviderNoMatchingPath()177 public void testRestrictingProviderNoMatchingPath() { 178 assertReadingContentUriAllowed(PERM_URI_PATH_RESTRICTING); 179 assertWritingContentUriAllowed(PERM_URI_PATH_RESTRICTING); 180 181 // allowed by no top-level permission 182 final Uri test = PERM_URI_PATH_RESTRICTING.buildUpon().appendPath("fo").build(); 183 assertReadingContentUriAllowed(test); 184 assertWritingContentUriAllowed(test); 185 } 186 187 /** 188 * Verify that paths under {@code path-permission} restriction aren't 189 * allowed, even though the {@code provider} requires no permissions. 190 */ 191 @Test testRestrictingProviderMatchingPathDenied()192 public void testRestrictingProviderMatchingPathDenied() { 193 // rejected by "foo" prefix 194 final Uri test1 = PERM_URI_PATH_RESTRICTING.buildUpon().appendPath("foo").build(); 195 assertReadingContentUriNotAllowed(test1, null); 196 assertWritingContentUriNotAllowed(test1, null); 197 198 // rejected by "foo" prefix 199 final Uri test2 = PERM_URI_PATH_RESTRICTING.buildUpon() 200 .appendPath("foo").appendPath("ba").build(); 201 assertReadingContentUriNotAllowed(test2, null); 202 assertWritingContentUriNotAllowed(test2, null); 203 } 204 205 /** 206 * Test that shady {@link Uri} are blocked by {@code path-permission}. 207 */ 208 @Test testRestrictingProviderMatchingShadyPaths()209 public void testRestrictingProviderMatchingShadyPaths() { 210 assertContentUriAllowed( 211 Uri.parse("content://ctspermissionwithsignaturepathrestricting/")); 212 assertContentUriAllowed( 213 Uri.parse("content://ctspermissionwithsignaturepathrestricting//")); 214 assertContentUriAllowed( 215 Uri.parse("content://ctspermissionwithsignaturepathrestricting///")); 216 assertContentUriNotAllowed( 217 Uri.parse("content://ctspermissionwithsignaturepathrestricting/foo"), null); 218 assertContentUriNotAllowed( 219 Uri.parse("content://ctspermissionwithsignaturepathrestricting//foo"), null); 220 assertContentUriNotAllowed( 221 Uri.parse("content://ctspermissionwithsignaturepathrestricting///foo"), null); 222 assertContentUriNotAllowed( 223 Uri.parse("content://ctspermissionwithsignaturepathrestricting/foo//baz"), null); 224 } 225 226 /** 227 * Verify that at least one {@code path-permission} rule will grant access, 228 * even if the caller doesn't hold another matching {@code path-permission}. 229 */ 230 @Test testRestrictingProviderMultipleMatchingPath()231 public void testRestrictingProviderMultipleMatchingPath() { 232 // allowed by narrow "foo/bar" prefix 233 final Uri test1 = PERM_URI_PATH_RESTRICTING.buildUpon() 234 .appendPath("foo").appendPath("bar").build(); 235 assertReadingContentUriAllowed(test1); 236 assertWritingContentUriAllowed(test1); 237 238 // allowed by narrow "foo/bar" prefix 239 final Uri test2 = PERM_URI_PATH_RESTRICTING.buildUpon() 240 .appendPath("foo").appendPath("bar2").build(); 241 assertReadingContentUriAllowed(test2); 242 assertWritingContentUriAllowed(test2); 243 } 244 245 @Test testGetMimeTypePermission()246 public void testGetMimeTypePermission() { 247 // Precondition: no current access. 248 assertReadingContentUriNotAllowed(PERM_URI, "shouldn't read when starting test"); 249 assertWritingContentUriNotAllowed(PERM_URI, "shouldn't write when starting test"); 250 251 // All apps should be able to get MIME type regardless of permission. 252 assertEquals(getContext().getContentResolver().getType(PERM_URI), EXPECTED_MIME_TYPE); 253 } 254 255 @Test testGetMimeTypePrivate()256 public void testGetMimeTypePrivate() { 257 // Precondition: no current access. 258 assertReadingContentUriNotAllowed(PRIV_URI, "shouldn't read when starting test"); 259 assertWritingContentUriNotAllowed(PRIV_URI, "shouldn't write when starting test"); 260 261 // All apps should be able to get MIME type even if provider is private. 262 assertEquals(getContext().getContentResolver().getType(PRIV_URI), EXPECTED_MIME_TYPE); 263 } 264 265 @Test testGetMimeTypeAmbiguous()266 public void testGetMimeTypeAmbiguous() { 267 // Precondition: no current access. 268 assertReadingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't read when starting test"); 269 assertWritingContentUriNotAllowed(AMBIGUOUS_URI, "shouldn't write when starting test"); 270 271 // All apps should be able to get MIME type even if provider is private. 272 assertEquals(getContext().getContentResolver().getType(AMBIGUOUS_URI), EXPECTED_MIME_TYPE); 273 } 274 275 /** 276 * Old App Compatibility Test 277 * 278 * We should be able to access the mime type of a content provider of an older 279 * application, even if that application didn't explicitly declare either 280 * exported=true or exported=false 281 */ 282 @Test testGetMimeTypeAmbiguousCompat()283 public void testGetMimeTypeAmbiguousCompat() { 284 // All apps should be able to get MIME type even if provider is private. 285 assertEquals(EXPECTED_MIME_TYPE_AMBIGUOUS, 286 getContext().getContentResolver().getType(AMBIGUOUS_URI_COMPAT)); 287 } 288 } 289