Do not resolve ActivityInfo in navigateUpTo

During navigateUpTo, it will first resolve the activity before creating
the ActivityStarter. This bypasses the explicit intent filter
enforcement introduced in T, exposing a security flaw that allows
non-matching intents to be delivered to components.

Bug: 238602879
Test: atest CtsWindowManagerDeviceTestCases
Change-Id: I9aa3e27f753f2f809e74a8f421f8b68e4d610702
This commit is contained in:
John Wu
2022-10-03 22:24:43 +00:00
parent 9720e32dcd
commit e3f0ca01cd
6 changed files with 40 additions and 42 deletions

View File

@@ -8051,8 +8051,9 @@ public class Activity extends ContextThemeWrapper
resultData.prepareToLeaveProcess(this); resultData.prepareToLeaveProcess(this);
} }
upIntent.prepareToLeaveProcess(this); upIntent.prepareToLeaveProcess(this);
return ActivityClient.getInstance().navigateUpTo(mToken, upIntent, resultCode, String resolvedType = upIntent.resolveTypeIfNeeded(getContentResolver());
resultData); return ActivityClient.getInstance().navigateUpTo(mToken, upIntent, resolvedType,
resultCode, resultData);
} else { } else {
return mParent.navigateUpToFromChild(this, upIntent); return mParent.navigateUpToFromChild(this, upIntent);
} }

View File

@@ -141,11 +141,11 @@ public class ActivityClient {
} }
} }
boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode, boolean navigateUpTo(IBinder token, Intent destIntent, String resolvedType, int resultCode,
Intent resultData) { Intent resultData) {
try { try {
return getActivityClientController().navigateUpTo(token, destIntent, resultCode, return getActivityClientController().navigateUpTo(token, destIntent, resolvedType,
resultData); resultCode, resultData);
} catch (RemoteException e) { } catch (RemoteException e) {
throw e.rethrowFromSystemServer(); throw e.rethrowFromSystemServer();
} }

View File

@@ -60,8 +60,8 @@ interface IActivityClientController {
in SizeConfigurationBuckets sizeConfigurations); in SizeConfigurationBuckets sizeConfigurations);
boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot); boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
boolean shouldUpRecreateTask(in IBinder token, in String destAffinity); boolean shouldUpRecreateTask(in IBinder token, in String destAffinity);
boolean navigateUpTo(in IBinder token, in Intent target, int resultCode, boolean navigateUpTo(in IBinder token, in Intent target, in String resolvedType,
in Intent resultData); int resultCode, in Intent resultData);
boolean releaseActivityInstance(in IBinder token); boolean releaseActivityInstance(in IBinder token);
boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask); boolean finishActivity(in IBinder token, int code, in Intent data, int finishTask);
boolean finishActivityAffinity(in IBinder token); boolean finishActivityAffinity(in IBinder token);

View File

@@ -332,8 +332,8 @@ class ActivityClientController extends IActivityClientController.Stub {
} }
@Override @Override
public boolean navigateUpTo(IBinder token, Intent destIntent, int resultCode, public boolean navigateUpTo(IBinder token, Intent destIntent, String resolvedType,
Intent resultData) { int resultCode, Intent resultData) {
final ActivityRecord r; final ActivityRecord r;
synchronized (mGlobalLock) { synchronized (mGlobalLock) {
r = ActivityRecord.isInRootTaskLocked(token); r = ActivityRecord.isInRootTaskLocked(token);
@@ -348,7 +348,7 @@ class ActivityClientController extends IActivityClientController.Stub {
synchronized (mGlobalLock) { synchronized (mGlobalLock) {
return r.getRootTask().navigateUpTo( return r.getRootTask().navigateUpTo(
r, destIntent, destGrants, resultCode, resultData, resultGrants); r, destIntent, resolvedType, destGrants, resultCode, resultData, resultGrants);
} }
} }

View File

@@ -5278,8 +5278,9 @@ class Task extends TaskFragment {
return false; return false;
} }
boolean navigateUpTo(ActivityRecord srec, Intent destIntent, NeededUriGrants destGrants, boolean navigateUpTo(ActivityRecord srec, Intent destIntent, String resolvedType,
int resultCode, Intent resultData, NeededUriGrants resultGrants) { NeededUriGrants destGrants, int resultCode, Intent resultData,
NeededUriGrants resultGrants) {
if (!srec.attachedToProcess()) { if (!srec.attachedToProcess()) {
// Nothing to do if the caller is not attached, because this method should be called // Nothing to do if the caller is not attached, because this method should be called
// from an alive activity. // from an alive activity.
@@ -5348,32 +5349,26 @@ class Task extends TaskFragment {
if (parent != null && foundParentInTask) { if (parent != null && foundParentInTask) {
final int callingUid = srec.info.applicationInfo.uid; final int callingUid = srec.info.applicationInfo.uid;
try { // TODO(b/64750076): Check if calling pid should really be -1.
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo( final int res = mAtmService.getActivityStartController()
destIntent.getComponent(), ActivityManagerService.STOCK_PM_FLAGS, .obtainStarter(destIntent, "navigateUpTo")
srec.mUserId); .setResolvedType(resolvedType)
// TODO(b/64750076): Check if calling pid should really be -1. .setUserId(srec.mUserId)
final int res = mAtmService.getActivityStartController() .setCaller(srec.app.getThread())
.obtainStarter(destIntent, "navigateUpTo") .setResultTo(parent.token)
.setCaller(srec.app.getThread()) .setIntentGrants(destGrants)
.setActivityInfo(aInfo) .setCallingPid(-1)
.setResultTo(parent.token) .setCallingUid(callingUid)
.setIntentGrants(destGrants) .setCallingPackage(srec.packageName)
.setCallingPid(-1) .setCallingFeatureId(parent.launchedFromFeatureId)
.setCallingUid(callingUid) .setRealCallingPid(-1)
.setCallingPackage(srec.packageName) .setRealCallingUid(callingUid)
.setCallingFeatureId(parent.launchedFromFeatureId) .setComponentSpecified(true)
.setRealCallingPid(-1) .execute();
.setRealCallingUid(callingUid) foundParentInTask = isStartResultSuccessful(res);
.setComponentSpecified(true) if (res == ActivityManager.START_SUCCESS) {
.execute(); parent.finishIfPossible(resultCode, resultData, resultGrants,
foundParentInTask = isStartResultSuccessful(res); "navigate-top", true /* oomAdj */);
if (res == ActivityManager.START_SUCCESS) {
parent.finishIfPossible(resultCode, resultData, resultGrants,
"navigate-top", true /* oomAdj */);
}
} catch (RemoteException e) {
foundParentInTask = false;
} }
} }
Binder.restoreCallingIdentity(origId); Binder.restoreCallingIdentity(origId);

View File

@@ -1312,13 +1312,15 @@ public class RootTaskTests extends WindowTestsBase {
secondActivity.app.setThread(null); secondActivity.app.setThread(null);
// This should do nothing from a non-attached caller. // This should do nothing from a non-attached caller.
assertFalse(task.navigateUpTo(secondActivity /* source record */, assertFalse(task.navigateUpTo(secondActivity /* source record */,
firstActivity.intent /* destIntent */, null /* destGrants */, firstActivity.intent /* destIntent */, null /* resolvedType */,
0 /* resultCode */, null /* resultData */, null /* resultGrants */)); null /* destGrants */, 0 /* resultCode */, null /* resultData */,
null /* resultGrants */));
secondActivity.app.setThread(thread); secondActivity.app.setThread(thread);
assertTrue(task.navigateUpTo(secondActivity /* source record */, assertTrue(task.navigateUpTo(secondActivity /* source record */,
firstActivity.intent /* destIntent */, null /* destGrants */, firstActivity.intent /* destIntent */, null /* resolvedType */,
0 /* resultCode */, null /* resultData */, null /* resultGrants */)); null /* destGrants */, 0 /* resultCode */, null /* resultData */,
null /* resultGrants */));
// The firstActivity uses default launch mode, so the activities between it and itself will // The firstActivity uses default launch mode, so the activities between it and itself will
// be finished. // be finished.
assertTrue(secondActivity.finishing); assertTrue(secondActivity.finishing);