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