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