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