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