Merge "Making runtime receivers safer by default"
This commit is contained in:
@@ -10684,6 +10684,8 @@ package android.content {
|
||||
field public static final String PERFORMANCE_HINT_SERVICE = "performance_hint";
|
||||
field public static final String POWER_SERVICE = "power";
|
||||
field public static final String PRINT_SERVICE = "print";
|
||||
field public static final int RECEIVER_EXPORTED = 2; // 0x2
|
||||
field public static final int RECEIVER_NOT_EXPORTED = 4; // 0x4
|
||||
field public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 1; // 0x1
|
||||
field public static final String RESTRICTIONS_SERVICE = "restrictions";
|
||||
field public static final String ROLE_SERVICE = "role";
|
||||
|
||||
@@ -534,8 +534,8 @@ public abstract class Context {
|
||||
| Context.BIND_NOT_PERCEPTIBLE | Context.BIND_NOT_VISIBLE;
|
||||
|
||||
/** @hide */
|
||||
@IntDef(flag = true, prefix = { "RECEIVER_VISIBLE_" }, value = {
|
||||
RECEIVER_VISIBLE_TO_INSTANT_APPS
|
||||
@IntDef(flag = true, prefix = { "RECEIVER_VISIBLE" }, value = {
|
||||
RECEIVER_VISIBLE_TO_INSTANT_APPS, RECEIVER_EXPORTED, RECEIVER_NOT_EXPORTED
|
||||
})
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
public @interface RegisterReceiverFlags {}
|
||||
@@ -545,6 +545,18 @@ public abstract class Context {
|
||||
*/
|
||||
public static final int RECEIVER_VISIBLE_TO_INSTANT_APPS = 0x1;
|
||||
|
||||
/**
|
||||
* Flag for {@link #registerReceiver}: The receiver can receive broadcasts from other Apps.
|
||||
* Has the same behavior as marking a statically registered receiver with "exported=true"
|
||||
*/
|
||||
public static final int RECEIVER_EXPORTED = 0x2;
|
||||
|
||||
/**
|
||||
* Flag for {@link #registerReceiver}: The receiver cannot receive broadcasts from other Apps.
|
||||
* Has the same behavior as marking a statically registered receiver with "exported=false"
|
||||
*/
|
||||
public static final int RECEIVER_NOT_EXPORTED = 0x4;
|
||||
|
||||
/**
|
||||
* Returns an AssetManager instance for the application's package.
|
||||
* <p>
|
||||
@@ -2989,8 +3001,12 @@ public abstract class Context {
|
||||
*
|
||||
* @param receiver The BroadcastReceiver to handle the broadcast.
|
||||
* @param filter Selects the Intent broadcasts to be received.
|
||||
* @param flags Additional options for the receiver. May be 0 or
|
||||
* {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
|
||||
* @param flags Additional options for the receiver. As of
|
||||
* {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
|
||||
* {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
|
||||
* for protected broadcasts, and may additionally specify
|
||||
* {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
|
||||
* specified.
|
||||
*
|
||||
* @return The first sticky intent found that matches <var>filter</var>,
|
||||
* or null if there are none.
|
||||
@@ -3062,8 +3078,12 @@ public abstract class Context {
|
||||
* no permission is required.
|
||||
* @param scheduler Handler identifying the thread that will receive
|
||||
* the Intent. If null, the main thread of the process will be used.
|
||||
* @param flags Additional options for the receiver. May be 0 or
|
||||
* {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS}.
|
||||
* @param flags Additional options for the receiver. As of
|
||||
* {@link android.os.Build.VERSION_CODES#TIRAMISU}, either {@link #RECEIVER_EXPORTED} or
|
||||
* {@link #RECEIVER_NOT_EXPORTED} must be specified if the receiver isn't being registered
|
||||
* for protected broadcasts, and may additionally specify
|
||||
* {@link #RECEIVER_VISIBLE_TO_INSTANT_APPS} if {@link #RECEIVER_EXPORTED} is
|
||||
* specified.
|
||||
*
|
||||
* @return The first sticky intent found that matches <var>filter</var>,
|
||||
* or null if there are none.
|
||||
|
||||
@@ -194,6 +194,9 @@ import android.app.usage.UsageStatsManager;
|
||||
import android.app.usage.UsageStatsManagerInternal;
|
||||
import android.appwidget.AppWidgetManager;
|
||||
import android.appwidget.AppWidgetManagerInternal;
|
||||
import android.compat.Compatibility;
|
||||
import android.compat.annotation.ChangeId;
|
||||
import android.compat.annotation.EnabledSince;
|
||||
import android.content.AttributionSource;
|
||||
import android.content.AutofillOptions;
|
||||
import android.content.BroadcastReceiver;
|
||||
@@ -543,6 +546,16 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
static final String EXTRA_DESCRIPTION = "android.intent.extra.DESCRIPTION";
|
||||
static final String EXTRA_BUGREPORT_TYPE = "android.intent.extra.BUGREPORT_TYPE";
|
||||
|
||||
/**
|
||||
* It is now required for apps to explicitly set either
|
||||
* {@link android.content.Context#RECEIVER_EXPORTED} or
|
||||
* {@link android.content.Context#RECEIVER_NOT_EXPORTED} when registering a receiver for an
|
||||
* unprotected broadcast in code.
|
||||
*/
|
||||
@ChangeId
|
||||
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.TIRAMISU)
|
||||
private static final long DYNAMIC_RECEIVER_EXPLICIT_EXPORT_REQUIRED = 161145287L;
|
||||
|
||||
/**
|
||||
* The maximum number of bytes that {@link #setProcessStateSummary} accepts.
|
||||
*
|
||||
@@ -12416,6 +12429,11 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
ProcessRecord callerApp = null;
|
||||
final boolean visibleToInstantApps
|
||||
= (flags & Context.RECEIVER_VISIBLE_TO_INSTANT_APPS) != 0;
|
||||
// Dynamic receivers are exported by default for versions prior to T
|
||||
final boolean exported =
|
||||
((flags & Context.RECEIVER_EXPORTED) != 0
|
||||
|| (!Compatibility.isChangeEnabled(161145287)));
|
||||
|
||||
int callingUid;
|
||||
int callingPid;
|
||||
boolean instantApp;
|
||||
@@ -12452,8 +12470,10 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
noAction.add(null);
|
||||
actions = noAction.iterator();
|
||||
}
|
||||
boolean onlyProtectedBroadcasts = actions.hasNext();
|
||||
|
||||
// Collect stickies of users
|
||||
// Collect stickies of users and check if broadcast is only registered for protected
|
||||
// broadcasts
|
||||
int[] userIds = { UserHandle.USER_ALL, UserHandle.getUserId(callingUid) };
|
||||
while (actions.hasNext()) {
|
||||
String action = actions.next();
|
||||
@@ -12469,6 +12489,31 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
}
|
||||
}
|
||||
}
|
||||
if (onlyProtectedBroadcasts) {
|
||||
try {
|
||||
onlyProtectedBroadcasts &=
|
||||
AppGlobals.getPackageManager().isProtectedBroadcast(action);
|
||||
} catch (RemoteException e) {
|
||||
onlyProtectedBroadcasts = false;
|
||||
Slog.w(TAG, "Remote exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the change is enabled, but neither exported or not exported is set, we need to log
|
||||
// an error so the consumer can know to explicitly set the value for their flag
|
||||
if (!onlyProtectedBroadcasts && (Compatibility.isChangeEnabled(161145287)
|
||||
&& (flags & (Context.RECEIVER_EXPORTED | Context.RECEIVER_NOT_EXPORTED))
|
||||
== 0)) {
|
||||
Slog.e(TAG,
|
||||
callerPackage + ": Targeting T+ (version " + Build.VERSION_CODES.TIRAMISU
|
||||
+ " and above) requires that one of RECEIVER_EXPORTED or "
|
||||
+ "RECEIVER_NOT_EXPORTED be specified when registering a receiver");
|
||||
} else if (((flags & Context.RECEIVER_EXPORTED) != 0) && (
|
||||
(flags & Context.RECEIVER_NOT_EXPORTED) != 0)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Receiver can't specify both RECEIVER_EXPORTED and RECEIVER_NOT_EXPORTED"
|
||||
+ "flag");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12557,7 +12602,8 @@ public class ActivityManagerService extends IActivityManager.Stub
|
||||
+ " callerPackage is " + callerPackage);
|
||||
}
|
||||
BroadcastFilter bf = new BroadcastFilter(filter, rl, callerPackage, callerFeatureId,
|
||||
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps);
|
||||
receiverId, permission, callingUid, userId, instantApp, visibleToInstantApps,
|
||||
exported);
|
||||
if (rl.containsFilter(filter)) {
|
||||
Slog.w(TAG, "Receiver with filter " + filter
|
||||
+ " already registered for pid " + rl.pid
|
||||
|
||||
@@ -34,10 +34,12 @@ final class BroadcastFilter extends IntentFilter {
|
||||
final int owningUserId;
|
||||
final boolean instantApp;
|
||||
final boolean visibleToInstantApp;
|
||||
final boolean exported;
|
||||
|
||||
BroadcastFilter(IntentFilter _filter, ReceiverList _receiverList,
|
||||
String _packageName, String _featureId, String _receiverId, String _requiredPermission,
|
||||
int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp) {
|
||||
int _owningUid, int _userId, boolean _instantApp, boolean _visibleToInstantApp,
|
||||
boolean _exported) {
|
||||
super(_filter);
|
||||
receiverList = _receiverList;
|
||||
packageName = _packageName;
|
||||
@@ -48,6 +50,7 @@ final class BroadcastFilter extends IntentFilter {
|
||||
owningUserId = _userId;
|
||||
instantApp = _instantApp;
|
||||
visibleToInstantApp = _visibleToInstantApp;
|
||||
exported = _exported;
|
||||
}
|
||||
|
||||
public void dumpDebug(ProtoOutputStream proto, long fieldId) {
|
||||
|
||||
@@ -775,6 +775,22 @@ public final class BroadcastQueue {
|
||||
skip = true;
|
||||
}
|
||||
|
||||
// Ensure that broadcasts are only sent to other apps if they are explicitly marked as
|
||||
// exported, or are System level broadcasts
|
||||
if (!skip && !filter.exported && Process.SYSTEM_UID != r.callingUid
|
||||
&& filter.receiverList.uid != r.callingUid) {
|
||||
|
||||
Slog.w(TAG, "Exported Denial: sending "
|
||||
+ r.intent.toString()
|
||||
+ ", action: " + r.intent.getAction()
|
||||
+ " from " + r.callerPackage
|
||||
+ " (uid=" + r.callingUid + ")"
|
||||
+ " due to receiver " + filter.receiverList.app
|
||||
+ " (uid " + filter.receiverList.uid + ")"
|
||||
+ " not specifying RECEIVER_EXPORTED");
|
||||
// skip = true;
|
||||
}
|
||||
|
||||
if (skip) {
|
||||
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user