summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/app/ActivityManagerInternal.java3
-rw-r--r--core/java/android/content/Intent.java45
-rw-r--r--core/java/android/os/BaseBundle.java4
-rw-r--r--core/java/android/os/Bundle.java11
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java72
-rw-r--r--services/core/java/com/android/server/am/PendingIntentRecord.java8
-rw-r--r--services/core/java/com/android/server/uri/NeededUriGrants.java25
-rw-r--r--services/core/java/com/android/server/wm/ActivityClientController.java4
-rw-r--r--services/core/java/com/android/server/wm/ActivityStartController.java32
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java159
-rw-r--r--services/core/java/com/android/server/wm/ActivityTaskManagerService.java17
-rw-r--r--services/core/java/com/android/server/wm/AppTaskImpl.java2
-rw-r--r--services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java49
13 files changed, 374 insertions, 57 deletions
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 3bd121a4a19b..f80121d0c9b6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -1328,7 +1328,8 @@ public abstract class ActivityManagerInternal {
* Add a creator token for all embedded intents (stored as extra) of the given intent.
*
* @param intent The given intent
+ * @param creatorPackage the package name of the creator app.
* @hide
*/
- public abstract void addCreatorToken(Intent intent);
+ public abstract void addCreatorToken(Intent intent, String creatorPackage);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0bb0027fb0c3..f71952849872 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -888,6 +888,22 @@ public class Intent implements Parcelable, Cloneable {
public static final String ACTION_ACTIVITY_RECOGNIZER =
"android.intent.action.ACTIVITY_RECOGNIZER";
+ /** @hide */
+ public static void maybeMarkAsMissingCreatorToken(Object object) {
+ if (object instanceof Intent intent) {
+ maybeMarkAsMissingCreatorTokenInternal(intent);
+ }
+ }
+
+ private static void maybeMarkAsMissingCreatorTokenInternal(Intent intent) {
+ boolean isForeign = (intent.mLocalFlags & LOCAL_FLAG_FROM_PARCEL) != 0;
+ boolean isWithoutTrustedCreatorToken =
+ (intent.mLocalFlags & Intent.LOCAL_FLAG_TRUSTED_CREATOR_TOKEN_PRESENT) == 0;
+ if (isForeign && isWithoutTrustedCreatorToken) {
+ intent.addExtendedFlags(EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN);
+ }
+ }
+
/**
* Represents a shortcut/live folder icon resource.
*
@@ -7684,10 +7700,8 @@ public class Intent implements Parcelable, Cloneable {
/**
* This flag indicates the creator token of this intent has been verified.
- *
- * @hide
*/
- public static final int LOCAL_FLAG_CREATOR_TOKEN_VERIFIED = 1 << 6;
+ private static final int LOCAL_FLAG_TRUSTED_CREATOR_TOKEN_PRESENT = 1 << 6;
/** @hide */
@IntDef(flag = true, prefix = { "EXTENDED_FLAG_" }, value = {
@@ -12243,6 +12257,30 @@ public class Intent implements Parcelable, Cloneable {
}
}
+ /** @hide */
+ public void checkCreatorToken() {
+ if (mExtras == null) return;
+ if (mCreatorTokenInfo != null && mCreatorTokenInfo.mExtraIntentKeys != null) {
+ for (String key : mCreatorTokenInfo.mExtraIntentKeys) {
+ try {
+ Intent extraIntent = mExtras.getParcelable(key, Intent.class);
+ if (extraIntent == null) {
+ Log.w(TAG, "The key {" + key
+ + "} does not correspond to an intent in the bundle.");
+ continue;
+ }
+ extraIntent.mLocalFlags |= LOCAL_FLAG_TRUSTED_CREATOR_TOKEN_PRESENT;
+ } catch (Exception e) {
+ Log.e(TAG, "Failed to validate creator token. key: " + key + ".", e);
+ }
+ }
+ }
+ // mark the bundle as intent extras after calls to getParcelable.
+ // otherwise, the logic to mark missing token would run before
+ // mark trusted creator token present.
+ mExtras.setIsIntentExtra();
+ }
+
public void writeToParcel(Parcel out, int flags) {
out.writeString8(mAction);
Uri.writeToParcel(out, mData);
@@ -12730,6 +12768,7 @@ public class Intent implements Parcelable, Cloneable {
}
mLocalFlags |= localFlags;
+ checkCreatorToken();
// Special attribution fix-up logic for any BluetoothDevice extras
// passed via Bluetooth intents
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 49ab15a40a8e..50121278f0e6 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -21,6 +21,7 @@ import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Intent;
import android.util.ArrayMap;
import android.util.Log;
import android.util.MathUtils;
@@ -401,6 +402,9 @@ public class BaseBundle {
synchronized (this) {
object = unwrapLazyValueFromMapLocked(i, clazz, itemTypes);
}
+ if ((mFlags & Bundle.FLAG_VERIFY_TOKENS_PRESENT) != 0) {
+ Intent.maybeMarkAsMissingCreatorToken(object);
+ }
}
return (clazz != null) ? clazz.cast(object) : (T) object;
}
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index ed4037c7d246..c18fb0c38b82 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -62,6 +62,12 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
@VisibleForTesting
static final int FLAG_HAS_BINDERS = 1 << 12;
+ /**
+ * Indicates there may be intents with creator tokens contained in this bundle. When unparceled,
+ * they should be verified if tokens are missing or invalid.
+ */
+ static final int FLAG_VERIFY_TOKENS_PRESENT = 1 << 13;
+
/**
* Status when the Bundle can <b>assert</b> that the underlying Parcel DOES NOT contain
@@ -274,6 +280,11 @@ public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
return orig;
}
+ /** {@hide} */
+ public void setIsIntentExtra() {
+ mFlags |= FLAG_VERIFY_TOKENS_PRESENT;
+ }
+
/**
* Mark if this Bundle is okay to "defuse." That is, it's okay for system
* processes to ignore any {@link BadParcelableException} encountered when
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3c95b9a02557..33a8fa58360d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5536,7 +5536,6 @@ public class ActivityManagerService extends IActivityManager.Stub
public int sendIntentSender(IApplicationThread caller, IIntentSender target,
IBinder allowlistToken, int code, Intent intent, String resolvedType,
IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {
- addCreatorToken(intent);
if (target instanceof PendingIntentRecord) {
final PendingIntentRecord originalRecord = (PendingIntentRecord) target;
@@ -5578,19 +5577,23 @@ public class ActivityManagerService extends IActivityManager.Stub
intent = new Intent(Intent.ACTION_MAIN);
}
try {
+ final int callingUid = Binder.getCallingUid();
+ final String packageName;
+ final long token = Binder.clearCallingIdentity();
+ try {
+ packageName = AppGlobals.getPackageManager().getNameForUid(callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+
if (allowlistToken != null) {
- final int callingUid = Binder.getCallingUid();
- final String packageName;
- final long token = Binder.clearCallingIdentity();
- try {
- packageName = AppGlobals.getPackageManager().getNameForUid(callingUid);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
Slog.wtf(TAG, "Send a non-null allowlistToken to a non-PI target."
+ " Calling package: " + packageName + "; intent: " + intent
+ "; options: " + options);
}
+
+ addCreatorToken(intent, packageName);
+
target.send(code, intent, resolvedType, null, null,
requiredPermission, options);
} catch (RemoteException e) {
@@ -13615,7 +13618,7 @@ public class ActivityManagerService extends IActivityManager.Stub
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
enforceAllowedToStartOrBindServiceIfSdkSandbox(service);
- addCreatorToken(service);
+ addCreatorToken(service, callingPackage);
if (service != null) {
// Refuse possible leaked file descriptors
if (service.hasFileDescriptors()) {
@@ -13877,7 +13880,7 @@ public class ActivityManagerService extends IActivityManager.Stub
validateServiceInstanceName(instanceName);
- addCreatorToken(service);
+ addCreatorToken(service, callingPackage);
try {
if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
final ComponentName cn = service.getComponent();
@@ -17155,7 +17158,7 @@ public class ActivityManagerService extends IActivityManager.Stub
Slog.v(TAG_SERVICE,
"startServiceInPackage: " + service + " type=" + resolvedType);
}
- addCreatorToken(service);
+ addCreatorToken(service, callingPackage);
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
@@ -17983,8 +17986,8 @@ public class ActivityManagerService extends IActivityManager.Stub
}
@Override
- public void addCreatorToken(Intent intent) {
- ActivityManagerService.this.addCreatorToken(intent);
+ public void addCreatorToken(Intent intent, String creatorPackage) {
+ ActivityManagerService.this.addCreatorToken(intent, creatorPackage);
}
}
@@ -19141,9 +19144,9 @@ public class ActivityManagerService extends IActivityManager.Stub
private final Key mKeyFields;
private final WeakReference<IntentCreatorToken> mRef;
- public IntentCreatorToken(int creatorUid, Intent intent) {
+ public IntentCreatorToken(int creatorUid, String creatorPackage, Intent intent) {
super();
- this.mKeyFields = new Key(creatorUid, intent);
+ this.mKeyFields = new Key(creatorUid, creatorPackage, intent);
mRef = new WeakReference<>(this);
}
@@ -19151,7 +19154,10 @@ public class ActivityManagerService extends IActivityManager.Stub
return mKeyFields.mCreatorUid;
}
- /** {@hide} */
+ public String getCreatorPackage() {
+ return mKeyFields.mCreatorPackage;
+ }
+
public static boolean isValid(@NonNull Intent intent) {
IBinder binder = intent.getCreatorToken();
IntentCreatorToken token = null;
@@ -19159,7 +19165,8 @@ public class ActivityManagerService extends IActivityManager.Stub
token = (IntentCreatorToken) binder;
}
return token != null && token.mKeyFields.equals(
- new Key(token.mKeyFields.mCreatorUid, intent));
+ new Key(token.mKeyFields.mCreatorUid, token.mKeyFields.mCreatorPackage,
+ intent));
}
@Override
@@ -19183,8 +19190,9 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private static class Key {
- private Key(int creatorUid, Intent intent) {
+ private Key(int creatorUid, String creatorPackage, Intent intent) {
this.mCreatorUid = creatorUid;
+ this.mCreatorPackage = creatorPackage;
this.mAction = intent.getAction();
this.mData = intent.getData();
this.mType = intent.getType();
@@ -19201,6 +19209,7 @@ public class ActivityManagerService extends IActivityManager.Stub
}
private final int mCreatorUid;
+ private final String mCreatorPackage;
private final String mAction;
private final Uri mData;
private final String mType;
@@ -19214,17 +19223,20 @@ public class ActivityManagerService extends IActivityManager.Stub
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Key key = (Key) o;
- return mCreatorUid == key.mCreatorUid && mFlags == key.mFlags && Objects.equals(
- mAction, key.mAction) && Objects.equals(mData, key.mData)
- && Objects.equals(mType, key.mType) && Objects.equals(mPackage,
- key.mPackage) && Objects.equals(mComponent, key.mComponent)
+ return mCreatorUid == key.mCreatorUid && mFlags == key.mFlags
+ && Objects.equals(mCreatorPackage, key.mCreatorPackage)
+ && Objects.equals(mAction, key.mAction)
+ && Objects.equals(mData, key.mData)
+ && Objects.equals(mType, key.mType)
+ && Objects.equals(mPackage, key.mPackage)
+ && Objects.equals(mComponent, key.mComponent)
&& Objects.equals(mClipDataUris, key.mClipDataUris);
}
@Override
public int hashCode() {
- return Objects.hash(mCreatorUid, mAction, mData, mType, mPackage, mComponent,
- mFlags, mClipDataUris);
+ return Objects.hash(mCreatorUid, mCreatorPackage, mAction, mData, mType, mPackage,
+ mComponent, mFlags, mClipDataUris);
}
}
}
@@ -19235,7 +19247,7 @@ public class ActivityManagerService extends IActivityManager.Stub
* @param intent The given intent
* @hide
*/
- public void addCreatorToken(@Nullable Intent intent) {
+ public void addCreatorToken(@Nullable Intent intent, String creatorPackage) {
if (!preventIntentRedirect()) return;
if (intent == null || intent.getExtraIntentKeys() == null) return;
@@ -19248,7 +19260,7 @@ public class ActivityManagerService extends IActivityManager.Stub
continue;
}
Slog.wtf(TAG, "A creator token is added to an intent.");
- IBinder creatorToken = createIntentCreatorToken(extraIntent);
+ IBinder creatorToken = createIntentCreatorToken(extraIntent, creatorPackage);
if (creatorToken != null) {
extraIntent.setCreatorToken(creatorToken);
}
@@ -19261,15 +19273,15 @@ public class ActivityManagerService extends IActivityManager.Stub
}
}
- private IBinder createIntentCreatorToken(Intent intent) {
+ private IBinder createIntentCreatorToken(Intent intent, String creatorPackage) {
if (IntentCreatorToken.isValid(intent)) return null;
int creatorUid = getCallingUid();
- IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, intent);
+ IntentCreatorToken.Key key = new IntentCreatorToken.Key(creatorUid, creatorPackage, intent);
IntentCreatorToken token;
synchronized (sIntentCreatorTokenCache) {
WeakReference<IntentCreatorToken> ref = sIntentCreatorTokenCache.get(key);
if (ref == null || ref.get() == null) {
- token = new IntentCreatorToken(creatorUid, intent);
+ token = new IntentCreatorToken(creatorUid, creatorPackage, intent);
sIntentCreatorTokenCache.put(key, token.mRef);
} else {
token = ref.get();
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 6857b6bcde15..3fb06a75d79f 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -432,6 +432,14 @@ public final class PendingIntentRecord extends IIntentSender.Stub {
}
}
+ /**
+ * get package name of the PendingIntent sender.
+ * @return package name of the PendingIntent sender.
+ */
+ public String getPackageName() {
+ return key.packageName;
+ }
+
@Deprecated
public int sendInner(int code, Intent intent, String resolvedType, IBinder allowlistToken,
IIntentReceiver finishedReceiver, String requiredPermission, IBinder resultTo,
diff --git a/services/core/java/com/android/server/uri/NeededUriGrants.java b/services/core/java/com/android/server/uri/NeededUriGrants.java
index 8c8f55304fbb..2fe61e00c97e 100644
--- a/services/core/java/com/android/server/uri/NeededUriGrants.java
+++ b/services/core/java/com/android/server/uri/NeededUriGrants.java
@@ -17,10 +17,13 @@
package com.android.server.uri;
import android.util.ArraySet;
+import android.util.Slog;
import android.util.proto.ProtoOutputStream;
import com.android.server.am.NeededUriGrantsProto;
+import java.util.Objects;
+
/** List of {@link GrantUri} a process needs. */
public class NeededUriGrants {
final String targetPkg;
@@ -35,6 +38,20 @@ public class NeededUriGrants {
this.uris = new ArraySet<>();
}
+ public void merge(NeededUriGrants other) {
+ if (other == null) return;
+ if (!Objects.equals(this.targetPkg, other.targetPkg)
+ || this.targetUid != other.targetUid || this.flags != other.flags) {
+ Slog.wtf("NeededUriGrants",
+ "The other NeededUriGrants does not share the same targetUid, targetPkg or "
+ + "flags. It cannot be merged into this NeededUriGrants. This "
+ + "NeededUriGrants: " + this.toStringWithoutUri()
+ + ". Other NeededUriGrants: " + other.toStringWithoutUri());
+ } else {
+ this.uris.addAll(other.uris);
+ }
+ }
+
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
long token = proto.start(fieldId);
proto.write(NeededUriGrantsProto.TARGET_PACKAGE, targetPkg);
@@ -47,4 +64,12 @@ public class NeededUriGrants {
}
proto.end(token);
}
+
+ public String toStringWithoutUri() {
+ return "NeededUriGrants{" +
+ "targetPkg='" + targetPkg + '\'' +
+ ", targetUid=" + targetUid +
+ ", flags=" + flags +
+ '}';
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index ae30fcde39e1..d119a08b0c85 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -442,8 +442,6 @@ class ActivityClientController extends IActivityClientController.Stub {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- mService.mAmInternal.addCreatorToken(resultData);
-
final ActivityRecord r;
synchronized (mGlobalLock) {
r = ActivityRecord.isInRootTaskLocked(token);
@@ -502,6 +500,8 @@ class ActivityClientController extends IActivityClientController.Stub {
r.app.setLastActivityFinishTimeIfNeeded(SystemClock.uptimeMillis());
}
+ mService.mAmInternal.addCreatorToken(resultData, r.packageName);
+
final long origId = Binder.clearCallingIdentity();
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "finishActivity");
try {
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 35ec5adf54b0..f71fe1973aca 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -25,6 +25,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static android.os.FactoryTest.FACTORY_TEST_LOW_LEVEL;
+import static com.android.server.wm.ActivityStarter.Request.DEFAULT_INTENT_CREATOR_UID;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
@@ -442,6 +443,17 @@ public class ActivityStartController {
0 /* startFlags */, null /* profilerInfo */, userId, filterCallingUid,
callingPid);
aInfo = mService.mAmInternal.getActivityInfoForUser(aInfo, userId);
+ int creatorUid = DEFAULT_INTENT_CREATOR_UID;
+ String creatorPackage = null;
+ if (ActivityManagerService.IntentCreatorToken.isValid(intent)) {
+ ActivityManagerService.IntentCreatorToken creatorToken =
+ (ActivityManagerService.IntentCreatorToken) intent.getCreatorToken();
+ if (creatorToken.getCreatorUid() != filterCallingUid) {
+ creatorUid = creatorToken.getCreatorUid();
+ creatorPackage = creatorToken.getCreatorPackage();
+ }
+ // leave creatorUid as -1 if the intent creator is the same as the launcher
+ }
if (aInfo != null) {
try {
@@ -455,6 +467,24 @@ public class ActivityStartController {
return START_CANCELED;
}
+ if (creatorUid != DEFAULT_INTENT_CREATOR_UID) {
+ try {
+ NeededUriGrants creatorIntentGrants = mSupervisor.mService.mUgmInternal
+ .checkGrantUriPermissionFromIntent(intent, creatorUid,
+ aInfo.applicationInfo.packageName,
+ UserHandle.getUserId(aInfo.applicationInfo.uid));
+ if (intentGrants == null) {
+ intentGrants = creatorIntentGrants;
+ } else {
+ intentGrants.merge(creatorIntentGrants);
+ }
+ } catch (SecurityException securityException) {
+ ActivityStarter.logForIntentRedirect(
+ "Creator URI Grant Caused Exception.", intent, creatorUid,
+ creatorPackage, filterCallingUid, callingPackage);
+ // TODO b/368559093 - rethrow the securityException.
+ }
+ }
if ((aInfo.applicationInfo.privateFlags
& ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) {
throw new IllegalArgumentException(
@@ -478,6 +508,8 @@ public class ActivityStartController {
.setCallingUid(callingUid)
.setCallingPackage(callingPackage)
.setCallingFeatureId(callingFeatureId)
+ .setIntentCreatorUid(creatorUid)
+ .setIntentCreatorPackage(creatorPackage)
.setRealCallingPid(realCallingPid)
.setRealCallingUid(realCallingUid)
.setActivityOptions(checkedOptions)
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 87fa62ac0e3b..7e6abe121dd3 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -131,6 +131,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.protolog.ProtoLog;
+import com.android.server.am.ActivityManagerService.IntentCreatorToken;
import com.android.server.am.PendingIntentRecord;
import com.android.server.pm.InstantAppResolver;
import com.android.server.pm.PackageArchiver;
@@ -383,6 +384,7 @@ class ActivityStarter {
private static final int DEFAULT_CALLING_PID = 0;
static final int DEFAULT_REAL_CALLING_UID = -1;
static final int DEFAULT_REAL_CALLING_PID = 0;
+ static final int DEFAULT_INTENT_CREATOR_UID = -1;
IApplicationThread caller;
Intent intent;
@@ -403,6 +405,8 @@ class ActivityStarter {
@Nullable String callingFeatureId;
int realCallingPid = DEFAULT_REAL_CALLING_PID;
int realCallingUid = DEFAULT_REAL_CALLING_UID;
+ int intentCreatorUid = DEFAULT_INTENT_CREATOR_UID;
+ String intentCreatorPackage;
int startFlags;
SafeActivityOptions activityOptions;
boolean ignoreTargetSecurity;
@@ -463,6 +467,8 @@ class ActivityStarter {
callingPid = DEFAULT_CALLING_PID;
callingUid = DEFAULT_CALLING_UID;
callingPackage = null;
+ intentCreatorUid = DEFAULT_INTENT_CREATOR_UID;
+ intentCreatorPackage = null;
callingFeatureId = null;
realCallingPid = DEFAULT_REAL_CALLING_PID;
realCallingUid = DEFAULT_REAL_CALLING_UID;
@@ -555,12 +561,14 @@ class ActivityStarter {
// "resolved" calling UID, where we try our best to identify the
// actual caller that is starting this activity
int resolvedCallingUid = callingUid;
+ String resolvedCallingPackage = callingPackage;
if (caller != null) {
synchronized (supervisor.mService.mGlobalLock) {
final WindowProcessController callerApp = supervisor.mService
.getProcessController(caller);
if (callerApp != null) {
resolvedCallingUid = callerApp.mInfo.uid;
+ resolvedCallingPackage = callerApp.mInfo.packageName;
}
}
}
@@ -596,7 +604,23 @@ class ActivityStarter {
// Collect information about the target of the Intent.
activityInfo = supervisor.resolveActivity(intent, resolveInfo, startFlags,
profilerInfo);
-
+ // Check if the Intent was redirected
+ if ((intent.getExtendedFlags() & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN)
+ != 0) {
+ ActivityStarter.logForIntentRedirect(
+ "Unparceled intent does not have a creator token set.", intent,
+ intentCreatorUid,
+ intentCreatorPackage, resolvedCallingUid, resolvedCallingPackage);
+ // TODO b/368559093 - eventually ramp up to throw SecurityException
+ }
+ if (IntentCreatorToken.isValid(intent)) {
+ IntentCreatorToken creatorToken = (IntentCreatorToken) intent.getCreatorToken();
+ if (creatorToken.getCreatorUid() != resolvedCallingUid) {
+ intentCreatorUid = creatorToken.getCreatorUid();
+ intentCreatorPackage = creatorToken.getCreatorPackage();
+ }
+ // leave intentCreatorUid as -1 if the intent creator is the same as the launcher
+ }
// Carefully collect grants without holding lock
if (activityInfo != null) {
if (android.security.Flags.contentUriPermissionApis()) {
@@ -606,11 +630,52 @@ class ActivityStarter {
UserHandle.getUserId(activityInfo.applicationInfo.uid),
activityInfo.requireContentUriPermissionFromCaller,
/* requestHashCode */ this.hashCode());
+ if (intentCreatorUid != DEFAULT_INTENT_CREATOR_UID) {
+ try {
+ NeededUriGrants creatorIntentGrants = supervisor.mService.mUgmInternal
+ .checkGrantUriPermissionFromIntent(intent, intentCreatorUid,
+ activityInfo.applicationInfo.packageName,
+ UserHandle.getUserId(activityInfo.applicationInfo.uid),
+ activityInfo.requireContentUriPermissionFromCaller,
+ /* requestHashCode */ this.hashCode());
+ if (intentGrants == null) {
+ intentGrants = creatorIntentGrants;
+ } else {
+ intentGrants.merge(creatorIntentGrants);
+ }
+ } catch (SecurityException securityException) {
+ ActivityStarter.logForIntentRedirect(
+ "Creator URI Grant Caused Exception.", intent, intentCreatorUid,
+ intentCreatorPackage, resolvedCallingUid,
+ resolvedCallingPackage);
+ // TODO b/368559093 - rethrow the securityException.
+ }
+ }
} else {
intentGrants = supervisor.mService.mUgmInternal
.checkGrantUriPermissionFromIntent(intent, resolvedCallingUid,
activityInfo.applicationInfo.packageName,
UserHandle.getUserId(activityInfo.applicationInfo.uid));
+ if (intentCreatorUid != DEFAULT_INTENT_CREATOR_UID && intentGrants != null) {
+ try {
+ NeededUriGrants creatorIntentGrants = supervisor.mService.mUgmInternal
+ .checkGrantUriPermissionFromIntent(intent, intentCreatorUid,
+ activityInfo.applicationInfo.packageName,
+ UserHandle.getUserId(
+ activityInfo.applicationInfo.uid));
+ if (intentGrants == null) {
+ intentGrants = creatorIntentGrants;
+ } else {
+ intentGrants.merge(creatorIntentGrants);
+ }
+ } catch (SecurityException securityException) {
+ ActivityStarter.logForIntentRedirect(
+ "Creator URI Grant Caused Exception.", intent, intentCreatorUid,
+ intentCreatorPackage, resolvedCallingUid,
+ resolvedCallingPackage);
+ // TODO b/368559093 - rethrow the securityException.
+ }
+ }
}
}
}
@@ -977,7 +1042,9 @@ class ActivityStarter {
int requestCode = request.requestCode;
int callingPid = request.callingPid;
int callingUid = request.callingUid;
- String callingPackage = request.callingPackage;
+ int intentCreatorUid = request.intentCreatorUid;
+ String intentCreatorPackage = request.intentCreatorPackage;
+ String intentCallingPackage = request.callingPackage;
String callingFeatureId = request.callingFeatureId;
final int realCallingPid = request.realCallingPid;
final int realCallingUid = request.realCallingUid;
@@ -1062,7 +1129,7 @@ class ActivityStarter {
// launched in the app flow to redirect to an activity picked by the user, where
// we want the final activity to consider it to have been launched by the
// previous app activity.
- callingPackage = sourceRecord.launchedFromPackage;
+ intentCallingPackage = sourceRecord.launchedFromPackage;
callingFeatureId = sourceRecord.launchedFromFeatureId;
}
}
@@ -1084,7 +1151,7 @@ class ActivityStarter {
if (packageArchiver.isIntentResolvedToArchivedApp(intent, mRequest.userId)) {
err = packageArchiver
.requestUnarchiveOnActivityStart(
- intent, callingPackage, mRequest.userId, realCallingUid);
+ intent, intentCallingPackage, mRequest.userId, realCallingUid);
}
}
}
@@ -1143,7 +1210,7 @@ class ActivityStarter {
boolean abort;
try {
abort = !mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
- requestCode, callingPid, callingUid, callingPackage, callingFeatureId,
+ requestCode, callingPid, callingUid, intentCallingPackage, callingFeatureId,
request.ignoreTargetSecurity, inTask != null, callerApp, resultRecord,
resultRootTask);
} catch (SecurityException e) {
@@ -1171,7 +1238,47 @@ class ActivityStarter {
abort |= !mService.mIntentFirewall.checkStartActivity(intent, callingUid,
callingPid, resolvedType, aInfo.applicationInfo);
abort |= !mService.getPermissionPolicyInternal().checkStartActivity(intent, callingUid,
- callingPackage);
+ intentCallingPackage);
+
+ if (intentCreatorUid != Request.DEFAULT_INTENT_CREATOR_UID) {
+ try {
+ if (!mSupervisor.checkStartAnyActivityPermission(intent, aInfo, resultWho,
+ requestCode, 0, intentCreatorUid, intentCreatorPackage, "",
+ request.ignoreTargetSecurity, inTask != null, null, resultRecord,
+ resultRootTask)) {
+ logForIntentRedirect("Creator checkStartAnyActivityPermission Caused abortion.",
+ intent, intentCreatorUid, intentCreatorPackage, callingUid,
+ intentCallingPackage);
+ // TODO b/368559093 - set abort to true.
+ // abort = true;
+ }
+ } catch (SecurityException e) {
+ logForIntentRedirect("Creator checkStartAnyActivityPermission Caused Exception.",
+ intent, intentCreatorUid, intentCreatorPackage, callingUid,
+ intentCallingPackage);
+ // TODO b/368559093 - rethrow the exception.
+ //throw e;
+ }
+ if (!mService.mIntentFirewall.checkStartActivity(intent, intentCreatorUid, 0,
+ resolvedType, aInfo.applicationInfo)) {
+ logForIntentRedirect("Creator IntentFirewall.checkStartActivity Caused abortion.",
+ intent, intentCreatorUid, intentCreatorPackage, callingUid,
+ intentCallingPackage);
+ // TODO b/368559093 - set abort to true.
+ // abort = true;
+ }
+
+ if (!mService.getPermissionPolicyInternal().checkStartActivity(intent, intentCreatorUid,
+ intentCreatorPackage)) {
+ logForIntentRedirect(
+ "Creator PermissionPolicyService.checkStartActivity Caused abortion.",
+ intent, intentCreatorUid, intentCreatorPackage, callingUid,
+ intentCallingPackage);
+ // TODO b/368559093 - set abort to true.
+ // abort = true;
+ }
+ intent.removeCreatorTokenInfo();
+ }
// Merge the two options bundles, while realCallerOptions takes precedence.
ActivityOptions checkedOptions = options != null
@@ -1188,7 +1295,7 @@ class ActivityStarter {
balController.checkBackgroundActivityStart(
callingUid,
callingPid,
- callingPackage,
+ intentCallingPackage,
realCallingUid,
realCallingPid,
callerApp,
@@ -1209,7 +1316,7 @@ class ActivityStarter {
if (request.allowPendingRemoteAnimationRegistryLookup) {
checkedOptions = mService.getActivityStartController()
.getPendingRemoteAnimationRegistry()
- .overrideOptionsIfNeeded(callingPackage, checkedOptions);
+ .overrideOptionsIfNeeded(intentCallingPackage, checkedOptions);
}
if (mService.mController != null) {
try {
@@ -1225,7 +1332,8 @@ class ActivityStarter {
final TaskDisplayArea suggestedLaunchDisplayArea =
computeSuggestedLaunchDisplayArea(inTask, sourceRecord, checkedOptions);
- mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags, callingPackage,
+ mInterceptor.setStates(userId, realCallingPid, realCallingUid, startFlags,
+ intentCallingPackage,
callingFeatureId);
if (mInterceptor.intercept(intent, rInfo, aInfo, resolvedType, inTask, inTaskFragment,
callingPid, callingUid, checkedOptions, suggestedLaunchDisplayArea)) {
@@ -1263,7 +1371,8 @@ class ActivityStarter {
if (mService.getPackageManagerInternalLocked().isPermissionsReviewRequired(
aInfo.packageName, userId)) {
final IIntentSender target = mService.getIntentSenderLocked(
- ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, callingFeatureId,
+ ActivityManager.INTENT_SENDER_ACTIVITY, intentCallingPackage,
+ callingFeatureId,
callingUid, userId, null, null, 0, new Intent[]{intent},
new String[]{resolvedType}, PendingIntent.FLAG_CANCEL_CURRENT
| PendingIntent.FLAG_ONE_SHOT, null);
@@ -1326,7 +1435,8 @@ class ActivityStarter {
// app [on install success].
if (rInfo != null && rInfo.auxiliaryInfo != null) {
intent = createLaunchIntent(rInfo.auxiliaryInfo, request.ephemeralIntent,
- callingPackage, callingFeatureId, verificationBundle, resolvedType, userId);
+ intentCallingPackage, callingFeatureId, verificationBundle, resolvedType,
+ userId);
resolvedType = null;
callingUid = realCallingUid;
callingPid = realCallingPid;
@@ -1349,7 +1459,7 @@ class ActivityStarter {
.setCaller(callerApp)
.setLaunchedFromPid(callingPid)
.setLaunchedFromUid(callingUid)
- .setLaunchedFromPackage(callingPackage)
+ .setLaunchedFromPackage(intentCallingPackage)
.setLaunchedFromFeature(callingFeatureId)
.setIntent(intent)
.setResolvedType(resolvedType)
@@ -3295,6 +3405,16 @@ class ActivityStarter {
return this;
}
+ ActivityStarter setIntentCreatorUid(int uid) {
+ mRequest.intentCreatorUid = uid;
+ return this;
+ }
+
+ ActivityStarter setIntentCreatorPackage(String intentCreatorPackage) {
+ mRequest.intentCreatorPackage = intentCreatorPackage;
+ return this;
+ }
+
/**
* Sets the pid of the caller who requested to launch the activity.
*
@@ -3454,4 +3574,19 @@ class ActivityStarter {
pw.print(" mInTaskFragment=");
pw.println(mInTaskFragment);
}
+
+ static void logForIntentRedirect(String message, Intent intent, int intentCreatorUid,
+ String intentCreatorPackage, int callingUid, String callingPackage) {
+ String msg = getIntentRedirectPreventedLogMessage(message, intent, intentCreatorUid,
+ intentCreatorPackage, callingUid, callingPackage);
+ Slog.wtf(TAG, msg);
+ }
+
+ private static String getIntentRedirectPreventedLogMessage(String message, Intent intent,
+ int intentCreatorUid, String intentCreatorPackage, int callingUid,
+ String callingPackage) {
+ return "[IntentRedirect]" + message + " intentCreatorUid: " + intentCreatorUid
+ + "; intentCreatorPackage: " + intentCreatorPackage + "; callingUid: " + callingUid
+ + "; callingPackage: " + callingPackage + "; intent: " + intent;
+ }
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 3dfc8f4e5bf9..de6c93ff363b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1228,7 +1228,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo,
String resultWho, int requestCode, int startFlags, ProfilerInfo profilerInfo,
Bundle bOptions) {
- mAmInternal.addCreatorToken(intent);
+ mAmInternal.addCreatorToken(intent, callingPackage);
return startActivityAsUser(caller, callingPackage, callingFeatureId, intent, resolvedType,
resultTo, resultWho, requestCode, startFlags, profilerInfo, bOptions,
UserHandle.getCallingUserId());
@@ -1243,7 +1243,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
enforceNotIsolatedCaller(reason);
if (intents != null) {
for (Intent intent : intents) {
- mAmInternal.addCreatorToken(intent);
+ mAmInternal.addCreatorToken(intent, callingPackage);
}
}
userId = handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, reason);
@@ -1275,7 +1275,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
@Nullable String callingFeatureId, Intent intent, String resolvedType,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
ProfilerInfo profilerInfo, Bundle bOptions, int userId, boolean validateIncomingUser) {
- mAmInternal.addCreatorToken(intent);
+ mAmInternal.addCreatorToken(intent, callingPackage);
final SafeActivityOptions opts = SafeActivityOptions.fromBundle(bOptions);
assertPackageMatchesCallingUid(callingPackage);
@@ -1330,7 +1330,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
}
// Remove existing mismatch flag so it can be properly updated later
fillInIntent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
- mAmInternal.addCreatorToken(fillInIntent);
}
if (!(target instanceof PendingIntentRecord)) {
@@ -1339,6 +1338,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
PendingIntentRecord pir = (PendingIntentRecord) target;
+ if (fillInIntent != null) {
+ mAmInternal.addCreatorToken(fillInIntent, pir.getPackageName());
+ }
+
synchronized (mGlobalLock) {
// If this is coming from the currently resumed activity, it is
// effectively saying that app switches are allowed at this point.
@@ -1349,6 +1352,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
mAppSwitchesState = APP_SWITCH_ALLOW;
}
}
+
return pir.sendInner(caller, 0, fillInIntent, resolvedType, allowlistToken, null, null,
resultTo, resultWho, requestCode, flagsMask, flagsValues, bOptions);
}
@@ -1361,8 +1365,6 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
throw new IllegalArgumentException("File descriptors passed in Intent");
}
- mAmInternal.addCreatorToken(intent);
-
SafeActivityOptions options = SafeActivityOptions.fromBundle(bOptions);
synchronized (mGlobalLock) {
@@ -1376,6 +1378,9 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
SafeActivityOptions.abort(options);
return false;
}
+
+ mAmInternal.addCreatorToken(intent, r.packageName);
+
intent = new Intent(intent);
// Remove existing mismatch flag so it can be properly updated later
intent.removeExtendedFlags(Intent.EXTENDED_FLAG_FILTER_MISMATCH);
diff --git a/services/core/java/com/android/server/wm/AppTaskImpl.java b/services/core/java/com/android/server/wm/AppTaskImpl.java
index 4d17ed24e734..eee4c86bc483 100644
--- a/services/core/java/com/android/server/wm/AppTaskImpl.java
+++ b/services/core/java/com/android/server/wm/AppTaskImpl.java
@@ -160,7 +160,7 @@ class AppTaskImpl extends IAppTask.Stub {
Intent intent, String resolvedType, Bundle bOptions) {
checkCallerOrSystemOrRoot();
mService.assertPackageMatchesCallingUid(callingPackage);
- mService.mAmInternal.addCreatorToken(intent);
+ mService.mAmInternal.addCreatorToken(intent, callingPackage);
int callingUser = UserHandle.getCallingUserId();
Task task;
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
index 6ccc03709b4f..2a825f35bf62 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceTest.java
@@ -107,6 +107,7 @@ import android.os.IBinder;
import android.os.IProgressListener;
import android.os.Looper;
import android.os.Message;
+import android.os.Parcel;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
@@ -1309,12 +1310,13 @@ public class ActivityManagerServiceTest {
intent.putExtra("EXTRA_INTENT0", extraIntent);
intent.collectExtraIntentKeys();
- mAms.addCreatorToken(intent);
+ mAms.addCreatorToken(intent, TEST_PACKAGE);
ActivityManagerService.IntentCreatorToken token =
(ActivityManagerService.IntentCreatorToken) extraIntent.getCreatorToken();
assertThat(token).isNotNull();
assertThat(token.getCreatorUid()).isEqualTo(mInjector.getCallingUid());
+ assertThat(token.getCreatorPackage()).isEqualTo(TEST_PACKAGE);
}
@Test
@@ -1330,7 +1332,7 @@ public class ActivityManagerServiceTest {
fillinIntent.collectExtraIntentKeys();
intent.fillIn(fillinIntent, FILL_IN_ACTION);
- mAms.addCreatorToken(fillinIntent);
+ mAms.addCreatorToken(fillinIntent, TEST_PACKAGE);
fillinExtraIntent = intent.getParcelableExtra("FILLIN_EXTRA_INTENT0", Intent.class);
@@ -1338,6 +1340,49 @@ public class ActivityManagerServiceTest {
(ActivityManagerService.IntentCreatorToken) fillinExtraIntent.getCreatorToken();
assertThat(token).isNotNull();
assertThat(token.getCreatorUid()).isEqualTo(mInjector.getCallingUid());
+ assertThat(token.getCreatorPackage()).isEqualTo(TEST_PACKAGE);
+ }
+
+ @Test
+ @RequiresFlagsEnabled(android.security.Flags.FLAG_PREVENT_INTENT_REDIRECT)
+ public void testCheckCreatorToken() {
+ Intent intent = new Intent();
+ Intent extraIntent = new Intent("EXTRA_INTENT_ACTION");
+ intent.putExtra("EXTRA_INTENT", extraIntent);
+
+ intent.collectExtraIntentKeys();
+
+ // mimic client hack and sneak in an extra intent without going thru collectExtraIntentKeys.
+ Intent extraIntent2 = new Intent("EXTRA_INTENT_ACTION2");
+ intent.putExtra("EXTRA_INTENT2", extraIntent2);
+
+ // mock parceling on the client side, unparcling on the system server side, then
+ // addCreatorToken on system server side.
+ final Parcel parcel = Parcel.obtain();
+ intent.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ Intent newIntent = new Intent();
+ newIntent.readFromParcel(parcel);
+ intent = newIntent;
+ mAms.addCreatorToken(intent, TEST_PACKAGE);
+ // entering the target app's process.
+ intent.checkCreatorToken();
+
+ Intent extraIntent3 = new Intent("EXTRA_INTENT_ACTION3");
+ intent.putExtra("EXTRA_INTENT3", extraIntent3);
+
+ extraIntent = intent.getParcelableExtra("EXTRA_INTENT", Intent.class);
+ extraIntent2 = intent.getParcelableExtra("EXTRA_INTENT2", Intent.class);
+ extraIntent3 = intent.getParcelableExtra("EXTRA_INTENT3", Intent.class);
+
+ assertThat(extraIntent.getExtendedFlags()
+ & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN).isEqualTo(0);
+ // sneaked in intent should have EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN set.
+ assertThat(extraIntent2.getExtendedFlags()
+ & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN).isNotEqualTo(0);
+ // local created intent should not have EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN set.
+ assertThat(extraIntent3.getExtendedFlags()
+ & Intent.EXTENDED_FLAG_MISSING_CREATOR_OR_INVALID_TOKEN).isEqualTo(0);
}
private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq,