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