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_KEYGUARD; 20 import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS; 21 import static android.Manifest.permission.MANAGE_ACTIVITY_TASKS; 22 import static android.Manifest.permission.START_TASKS_FROM_RECENTS; 23 import static android.Manifest.permission.STATUS_BAR_SERVICE; 24 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 25 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT; 26 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; 27 import static android.app.WindowConfiguration.activityTypeToString; 28 import static android.content.pm.PackageManager.PERMISSION_DENIED; 29 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 30 import static android.view.Display.DEFAULT_DISPLAY; 31 import static android.view.Display.INVALID_DISPLAY; 32 import static android.window.DisplayAreaOrganizer.FEATURE_UNDEFINED; 33 34 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM; 35 import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME; 36 37 import android.annotation.Nullable; 38 import android.app.ActivityOptions; 39 import android.app.AppGlobals; 40 import android.app.PendingIntent; 41 import android.content.Intent; 42 import android.content.pm.ActivityInfo; 43 import android.content.pm.PackageManager; 44 import android.os.Binder; 45 import android.os.Bundle; 46 import android.os.Process; 47 import android.os.RemoteException; 48 import android.os.UserHandle; 49 import android.util.Slog; 50 import android.view.RemoteAnimationAdapter; 51 import android.window.RemoteTransition; 52 import android.window.WindowContainerToken; 53 54 import com.android.internal.annotations.VisibleForTesting; 55 56 /** 57 * Wraps {@link ActivityOptions}, records binder identity, and checks permission when retrieving 58 * the inner options. Also supports having two set of options: Once from the original caller, and 59 * once from the caller that is overriding it, which happens when sending a {@link PendingIntent}. 60 */ 61 public class SafeActivityOptions { 62 63 private static final String TAG = TAG_WITH_CLASS_NAME ? "SafeActivityOptions" : TAG_ATM; 64 65 private final int mOriginalCallingPid; 66 private final int mOriginalCallingUid; 67 private int mRealCallingPid; 68 private int mRealCallingUid; 69 private final @Nullable ActivityOptions mOriginalOptions; 70 private @Nullable ActivityOptions mCallerOptions; 71 72 /** 73 * Constructs a new instance from a bundle and provided pid/uid. 74 * 75 * @param bOptions The {@link ActivityOptions} as {@link Bundle}. 76 */ fromBundle(Bundle bOptions, int callingPid, int callingUid)77 static SafeActivityOptions fromBundle(Bundle bOptions, int callingPid, int callingUid) { 78 return bOptions != null 79 ? new SafeActivityOptions(ActivityOptions.fromBundle(bOptions), 80 callingPid, callingUid) 81 : null; 82 } 83 84 /** 85 * Constructs a new instance. 86 * 87 * @param options The options to wrap. 88 */ SafeActivityOptions(@ullable ActivityOptions options, int callingPid, int callingUid)89 public SafeActivityOptions(@Nullable ActivityOptions options, int callingPid, int callingUid) { 90 mOriginalCallingPid = callingPid; 91 mOriginalCallingUid = callingUid; 92 mOriginalOptions = options; 93 } 94 95 /** 96 * To ensure that two activities, one using this object, and the other using the 97 * SafeActivityOptions returned from this function, are launched into the same display/root task 98 * through ActivityStartController#startActivities, all display-related information, i.e. 99 * displayAreaToken, launchDisplayId, callerDisplayId and the launch root task are cloned. 100 */ selectiveCloneLaunchOptions()101 @Nullable SafeActivityOptions selectiveCloneLaunchOptions() { 102 final ActivityOptions options = cloneLaunchingOptions(mOriginalOptions); 103 final ActivityOptions callerOptions = cloneLaunchingOptions(mCallerOptions); 104 if (options == null && callerOptions == null) { 105 return null; 106 } 107 108 final SafeActivityOptions safeOptions = new SafeActivityOptions(options, 109 mOriginalCallingPid, mOriginalCallingUid); 110 safeOptions.mCallerOptions = callerOptions; 111 safeOptions.mRealCallingPid = mRealCallingPid; 112 safeOptions.mRealCallingUid = mRealCallingUid; 113 return safeOptions; 114 } 115 cloneLaunchingOptions(ActivityOptions options)116 private ActivityOptions cloneLaunchingOptions(ActivityOptions options) { 117 if (options == null) return null; 118 119 final ActivityOptions cloneOptions = ActivityOptions.makeBasic() 120 .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea()) 121 .setLaunchDisplayId(options.getLaunchDisplayId()) 122 .setCallerDisplayId(options.getCallerDisplayId()) 123 .setLaunchRootTask(options.getLaunchRootTask()) 124 .setPendingIntentBackgroundActivityStartMode( 125 options.getPendingIntentBackgroundActivityStartMode()) 126 .setPendingIntentCreatorBackgroundActivityStartMode( 127 options.getPendingIntentCreatorBackgroundActivityStartMode()) 128 .setRemoteTransition(options.getRemoteTransition()); 129 cloneOptions.setLaunchWindowingMode(options.getLaunchWindowingMode()); 130 return cloneOptions; 131 } 132 133 /** 134 * Overrides options with options from a caller and records {@link Binder#getCallingPid}/ 135 * {@link Binder#getCallingUid}. 136 */ setCallerOptions(@ullable ActivityOptions options, int callingPid, int callingUid)137 public void setCallerOptions(@Nullable ActivityOptions options, int callingPid, 138 int callingUid) { 139 mRealCallingPid = callingPid; 140 mRealCallingUid = callingUid; 141 mCallerOptions = options; 142 } 143 144 /** 145 * Performs permission check and retrieves the options. 146 * 147 * @param r The record of the being started activity. 148 */ getOptions(ActivityRecord r)149 ActivityOptions getOptions(ActivityRecord r) throws SecurityException { 150 return getOptions(r.intent, r.info, r.app, r.mTaskSupervisor); 151 } 152 153 /** 154 * Performs permission check and retrieves the options when options are not being used to launch 155 * a specific activity (i.e. a task is moved to front). 156 */ getOptions(ActivityTaskSupervisor supervisor)157 ActivityOptions getOptions(ActivityTaskSupervisor supervisor) throws SecurityException { 158 return getOptions(null, null, null, supervisor); 159 } 160 161 /** 162 * Performs permission check and retrieves the options. 163 * 164 * @param intent The intent that is being launched. 165 * @param aInfo The info of the activity being launched. 166 * @param callerApp The record of the caller. 167 */ getOptions(@ullable Intent intent, @Nullable ActivityInfo aInfo, @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor)168 ActivityOptions getOptions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, 169 @Nullable WindowProcessController callerApp, 170 ActivityTaskSupervisor supervisor) throws SecurityException { 171 if (mOriginalOptions != null) { 172 checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, 173 mOriginalCallingPid, mOriginalCallingUid); 174 setCallingPidUidForRemoteAnimationAdapter(mOriginalOptions, mOriginalCallingPid, 175 mOriginalCallingUid); 176 } 177 if (mCallerOptions != null) { 178 checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, 179 mRealCallingPid, mRealCallingUid); 180 setCallingPidUidForRemoteAnimationAdapter(mCallerOptions, mRealCallingPid, 181 mRealCallingUid); 182 } 183 return mergeActivityOptions(mOriginalOptions, mCallerOptions); 184 } 185 setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, int callingPid, int callingUid)186 private void setCallingPidUidForRemoteAnimationAdapter(ActivityOptions options, 187 int callingPid, int callingUid) { 188 final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); 189 if (adapter == null) { 190 return; 191 } 192 if (callingPid == WindowManagerService.MY_PID) { 193 Slog.wtf(TAG, "Safe activity options constructed after clearing calling id"); 194 return; 195 } 196 adapter.setCallingPidUid(callingPid, callingUid); 197 } 198 199 /** 200 * Gets the original options passed in. It should only be used for logging. DO NOT use it as a 201 * condition in the logic of activity launch. 202 */ getOriginalOptions()203 ActivityOptions getOriginalOptions() { 204 return mOriginalOptions; 205 } 206 207 /** 208 * @see ActivityOptions#popAppVerificationBundle 209 */ popAppVerificationBundle()210 Bundle popAppVerificationBundle() { 211 return mOriginalOptions != null ? mOriginalOptions.popAppVerificationBundle() : null; 212 } 213 abort()214 private void abort() { 215 if (mOriginalOptions != null) { 216 ActivityOptions.abort(mOriginalOptions); 217 } 218 if (mCallerOptions != null) { 219 ActivityOptions.abort(mCallerOptions); 220 } 221 } 222 abort(@ullable SafeActivityOptions options)223 static void abort(@Nullable SafeActivityOptions options) { 224 if (options != null) { 225 options.abort(); 226 } 227 } 228 229 /** 230 * Merges two activity options into one, with {@code options2} taking precedence in case of a 231 * conflict. 232 */ 233 @VisibleForTesting mergeActivityOptions(@ullable ActivityOptions options1, @Nullable ActivityOptions options2)234 @Nullable ActivityOptions mergeActivityOptions(@Nullable ActivityOptions options1, 235 @Nullable ActivityOptions options2) { 236 if (options1 == null) { 237 return options2; 238 } 239 if (options2 == null) { 240 return options1; 241 } 242 final Bundle b1 = options1.toBundle(); 243 final Bundle b2 = options2.toBundle(); 244 b1.putAll(b2); 245 return ActivityOptions.fromBundle(b1); 246 } 247 checkPermissions(@ullable Intent intent, @Nullable ActivityInfo aInfo, @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor, ActivityOptions options, int callingPid, int callingUid)248 private void checkPermissions(@Nullable Intent intent, @Nullable ActivityInfo aInfo, 249 @Nullable WindowProcessController callerApp, ActivityTaskSupervisor supervisor, 250 ActivityOptions options, int callingPid, int callingUid) { 251 // If a launch task id is specified, then ensure that the caller is the recents 252 // component or has the START_TASKS_FROM_RECENTS permission 253 if ((options.getLaunchTaskId() != INVALID_TASK_ID || options.getDisableStartingWindow()) 254 && !supervisor.mRecentTasks.isCallerRecents(callingUid)) { 255 final int startInTaskPerm = ActivityTaskManagerService.checkPermission( 256 START_TASKS_FROM_RECENTS, callingPid, callingUid); 257 if (startInTaskPerm == PERMISSION_DENIED) { 258 final String msg = "Permission Denial: starting " + getIntentString(intent) 259 + " from " + callerApp + " (pid=" + callingPid 260 + ", uid=" + callingUid + ") with launchTaskId=" 261 + options.getLaunchTaskId(); 262 Slog.w(TAG, msg); 263 throw new SecurityException(msg); 264 } 265 } 266 if (options.getTransientLaunch() && !supervisor.mRecentTasks.isCallerRecents(callingUid) 267 && ActivityTaskManagerService.checkPermission( 268 MANAGE_ACTIVITY_TASKS, callingPid, callingUid) == PERMISSION_DENIED) { 269 final String msg = "Permission Denial: starting transient launch from " + callerApp 270 + ", pid=" + callingPid + ", uid=" + callingUid; 271 Slog.w(TAG, msg); 272 throw new SecurityException(msg); 273 } 274 // Check if the caller is allowed to launch on the specified display area. 275 final TaskDisplayArea taskDisplayArea = getLaunchTaskDisplayArea(options, supervisor); 276 if (aInfo != null && taskDisplayArea != null 277 && !supervisor.isCallerAllowedToLaunchOnTaskDisplayArea(callingPid, callingUid, 278 taskDisplayArea, aInfo)) { 279 final String msg = "Permission Denial: starting " + getIntentString(intent) 280 + " from " + callerApp + " (pid=" + callingPid 281 + ", uid=" + callingUid + ") with launchTaskDisplayArea=" + taskDisplayArea; 282 Slog.w(TAG, msg); 283 throw new SecurityException(msg); 284 } 285 // Check if the caller is allowed to launch on the specified display. 286 final int launchDisplayId = options.getLaunchDisplayId(); 287 if (aInfo != null && launchDisplayId != INVALID_DISPLAY 288 && !supervisor.isCallerAllowedToLaunchOnDisplay(callingPid, callingUid, 289 launchDisplayId, aInfo)) { 290 final String msg = "Permission Denial: starting " + getIntentString(intent) 291 + " from " + callerApp + " (pid=" + callingPid 292 + ", uid=" + callingUid + ") with launchDisplayId=" 293 + launchDisplayId; 294 Slog.w(TAG, msg); 295 throw new SecurityException(msg); 296 } 297 // Check if someone tries to launch an unallowlisted activity into LockTask mode. 298 final boolean lockTaskMode = options.getLockTaskMode(); 299 if (aInfo != null && lockTaskMode 300 && !supervisor.mService.getLockTaskController().isPackageAllowlisted( 301 UserHandle.getUserId(callingUid), aInfo.packageName)) { 302 final String msg = "Permission Denial: starting " + getIntentString(intent) 303 + " from " + callerApp + " (pid=" + callingPid 304 + ", uid=" + callingUid + ") with lockTaskMode=true"; 305 Slog.w(TAG, msg); 306 throw new SecurityException(msg); 307 } 308 309 // Check if the caller is allowed to override any app transition animation. 310 final boolean overrideTaskTransition = options.getOverrideTaskTransition(); 311 if (aInfo != null && overrideTaskTransition) { 312 final int startTasksFromRecentsPerm = ActivityTaskManagerService.checkPermission( 313 START_TASKS_FROM_RECENTS, callingPid, callingUid); 314 // Allow if calling uid is from assistant, or start task from recents 315 if (startTasksFromRecentsPerm != PERMISSION_GRANTED 316 && !isAssistant(supervisor.mService, callingUid)) { 317 final String msg = "Permission Denial: starting " + getIntentString(intent) 318 + " from " + callerApp + " (pid=" + callingPid 319 + ", uid=" + callingUid + ") with overrideTaskTransition=true"; 320 Slog.w(TAG, msg); 321 throw new SecurityException(msg); 322 } 323 } 324 325 // Check if the caller is allowed to dismiss keyguard. 326 final boolean dismissKeyguardIfInsecure = options.getDismissKeyguardIfInsecure(); 327 if (aInfo != null && dismissKeyguardIfInsecure) { 328 final int controlKeyguardPerm = ActivityTaskManagerService.checkPermission( 329 CONTROL_KEYGUARD, callingPid, callingUid); 330 if (controlKeyguardPerm != PERMISSION_GRANTED) { 331 final String msg = "Permission Denial: starting " + getIntentString(intent) 332 + " from " + callerApp + " (pid=" + callingPid 333 + ", uid=" + callingUid + ") with dismissKeyguardIfInsecure=true"; 334 Slog.w(TAG, msg); 335 throw new SecurityException(msg); 336 } 337 } 338 339 // Check permission for remote animations 340 final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter(); 341 if (adapter != null && supervisor.mService.checkPermission( 342 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid) 343 != PERMISSION_GRANTED) { 344 final String msg = "Permission Denial: starting " + getIntentString(intent) 345 + " from " + callerApp + " (pid=" + callingPid 346 + ", uid=" + callingUid + ") with remoteAnimationAdapter"; 347 Slog.w(TAG, msg); 348 throw new SecurityException(msg); 349 } 350 351 // Check permission for remote transitions 352 final RemoteTransition transition = options.getRemoteTransition(); 353 if (transition != null && supervisor.mService.checkPermission( 354 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid) 355 != PERMISSION_GRANTED) { 356 final String msg = "Permission Denial: starting " + getIntentString(intent) 357 + " from " + callerApp + " (pid=" + callingPid 358 + ", uid=" + callingUid + ") with remoteTransition"; 359 Slog.w(TAG, msg); 360 throw new SecurityException(msg); 361 } 362 363 // If launched from bubble is specified, then ensure that the caller is system or sysui. 364 if ((options.getLaunchedFromBubble() || options.getTaskAlwaysOnTop()) 365 && !isSystemOrSystemUI(callingPid, callingUid)) { 366 final String msg = "Permission Denial: starting " + getIntentString(intent) 367 + " from " + callerApp + " (pid=" + callingPid 368 + ", uid=" + callingUid + ") with" 369 + (options.getLaunchedFromBubble() ? " launchedFromBubble=true" : "") 370 + (options.getTaskAlwaysOnTop() ? " taskAlwaysOnTop=true" : ""); 371 Slog.w(TAG, msg); 372 throw new SecurityException(msg); 373 } 374 375 final int activityType = options.getLaunchActivityType(); 376 if (activityType != ACTIVITY_TYPE_UNDEFINED 377 && !isSystemOrSystemUI(callingPid, callingUid)) { 378 // Granted if it is assistant type and the calling uid is assistant. 379 boolean activityTypeGranted = false; 380 if (activityType == ACTIVITY_TYPE_ASSISTANT 381 && isAssistant(supervisor.mService, callingUid)) { 382 activityTypeGranted = true; 383 } 384 385 if (!activityTypeGranted) { 386 final String msg = "Permission Denial: starting " + getIntentString(intent) 387 + " from " + callerApp + " (pid=" + callingPid 388 + ", uid=" + callingUid + ") with launchActivityType=" 389 + activityTypeToString(options.getLaunchActivityType()); 390 Slog.w(TAG, msg); 391 throw new SecurityException(msg); 392 } 393 } 394 } 395 396 @VisibleForTesting getLaunchTaskDisplayArea(ActivityOptions options, ActivityTaskSupervisor supervisor)397 TaskDisplayArea getLaunchTaskDisplayArea(ActivityOptions options, 398 ActivityTaskSupervisor supervisor) { 399 final WindowContainerToken daToken = options.getLaunchTaskDisplayArea(); 400 TaskDisplayArea taskDisplayArea = daToken != null 401 ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null; 402 if (taskDisplayArea != null) { 403 return taskDisplayArea; 404 } 405 406 // If we do not have a task display area token, check if the launch task display area 407 // feature id is specified. 408 final int launchTaskDisplayAreaFeatureId = options.getLaunchTaskDisplayAreaFeatureId(); 409 if (launchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) { 410 final int launchDisplayId = options.getLaunchDisplayId() == INVALID_DISPLAY 411 ? DEFAULT_DISPLAY : options.getLaunchDisplayId(); 412 final DisplayContent dc = supervisor.mRootWindowContainer 413 .getDisplayContent(launchDisplayId); 414 if (dc != null) { 415 taskDisplayArea = dc.getItemFromTaskDisplayAreas(tda -> 416 tda.mFeatureId == launchTaskDisplayAreaFeatureId ? tda : null); 417 } 418 } 419 return taskDisplayArea; 420 } 421 422 /** 423 * Returns whether the given UID caller is the assistant. 424 */ isAssistant(ActivityTaskManagerService atmService, int callingUid)425 public static boolean isAssistant(ActivityTaskManagerService atmService, int callingUid) { 426 if (atmService.mActiveVoiceInteractionServiceComponent == null) { 427 return false; 428 } 429 430 final String assistantPackage = 431 atmService.mActiveVoiceInteractionServiceComponent.getPackageName(); 432 try { 433 final int uid = AppGlobals.getPackageManager().getPackageUid(assistantPackage, 434 PackageManager.MATCH_DIRECT_BOOT_AUTO, 435 UserHandle.getUserId(callingUid)); 436 if (uid == callingUid) { 437 return true; 438 } 439 } catch (RemoteException e) { 440 // Should not happen 441 } 442 return false; 443 } 444 isSystemOrSystemUI(int callingPid, int callingUid)445 private boolean isSystemOrSystemUI(int callingPid, int callingUid) { 446 if (callingUid == Process.SYSTEM_UID) { 447 return true; 448 } 449 450 final int statusBarPerm = ActivityTaskManagerService.checkPermission( 451 STATUS_BAR_SERVICE, callingPid, callingUid); 452 return statusBarPerm == PERMISSION_GRANTED; 453 } 454 getIntentString(Intent intent)455 private String getIntentString(Intent intent) { 456 return intent != null ? intent.toString() : "(no intent)"; 457 } 458 } 459