Merge "Fix security bug for TaskFragment creation" into sc-v2-dev
This commit is contained in:
@@ -496,11 +496,13 @@ public class ActivityStartController {
|
|||||||
* @param activityIntent intent to start the activity.
|
* @param activityIntent intent to start the activity.
|
||||||
* @param activityOptions ActivityOptions to start the activity with.
|
* @param activityOptions ActivityOptions to start the activity with.
|
||||||
* @param resultTo the caller activity
|
* @param resultTo the caller activity
|
||||||
|
* @param callingUid the caller uid
|
||||||
|
* @param callingPid the caller pid
|
||||||
* @return the start result.
|
* @return the start result.
|
||||||
*/
|
*/
|
||||||
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
|
int startActivityInTaskFragment(@NonNull TaskFragment taskFragment,
|
||||||
@NonNull Intent activityIntent, @Nullable Bundle activityOptions,
|
@NonNull Intent activityIntent, @Nullable Bundle activityOptions,
|
||||||
@Nullable IBinder resultTo) {
|
@Nullable IBinder resultTo, int callingUid, int callingPid) {
|
||||||
final ActivityRecord caller =
|
final ActivityRecord caller =
|
||||||
resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
|
resultTo != null ? ActivityRecord.forTokenLocked(resultTo) : null;
|
||||||
return obtainStarter(activityIntent, "startActivityInTaskFragment")
|
return obtainStarter(activityIntent, "startActivityInTaskFragment")
|
||||||
@@ -508,8 +510,8 @@ public class ActivityStartController {
|
|||||||
.setInTaskFragment(taskFragment)
|
.setInTaskFragment(taskFragment)
|
||||||
.setResultTo(resultTo)
|
.setResultTo(resultTo)
|
||||||
.setRequestCode(-1)
|
.setRequestCode(-1)
|
||||||
.setCallingUid(Binder.getCallingUid())
|
.setCallingUid(callingUid)
|
||||||
.setCallingPid(Binder.getCallingPid())
|
.setCallingPid(callingPid)
|
||||||
.setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
|
.setUserId(caller != null ? caller.mUserId : mService.getCurrentUserId())
|
||||||
.execute();
|
.execute();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -590,7 +590,7 @@ public class AppTransitionController {
|
|||||||
}
|
}
|
||||||
// We don't want the organizer to handle transition of non-embedded activity of other
|
// We don't want the organizer to handle transition of non-embedded activity of other
|
||||||
// app.
|
// app.
|
||||||
if (r.getUid() != rootActivity.getUid() && !r.isEmbedded()) {
|
if (r.getUid() != task.effectiveUid && !r.isEmbedded()) {
|
||||||
leafTask = null;
|
leafTask = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -588,7 +588,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
|
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT: {
|
||||||
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
final TaskFragmentCreationParams taskFragmentCreationOptions =
|
||||||
hop.getTaskFragmentCreationOptions();
|
hop.getTaskFragmentCreationOptions();
|
||||||
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken);
|
createTaskFragment(taskFragmentCreationOptions, errorCallbackToken, caller);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
|
case HIERARCHY_OP_TYPE_DELETE_TASK_FRAGMENT: {
|
||||||
@@ -631,7 +631,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
|
final TaskFragment tf = mLaunchTaskFragments.get(fragmentToken);
|
||||||
final int result = mService.getActivityStartController()
|
final int result = mService.getActivityStartController()
|
||||||
.startActivityInTaskFragment(tf, activityIntent, activityOptions,
|
.startActivityInTaskFragment(tf, activityIntent, activityOptions,
|
||||||
hop.getCallingActivity());
|
hop.getCallingActivity(), caller.mUid, caller.mPid);
|
||||||
if (!isStartResultSuccessful(result)) {
|
if (!isStartResultSuccessful(result)) {
|
||||||
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
|
sendTaskFragmentOperationFailure(tf.getTaskFragmentOrganizer(),
|
||||||
errorCallbackToken,
|
errorCallbackToken,
|
||||||
@@ -1200,7 +1200,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
}
|
}
|
||||||
|
|
||||||
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
|
void createTaskFragment(@NonNull TaskFragmentCreationParams creationParams,
|
||||||
@Nullable IBinder errorCallbackToken) {
|
@Nullable IBinder errorCallbackToken, @NonNull CallerInfo caller) {
|
||||||
final ActivityRecord ownerActivity =
|
final ActivityRecord ownerActivity =
|
||||||
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
|
ActivityRecord.forTokenLocked(creationParams.getOwnerToken());
|
||||||
final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
|
final ITaskFragmentOrganizer organizer = ITaskFragmentOrganizer.Stub.asInterface(
|
||||||
@@ -1218,9 +1218,9 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub
|
|||||||
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
|
sendTaskFragmentOperationFailure(organizer, errorCallbackToken, exception);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// The ownerActivity has to belong to the same app as the root Activity of the target Task.
|
// The ownerActivity has to belong to the same app as the target Task.
|
||||||
final ActivityRecord rootActivity = ownerActivity.getTask().getRootActivity();
|
if (ownerActivity.getTask().effectiveUid != ownerActivity.getUid()
|
||||||
if (rootActivity.getUid() != ownerActivity.getUid()) {
|
|| ownerActivity.getTask().effectiveUid != caller.mUid) {
|
||||||
final Throwable exception =
|
final Throwable exception =
|
||||||
new IllegalArgumentException("Not allowed to operate with the ownerToken while "
|
new IllegalArgumentException("Not allowed to operate with the ownerToken while "
|
||||||
+ "the root activity of the target task belong to the different app");
|
+ "the root activity of the target task belong to the different app");
|
||||||
|
|||||||
@@ -803,6 +803,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
final TaskFragment taskFragment = createTaskFragmentWithEmbeddedActivity(task, organizer);
|
||||||
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
final ActivityRecord openingActivity = taskFragment.getTopMostActivity();
|
||||||
openingActivity.allDrawn = true;
|
openingActivity.allDrawn = true;
|
||||||
|
task.effectiveUid = openingActivity.getUid();
|
||||||
spyOn(mDisplayContent.mAppTransition);
|
spyOn(mDisplayContent.mAppTransition);
|
||||||
|
|
||||||
// Prepare a transition.
|
// Prepare a transition.
|
||||||
@@ -879,6 +880,7 @@ public class AppTransitionControllerTest extends WindowTestsBase {
|
|||||||
final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
|
final ActivityRecord closingActivity = taskFragment.getTopMostActivity();
|
||||||
closingActivity.allDrawn = true;
|
closingActivity.allDrawn = true;
|
||||||
closingActivity.info.applicationInfo.uid = 12345;
|
closingActivity.info.applicationInfo.uid = 12345;
|
||||||
|
task.effectiveUid = closingActivity.getUid();
|
||||||
// Opening non-embedded activity with different UID.
|
// Opening non-embedded activity with different UID.
|
||||||
final ActivityRecord openingActivity = createActivityRecord(task);
|
final ActivityRecord openingActivity = createActivityRecord(task);
|
||||||
openingActivity.info.applicationInfo.uid = 54321;
|
openingActivity.info.applicationInfo.uid = 54321;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
|||||||
import static com.android.server.wm.testing.Assert.assertThrows;
|
import static com.android.server.wm.testing.Assert.assertThrows;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
@@ -352,28 +353,66 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment() {
|
public void testApplyTransaction_enforceHierarchyChange_createTaskFragment()
|
||||||
|
throws RemoteException {
|
||||||
|
mController.registerOrganizer(mIOrganizer);
|
||||||
|
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||||
|
final int uid = Binder.getCallingUid();
|
||||||
|
activity.info.applicationInfo.uid = uid;
|
||||||
|
activity.getTask().effectiveUid = uid;
|
||||||
|
final IBinder fragmentToken = new Binder();
|
||||||
|
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||||
|
mOrganizerToken, fragmentToken, activity.token).build();
|
||||||
mOrganizer.applyTransaction(mTransaction);
|
mOrganizer.applyTransaction(mTransaction);
|
||||||
|
|
||||||
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
// Allow organizer to create TaskFragment and start/reparent activity to TaskFragment.
|
||||||
final TaskFragmentCreationParams mockParams = mock(TaskFragmentCreationParams.class);
|
mTransaction.createTaskFragment(params);
|
||||||
doReturn(mOrganizerToken).when(mockParams).getOrganizer();
|
|
||||||
mTransaction.createTaskFragment(mockParams);
|
|
||||||
mTransaction.startActivityInTaskFragment(
|
mTransaction.startActivityInTaskFragment(
|
||||||
mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
|
mFragmentToken, null /* callerToken */, new Intent(), null /* activityOptions */);
|
||||||
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
|
mTransaction.reparentActivityToTaskFragment(mFragmentToken, mock(IBinder.class));
|
||||||
mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
|
mTransaction.setAdjacentTaskFragments(mFragmentToken, mock(IBinder.class),
|
||||||
null /* options */);
|
null /* options */);
|
||||||
|
|
||||||
// It is expected to fail for the mock TaskFragmentCreationParams. It is ok as we are
|
|
||||||
// testing the security check here.
|
|
||||||
assertThrows(IllegalArgumentException.class, () -> {
|
|
||||||
try {
|
|
||||||
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||||
} catch (RemoteException e) {
|
|
||||||
fail();
|
// Successfully created a TaskFragment.
|
||||||
|
final TaskFragment taskFragment = mAtm.mWindowOrganizerController
|
||||||
|
.getTaskFragment(fragmentToken);
|
||||||
|
assertNotNull(taskFragment);
|
||||||
|
assertEquals(activity.getTask(), taskFragment.getTask());
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
@Test
|
||||||
|
public void testApplyTransaction_createTaskFragment_failForDifferentUid()
|
||||||
|
throws RemoteException {
|
||||||
|
mController.registerOrganizer(mIOrganizer);
|
||||||
|
final ActivityRecord activity = createActivityRecord(mDisplayContent);
|
||||||
|
final int uid = Binder.getCallingUid();
|
||||||
|
final IBinder fragmentToken = new Binder();
|
||||||
|
final TaskFragmentCreationParams params = new TaskFragmentCreationParams.Builder(
|
||||||
|
mOrganizerToken, fragmentToken, activity.token).build();
|
||||||
|
mOrganizer.applyTransaction(mTransaction);
|
||||||
|
mTransaction.createTaskFragment(params);
|
||||||
|
|
||||||
|
// Fail to create TaskFragment when the task uid is different from caller.
|
||||||
|
activity.info.applicationInfo.uid = uid;
|
||||||
|
activity.getTask().effectiveUid = uid + 1;
|
||||||
|
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||||
|
|
||||||
|
assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
|
|
||||||
|
// Fail to create TaskFragment when the task uid is different from owner activity.
|
||||||
|
activity.info.applicationInfo.uid = uid + 1;
|
||||||
|
activity.getTask().effectiveUid = uid;
|
||||||
|
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||||
|
|
||||||
|
assertNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
|
|
||||||
|
// Successfully created a TaskFragment for same uid.
|
||||||
|
activity.info.applicationInfo.uid = uid;
|
||||||
|
activity.getTask().effectiveUid = uid;
|
||||||
|
mAtm.getWindowOrganizerController().applyTransaction(mTransaction);
|
||||||
|
|
||||||
|
assertNotNull(mAtm.mWindowOrganizerController.getTaskFragment(fragmentToken));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user