Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 39a275b3 authored by Jeff Sharkey's avatar Jeff Sharkey
Browse files

Better protection for system broadcast intents.

When the system sends broadcast intents, it's in a very authoritative
position, and many apps blindly trust the sender.  This is why we've
historically had the concept of "protected broadcasts" which can only
be sent by the system.

However, it's far too easy to send new broadcasts from the system
without adding them to the protected list.  This CL adds logic to help
catch those cases.  Currently it just logs the error and continues
sending the broadcast.

Based on boot analysis of a typical device, add 36 new protected
broadcasts.

Bug: 24571095
Change-Id: Ie2cc6b0b2026e67c64730af897e4eb3e0e8404f1
parent 152ffc2c
Loading
Loading
Loading
Loading
+43 −0
Original line number Diff line number Diff line
@@ -325,6 +325,49 @@

    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED" />
    <protected-broadcast android:name="android.intent.action.AVAILABILITY_CHANGED" />

    <!-- Added in N -->
    <protected-broadcast android:name="android.intent.action.ANR" />
    <protected-broadcast android:name="android.intent.action.CALL" />
    <protected-broadcast android:name="android.intent.action.DROPBOX_ENTRY_ADDED" />
    <protected-broadcast android:name="android.intent.action.INPUT_METHOD_CHANGED" />
    <protected-broadcast android:name="android.intent.action.internal_sim_state_changed" />
    <protected-broadcast android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
    <protected-broadcast android:name="android.intent.action.PRECISE_CALL_STATE" />
    <protected-broadcast android:name="android.intent.action.PRECISE_DATA_CONNECTION_STATE_CHANGED" />
    <protected-broadcast android:name="android.intent.action.SUBSCRIPTION_PHONE_STATE" />
    <protected-broadcast android:name="android.intent.action.USER_INFO_CHANGED" />
    <protected-broadcast android:name="android.intent.action.USER_UNLOCKED" />
    <protected-broadcast android:name="android.intent.action.WALLPAPER_CHANGED" />

    <protected-broadcast android:name="android.app.action.DEVICE_POLICY_MANAGER_STATE_CHANGED" />
    <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
    <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
    <protected-broadcast android:name="android.content.syncmanager.SYNC_ALARM" />
    <protected-broadcast android:name="android.media.INTERNAL_RINGER_MODE_CHANGED_ACTION" />
    <protected-broadcast android:name="android.media.STREAM_DEVICES_CHANGED_ACTION" />
    <protected-broadcast android:name="android.media.STREAM_MUTE_CHANGED_ACTION" />
    <protected-broadcast android:name="android.net.sip.SIP_SERVICE_UP" />
    <protected-broadcast android:name="android.nfc.action.ADAPTER_STATE_CHANGED" />
    <protected-broadcast android:name="android.os.action.CHARGING" />
    <protected-broadcast android:name="android.os.action.DISCHARGING" />
    <protected-broadcast android:name="android.search.action.SEARCHABLES_CHANGED" />
    <protected-broadcast android:name="android.security.STORAGE_CHANGED" />
    <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_REGISTERED" />
    <protected-broadcast android:name="android.telecom.action.PHONE_ACCOUNT_UNREGISTERED" />
    <protected-broadcast android:name="android.telephony.action.CARRIER_CONFIG_CHANGED" />

    <protected-broadcast android:name="com.android.bluetooth.btservice.action.ALARM_WAKEUP" />
    <protected-broadcast android:name="com.android.ims.IMS_SERVICE_UP" />
    <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_POLL" />
    <protected-broadcast android:name="com.android.server.action.NETWORK_STATS_UPDATED" />
    <protected-broadcast android:name="com.android.server.NetworkTimeUpdateService.action.POLL" />
    <protected-broadcast android:name="com.android.server.telecom.intent.action.CALLS_ADD_ENTRY" />
    <protected-broadcast android:name="com.android.settings.location.MODE_CHANGING" />

    <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
    <protected-broadcast android:name="wifi_scan_available" />

    <!-- ====================================================================== -->
    <!--                          RUNTIME PERMISSIONS                           -->
    <!-- ====================================================================== -->
+45 −31
Original line number Diff line number Diff line
@@ -17000,6 +17000,15 @@ public final class ActivityManagerService extends ActivityManagerNative
            }
        }
        final String action = intent.getAction();
        final boolean isProtectedBroadcast;
        try {
            isProtectedBroadcast = AppGlobals.getPackageManager().isProtectedBroadcast(action);
        } catch (RemoteException e) {
            Slog.w(TAG, "Remote exception", e);
            return ActivityManager.BROADCAST_SUCCESS;
        }
        /*
         * Prevent non-system code (defined here to be non-persistent
         * processes) from sending protected broadcasts.
@@ -17009,23 +17018,33 @@ public final class ActivityManagerService extends ActivityManagerNative
            || callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
            || callingAppId == Process.NFC_UID || callingUid == 0) {
            // Always okay.
            // Yell if the system is trying to send a non-protected broadcast.
            // The vast majority of broadcasts sent from system callers should
            // be protected to avoid security holes, so exceptions here should
            // be incredibly rare.
            if (!isProtectedBroadcast
                    && !Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
                // TODO: eventually switch over to hard throw
                Log.wtf(TAG, "Sending non-protected broadcast " + action
                        + " from system", new Throwable());
            }
        } else if (callerApp == null || !callerApp.persistent) {
            try {
                if (AppGlobals.getPackageManager().isProtectedBroadcast(
                        intent.getAction())) {
            if (isProtectedBroadcast) {
                String msg = "Permission Denial: not allowed to send broadcast "
                            + intent.getAction() + " from pid="
                        + action + " from pid="
                        + callingPid + ", uid=" + callingUid;
                Slog.w(TAG, msg);
                throw new SecurityException(msg);
                } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
            } else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)) {
                // Special case for compatibility: we don't want apps to send this,
                // but historically it has not been protected and apps may be using it
                // to poke their own app widget.  So, instead of making it protected,
                // just limit it to the caller.
                if (callerApp == null) {
                    String msg = "Permission Denial: not allowed to send broadcast "
                                + intent.getAction() + " from unknown caller.";
                            + action + " from unknown caller.";
                    Slog.w(TAG, msg);
                    throw new SecurityException(msg);
                } else if (intent.getComponent() != null) {
@@ -17034,7 +17053,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                    if (!intent.getComponent().getPackageName().equals(
                            callerApp.info.packageName)) {
                        String msg = "Permission Denial: not allowed to send broadcast "
                                    + intent.getAction() + " to "
                                + action + " to "
                                + intent.getComponent().getPackageName() + " from "
                                + callerApp.info.packageName;
                        Slog.w(TAG, msg);
@@ -17045,13 +17064,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                    intent.setPackage(callerApp.info.packageName);
                }
            }
            } catch (RemoteException e) {
                Slog.w(TAG, "Remote exception", e);
                return ActivityManager.BROADCAST_SUCCESS;
            }
        }
        final String action = intent.getAction();
        if (action != null) {
            switch (action) {
                case Intent.ACTION_UID_REMOVED:
+8 −1
Original line number Diff line number Diff line
@@ -4093,9 +4093,16 @@ public class PackageManagerService extends IPackageManager.Stub {
    @Override
    public boolean isProtectedBroadcast(String actionName) {
        synchronized (mPackages) {
            return mProtectedBroadcasts.contains(actionName);
            if (mProtectedBroadcasts.contains(actionName)) {
                return true;
            } else if (actionName != null
                    && actionName.startsWith("android.net.netmon.lingerExpired")) {
                // TODO: remove this terrible hack
                return true;
            }
        }
        return false;
    }
    @Override
    public int checkSignatures(String pkg1, String pkg2) {