diff options
| author | 2021-10-27 17:59:52 +0800 | |
|---|---|---|
| committer | 2021-12-08 06:38:16 +0000 | |
| commit | c668064c04be23384a02cc404e49c6261e76e21f (patch) | |
| tree | afd13874e06191569bb869d74b731dc51e9f87b7 | |
| parent | 20e71a637f90179ded4eb333a31f1983cec88454 (diff) | |
[RESTRICT AUTOMERGE]Only allow system and same app to apply relinquishTaskIdentity
Any malicious application could hijack tasks by
android:relinquishTaskIdentity. This vulnerability can perform UI
spoofing or spy on user’s activities.
This CL limit the usage which only allow system and same app to apply
relinquishTaskIdentity.
Bug: 185810717
Test: atest IntentTests
atest testActivityWithRelinquishTaskIdentity
atest com.android.server.wm.TaskTests
Change-Id: I55fe8938cd9a0dd7c0268e1cfec89d4e95eee049
| -rw-r--r-- | services/core/java/com/android/server/wm/Task.java | 48 | ||||
| -rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/TaskTests.java | 73 |
2 files changed, 89 insertions, 32 deletions
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index a53a8cdea0a7..7a363eddcbdf 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -321,6 +321,11 @@ class Task extends TaskFragment { */ boolean mInResumeTopActivity = false; + /** + * Used to identify if the activity that is installed from device's system image. + */ + boolean mIsEffectivelySystemApp; + int mCurrentUser; String affinity; // The affinity name for this task, or null; may change identity. @@ -568,13 +573,24 @@ class Task extends TaskFragment { if (r.finishing) return false; - // Set this as the candidate root since it isn't finishing. - mRoot = r; + if (mRoot == null || mRoot.finishing) { + // Set this as the candidate root since it isn't finishing. + mRoot = r; + } + + final int uid = mRoot == r ? effectiveUid : r.info.applicationInfo.uid; + if (ignoreRelinquishIdentity + || (mRoot.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0 + || (mRoot.info.applicationInfo.uid != Process.SYSTEM_UID + && !mRoot.info.applicationInfo.isSystemApp() + && mRoot.info.applicationInfo.uid != uid)) { + // No need to relinquish identity, end search. + return true; + } - // Only end search if we are ignore relinquishing identity or we are not relinquishing. - return ignoreRelinquishIdentity - || mNeverRelinquishIdentity - || (r.info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; + // Relinquish to next activity + mRoot = r; + return false; } } @@ -999,7 +1015,15 @@ class Task extends TaskFragment { * @param info The activity info which could be different from {@code r.info} if set. */ void setIntent(ActivityRecord r, @Nullable Intent intent, @Nullable ActivityInfo info) { - if (this.intent == null || !mNeverRelinquishIdentity) { + boolean updateIdentity = false; + if (this.intent == null) { + updateIdentity = true; + } else if (!mNeverRelinquishIdentity) { + final ActivityInfo activityInfo = info != null ? info : r.info; + updateIdentity = (effectiveUid == Process.SYSTEM_UID || mIsEffectivelySystemApp + || effectiveUid == activityInfo.applicationInfo.uid); + } + if (updateIdentity) { mCallingUid = r.launchedFromUid; mCallingPackage = r.launchedFromPackage; mCallingFeatureId = r.launchedFromFeatureId; @@ -1012,14 +1036,7 @@ class Task extends TaskFragment { private void setIntent(Intent _intent, ActivityInfo info) { if (!isLeafTask()) return; - if (info.applicationInfo.uid == Process.SYSTEM_UID - || info.applicationInfo.isSystemApp()) { - // Only allow the apps that pre-installed on the system image to apply - // relinquishTaskIdentity - mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; - } else { - mNeverRelinquishIdentity = true; - } + mNeverRelinquishIdentity = (info.flags & FLAG_RELINQUISH_TASK_IDENTITY) == 0; affinity = info.taskAffinity; if (intent == null) { // If this task already has an intent associated with it, don't set the root @@ -1028,6 +1045,7 @@ class Task extends TaskFragment { rootAffinity = affinity; } effectiveUid = info.applicationInfo.uid; + mIsEffectivelySystemApp = info.applicationInfo.isSystemApp(); stringName = null; if (info.targetActivity == null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 8c1045d995d6..bfaa8150cb99 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -899,22 +899,21 @@ public class TaskTests extends WindowTestsBase { /** * Test that root activity index is reported correctly when looking for the 'effective root' in - * case when bottom activity is finishing. Ignore the relinquishing task identity if it's not a - * system activity even with the FLAG_RELINQUISH_TASK_IDENTITY. + * case when bottom activities are relinquishing task identity or finishing. */ @Test public void testFindRootIndex_effectiveRoot_finishingAndRelinquishing() { - final Task task = getTestTask(); + final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final Task task = activity0.getTask(); // Add extra two activities. Mark the one on the bottom with "relinquishTaskIdentity" and // one above as finishing. - final ActivityRecord activity0 = task.getBottomMostActivity(); activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY; final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build(); activity1.finishing = true; new ActivityBuilder(mAtm).setTask(task).build(); assertEquals("The first non-finishing activity and non-relinquishing task identity " - + "must be reported.", task.getChildAt(0), task.getRootActivity( + + "must be reported.", task.getChildAt(2), task.getRootActivity( false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)); } @@ -934,21 +933,21 @@ public class TaskTests extends WindowTestsBase { } /** - * Test that the root activity index is reported correctly when looking for the - * 'effective root' for the case when all non-system activities have relinquishTaskIdentity set. + * Test that the topmost activity index is reported correctly when looking for the + * 'effective root' for the case when all activities have relinquishTaskIdentity set. */ @Test public void testFindRootIndex_effectiveRoot_relinquishingMultipleActivities() { - final Task task = getTestTask(); + final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final Task task = activity0.getTask(); // Set relinquishTaskIdentity for all activities in the task - final ActivityRecord activity0 = task.getBottomMostActivity(); activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY; final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build(); activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY; - assertEquals("The topmost activity in the task must be reported.", task.getChildAt(0), - task.getRootActivity(false /*ignoreRelinquishIdentity*/, - true /*setToBottomIfNone*/)); + assertEquals("The topmost activity in the task must be reported.", + task.getChildAt(task.getChildCount() - 1), task.getRootActivity( + false /*ignoreRelinquishIdentity*/, true /*setToBottomIfNone*/)); } /** Test that bottom-most activity is reported in {@link Task#getRootActivity()}. */ @@ -1086,14 +1085,14 @@ public class TaskTests extends WindowTestsBase { } /** - * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with non-system - * activity that relinquishes task identity. + * Test {@link ActivityRecord#getTaskForActivityLocked(IBinder, boolean)} with activity that + * relinquishes task identity. */ @Test public void testGetTaskForActivity_onlyRoot_relinquishTaskIdentity() { - final Task task = getTestTask(); + final ActivityRecord activity0 = new ActivityBuilder(mAtm).setCreateTask(true).build(); + final Task task = activity0.getTask(); // Make the current root activity relinquish task identity - final ActivityRecord activity0 = task.getBottomMostActivity(); activity0.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY; // Add an extra activity on top - this will be the new root final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build(); @@ -1102,7 +1101,7 @@ public class TaskTests extends WindowTestsBase { assertEquals(task.mTaskId, ActivityRecord.getTaskForActivityLocked(activity0.appToken, true /* onlyRoot */)); - assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID, + assertEquals(task.mTaskId, ActivityRecord.getTaskForActivityLocked(activity1.appToken, true /* onlyRoot */)); assertEquals("No task must be reported for activity that is above root", INVALID_TASK_ID, ActivityRecord.getTaskForActivityLocked(activity2.appToken, true /* onlyRoot */)); @@ -1189,6 +1188,46 @@ public class TaskTests extends WindowTestsBase { verify(task).setIntent(eq(activity0)); } + /** + * Test {@link Task#updateEffectiveIntent()} when activity with relinquishTaskIdentity but + * another with different uid. This should make the task use the root activity when updating the + * intent. + */ + @Test + public void testUpdateEffectiveIntent_relinquishingWithDifferentUid() { + final ActivityRecord activity0 = new ActivityBuilder(mAtm) + .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build(); + final Task task = activity0.getTask(); + + // Add an extra activity on top + new ActivityBuilder(mAtm).setUid(11).setTask(task).build(); + + spyOn(task); + task.updateEffectiveIntent(); + verify(task).setIntent(eq(activity0)); + } + + /** + * Test {@link Task#updateEffectiveIntent()} with activities set as relinquishTaskIdentity. + * This should make the task use the topmost activity when updating the intent. + */ + @Test + public void testUpdateEffectiveIntent_relinquishingMultipleActivities() { + final ActivityRecord activity0 = new ActivityBuilder(mAtm) + .setActivityFlags(FLAG_RELINQUISH_TASK_IDENTITY).setCreateTask(true).build(); + final Task task = activity0.getTask(); + // Add an extra activity on top + final ActivityRecord activity1 = new ActivityBuilder(mAtm).setTask(task).build(); + activity1.info.flags |= FLAG_RELINQUISH_TASK_IDENTITY; + + // Add an extra activity on top + final ActivityRecord activity2 = new ActivityBuilder(mAtm).setTask(task).build(); + + spyOn(task); + task.updateEffectiveIntent(); + verify(task).setIntent(eq(activity2)); + } + @Test public void testSaveLaunchingStateWhenConfigurationChanged() { LaunchParamsPersister persister = mAtm.mTaskSupervisor.mLaunchParamsPersister; |