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

Commit 126e7839 authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by android-build-merger
Browse files

Merge "Close open sockets when enabling firewall rules." into nyc-dev am: b414eb8d

am: f35865b7

* commit 'f35865b7':
  Close open sockets when enabling firewall rules.

Change-Id: I3a1a13f20322d0e93f3cc083c2abb63d05fd68f5
parents 3ca9165d f35865b7
Loading
Loading
Loading
Loading
+85 −15
Original line number Diff line number Diff line
@@ -72,6 +72,7 @@ import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
import android.os.StrictMode;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -2047,6 +2048,65 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }
    }

    private void closeSocketsForFirewallChain(int chain, String chainName) {
        // UID ranges to close sockets on.
        UidRange[] ranges;
        // UID ranges whose sockets we won't touch.
        int[] exemptUids;

        SparseIntArray rules = getUidFirewallRules(chain);
        int numUids = 0;

        if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
            // Close all sockets on all non-system UIDs...
            ranges = new UidRange[] {
                // TODO: is there a better way of finding all existing users? If so, we could
                // specify their ranges here.
                new UidRange(Process.FIRST_APPLICATION_UID, Integer.MAX_VALUE),
            };
            // ... except for the UIDs that have allow rules.
            exemptUids = new int[rules.size()];
            for (int i = 0; i < exemptUids.length; i++) {
                if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
                    exemptUids[numUids] = rules.keyAt(i);
                    numUids++;
                }
            }
            // Normally, whitelist chains only contain deny rules, so numUids == exemptUids.length.
            // But the code does not guarantee this in any way, and at least in one case - if we add
            // a UID rule to the firewall, and then disable the firewall - the chains can contain
            // the wrong type of rule. In this case, don't close connections that we shouldn't.
            //
            // TODO: tighten up this code by ensuring we never set the wrong type of rule, and
            // fix setFirewallEnabled to grab mQuotaLock and clear rules.
            if (numUids != exemptUids.length) {
                exemptUids = Arrays.copyOf(exemptUids, numUids);
            }
        } else {
            // Close sockets for every UID that has a deny rule...
            ranges = new UidRange[rules.size()];
            for (int i = 0; i < ranges.length; i++) {
                if (rules.valueAt(i) == NetworkPolicyManager.FIREWALL_RULE_DENY) {
                    int uid = rules.keyAt(i);
                    ranges[numUids] = new UidRange(uid, uid);
                    numUids++;
                }
            }
            // As above; usually numUids == ranges.length, but not always.
            if (numUids != ranges.length) {
                ranges = Arrays.copyOf(ranges, numUids);
            }
            // ... with no exceptions.
            exemptUids = new int[0];
        }

        try {
            mNetdService.socketDestroy(ranges, exemptUids);
        } catch(RemoteException | ServiceSpecificException e) {
            Slog.e(TAG, "Error closing sockets after enabling chain " + chainName + ": " + e);
        }
    }

    @Override
    public void setFirewallChainEnabled(int chain, boolean enable) {
        enforceSystemUid();
@@ -2059,7 +2119,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
            mFirewallChainStates.put(chain, enable);

            final String operation = enable ? "enable_chain" : "disable_chain";
            try {
            String chainName;
            switch(chain) {
                case FIREWALL_CHAIN_STANDBY:
@@ -2074,10 +2133,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                default:
                    throw new IllegalArgumentException("Bad child chain: " + chain);
            }

            try {
                mConnector.execute("firewall", operation, chainName);
            } catch (NativeDaemonConnectorException e) {
                throw e.rethrowAsParcelableException();
            }

            // Close any sockets that were opened by the affected UIDs. This has to be done after
            // disabling network connectivity, in case they react to the socket close by reopening
            // the connection and race with the iptables commands that enable the firewall. All
            // whitelist and blacklist chains allow RSTs through.
            if (enable) {
                if (DBG) Slog.d(TAG, "Closing sockets after enabling chain " + chainName);
                closeSocketsForFirewallChain(chain, chainName);
            }
        }
    }