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

Commit b414eb8d authored by Lorenzo Colitti's avatar Lorenzo Colitti Committed by Android (Google) Code Review
Browse files

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

parents e24708e8 4cb4240b
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);
            }
        }
    }