BasePermission.java revision c842393bc55509b094d3a71f164fcdbadf5c7997
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 17package com.android.server.pm.permission; 18 19import static android.Manifest.permission.READ_EXTERNAL_STORAGE; 20import static android.content.pm.PermissionInfo.PROTECTION_DANGEROUS; 21import static android.content.pm.PermissionInfo.PROTECTION_NORMAL; 22import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE; 23import static android.content.pm.PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM; 24 25import static com.android.server.pm.Settings.ATTR_NAME; 26import static com.android.server.pm.Settings.ATTR_PACKAGE; 27import static com.android.server.pm.Settings.TAG_ITEM; 28 29import android.annotation.IntDef; 30import android.annotation.NonNull; 31import android.annotation.Nullable; 32import android.content.pm.PackageParser; 33import android.content.pm.PackageParser.Permission; 34import android.content.pm.PermissionInfo; 35import android.os.UserHandle; 36import android.util.Log; 37import android.util.Slog; 38 39import com.android.server.pm.DumpState; 40import com.android.server.pm.PackageManagerService; 41import com.android.server.pm.PackageSettingBase; 42 43import org.xmlpull.v1.XmlPullParser; 44import org.xmlpull.v1.XmlSerializer; 45 46import java.io.IOException; 47import java.io.PrintWriter; 48import java.lang.annotation.Retention; 49import java.lang.annotation.RetentionPolicy; 50import java.util.Arrays; 51import java.util.Collection; 52import java.util.Map; 53import java.util.Objects; 54import java.util.Set; 55 56public final class BasePermission { 57 static final String TAG = "PackageManager"; 58 59 public static final int TYPE_NORMAL = 0; 60 public static final int TYPE_BUILTIN = 1; 61 public static final int TYPE_DYNAMIC = 2; 62 @IntDef(value = { 63 TYPE_NORMAL, 64 TYPE_BUILTIN, 65 TYPE_DYNAMIC, 66 }) 67 @Retention(RetentionPolicy.SOURCE) 68 public @interface PermissionType {} 69 70 @IntDef(value = { 71 PROTECTION_DANGEROUS, 72 PROTECTION_NORMAL, 73 PROTECTION_SIGNATURE, 74 PROTECTION_SIGNATURE_OR_SYSTEM, 75 }) 76 @Retention(RetentionPolicy.SOURCE) 77 public @interface ProtectionLevel {} 78 79 final String name; 80 81 final @PermissionType int type; 82 83 String sourcePackageName; 84 85 // TODO: Can we get rid of this? Seems we only use some signature info from the setting 86 PackageSettingBase sourcePackageSetting; 87 88 int protectionLevel; 89 90 PackageParser.Permission perm; 91 92 PermissionInfo pendingPermissionInfo; 93 94 /** UID that owns the definition of this permission */ 95 int uid; 96 97 /** Additional GIDs given to apps granted this permission */ 98 private int[] gids; 99 100 /** 101 * Flag indicating that {@link #gids} should be adjusted based on the 102 * {@link UserHandle} the granted app is running as. 103 */ 104 private boolean perUser; 105 106 public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) { 107 name = _name; 108 sourcePackageName = _sourcePackageName; 109 type = _type; 110 // Default to most conservative protection level. 111 protectionLevel = PermissionInfo.PROTECTION_SIGNATURE; 112 } 113 114 @Override 115 public String toString() { 116 return "BasePermission{" + Integer.toHexString(System.identityHashCode(this)) + " " + name 117 + "}"; 118 } 119 120 public String getName() { 121 return name; 122 } 123 public int getProtectionLevel() { 124 return protectionLevel; 125 } 126 public String getSourcePackageName() { 127 return sourcePackageName; 128 } 129 public PackageSettingBase getSourcePackageSetting() { 130 return sourcePackageSetting; 131 } 132 public int getType() { 133 return type; 134 } 135 public int getUid() { 136 return uid; 137 } 138 public void setGids(int[] gids, boolean perUser) { 139 this.gids = gids; 140 this.perUser = perUser; 141 } 142 public void setPermission(@Nullable Permission perm) { 143 this.perm = perm; 144 } 145 public void setSourcePackageSetting(PackageSettingBase sourcePackageSetting) { 146 this.sourcePackageSetting = sourcePackageSetting; 147 } 148 149 public int[] computeGids(int userId) { 150 if (perUser) { 151 final int[] userGids = new int[gids.length]; 152 for (int i = 0; i < gids.length; i++) { 153 userGids[i] = UserHandle.getUid(userId, gids[i]); 154 } 155 return userGids; 156 } else { 157 return gids; 158 } 159 } 160 161 public int calculateFootprint(BasePermission perm) { 162 if (uid == perm.uid) { 163 return perm.name.length() + perm.perm.info.calculateFootprint(); 164 } 165 return 0; 166 } 167 168 public boolean isPermission(Permission perm) { 169 return this.perm == perm; 170 } 171 172 public boolean isDynamic() { 173 return type == TYPE_DYNAMIC; 174 } 175 176 177 public boolean isNormal() { 178 return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) 179 == PermissionInfo.PROTECTION_NORMAL; 180 } 181 public boolean isRuntime() { 182 return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) 183 == PermissionInfo.PROTECTION_DANGEROUS; 184 } 185 public boolean isSignature() { 186 return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) == 187 PermissionInfo.PROTECTION_SIGNATURE; 188 } 189 190 public boolean isAppOp() { 191 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_APPOP) != 0; 192 } 193 public boolean isDevelopment() { 194 return isSignature() 195 && (protectionLevel & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0; 196 } 197 public boolean isInstaller() { 198 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0; 199 } 200 public boolean isInstant() { 201 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0; 202 } 203 public boolean isOEM() { 204 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_OEM) != 0; 205 } 206 public boolean isPre23() { 207 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRE23) != 0; 208 } 209 public boolean isPreInstalled() { 210 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0; 211 } 212 public boolean isPrivileged() { 213 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0; 214 } 215 public boolean isRuntimeOnly() { 216 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0; 217 } 218 public boolean isSetup() { 219 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_SETUP) != 0; 220 } 221 public boolean isVerifier() { 222 return (protectionLevel & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0; 223 } 224 225 public void transfer(@NonNull String origPackageName, @NonNull String newPackageName) { 226 if (!origPackageName.equals(sourcePackageName)) { 227 return; 228 } 229 sourcePackageName = newPackageName; 230 sourcePackageSetting = null; 231 perm = null; 232 if (pendingPermissionInfo != null) { 233 pendingPermissionInfo.packageName = newPackageName; 234 } 235 uid = 0; 236 setGids(null, false); 237 } 238 239 public boolean addToTree(@ProtectionLevel int protectionLevel, 240 @NonNull PermissionInfo info, @NonNull BasePermission tree) { 241 final boolean changed = 242 (this.protectionLevel != protectionLevel 243 || perm == null 244 || uid != tree.uid 245 || !perm.owner.equals(tree.perm.owner) 246 || !comparePermissionInfos(perm.info, info)); 247 this.protectionLevel = protectionLevel; 248 info = new PermissionInfo(info); 249 info.protectionLevel = protectionLevel; 250 perm = new PackageParser.Permission(tree.perm.owner, info); 251 perm.info.packageName = tree.perm.info.packageName; 252 uid = tree.uid; 253 return changed; 254 } 255 256 public void updateDynamicPermission(Collection<BasePermission> permissionTrees) { 257 if (PackageManagerService.DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" 258 + getName() + " pkg=" + getSourcePackageName() 259 + " info=" + pendingPermissionInfo); 260 if (sourcePackageSetting == null && pendingPermissionInfo != null) { 261 final BasePermission tree = findPermissionTree(permissionTrees, name); 262 if (tree != null && tree.perm != null) { 263 sourcePackageSetting = tree.sourcePackageSetting; 264 perm = new PackageParser.Permission(tree.perm.owner, 265 new PermissionInfo(pendingPermissionInfo)); 266 perm.info.packageName = tree.perm.info.packageName; 267 perm.info.name = name; 268 uid = tree.uid; 269 } 270 } 271 } 272 273 static BasePermission createOrUpdate(@Nullable BasePermission bp, @NonNull Permission p, 274 @NonNull PackageParser.Package pkg, Collection<BasePermission> permissionTrees, 275 boolean chatty) { 276 final PackageSettingBase pkgSetting = (PackageSettingBase) pkg.mExtras; 277 // Allow system apps to redefine non-system permissions 278 if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) { 279 final boolean currentOwnerIsSystem = (bp.perm != null 280 && bp.perm.owner.isSystemApp()); 281 if (p.owner.isSystemApp()) { 282 if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { 283 // It's a built-in permission and no owner, take ownership now 284 bp.sourcePackageSetting = pkgSetting; 285 bp.perm = p; 286 bp.uid = pkg.applicationInfo.uid; 287 bp.sourcePackageName = p.info.packageName; 288 p.info.flags |= PermissionInfo.FLAG_INSTALLED; 289 } else if (!currentOwnerIsSystem) { 290 String msg = "New decl " + p.owner + " of permission " 291 + p.info.name + " is system; overriding " + bp.sourcePackageName; 292 PackageManagerService.reportSettingsProblem(Log.WARN, msg); 293 bp = null; 294 } 295 } 296 } 297 if (bp == null) { 298 bp = new BasePermission(p.info.name, p.info.packageName, TYPE_NORMAL); 299 } 300 StringBuilder r = null; 301 if (bp.perm == null) { 302 if (bp.sourcePackageName == null 303 || bp.sourcePackageName.equals(p.info.packageName)) { 304 final BasePermission tree = findPermissionTree(permissionTrees, p.info.name); 305 if (tree == null 306 || tree.sourcePackageName.equals(p.info.packageName)) { 307 bp.sourcePackageSetting = pkgSetting; 308 bp.perm = p; 309 bp.uid = pkg.applicationInfo.uid; 310 bp.sourcePackageName = p.info.packageName; 311 p.info.flags |= PermissionInfo.FLAG_INSTALLED; 312 if (chatty) { 313 if (r == null) { 314 r = new StringBuilder(256); 315 } else { 316 r.append(' '); 317 } 318 r.append(p.info.name); 319 } 320 } else { 321 Slog.w(TAG, "Permission " + p.info.name + " from package " 322 + p.info.packageName + " ignored: base tree " 323 + tree.name + " is from package " 324 + tree.sourcePackageName); 325 } 326 } else { 327 Slog.w(TAG, "Permission " + p.info.name + " from package " 328 + p.info.packageName + " ignored: original from " 329 + bp.sourcePackageName); 330 } 331 } else if (chatty) { 332 if (r == null) { 333 r = new StringBuilder(256); 334 } else { 335 r.append(' '); 336 } 337 r.append("DUP:"); 338 r.append(p.info.name); 339 } 340 if (bp.perm == p) { 341 bp.protectionLevel = p.info.protectionLevel; 342 } 343 if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) { 344 Log.d(TAG, " Permissions: " + r); 345 } 346 return bp; 347 } 348 349 static BasePermission enforcePermissionTree( 350 Collection<BasePermission> permissionTrees, String permName, int callingUid) { 351 if (permName != null) { 352 BasePermission bp = findPermissionTree(permissionTrees, permName); 353 if (bp != null) { 354 if (bp.uid == UserHandle.getAppId(callingUid)) { 355 return bp; 356 } 357 throw new SecurityException("Calling uid " + callingUid 358 + " is not allowed to add to permission tree " 359 + bp.name + " owned by uid " + bp.uid); 360 } 361 } 362 throw new SecurityException("No permission tree found for " + permName); 363 } 364 365 public void enforceDeclaredUsedAndRuntimeOrDevelopment(PackageParser.Package pkg) { 366 int index = pkg.requestedPermissions.indexOf(name); 367 if (index == -1) { 368 throw new SecurityException("Package " + pkg.packageName 369 + " has not requested permission " + name); 370 } 371 if (!isRuntime() && !isDevelopment()) { 372 throw new SecurityException("Permission " + name 373 + " is not a changeable permission type"); 374 } 375 } 376 377 private static BasePermission findPermissionTree( 378 Collection<BasePermission> permissionTrees, String permName) { 379 for (BasePermission bp : permissionTrees) { 380 if (permName.startsWith(bp.name) && 381 permName.length() > bp.name.length() && 382 permName.charAt(bp.name.length()) == '.') { 383 return bp; 384 } 385 } 386 return null; 387 } 388 389 public @Nullable PermissionInfo generatePermissionInfo(@NonNull String groupName, int flags) { 390 if (groupName == null) { 391 if (perm == null || perm.info.group == null) { 392 return generatePermissionInfo(protectionLevel, flags); 393 } 394 } else { 395 if (perm != null && groupName.equals(perm.info.group)) { 396 return PackageParser.generatePermissionInfo(perm, flags); 397 } 398 } 399 return null; 400 } 401 402 public @NonNull PermissionInfo generatePermissionInfo(int adjustedProtectionLevel, int flags) { 403 final boolean protectionLevelChanged = protectionLevel != adjustedProtectionLevel; 404 // if we return different protection level, don't use the cached info 405 if (perm != null && !protectionLevelChanged) { 406 return PackageParser.generatePermissionInfo(perm, flags); 407 } 408 final PermissionInfo pi = new PermissionInfo(); 409 pi.name = name; 410 pi.packageName = sourcePackageName; 411 pi.nonLocalizedLabel = name; 412 pi.protectionLevel = protectionLevelChanged ? adjustedProtectionLevel : protectionLevel; 413 return pi; 414 } 415 416 public static boolean readLPw(@NonNull Map<String, BasePermission> out, 417 @NonNull XmlPullParser parser) { 418 final String tagName = parser.getName(); 419 if (!tagName.equals(TAG_ITEM)) { 420 return false; 421 } 422 final String name = parser.getAttributeValue(null, ATTR_NAME); 423 final String sourcePackage = parser.getAttributeValue(null, ATTR_PACKAGE); 424 final String ptype = parser.getAttributeValue(null, "type"); 425 if (name == null || sourcePackage == null) { 426 PackageManagerService.reportSettingsProblem(Log.WARN, 427 "Error in package manager settings: permissions has" + " no name at " 428 + parser.getPositionDescription()); 429 return false; 430 } 431 final boolean dynamic = "dynamic".equals(ptype); 432 BasePermission bp = out.get(name); 433 // If the permission is builtin, do not clobber it. 434 if (bp == null || bp.type != TYPE_BUILTIN) { 435 bp = new BasePermission(name.intern(), sourcePackage, 436 dynamic ? TYPE_DYNAMIC : TYPE_NORMAL); 437 } 438 bp.protectionLevel = readInt(parser, null, "protection", 439 PermissionInfo.PROTECTION_NORMAL); 440 bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel); 441 if (dynamic) { 442 final PermissionInfo pi = new PermissionInfo(); 443 pi.packageName = sourcePackage.intern(); 444 pi.name = name.intern(); 445 pi.icon = readInt(parser, null, "icon", 0); 446 pi.nonLocalizedLabel = parser.getAttributeValue(null, "label"); 447 pi.protectionLevel = bp.protectionLevel; 448 bp.pendingPermissionInfo = pi; 449 } 450 out.put(bp.name, bp); 451 return true; 452 } 453 454 private static int readInt(XmlPullParser parser, String ns, String name, int defValue) { 455 String v = parser.getAttributeValue(ns, name); 456 try { 457 if (v == null) { 458 return defValue; 459 } 460 return Integer.parseInt(v); 461 } catch (NumberFormatException e) { 462 PackageManagerService.reportSettingsProblem(Log.WARN, 463 "Error in package manager settings: attribute " + name 464 + " has bad integer value " + v + " at " 465 + parser.getPositionDescription()); 466 } 467 return defValue; 468 } 469 470 public void writeLPr(@NonNull XmlSerializer serializer) throws IOException { 471 if (sourcePackageName == null) { 472 return; 473 } 474 serializer.startTag(null, TAG_ITEM); 475 serializer.attribute(null, ATTR_NAME, name); 476 serializer.attribute(null, ATTR_PACKAGE, sourcePackageName); 477 if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) { 478 serializer.attribute(null, "protection", Integer.toString(protectionLevel)); 479 } 480 if (type == BasePermission.TYPE_DYNAMIC) { 481 final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo; 482 if (pi != null) { 483 serializer.attribute(null, "type", "dynamic"); 484 if (pi.icon != 0) { 485 serializer.attribute(null, "icon", Integer.toString(pi.icon)); 486 } 487 if (pi.nonLocalizedLabel != null) { 488 serializer.attribute(null, "label", pi.nonLocalizedLabel.toString()); 489 } 490 } 491 } 492 serializer.endTag(null, TAG_ITEM); 493 } 494 495 private static boolean compareStrings(CharSequence s1, CharSequence s2) { 496 if (s1 == null) { 497 return s2 == null; 498 } 499 if (s2 == null) { 500 return false; 501 } 502 if (s1.getClass() != s2.getClass()) { 503 return false; 504 } 505 return s1.equals(s2); 506 } 507 508 private static boolean comparePermissionInfos(PermissionInfo pi1, PermissionInfo pi2) { 509 if (pi1.icon != pi2.icon) return false; 510 if (pi1.logo != pi2.logo) return false; 511 if (pi1.protectionLevel != pi2.protectionLevel) return false; 512 if (!compareStrings(pi1.name, pi2.name)) return false; 513 if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false; 514 // We'll take care of setting this one. 515 if (!compareStrings(pi1.packageName, pi2.packageName)) return false; 516 // These are not currently stored in settings. 517 //if (!compareStrings(pi1.group, pi2.group)) return false; 518 //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false; 519 //if (pi1.labelRes != pi2.labelRes) return false; 520 //if (pi1.descriptionRes != pi2.descriptionRes) return false; 521 return true; 522 } 523 524 public boolean dumpPermissionsLPr(@NonNull PrintWriter pw, @NonNull String packageName, 525 @NonNull Set<String> permissionNames, boolean readEnforced, 526 boolean printedSomething, @NonNull DumpState dumpState) { 527 if (packageName != null && !packageName.equals(sourcePackageName)) { 528 return false; 529 } 530 if (permissionNames != null && !permissionNames.contains(name)) { 531 return false; 532 } 533 if (!printedSomething) { 534 if (dumpState.onTitlePrinted()) 535 pw.println(); 536 pw.println("Permissions:"); 537 printedSomething = true; 538 } 539 pw.print(" Permission ["); pw.print(name); pw.print("] ("); 540 pw.print(Integer.toHexString(System.identityHashCode(this))); 541 pw.println("):"); 542 pw.print(" sourcePackage="); pw.println(sourcePackageName); 543 pw.print(" uid="); pw.print(uid); 544 pw.print(" gids="); pw.print(Arrays.toString( 545 computeGids(UserHandle.USER_SYSTEM))); 546 pw.print(" type="); pw.print(type); 547 pw.print(" prot="); 548 pw.println(PermissionInfo.protectionToString(protectionLevel)); 549 if (perm != null) { 550 pw.print(" perm="); pw.println(perm); 551 if ((perm.info.flags & PermissionInfo.FLAG_INSTALLED) == 0 552 || (perm.info.flags & PermissionInfo.FLAG_REMOVED) != 0) { 553 pw.print(" flags=0x"); pw.println(Integer.toHexString(perm.info.flags)); 554 } 555 } 556 if (sourcePackageSetting != null) { 557 pw.print(" packageSetting="); pw.println(sourcePackageSetting); 558 } 559 if (READ_EXTERNAL_STORAGE.equals(name)) { 560 pw.print(" enforced="); 561 pw.println(readEnforced); 562 } 563 return true; 564 } 565} 566