1 /* 2 * Copyright (C) 2018 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.wm; 18 19 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; 20 import static android.Manifest.permission.START_TASKS_FROM_RECENTS; 21 import static android.Manifest.permission.STATUS_BAR_SERVICE; 22 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 23 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 24 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 25 import static android.app.WindowConfiguration.activityTypeToString; 26 import static android.content.pm.PackageManager.PERMISSION_DENIED; 27 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 28 import static android.view.Display.INVALID_DISPLAY; 29 30 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 31 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 32 33 import android.annotation.Nullable; 34 import android.app.ActivityOptions; 35 import android.app.AppGlobals; 36 import android.app.PendingIntent; 37 import android.content.Intent; 38 import android.content.pm.ActivityInfo; 39 import android.content.pm.PackageManager; 40 import android.os.Binder; 41 import android.os.Bundle; 42 import android.os.Process; 43 import android.os.RemoteException; 44 import android.os.UserHandle; 45 import android.util.Slog; 46 import android.view.RemoteAnimationAdapter; 47 import android.window.WindowContainerToken; 48 49 import com.android.internal.annotations.VisibleForTesting; 50 51 /** 52 * Wraps {@link ActivityOptions}, records binder identity, and checks permission when retrieving 53 * the inner options. Also supports having two set of options: Once from the original caller, and 54 * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}. 55 */ 56 public class SafeActivityOptions { 57 58 private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_ATM; 59 60 private final int mOriginalCallingPid; 61 private final int mOriginalCallingUid; 62 private int mRealCallingPid; 63 private int mRealCallingUid; 64 private final @Nullable ActivityOptions mOriginalOptions; 65 private @Nullable ActivityOptions mCallerOptions; 66 67 /** 68 * Constructs a new instance from a bundle and records {@link Binder#getCallingPid}/ 69 * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing 70 * this object. 71 * 72 * @param bOptions The {@link ActivityOptions} as {@link Bundle}. 73 */ fromBundle(Bundle bOptions)74 public static SafeActivityOptions fromBundle(Bundle bOptions) { 75 return bOptions != null 76 ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions)) 77 : null; 78 } 79 80 /** 81 * Constructs a new instance and records {@link Binder#getCallingPid}/ 82 * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when constructing 83 * this object. 84 * 85 * @param options The options to wrap. 86 */ SafeActivityOptions(@ullable ActivityOptions options)87 public SafeActivityOptions(@Nullable ActivityOptions options) { 88 mOriginalCallingPid = Binder.getCallingPid(); 89 mOriginalCallingUid = Binder.getCallingUid(); 90 mOriginalOptions = options; 91 } 92 93 /** 94 * Overrides options with options from a caller and records {@link Binder#getCallingPid}/ 95 * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this 96 * method. 97 */ setCallerOptions(@ullable ActivityOptions options)98 public void setCallerOptions(@Nullable ActivityOptions options) { 99 mRealCallingPid = Binder.getCallingPid(); 100 mRealCallingUid = Binder.getCallingUid(); 101 mCallerOptions = options; 102 } 103 104 /** 105 * Performs permission check and retrieves the options. 106 * 107 * @param r The record of the being started activity. 108 */ getOptions(ActivityRecord r)109 ActivityOptions getOptions(ActivityRecord r) throws SecurityException { 110 return getOptions(r.intent, r.info, r.app, r.mTaskSupervisor); 111 } 112 113 /** 114 * Performs permission check and retrieves the options when options are not being used to launch 115 * a specific activity (i.e. a task is moved to front). 116 */ getOptions(ActivityTaskSupervisor supervisor)117 ActivityOptions getOptions(ActivityTaskSupervisor supervisor) throws SecurityException { 118 return getOptions(null, null, null, supervisor); 119 } 120 121 /** 122 * Performs permission check and retrieves the options. 123 * 124 * @param intent The intent that is being launched. 125 * @param aInfo The info of the activity being launched. 126 * @param callerApp The record of the caller. 127 */ getOptions(@ullable Intent intent, @Nullable ActivityInfo aInfo, @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor)128 ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, 129 @Nullable WindowProcessController callerApp, 130 ActivityTaskSupervisor supervisor) throws SecurityException { 131 if (mOriginalOptions != null) { 132 checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, 133 mOriginalCallingPid, mOriginalCallingUid); 134 setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid, 135 mOriginalCallingUid); 136 } 137 if (mCallerOptions != null) { 138 checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, 139 mRealCallingPid, mRealCallingUid); 140 setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid, 141 mRealCallingUid); 142 } 143 return mergeActivityOptions(mOriginalOptions, mCallerOptions); 144 } 145 setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, int callingPid, int callingUid)146 private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, 147 int callingPid, int callingUid) { 148 final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); 149 if (adapter == null) { 150 return; 151 } 152 if (callingPid == Process.myPid()) { 153 Slog.wtf(TAG, "Safe activity options constructed after clearing calling id"); 154 return; 155 } 156 adapter.setCallingPidUid(callingPid, callingUid); 157 } 158 159 /** 160 * Gets the original options passed in. It should only be used for logging. DO NOT use it as a 161 * condition in the logic of activity launch. 162 */ getOriginalOptions()163 ActivityOptions getOriginalOptions() { 164 return mOriginalOptions; 165 } 166 167 /** 168 * @see ActivityOptions#popAppVerificationBundle 169 */ popAppVerificationBundle()170 Bundle popAppVerificationBundle() { 171 return mOriginalOptions != null ? mOriginalOptions.popAppVerificationBundle() : null; 172 } 173 abort()174 private void abort() { 175 if (mOriginalOptions != null) { 176 ActivityOptions.abort(mOriginalOptions); 177 } 178 if (mCallerOptions != null) { 179 ActivityOptions.abort(mCallerOptions); 180 } 181 } 182 abort(@ullable SafeActivityOptions options)183 static void abort(@Nullable SafeActivityOptions options) { 184 if (options != null) { 185 options.abort(); 186 } 187 } 188 189 /** 190 * Merges two activity options into one, with {@code options2} taking precedence in case of a 191 * conflict. 192 */ 193 @VisibleForTesting mergeActivityOptions(@ullable ActivityOptions options1, @Nullable ActivityOptions options2)194 @Nullable ActivityOptions mergeActivityOptions(@Nullable ActivityOptions options1, 195 @Nullable ActivityOptions options2) { 196 if (options1 == null) { 197 return options2; 198 } 199 if (options2 == null) { 200 return options1; 201 } 202 final Bundle b1 = options1.toBundle(); 203 final Bundle b2 = options2.toBundle(); 204 b1.putAll(b2); 205 return ActivityOptions.fromBundle(b1); 206 } 207 checkPermissions(@ullable Intent intent, @Nullable ActivityInfo aInfo, @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor, ActivityOptions options, int callingPid, int callingUid)208 private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, 209 @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor, 210 ActivityOptions options, int callingPid, int callingUid) { 211 // If a launch task id is specified, then ensure that the caller is the recents 212 // component or has the START_TASKS_FROM_RECENTS permission 213 if (options.getLaunchTaskId() != INVALID_TASK_ID 214 && !supervisor.mRecentTasks.isCallerRecents(callingUid)) { 215 final int startInTaskPerm = ActivityTaskManagerService.checkPermission( 216 START_TASKS_FROM_RECENTS, callingPid, callingUid); 217 if (startInTaskPerm == PERMISSION_DENIED) { 218 final String msg = "Permission Denial: starting " + getIntentString(intent) 219 + " from " + callerApp + " (pid=" + callingPid 220 + ", uid=" + callingUid + ") with launchTaskId=" 221 + options.getLaunchTaskId(); 222 Slog.w(TAG, msg); 223 throw new SecurityException(msg); 224 } 225 } 226 // Check if the caller is allowed to launch on the specified display area. 227 final WindowContainerToken daToken = options.getLaunchTaskDisplayArea(); 228 final TaskDisplayArea taskDisplayArea = daToken != null 229 ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null; 230 if (aInfo != null && taskDisplayArea != null 231 && !supervisor.isCallerAllowedToLaunchOnTaskDisplayArea(callingPid, callingUid, 232 taskDisplayArea, aInfo)) { 233 final String msg = "Permission Denial: starting " + getIntentString(intent) 234 + " from " + callerApp + " (pid=" + callingPid 235 + ", uid=" + callingUid + ") with launchTaskDisplayArea=" + taskDisplayArea; 236 Slog.w(TAG, msg); 237 throw new SecurityException(msg); 238 } 239 // Check if the caller is allowed to launch on the specified display. 240 final int launchDisplayId = options.getLaunchDisplayId(); 241 if (aInfo != null && launchDisplayId != INVALID_DISPLAY 242 && !supervisor.isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, 243 launchDisplayId, aInfo)) { 244 final String msg = "Permission Denial: starting " + getIntentString(intent) 245 + " from " + callerApp + " (pid=" + callingPid 246 + ", uid=" + callingUid + ") with launchDisplayId=" 247 + launchDisplayId; 248 Slog.w(TAG, msg); 249 throw new SecurityException(msg); 250 } 251 // Check if someone tries to launch an unallowlisted activity into LockTask mode. 252 final boolean lockTaskMode = options.getLockTaskMode(); 253 if (aInfo != null && lockTaskMode 254 && !supervisor.mService.getLockTaskController().isPackageAllowlisted( 255 UserHandle.getUserId(callingUid), aInfo.packageName)) { 256 final String msg = "Permission Denial: starting " + getIntentString(intent) 257 + " from " + callerApp + " (pid=" + callingPid 258 + ", uid=" + callingUid + ") with lockTaskMode=true"; 259 Slog.w(TAG, msg); 260 throw new SecurityException(msg); 261 } 262 263 // Check if the caller is allowed to override any app transition animation. 264 final boolean overrideTaskTransition = options.getOverrideTaskTransition(); 265 if (aInfo != null && overrideTaskTransition) { 266 final int startTasksFromRecentsPerm = ActivityTaskManagerService.checkPermission( 267 START_TASKS_FROM_RECENTS, callingPid, callingUid); 268 if (startTasksFromRecentsPerm != PERMISSION_GRANTED) { 269 final String msg = "Permission Denial: starting " + getIntentString(intent) 270 + " from " + callerApp + " (pid=" + callingPid 271 + ", uid=" + callingUid + ") with overrideTaskTransition=true"; 272 Slog.w(TAG, msg); 273 throw new SecurityException(msg); 274 } 275 } 276 277 // Check permission for remote animations 278 final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); 279 if (adapter != null && supervisor.mService.checkPermission( 280 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid) 281 != PERMISSION_GRANTED) { 282 final String msg = "Permission Denial: starting " + getIntentString(intent) 283 + " from " + callerApp + " (pid=" + callingPid 284 + ", uid=" + callingUid + ") with remoteAnimationAdapter"; 285 Slog.w(TAG, msg); 286 throw new SecurityException(msg); 287 } 288 289 // If launched from bubble is specified, then ensure that the caller is system or sysui. 290 if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) { 291 final String msg = "Permission Denial: starting " + getIntentString(intent) 292 + " from " + callerApp + " (pid=" + callingPid 293 + ", uid=" + callingUid + ") with launchedFromBubble=true"; 294 Slog.w(TAG, msg); 295 throw new SecurityException(msg); 296 } 297 298 final int activityType = options.getLaunchActivityType(); 299 if (activityType != ACTIVITY_TYPE_UNDEFINED 300 && !isSystemOrSystemUI(callingPid, callingUid)) { 301 // Granted if it is assistant type and the calling uid is assistant. 302 boolean activityTypeGranted = false; 303 if (activityType == ACTIVITY_TYPE_ASSISTANT 304 && isAssistant(supervisor.mService, callingUid)) { 305 activityTypeGranted = true; 306 } 307 308 if (!activityTypeGranted) { 309 final String msg = "Permission Denial: starting " + getIntentString(intent) 310 + " from " + callerApp + " (pid=" + callingPid 311 + ", uid=" + callingUid + ") with launchActivityType=" 312 + activityTypeToString(options.getLaunchActivityType()); 313 Slog.w(TAG, msg); 314 throw new SecurityException(msg); 315 } 316 } 317 } 318 isAssistant(ActivityTaskManagerService atmService, int callingUid)319 private boolean isAssistant(ActivityTaskManagerService atmService, int callingUid) { 320 if (atmService.mActiveVoiceInteractionServiceComponent == null) { 321 return false; 322 } 323 324 final String assistantPackage = 325 atmService.mActiveVoiceInteractionServiceComponent.getPackageName(); 326 try { 327 final int uid = AppGlobals.getPackageManager().getPackageUid(assistantPackage, 328 PackageManager.MATCH_DIRECT_BOOT_AUTO, 329 UserHandle.getUserId(callingUid)); 330 if (uid == callingUid) { 331 return true; 332 } 333 } catch (RemoteException e) { 334 // Should not happen 335 } 336 return false; 337 } 338 isSystemOrSystemUI(int callingPid, int callingUid)339 private boolean isSystemOrSystemUI(int callingPid, int callingUid) { 340 if (callingUid == Process.SYSTEM_UID) { 341 return true; 342 } 343 344 final int statusBarPerm = ActivityTaskManagerService.checkPermission( 345 STATUS_BAR_SERVICE, callingPid, callingUid); 346 return statusBarPerm == PERMISSION_GRANTED; 347 } 348 getIntentString(Intent intent)349 private String getIntentString(Intent intent) { 350 return intent != null ? intent.toString() : "(no intent)"; 351 } 352 } 353