1 /* 2 * Copyright (C) 2019 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.om; 18 19 import android.annotation.NonNull; 20 import android.content.om.OverlayInfo; 21 import android.content.om.OverlayableInfo; 22 import android.net.Uri; 23 import android.os.Process; 24 import android.text.TextUtils; 25 import android.util.Pair; 26 import android.util.Slog; 27 28 import com.android.internal.annotations.VisibleForTesting; 29 import com.android.internal.util.ArrayUtils; 30 import com.android.internal.util.CollectionUtils; 31 import com.android.server.pm.parsing.pkg.AndroidPackage; 32 33 import java.io.IOException; 34 import java.util.List; 35 import java.util.Map; 36 37 /** 38 * Performs verification that a calling UID can act on a target package's overlayable. 39 * 40 * Actors requirements are specified in {@link android.content.om.OverlayManager}. 41 * 42 * @hide 43 */ 44 public class OverlayActorEnforcer { 45 46 private final PackageManagerHelper mPackageManager; 47 48 /** 49 * @return nullable actor result with {@link ActorState} failure status 50 */ getPackageNameForActor(@onNull String actorUriString, @NonNull Map<String, Map<String, String>> namedActors)51 static Pair<String, ActorState> getPackageNameForActor(@NonNull String actorUriString, 52 @NonNull Map<String, Map<String, String>> namedActors) { 53 Uri actorUri = Uri.parse(actorUriString); 54 55 String actorScheme = actorUri.getScheme(); 56 List<String> actorPathSegments = actorUri.getPathSegments(); 57 if (!"overlay".equals(actorScheme) || CollectionUtils.size(actorPathSegments) != 1) { 58 return Pair.create(null, ActorState.INVALID_OVERLAYABLE_ACTOR_NAME); 59 } 60 61 if (namedActors.isEmpty()) { 62 return Pair.create(null, ActorState.NO_NAMED_ACTORS); 63 } 64 65 String actorNamespace = actorUri.getAuthority(); 66 Map<String, String> namespace = namedActors.get(actorNamespace); 67 if (ArrayUtils.isEmpty(namespace)) { 68 return Pair.create(null, ActorState.MISSING_NAMESPACE); 69 } 70 71 String actorName = actorPathSegments.get(0); 72 String packageName = namespace.get(actorName); 73 if (TextUtils.isEmpty(packageName)) { 74 return Pair.create(null, ActorState.MISSING_ACTOR_NAME); 75 } 76 77 return Pair.create(packageName, ActorState.ALLOWED); 78 } 79 OverlayActorEnforcer(@onNull PackageManagerHelper packageManager)80 public OverlayActorEnforcer(@NonNull PackageManagerHelper packageManager) { 81 mPackageManager = packageManager; 82 } 83 enforceActor(@onNull OverlayInfo overlayInfo, @NonNull String methodName, int callingUid, int userId)84 void enforceActor(@NonNull OverlayInfo overlayInfo, @NonNull String methodName, 85 int callingUid, int userId) throws SecurityException { 86 final ActorState actorState = isAllowedActor(methodName, overlayInfo, callingUid, userId); 87 if (actorState == ActorState.ALLOWED) { 88 return; 89 } 90 91 final String targetOverlayableName = overlayInfo.targetOverlayableName; 92 final String errorMessage = "UID" + callingUid + " is not allowed to call " + methodName 93 + " for " 94 + (TextUtils.isEmpty(targetOverlayableName) ? "" : (targetOverlayableName + " in ")) 95 + overlayInfo.targetPackageName + " for user " + userId; 96 Slog.w(OverlayManagerService.TAG, errorMessage + " because " + actorState); 97 throw new SecurityException(errorMessage); 98 } 99 100 /** 101 * See {@link OverlayActorEnforcer} class comment for actor requirements. 102 * @return true if the actor is allowed to act on the target overlayInfo 103 */ 104 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) isAllowedActor(String methodName, OverlayInfo overlayInfo, int callingUid, int userId)105 public ActorState isAllowedActor(String methodName, OverlayInfo overlayInfo, 106 int callingUid, int userId) { 107 // Checked first to avoid package not found errors, which are ignored for calls from shell 108 switch (callingUid) { 109 case Process.ROOT_UID: 110 case Process.SYSTEM_UID: 111 return ActorState.ALLOWED; 112 } 113 114 final String targetPackageName = overlayInfo.targetPackageName; 115 final AndroidPackage targetPkgInfo = mPackageManager.getPackageForUser(targetPackageName, 116 userId); 117 if (targetPkgInfo == null) { 118 return ActorState.TARGET_NOT_FOUND; 119 } 120 121 if (targetPkgInfo.isDebuggable()) { 122 return ActorState.ALLOWED; 123 } 124 125 String[] callingPackageNames = mPackageManager.getPackagesForUid(callingUid); 126 if (ArrayUtils.isEmpty(callingPackageNames)) { 127 return ActorState.NO_PACKAGES_FOR_UID; 128 } 129 130 // A target is always an allowed actor for itself 131 if (ArrayUtils.contains(callingPackageNames, targetPackageName)) { 132 return ActorState.ALLOWED; 133 } 134 135 String targetOverlayableName = overlayInfo.targetOverlayableName; 136 137 if (TextUtils.isEmpty(targetOverlayableName)) { 138 try { 139 if (mPackageManager.doesTargetDefineOverlayable(targetPackageName, userId)) { 140 return ActorState.MISSING_TARGET_OVERLAYABLE_NAME; 141 } else { 142 // If there's no overlayable defined, fallback to the legacy permission check 143 try { 144 mPackageManager.enforcePermission( 145 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); 146 147 // If the previous method didn't throw, check passed 148 return ActorState.ALLOWED; 149 } catch (SecurityException e) { 150 return ActorState.MISSING_LEGACY_PERMISSION; 151 } 152 } 153 } catch (IOException e) { 154 return ActorState.ERROR_READING_OVERLAYABLE; 155 } 156 } 157 158 OverlayableInfo targetOverlayable; 159 try { 160 targetOverlayable = mPackageManager.getOverlayableForTarget(targetPackageName, 161 targetOverlayableName, userId); 162 } catch (IOException e) { 163 return ActorState.UNABLE_TO_GET_TARGET_OVERLAYABLE; 164 } 165 166 if (targetOverlayable == null) { 167 return ActorState.MISSING_OVERLAYABLE; 168 } 169 170 String actor = targetOverlayable.actor; 171 if (TextUtils.isEmpty(actor)) { 172 // If there's no actor defined, fallback to the legacy permission check 173 try { 174 mPackageManager.enforcePermission( 175 android.Manifest.permission.CHANGE_OVERLAY_PACKAGES, methodName); 176 177 // If the previous method didn't throw, check passed 178 return ActorState.ALLOWED; 179 } catch (SecurityException e) { 180 return ActorState.MISSING_LEGACY_PERMISSION; 181 } 182 } 183 184 Map<String, Map<String, String>> namedActors = mPackageManager.getNamedActors(); 185 Pair<String, ActorState> actorUriPair = getPackageNameForActor(actor, namedActors); 186 ActorState actorUriState = actorUriPair.second; 187 if (actorUriState != ActorState.ALLOWED) { 188 return actorUriState; 189 } 190 191 String actorPackageName = actorUriPair.first; 192 AndroidPackage actorPackage = mPackageManager.getPackageForUser(actorPackageName, userId); 193 if (actorPackage == null) { 194 return ActorState.ACTOR_NOT_FOUND; 195 } 196 197 // Currently only pre-installed apps can be actors 198 if (!actorPackage.isSystem()) { 199 return ActorState.ACTOR_NOT_PREINSTALLED; 200 } 201 202 if (ArrayUtils.contains(callingPackageNames, actorPackageName)) { 203 return ActorState.ALLOWED; 204 } 205 206 return ActorState.INVALID_ACTOR; 207 } 208 209 /** 210 * For easier logging/debugging, a set of all possible failure/success states when running 211 * enforcement. 212 * 213 * The ordering of this enum should be maintained in the order that cases are checked in code, 214 * as this ordering is used inside OverlayActorEnforcerTests. 215 */ 216 public enum ActorState { 217 TARGET_NOT_FOUND, 218 NO_PACKAGES_FOR_UID, 219 MISSING_TARGET_OVERLAYABLE_NAME, 220 MISSING_LEGACY_PERMISSION, 221 ERROR_READING_OVERLAYABLE, 222 UNABLE_TO_GET_TARGET_OVERLAYABLE, 223 MISSING_OVERLAYABLE, 224 INVALID_OVERLAYABLE_ACTOR_NAME, 225 NO_NAMED_ACTORS, 226 MISSING_NAMESPACE, 227 MISSING_ACTOR_NAME, 228 ACTOR_NOT_FOUND, 229 ACTOR_NOT_PREINSTALLED, 230 INVALID_ACTOR, 231 ALLOWED 232 } 233 } 234