Merge "Enforce onActivityReparentedToTask" into tm-qpr-dev

This commit is contained in:
TreeHugger Robot
2022-11-18 02:22:41 +00:00
committed by Android (Google) Code Review
2 changed files with 90 additions and 5 deletions

View File

@@ -34,6 +34,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Binder;
@@ -322,9 +323,10 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
+ " is not in a task belong to the organizer app.");
return null;
}
if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED) {
if (task.isAllowedToEmbedActivity(activity, mOrganizerUid) != EMBEDDING_ALLOWED
|| !task.isAllowedToEmbedActivityInTrustedMode(activity, mOrganizerUid)) {
Slog.d(TAG, "Reparent activity=" + activity.token
+ " is not allowed to be embedded.");
+ " is not allowed to be embedded in trusted mode.");
return null;
}
@@ -350,7 +352,7 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
activity.token, task.mTaskId);
return new TaskFragmentTransaction.Change(TYPE_ACTIVITY_REPARENTED_TO_TASK)
.setTaskId(task.mTaskId)
.setActivityIntent(activity.intent)
.setActivityIntent(trimIntent(activity.intent))
.setActivityToken(activityToken);
}
@@ -1095,4 +1097,15 @@ public class TaskFragmentOrganizerController extends ITaskFragmentOrganizerContr
return false;
}
}
/**
* Trims the given Intent to only those that are needed to for embedding rules. This helps to
* make it safer for cross-uid embedding even if we only send the Intent for trusted embedding.
*/
private static Intent trimIntent(@NonNull Intent intent) {
return new Intent()
.setComponent(intent.getComponent())
.setPackage(intent.getPackage())
.setAction(intent.getAction());
}
}

View File

@@ -62,10 +62,12 @@ import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import android.annotation.NonNull;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
@@ -403,7 +405,7 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final TaskFragmentTransaction.Change change = changes.get(0);
assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType());
assertEquals(task.mTaskId, change.getTaskId());
assertEquals(activity.intent, change.getActivityIntent());
assertIntentsEqualForOrganizer(activity.intent, change.getActivityIntent());
assertNotEquals(activity.token, change.getActivityToken());
mTransaction.reparentActivityToTaskFragment(mFragmentToken, change.getActivityToken());
assertApplyTransactionAllowed(mTransaction);
@@ -414,6 +416,62 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
change.getActivityToken()));
}
@Test
public void testOnActivityReparentedToTask_untrustedEmbed_notReported() {
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
mTaskFragment.setTaskFragmentOrganizer(mOrganizer.getOrganizerToken(), uid,
DEFAULT_TASK_FRAGMENT_ORGANIZER_PROCESS_NAME);
mWindowOrganizerController.mLaunchTaskFragments.put(mFragmentToken, mTaskFragment);
final Task task = createTask(mDisplayContent);
task.addChild(mTaskFragment, POSITION_TOP);
final ActivityRecord activity = createActivityRecord(task);
// Make sure the activity is embedded in untrusted mode.
activity.info.applicationInfo.uid = uid + 1;
doReturn(pid + 1).when(activity).getPid();
task.effectiveUid = uid;
doReturn(EMBEDDING_ALLOWED).when(task).isAllowedToEmbedActivity(activity, uid);
doReturn(false).when(task).isAllowedToEmbedActivityInTrustedMode(activity, uid);
doReturn(true).when(task).isAllowedToEmbedActivityInUntrustedMode(activity);
// Notify organizer if it was embedded before entered Pip.
// Create a temporary token since the activity doesn't belong to the same process.
clearInvocations(mOrganizer);
activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
mController.onActivityReparentedToTask(activity);
mController.dispatchPendingEvents();
// Disallow organizer to reparent activity that is untrusted embedded.
verify(mOrganizer, never()).onTransactionReady(mTransactionCaptor.capture());
}
@Test
public void testOnActivityReparentedToTask_trimReportedIntent() {
// Make sure the activity pid/uid is the same as the organizer caller.
final int pid = Binder.getCallingPid();
final int uid = Binder.getCallingUid();
final ActivityRecord activity = createActivityRecord(mDisplayContent);
final Task task = activity.getTask();
activity.info.applicationInfo.uid = uid;
doReturn(pid).when(activity).getPid();
task.effectiveUid = uid;
activity.mLastTaskFragmentOrganizerBeforePip = mIOrganizer;
// Test the Intent trim in #assertIntentTrimmed
activity.intent.setComponent(new ComponentName("TestPackage", "TestClass"))
.setPackage("TestPackage")
.setAction("TestAction")
.setData(mock(Uri.class))
.putExtra("Test", 123)
.setFlags(10);
mController.onActivityReparentedToTask(activity);
mController.dispatchPendingEvents();
assertActivityReparentedToTaskTransaction(task.mTaskId, activity.intent, activity.token);
}
@Test
public void testRegisterRemoteAnimations() {
mController.registerRemoteAnimations(mIOrganizer, TASK_ID, mDefinition);
@@ -1425,7 +1483,8 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
final TaskFragmentTransaction.Change change = changes.remove(0);
assertEquals(TYPE_ACTIVITY_REPARENTED_TO_TASK, change.getType());
assertEquals(taskId, change.getTaskId());
assertEquals(intent, change.getActivityIntent());
assertIntentsEqualForOrganizer(intent, change.getActivityIntent());
assertIntentTrimmed(change.getActivityIntent());
assertEquals(activityToken, change.getActivityToken());
}
@@ -1452,4 +1511,17 @@ public class TaskFragmentOrganizerControllerTest extends WindowTestsBase {
mockParent.lastActiveTime = 100;
doReturn(true).when(mockParent).shouldBeVisible(any());
}
private static void assertIntentsEqualForOrganizer(@NonNull Intent expected,
@NonNull Intent actual) {
assertEquals(expected.getComponent(), actual.getComponent());
assertEquals(expected.getPackage(), actual.getPackage());
assertEquals(expected.getAction(), actual.getAction());
}
private static void assertIntentTrimmed(@NonNull Intent intent) {
assertNull(intent.getData());
assertNull(intent.getExtras());
assertEquals(0, intent.getFlags());
}
}