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 WindowContainerToken daToken = options.getLaunchTaskDisplayArea();
298         TaskDisplayArea taskDisplayArea = daToken != null
299                 ? (TaskDisplayArea) WindowContainer.fromBinder(daToken.asBinder()) : null;
300 
301         // If we do not have a task display area token, check if the launch task display area
302         // feature id is specified.
303         if (taskDisplayArea == null) {
304             final int launchTaskDisplayAreaFeatureId = options.getLaunchTaskDisplayAreaFeatureId();
305             if (launchTaskDisplayAreaFeatureId != FEATURE_UNDEFINED) {
306                 final int launchDisplayId = options.getLaunchDisplayId() == INVALID_DISPLAY
307                         ? DEFAULT_DISPLAY : options.getLaunchDisplayId();
308                 final DisplayContent dc = supervisor.mRootWindowContainer
309                         .getDisplayContent(launchDisplayId);
310                 if (dc != null) {
311                     taskDisplayArea = dc.getItemFromTaskDisplayAreas(tda ->
312                             tda.mFeatureId == launchTaskDisplayAreaFeatureId ? tda : null);
313                 }
314             }
315         }
316 
317         if (aInfo != null && taskDisplayArea != null
318                 && !supervisor.isCallerAllowedToLaunchOnTaskDisplayArea(callingPid, callingUid,
319                 taskDisplayArea, aInfo)) {
320             final String msg = "Permission Denial: starting " + getIntentString(intent)
321                     + " from " + callerApp + " (pid=" + callingPid
322                     + ", uid=" + callingUid + ") with launchTaskDisplayArea=" + taskDisplayArea;
323             Slog.w(TAG, msg);
324             throw new SecurityException(msg);
325         }
326         // Check if the caller is allowed to launch on the specified display.
327         final int launchDisplayId = options.getLaunchDisplayId();
328         if (aInfo != null && launchDisplayId != INVALID_DISPLAY
329                 && !supervisor.isCallerAllowedToLaunchOnDisplay(callingPid, callingUid,
330                         launchDisplayId, aInfo)) {
331             final String msg = "Permission Denial: starting " + getIntentString(intent)
332                     + " from " + callerApp + " (pid=" + callingPid
333                     + ", uid=" + callingUid + ") with launchDisplayId="
334                     + launchDisplayId;
335             Slog.w(TAG, msg);
336             throw new SecurityException(msg);
337         }
338         // Check if someone tries to launch an unallowlisted activity into LockTask mode.
339         final boolean lockTaskMode = options.getLockTaskMode();
340         if (aInfo != null && lockTaskMode
341                 && !supervisor.mService.getLockTaskController().isPackageAllowlisted(
342                         UserHandle.getUserId(callingUid), aInfo.packageName)) {
343             final String msg = "Permission Denial: starting " + getIntentString(intent)
344                     + " from " + callerApp + " (pid=" + callingPid
345                     + ", uid=" + callingUid + ") with lockTaskMode=true";
346             Slog.w(TAG, msg);
347             throw new SecurityException(msg);
348         }
349 
350         // Check if the caller is allowed to override any app transition animation.
351         final boolean overrideTaskTransition = options.getOverrideTaskTransition();
352         if (aInfo != null && overrideTaskTransition) {
353             final int startTasksFromRecentsPerm = ActivityTaskManagerService.checkPermission(
354                     START_TASKS_FROM_RECENTS, callingPid, callingUid);
355             if (startTasksFromRecentsPerm != PERMISSION_GRANTED) {
356                 final String msg = "Permission Denial: starting " + getIntentString(intent)
357                         + " from " + callerApp + " (pid=" + callingPid
358                         + ", uid=" + callingUid + ") with overrideTaskTransition=true";
359                 Slog.w(TAG, msg);
360                 throw new SecurityException(msg);
361             }
362         }
363 
364         // Check if the caller is allowed to dismiss keyguard.
365         final boolean dismissKeyguard = options.getDismissKeyguard();
366         if (aInfo != null && dismissKeyguard) {
367             final int controlKeyguardPerm = ActivityTaskManagerService.checkPermission(
368                     CONTROL_KEYGUARD, callingPid, callingUid);
369             if (controlKeyguardPerm != PERMISSION_GRANTED) {
370                 final String msg = "Permission Denial: starting " + getIntentString(intent)
371                         + " from " + callerApp + " (pid=" + callingPid
372                         + ", uid=" + callingUid + ") with dismissKeyguard=true";
373                 Slog.w(TAG, msg);
374                 throw new SecurityException(msg);
375             }
376         }
377 
378         // Check permission for remote animations
379         final RemoteAnimationAdapter adapter = options.getRemoteAnimationAdapter();
380         if (adapter != null && supervisor.mService.checkPermission(
381                 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid)
382                         != PERMISSION_GRANTED) {
383             final String msg = "Permission Denial: starting " + getIntentString(intent)
384                     + " from " + callerApp + " (pid=" + callingPid
385                     + ", uid=" + callingUid + ") with remoteAnimationAdapter";
386             Slog.w(TAG, msg);
387             throw new SecurityException(msg);
388         }
389 
390         // Check permission for remote transitions
391         final RemoteTransition transition = options.getRemoteTransition();
392         if (transition != null && supervisor.mService.checkPermission(
393                 CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, callingPid, callingUid)
394                 != PERMISSION_GRANTED) {
395             final String msg = "Permission Denial: starting " + getIntentString(intent)
396                     + " from " + callerApp + " (pid=" + callingPid
397                     + ", uid=" + callingUid + ") with remoteTransition";
398             Slog.w(TAG, msg);
399             throw new SecurityException(msg);
400         }
401 
402         // If launched from bubble is specified, then ensure that the caller is system or sysui.
403         if (options.getLaunchedFromBubble() && !isSystemOrSystemUI(callingPid, callingUid)) {
404             final String msg = "Permission Denial: starting " + getIntentString(intent)
405                     + " from " + callerApp + " (pid=" + callingPid
406                     + ", uid=" + callingUid + ") with launchedFromBubble=true";
407             Slog.w(TAG, msg);
408             throw new SecurityException(msg);
409         }
410 
411         final int activityType = options.getLaunchActivityType();
412         if (activityType != ACTIVITY_TYPE_UNDEFINED
413                 && !isSystemOrSystemUI(callingPid, callingUid)) {
414             // Granted if it is assistant type and the calling uid is assistant.
415             boolean activityTypeGranted = false;
416             if (activityType == ACTIVITY_TYPE_ASSISTANT
417                     && isAssistant(supervisor.mService, callingUid)) {
418                 activityTypeGranted = true;
419             }
420 
421             if (!activityTypeGranted) {
422                 final String msg = "Permission Denial: starting " + getIntentString(intent)
423                         + " from " + callerApp + " (pid=" + callingPid
424                         + ", uid=" + callingUid + ") with launchActivityType="
425                         + activityTypeToString(options.getLaunchActivityType());
426                 Slog.w(TAG, msg);
427                 throw new SecurityException(msg);
428             }
429         }
430     }
431 
isAssistant(ActivityTaskManagerService atmService, int callingUid)432     private boolean isAssistant(ActivityTaskManagerService atmService, int callingUid) {
433         if (atmService.mActiveVoiceInteractionServiceComponent == null) {
434             return false;
435         }
436 
437         final String assistantPackage =
438                 atmService.mActiveVoiceInteractionServiceComponent.getPackageName();
439         try {
440             final int uid = AppGlobals.getPackageManager().getPackageUid(assistantPackage,
441                     PackageManager.MATCH_DIRECT_BOOT_AUTO,
442                     UserHandle.getUserId(callingUid));
443             if (uid == callingUid) {
444                 return true;
445             }
446         } catch (RemoteException e) {
447             // Should not happen
448         }
449         return false;
450     }
451 
isSystemOrSystemUI(int callingPid, int callingUid)452     private boolean isSystemOrSystemUI(int callingPid, int callingUid) {
453         if (callingUid == Process.SYSTEM_UID) {
454             return true;
455         }
456 
457         final int statusBarPerm = ActivityTaskManagerService.checkPermission(
458                 STATUS_BAR_SERVICE, callingPid, callingUid);
459         return statusBarPerm == PERMISSION_GRANTED;
460     }
461 
getIntentString(Intent intent)462     private String getIntentString(Intent intent) {
463         return intent != null ? intent.toString() : "(no intent)";
464     }
465 }
466