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