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.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.google.android.collect.Sets; 28 29 import java.io.PrintWriter; 30 import java.util.Comparator; 31 32 /** 33 * Description of a permission granted to an app to access a particular URI. 34 * 35 * CTS tests for this functionality can be run with "runtest cts-appsecurity". 36 * 37 * Test cases are at cts/tests/appsecurity-tests/test-apps/UsePermissionDiffCert/ 38 * src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java 39 */ 40 final class UriPermission { 41 private static final String TAG = "UriPermission"; 42 43 public static final int STRENGTH_NONE = 0; 44 public static final int STRENGTH_OWNED = 1; 45 public static final int STRENGTH_GLOBAL = 2; 46 public static final int STRENGTH_PERSISTABLE = 3; 47 48 final int targetUserId; 49 final String sourcePkg; 50 final String targetPkg; 51 52 /** Cached UID of {@link #targetPkg}; should not be persisted */ 53 final int targetUid; 54 55 final GrantUri uri; 56 57 /** 58 * Allowed modes. All permission enforcement should use this field. Must 59 * always be a combination of {@link #ownedModeFlags}, 60 * {@link #globalModeFlags}, {@link #persistableModeFlags}, and 61 * {@link #persistedModeFlags}. Mutations <em>must</em> only be performed by 62 * the owning class. 63 */ 64 int modeFlags = 0; 65 66 /** Allowed modes with active owner. */ 67 int ownedModeFlags = 0; 68 /** Allowed modes without explicit owner. */ 69 int globalModeFlags = 0; 70 /** Allowed modes that have been offered for possible persisting. */ 71 int persistableModeFlags = 0; 72 73 /** Allowed modes that should be persisted across device boots. */ 74 int persistedModeFlags = 0; 75 76 /** 77 * Timestamp when {@link #persistedModeFlags} was first defined in 78 * {@link System#currentTimeMillis()} time base. 79 */ 80 long persistedCreateTime = INVALID_TIME; 81 82 private static final long INVALID_TIME = Long.MIN_VALUE; 83 84 private ArraySet<UriPermissionOwner> mReadOwners; 85 private ArraySet<UriPermissionOwner> mWriteOwners; 86 87 private String stringName; 88 UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri)89 UriPermission(String sourcePkg, String targetPkg, int targetUid, GrantUri uri) { 90 this.targetUserId = UserHandle.getUserId(targetUid); 91 this.sourcePkg = sourcePkg; 92 this.targetPkg = targetPkg; 93 this.targetUid = targetUid; 94 this.uri = uri; 95 } 96 updateModeFlags()97 private void updateModeFlags() { 98 final int oldModeFlags = modeFlags; 99 modeFlags = ownedModeFlags | globalModeFlags | persistableModeFlags | persistedModeFlags; 100 101 if (Log.isLoggable(TAG, Log.VERBOSE) && (modeFlags != oldModeFlags)) { 102 Slog.d(TAG, 103 "Permission for " + targetPkg + " to " + uri + " is changing from 0x" 104 + Integer.toHexString(oldModeFlags) + " to 0x" 105 + Integer.toHexString(modeFlags) + " via calling UID " 106 + Binder.getCallingUid() + " PID " + Binder.getCallingPid(), 107 new Throwable()); 108 } 109 } 110 111 /** 112 * Initialize persisted modes as read from file. This doesn't issue any 113 * global or owner grants. 114 */ initPersistedModes(int modeFlags, long createdTime)115 void initPersistedModes(int modeFlags, long createdTime) { 116 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 117 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 118 119 persistableModeFlags = modeFlags; 120 persistedModeFlags = modeFlags; 121 persistedCreateTime = createdTime; 122 123 updateModeFlags(); 124 } 125 grantModes(int modeFlags, UriPermissionOwner owner)126 void grantModes(int modeFlags, UriPermissionOwner owner) { 127 final boolean persistable = (modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0; 128 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 129 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 130 131 if (persistable) { 132 persistableModeFlags |= modeFlags; 133 } 134 135 if (owner == null) { 136 globalModeFlags |= modeFlags; 137 } else { 138 if ((modeFlags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) { 139 addReadOwner(owner); 140 } 141 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 142 addWriteOwner(owner); 143 } 144 } 145 146 updateModeFlags(); 147 } 148 149 /** 150 * @return if mode changes should trigger persisting. 151 */ takePersistableModes(int modeFlags)152 boolean takePersistableModes(int modeFlags) { 153 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 154 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 155 156 if ((modeFlags & persistableModeFlags) != modeFlags) { 157 Slog.w(TAG, "Requested flags 0x" 158 + Integer.toHexString(modeFlags) + ", but only 0x" 159 + Integer.toHexString(persistableModeFlags) + " are allowed"); 160 return false; 161 } 162 163 final int before = persistedModeFlags; 164 persistedModeFlags |= (persistableModeFlags & modeFlags); 165 166 if (persistedModeFlags != 0) { 167 persistedCreateTime = System.currentTimeMillis(); 168 } 169 170 updateModeFlags(); 171 return persistedModeFlags != before; 172 } 173 releasePersistableModes(int modeFlags)174 boolean releasePersistableModes(int modeFlags) { 175 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 176 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 177 178 final int before = persistedModeFlags; 179 180 persistableModeFlags &= ~modeFlags; 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 r.removeReadPermission(this); 211 } 212 mReadOwners = null; 213 } 214 } 215 if ((modeFlags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) { 216 if (persistable) { 217 persistableModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 218 persistedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 219 } 220 globalModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 221 if (mWriteOwners != null && includingOwners) { 222 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 223 for (UriPermissionOwner r : mWriteOwners) { 224 r.removeWritePermission(this); 225 } 226 mWriteOwners = null; 227 } 228 } 229 230 if (persistedModeFlags == 0) { 231 persistedCreateTime = INVALID_TIME; 232 } 233 234 updateModeFlags(); 235 return persistedModeFlags != before; 236 } 237 238 /** 239 * Return strength of this permission grant for the given flags. 240 */ getStrength(int modeFlags)241 public int getStrength(int modeFlags) { 242 modeFlags &= (Intent.FLAG_GRANT_READ_URI_PERMISSION 243 | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); 244 if ((persistableModeFlags & modeFlags) == modeFlags) { 245 return STRENGTH_PERSISTABLE; 246 } else if ((globalModeFlags & modeFlags) == modeFlags) { 247 return STRENGTH_GLOBAL; 248 } else if ((ownedModeFlags & modeFlags) == modeFlags) { 249 return STRENGTH_OWNED; 250 } else { 251 return STRENGTH_NONE; 252 } 253 } 254 addReadOwner(UriPermissionOwner owner)255 private void addReadOwner(UriPermissionOwner owner) { 256 if (mReadOwners == null) { 257 mReadOwners = Sets.newArraySet(); 258 ownedModeFlags |= Intent.FLAG_GRANT_READ_URI_PERMISSION; 259 updateModeFlags(); 260 } 261 if (mReadOwners.add(owner)) { 262 owner.addReadPermission(this); 263 } 264 } 265 266 /** 267 * Remove given read owner, updating {@Link #modeFlags} as needed. 268 */ removeReadOwner(UriPermissionOwner owner)269 void removeReadOwner(UriPermissionOwner owner) { 270 if (!mReadOwners.remove(owner)) { 271 Slog.wtf(TAG, "Unknown read owner " + owner + " in " + this); 272 } 273 if (mReadOwners.size() == 0) { 274 mReadOwners = null; 275 ownedModeFlags &= ~Intent.FLAG_GRANT_READ_URI_PERMISSION; 276 updateModeFlags(); 277 } 278 } 279 addWriteOwner(UriPermissionOwner owner)280 private void addWriteOwner(UriPermissionOwner owner) { 281 if (mWriteOwners == null) { 282 mWriteOwners = Sets.newArraySet(); 283 ownedModeFlags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 284 updateModeFlags(); 285 } 286 if (mWriteOwners.add(owner)) { 287 owner.addWritePermission(this); 288 } 289 } 290 291 /** 292 * Remove given write owner, updating {@Link #modeFlags} as needed. 293 */ removeWriteOwner(UriPermissionOwner owner)294 void removeWriteOwner(UriPermissionOwner owner) { 295 if (!mWriteOwners.remove(owner)) { 296 Slog.wtf(TAG, "Unknown write owner " + owner + " in " + this); 297 } 298 if (mWriteOwners.size() == 0) { 299 mWriteOwners = null; 300 ownedModeFlags &= ~Intent.FLAG_GRANT_WRITE_URI_PERMISSION; 301 updateModeFlags(); 302 } 303 } 304 305 @Override toString()306 public String toString() { 307 if (stringName != null) { 308 return stringName; 309 } 310 StringBuilder sb = new StringBuilder(128); 311 sb.append("UriPermission{"); 312 sb.append(Integer.toHexString(System.identityHashCode(this))); 313 sb.append(' '); 314 sb.append(uri); 315 sb.append('}'); 316 return stringName = sb.toString(); 317 } 318 dump(PrintWriter pw, String prefix)319 void dump(PrintWriter pw, String prefix) { 320 pw.print(prefix); 321 pw.print("targetUserId=" + targetUserId); 322 pw.print(" sourcePkg=" + sourcePkg); 323 pw.println(" targetPkg=" + targetPkg); 324 325 pw.print(prefix); 326 pw.print("mode=0x" + Integer.toHexString(modeFlags)); 327 pw.print(" owned=0x" + Integer.toHexString(ownedModeFlags)); 328 pw.print(" global=0x" + Integer.toHexString(globalModeFlags)); 329 pw.print(" persistable=0x" + Integer.toHexString(persistableModeFlags)); 330 pw.print(" persisted=0x" + Integer.toHexString(persistedModeFlags)); 331 if (persistedCreateTime != INVALID_TIME) { 332 pw.print(" persistedCreate=" + persistedCreateTime); 333 } 334 pw.println(); 335 336 if (mReadOwners != null) { 337 pw.print(prefix); 338 pw.println("readOwners:"); 339 for (UriPermissionOwner owner : mReadOwners) { 340 pw.print(prefix); 341 pw.println(" * " + owner); 342 } 343 } 344 if (mWriteOwners != null) { 345 pw.print(prefix); 346 pw.println("writeOwners:"); 347 for (UriPermissionOwner owner : mReadOwners) { 348 pw.print(prefix); 349 pw.println(" * " + owner); 350 } 351 } 352 } 353 354 public static class PersistedTimeComparator implements Comparator<UriPermission> { 355 @Override compare(UriPermission lhs, UriPermission rhs)356 public int compare(UriPermission lhs, UriPermission rhs) { 357 return Long.compare(lhs.persistedCreateTime, rhs.persistedCreateTime); 358 } 359 } 360 361 /** 362 * Snapshot of {@link UriPermission} with frozen 363 * {@link UriPermission#persistedModeFlags} state. 364 */ 365 public static class Snapshot { 366 final int targetUserId; 367 final String sourcePkg; 368 final String targetPkg; 369 final GrantUri uri; 370 final int persistedModeFlags; 371 final long persistedCreateTime; 372 Snapshot(UriPermission perm)373 private Snapshot(UriPermission perm) { 374 this.targetUserId = perm.targetUserId; 375 this.sourcePkg = perm.sourcePkg; 376 this.targetPkg = perm.targetPkg; 377 this.uri = perm.uri; 378 this.persistedModeFlags = perm.persistedModeFlags; 379 this.persistedCreateTime = perm.persistedCreateTime; 380 } 381 } 382 snapshot()383 public Snapshot snapshot() { 384 return new Snapshot(this); 385 } 386 buildPersistedPublicApiObject()387 public android.content.UriPermission buildPersistedPublicApiObject() { 388 return new android.content.UriPermission(uri.uri, persistedModeFlags, persistedCreateTime); 389 } 390 buildGrantedUriPermission()391 public GrantedUriPermission buildGrantedUriPermission() { 392 return new GrantedUriPermission(uri.uri, targetPkg); 393 } 394 } 395