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