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

Unverified Commit d0123482 authored by Oliver Scott's avatar Oliver Scott Committed by Michael Bestas
Browse files

Firewall: Transport-based toggle support (1/3)

Update Connectivity with the network transports that UIDs are allowed
to use, e.g. Wi-Fi or Cellular.

Needs corresponding Connectivity and netd changes.

Also includes squashed changes:

(constants from NetworkPolicyManager.java)
Author: Oliver Scott <olivercscott@gmail.com>
Date:   Mon Feb 29 10:02:34 2016 -0800

    fw/b: Add support for allowing/disallowing apps on cellular, vpn and wifi networks

    Dynamically add/remove apps from restricted networking mode's allowlist based on policy and network transport changes

    Change-Id: I526d0058cda71a9e93046d116c0d79093390a85b

Author: Tommy Webb <tommy@calyxinstitute.org>
Date:   Wed Apr 12 13:43:18 2023 -0400

    NPMS: Check if UID is disallowed by transports

    The isUidNetworkingBlocked method now also consults Connectivity as to
    whether the UID is currently disallowed from accessing networks.

    Requires: I2729b61c349ec2812a74d7d1c04b90a58b0f5b88
    Change-Id: I1cf17b837af5f62c97d99127e1811aa58ef734bf

Author: Tommy Webb <tommy@calyxinstitute.org>
Date:   Wed Sep 20 16:26:11 2023 -0400

    Notify about changes to allowed transports

    Add a method to NetworkPolicyCallback to be notified when a UID's
    allowed transports have changed.

    Requires Connectivity change of the same Change-Id.

    Squash with: Ifeb8342698a8ba4ce2453d64dc32590aebca5fe5
    "Track and send allowed transports to Connectivity"

    Change-Id: Ie476f23684b00397197184e965201d6823b28de2

Author: Tommy Webb <tommy@calyxinstitute.org>
Date:   Wed Sep 20 16:38:07 2023 -0400

    Allow Connectivity to report denylist changes

    Rather than calling an API provided by Connectivity to check for
    a UID's presence on the denylist, provide an API that Connectivity
    itself can use to update NetworkPolicyManagerService with the latest
    denied UIDs.

    Requires Connectivity change of the same Change-Id.

    Squash with: I1cf17b837af5f62c97d99127e1811aa58ef734bf
    "NPMS: Check if UID is disallowed by transports"

    Change-Id: I3c3593f110753a3ce02af3739f600190f22e9663

Requires: I79342edbec92090cca20853ba50ea7fd48ec81c2
Change-Id: Ifeb8342698a8ba4ce2453d64dc32590aebca5fe5
parent 807f2ea3
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -266,6 +266,7 @@ package android.net {
    method @Nullable @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public android.telephony.SubscriptionPlan getSubscriptionPlan(@NonNull android.net.NetworkTemplate);
    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidNetworkingBlocked(int, boolean);
    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public boolean isUidRestrictedOnMeteredNetworks(int);
    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void notifyDenylistChanged(@NonNull int[], @NonNull int[]);
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderLimitReached();
    method @RequiresPermission(anyOf={android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, android.Manifest.permission.NETWORK_STACK}) public void notifyStatsProviderWarningReached();
    method @RequiresPermission(android.Manifest.permission.OBSERVE_NETWORK_POLICY) public void registerNetworkPolicyCallback(@Nullable java.util.concurrent.Executor, @NonNull android.net.NetworkPolicyManager.NetworkPolicyCallback);
@@ -274,6 +275,7 @@ package android.net {

  public static interface NetworkPolicyManager.NetworkPolicyCallback {
    method public default void onUidBlockedReasonChanged(int, int);
    method public default void onUidsAllowedTransportsChanged(@NonNull int[], @NonNull long[]);
  }

  public class NetworkWatchlistManager {
+1 −0
Original line number Diff line number Diff line
@@ -26,4 +26,5 @@ oneway interface INetworkPolicyListener {
    void onSubscriptionOverride(int subId, int overrideMask, int overrideValue, in int[] networkTypes);
    void onSubscriptionPlansChanged(int subId, in SubscriptionPlan[] plans);
    void onBlockedReasonChanged(int uid, int oldBlockedReason, int newBlockedReason);
    void onAllowedTransportsChanged(in int[] uids, in long[] allowedTransports);
}
+2 −0
Original line number Diff line number Diff line
@@ -83,4 +83,6 @@ interface INetworkPolicyManager {

    byte[] getBackupPayload(int user);
    void applyRestore(in byte[] payload, int user);

    void notifyDenylistChanged(in int[] uidsAdded, in int[] uidsRemoved);
}
+45 −0
Original line number Diff line number Diff line
@@ -85,6 +85,18 @@ public class NetworkPolicyManager {
     * @hide
     */
    public static final int POLICY_ALLOW_METERED_BACKGROUND = 0x4;
    /** Reject network usage on cellular network
     * @hide
     */
    public static final int POLICY_REJECT_CELLULAR = 0x10000;
    /** Reject network usage on virtual private network
     * @hide
     */
    public static final int POLICY_REJECT_VPN = 0x20000;
    /** Reject network usage on wifi network
     * @hide
     */
    public static final int POLICY_REJECT_WIFI = 0x8000;
    /** Reject network usage on all networks
     * @hide
     */
@@ -387,6 +399,17 @@ public class NetworkPolicyManager {
        }
    }

    /** @hide */
    @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
    @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
    public void notifyDenylistChanged(@NonNull int[] uidsAdded, @NonNull int[] uidsRemoved) {
        try {
            mService.notifyDenylistChanged(uidsAdded, uidsRemoved);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /** @hide */
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
    public void registerListener(INetworkPolicyListener listener) {
@@ -971,6 +994,11 @@ public class NetworkPolicyManager {
         */
        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
        default void onUidBlockedReasonChanged(int uid, int blockedReasons) {}

        /** @hide */
        @SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
        default void onUidsAllowedTransportsChanged(@NonNull int[] uids,
                @NonNull long[] allowedTransports) {}
    }

    /** @hide */
@@ -990,6 +1018,11 @@ public class NetworkPolicyManager {
                dispatchOnUidBlockedReasonChanged(mExecutor, mCallback, uid, newBlockedReasons);
            }
        }

        @Override
        public void onAllowedTransportsChanged(int[] uids, long[] allowedTransports) {
            dispatchOnUidsAllowedTransportsChanged(mExecutor, mCallback, uids, allowedTransports);
        }
    }

    private static void dispatchOnUidBlockedReasonChanged(@Nullable Executor executor,
@@ -1003,6 +1036,17 @@ public class NetworkPolicyManager {
        }
    }

    private static void dispatchOnUidsAllowedTransportsChanged(@Nullable Executor executor,
            @NonNull NetworkPolicyCallback callback, int[] uids, long[] allowedTransports) {
        if (executor == null) {
            callback.onUidsAllowedTransportsChanged(uids, allowedTransports);
        } else {
            executor.execute(PooledLambda.obtainRunnable(
                    NetworkPolicyCallback::onUidsAllowedTransportsChanged,
                    callback, uids, allowedTransports).recycleOnUse());
        }
    }

    /** @hide */
    public static class SubscriptionCallback {
        /**
@@ -1059,5 +1103,6 @@ public class NetworkPolicyManager {
        @Override public void onSubscriptionPlansChanged(int subId, SubscriptionPlan[] plans) { }
        @Override public void onBlockedReasonChanged(int uid,
                int oldBlockedReasons, int newBlockedReasons) { }
        @Override public void onAllowedTransportsChanged(int[] uids, long[] allowedTransports) { }
    }
}
+102 −1
Original line number Diff line number Diff line
@@ -70,6 +70,10 @@ import static android.net.INetd.FIREWALL_RULE_ALLOW;
import static android.net.INetd.FIREWALL_RULE_DENY;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_USB;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
import static android.net.NetworkPolicy.LIMIT_DISABLED;
import static android.net.NetworkPolicy.SNOOZE_NEVER;
import static android.net.NetworkPolicy.WARNING_DISABLED;
@@ -90,7 +94,10 @@ import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
import static android.net.NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_NONE;
import static android.net.NetworkPolicyManager.POLICY_REJECT_ALL;
import static android.net.NetworkPolicyManager.POLICY_REJECT_CELLULAR;
import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
import static android.net.NetworkPolicyManager.POLICY_REJECT_VPN;
import static android.net.NetworkPolicyManager.POLICY_REJECT_WIFI;
import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
import static android.net.NetworkPolicyManager.RULE_NONE;
import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
@@ -571,6 +578,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    final SparseIntArray mUidFirewallRestrictedModeRules = new SparseIntArray();
    @GuardedBy("mUidRulesFirstLock")
    final SparseIntArray mUidFirewallLowPowerStandbyModeRules = new SparseIntArray();
    @GuardedBy("mDisallowedUidsDenylist")
    final Set<Integer> mDisallowedUidsDenylist = new ArraySet<Integer>();

    /** Set of states for the child firewall chains. True if the chain is active. */
    @GuardedBy("mUidRulesFirstLock")
@@ -1113,6 +1122,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
            mAppStandby.addListener(new NetPolicyAppIdleStateChangeListener());
            synchronized (mUidRulesFirstLock) {
                updateRulesForAppIdleParoleUL();
                sendUidsAllowedTransportsUL();
            }

            // Listen for subscriber changes
@@ -1134,6 +1144,70 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    // sync with NetworkCapabilities
    private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
    private static final int MAX_TRANSPORT = TRANSPORT_USB;
    private static final int ALL_VALID_TRANSPORTS;
    static {
        int transports = 0;
        for (int i = MIN_TRANSPORT; i <= MAX_TRANSPORT; ++i) {
            transports |= 1 << i;
        }
        ALL_VALID_TRANSPORTS = transports;
    }

    private static int getAllowedTransportsPackedForUidPolicy(int policy) {
        int allowedTransports = ALL_VALID_TRANSPORTS;
        // Where policy rejects a transport, remove the flags that allow it.
        if ((policy & POLICY_REJECT_VPN) == POLICY_REJECT_VPN) {
            allowedTransports &= ~(1 << TRANSPORT_VPN);
        }
        if ((policy & POLICY_REJECT_WIFI) == POLICY_REJECT_WIFI) {
            allowedTransports &= ~(1 << TRANSPORT_WIFI);
        }
        if ((policy & POLICY_REJECT_CELLULAR) == POLICY_REJECT_CELLULAR) {
            allowedTransports &= ~(1 << TRANSPORT_CELLULAR);
        }
        return allowedTransports;
    }

    @GuardedBy("mUidRulesFirstLock")
    private void sendUidsAllowedTransportsUL() {
        final int size = mUidPolicy.size();
        final int[] uids = new int[size];
        final long[] allowedTransportsPacked = new long[size];
        for (int i = 0; i < size; i++) {
            final int uid = mUidPolicy.keyAt(i);
            final int policy = mUidPolicy.valueAt(i);
            uids[i] = uid;
            allowedTransportsPacked[i] = getAllowedTransportsPackedForUidPolicy(policy);
        }
        dispatchUidsAllowedTransportsUL(uids, allowedTransportsPacked);
    }

    @GuardedBy("mUidRulesFirstLock")
    private void dispatchUidsAllowedTransportsUL(@NonNull final int[] uids,
            @NonNull final long[] transports) {
        final int length = mListeners.beginBroadcast();
        for (int i = 0; i < length; i++) {
            final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
            dispatchUidsAllowedTransportsChanged(listener, uids, transports);
        }
        mListeners.finishBroadcast();
    }

    public void notifyDenylistChanged(@NonNull final int[] uidsAdded,
            @NonNull final int[] uidsRemoved) {
        synchronized (mDisallowedUidsDenylist) {
            for (final int uid : uidsAdded) {
                mDisallowedUidsDenylist.add(uid);
            }
            for (final int uid : uidsRemoved) {
                mDisallowedUidsDenylist.remove(uid);
            }
        }
    }

    public CountDownLatch networkScoreAndNetworkManagementServiceReady() {
        mNetworkManagerReady = true;
        final CountDownLatch initCompleteSignal = new CountDownLatch(1);
@@ -3102,6 +3176,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
    private void setUidPolicyUncheckedUL(int uid, int oldPolicy, int policy, boolean persist) {
        setUidPolicyUncheckedUL(uid, policy, false);

        final long lastAllowedTransportsPacked = getAllowedTransportsPackedForUidPolicy(oldPolicy);
        final long allowedTransportsPacked = getAllowedTransportsPackedForUidPolicy(policy);

        if (lastAllowedTransportsPacked != allowedTransportsPacked) {
            dispatchUidsAllowedTransportsUL(new int[] { uid },
                    new long[] { allowedTransportsPacked });
        }

        final boolean notifyApp;
        if (!isUidValidForAllowlistRulesUL(uid)) {
            notifyApp = false;
@@ -5499,6 +5581,15 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
        }
    }

    private void dispatchUidsAllowedTransportsChanged(INetworkPolicyListener listener, int[] uids,
            long[] allowedTransports) {
        try {
            listener.onAllowedTransportsChanged(uids, allowedTransports);
        } catch (RemoteException ignored) {
            // Ignore if there is an error sending the callback to the client.
        }
    }

    private void dispatchSubscriptionOverride(INetworkPolicyListener listener, int subId,
            int overrideMask, int overrideValue, int[] networkTypes) {
        try {
@@ -5607,9 +5698,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                    final Boolean notifyApp = (Boolean) msg.obj;
                    // First notify internal listeners...
                    final int length = mListeners.beginBroadcast();
                    final int[] uids = new int[] { uid };
                    final long[] allowedTransports =
                            new long[] { getAllowedTransportsPackedForUidPolicy(policy) };
                    for (int i = 0; i < length; i++) {
                        final INetworkPolicyListener listener = mListeners.getBroadcastItem(i);
                        dispatchUidPoliciesChanged(listener, uid, policy);
                        dispatchUidsAllowedTransportsChanged(listener, uids, allowedTransports);
                    }
                    mListeners.finishBroadcast();
                    // ...then apps listening to ACTION_RESTRICT_BACKGROUND_CHANGED
@@ -6247,7 +6342,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {

        mStatLogger.logDurationStat(Stats.IS_UID_NETWORKING_BLOCKED, startTime);

        return blockedReasons != BLOCKED_REASON_NONE;
        if (blockedReasons != BLOCKED_REASON_NONE) {
            return true;
        } else {
            synchronized (mDisallowedUidsDenylist) {
                return mDisallowedUidsDenylist.contains(uid);
            }
        }
    }

    @Override