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.app.GrantedUriPermission; 20 import android.content.Intent; 21 import android.os.Binder; 22 import android.os.UserHandle; 23 import android.util.ArraySet; 24 import android.util.Log; 25 import android.util.Slog; 26 27 import com.android.server.am.ActivityManagerService.GrantUri; 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 private 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 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 98 private void updateModeFlags() { 99 final int oldModeFlags = modeFlags; 100 modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | 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 */ 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 127 void grantModes(int modeFlags, 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 } 149 150 /** 151 * @return if mode changes should trigger persisting. 152 */ 153 boolean takePersistableModes(int modeFlags) { 154 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 155 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 156 157 if ((modeFlags & persistableModeFlags) != modeFlags) { 158 Slog.w(TAG, "Requested flags 0x" 159 + Integer.toHexString(modeFlags) + ", but only 0x" 160 + Integer.toHexString(persistableModeFlags) + " are allowed"); 161 return false; 162 } 163 164 final int before = persistedModeFlags; 165 persistedModeFlags |= (persistableModeFlags & modeFlags); 166 167 if (persistedModeFlags != 0) { 168 persistedCreateTime = System.currentTimeMillis(); 169 } 170 171 updateModeFlags(); 172 return persistedModeFlags != before; 173 } 174 175 boolean releasePersistableModes(int modeFlags) { 176 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 177 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 178 179 final int before = persistedModeFlags; 180 181 persistableModeFlags &= ~modeFlags; 182 persistedModeFlags &= ~modeFlags; 183 184 if (persistedModeFlags == 0) { 185 persistedCreateTime = INVALID_TIME; 186 } 187 188 updateModeFlags(); 189 return persistedModeFlags != before; 190 } 191 192 /** 193 * @return if mode changes should trigger persisting. 194 */ 195 boolean revokeModes(int modeFlags, boolean includingOwners) { 196 final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0; 197 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 198 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 199 200 final int before = persistedModeFlags; 201 202 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { 203 if (persistable) { 204 persistableModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 205 persistedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 206 } 207 globalModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 208 if (mReadOwners != null && includingOwners) { 209 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 210 for (UriPermissionOwner r : mReadOwners) { 211 r.removeReadPermission(this); 212 } 213 mReadOwners = null; 214 } 215 } 216 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 217 if (persistable) { 218 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 219 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 220 } 221 globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 222 if (mWriteOwners != null && includingOwners) { 223 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 224 for (UriPermissionOwner r : mWriteOwners) { 225 r.removeWritePermission(this); 226 } 227 mWriteOwners = null; 228 } 229 } 230 231 if (persistedModeFlags == 0) { 232 persistedCreateTime = INVALID_TIME; 233 } 234 235 updateModeFlags(); 236 return persistedModeFlags != before; 237 } 238 239 /** 240 * Return strength of this permission grant for the given flags. 241 */ 242 public int getStrength(int modeFlags) { 243 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 244 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 245 if ((persistableModeFlags & modeFlags) == modeFlags) { 246 return STRENGTH_PERSISTABLE; 247 } else if ((globalModeFlags & modeFlags) == modeFlags) { 248 return STRENGTH_GLOBAL; 249 } else if ((ownedModeFlags & modeFlags) == modeFlags) { 250 return STRENGTH_OWNED; 251 } else { 252 return STRENGTH_NONE; 253 } 254 } 255 256 private void addReadOwner(UriPermissionOwner owner) { 257 if (mReadOwners == null) { 258 mReadOwners = Sets.newArraySet(); 259 ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION; 260 updateModeFlags(); 261 } 262 if (mReadOwners.add(owner)) { 263 owner.addReadPermission(this); 264 } 265 } 266 267 /** 268 * Remove given read owner, updating {@Link #modeFlags} as needed. 269 */ 270 void removeReadOwner(UriPermissionOwner owner) { 271 if (!mReadOwners.remove(owner)) { 272 Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this); 273 } 274 if (mReadOwners.size() == 0) { 275 mReadOwners = null; 276 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 277 updateModeFlags(); 278 } 279 } 280 281 private void addWriteOwner(UriPermissionOwner owner) { 282 if (mWriteOwners == null) { 283 mWriteOwners = Sets.newArraySet(); 284 ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 285 updateModeFlags(); 286 } 287 if (mWriteOwners.add(owner)) { 288 owner.addWritePermission(this); 289 } 290 } 291 292 /** 293 * Remove given write owner, updating {@Link #modeFlags} as needed. 294 */ 295 void removeWriteOwner(UriPermissionOwner owner) { 296 if (!mWriteOwners.remove(owner)) { 297 Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this); 298 } 299 if (mWriteOwners.size() == 0) { 300 mWriteOwners = null; 301 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 302 updateModeFlags(); 303 } 304 } 305 306 @Override 307 public String toString() { 308 if (stringName != null) { 309 return stringName; 310 } 311 StringBuilder sb = new StringBuilder(128); 312 sb.append("UriPermission{"); 313 sb.append(Integer.toHexString(System.identityHashCode(this))); 314 sb.append(' '); 315 sb.append(uri); 316 sb.append('}'); 317 return stringName = sb.toString(); 318 } 319 320 void dump(PrintWriter pw, String prefix) { 321 pw.print(prefix); 322 pw.print("targetUserId=" + targetUserId); 323 pw.print(" sourcePkg=" + sourcePkg); 324 pw.println(" targetPkg=" + targetPkg); 325 326 pw.print(prefix); 327 pw.print("mode=0x" + Integer.toHexString(modeFlags)); 328 pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags)); 329 pw.print(" global=0x" + Integer.toHexString(globalModeFlags)); 330 pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags)); 331 pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags)); 332 if (persistedCreateTime != INVALID_TIME) { 333 pw.print(" persistedCreate=" + persistedCreateTime); 334 } 335 pw.println(); 336 337 if (mReadOwners != null) { 338 pw.print(prefix); 339 pw.println("readOwners:"); 340 for (UriPermissionOwner owner : mReadOwners) { 341 pw.print(prefix); 342 pw.println(" * " + owner); 343 } 344 } 345 if (mWriteOwners != null) { 346 pw.print(prefix); 347 pw.println("writeOwners:"); 348 for (UriPermissionOwner owner : mReadOwners) { 349 pw.print(prefix); 350 pw.println(" * " + owner); 351 } 352 } 353 } 354 355 public static class PersistedTimeComparator implements Comparator<UriPermission> { 356 @Override 357 public int compare(UriPermission lhs, UriPermission rhs) { 358 return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime); 359 } 360 } 361 362 /** 363 * Snapshot of {@link UriPermission} with frozen 364 * {@link UriPermission#persistedModeFlags} state. 365 */ 366 public static class Snapshot { 367 final int targetUserId; 368 final String sourcePkg; 369 final String targetPkg; 370 final GrantUri uri; 371 final int persistedModeFlags; 372 final long persistedCreateTime; 373 374 private Snapshot(UriPermission perm) { 375 this.targetUserId = perm.targetUserId; 376 this.sourcePkg = perm.sourcePkg; 377 this.targetPkg = perm.targetPkg; 378 this.uri = perm.uri; 379 this.persistedModeFlags = perm.persistedModeFlags; 380 this.persistedCreateTime = perm.persistedCreateTime; 381 } 382 } 383 384 public Snapshot snapshot() { 385 return new Snapshot(this); 386 } 387 388 public android.content.UriPermission buildPersistedPublicApiObject() { 389 return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime); 390 } 391 392 public GrantedUriPermission buildGrantedUriPermission() { 393 return new GrantedUriPermission(uri.uri, targetPkg); 394 } 395 } 396