system/netd: Add support for per app network isolation

* Add a new firewall chain fw_isolated that blocks all network access.

* Legacy ipchains and bpf are both supported.

Change-Id: Iab892d8d3d1803fe2626b2a5966e5646cb8b4922
diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h
index cc5f845..a0e586a 100644
--- a/bpf_progs/netd.h
+++ b/bpf_progs/netd.h
@@ -187,6 +187,9 @@
         if ((enabledRules & POWERSAVE_MATCH) && !(uidRules & POWERSAVE_MATCH)) {
             return BPF_DROP;
         }
+        if ((enabledRules & ISOLATED_MATCH) && (uidRules & ISOLATED_MATCH)) {
+            return BPF_DROP;
+        }
     }
     if (direction == BPF_INGRESS && (uidRules & IIF_MATCH)) {
         // Drops packets not coming from lo nor the whitelisted interface
diff --git a/libnetdbpf/include/netdbpf/bpf_shared.h b/libnetdbpf/include/netdbpf/bpf_shared.h
index 6424c81..4335373 100644
--- a/libnetdbpf/include/netdbpf/bpf_shared.h
+++ b/libnetdbpf/include/netdbpf/bpf_shared.h
@@ -86,6 +86,7 @@
     POWERSAVE_MATCH = (1 << 4),
     IIF_MATCH = (1 << 5),
     IF_BLACKLIST = (1 << 6),
+    ISOLATED_MATCH = (1 << 7),
 };
 
 enum BpfPemissionMatch {
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 7512c09..d15aeb2 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -74,6 +74,7 @@
 const char* FirewallController::LOCAL_DOZABLE = "fw_dozable";
 const char* FirewallController::LOCAL_STANDBY = "fw_standby";
 const char* FirewallController::LOCAL_POWERSAVE = "fw_powersave";
+const char* FirewallController::LOCAL_ISOLATED = "fw_isolated";
 
 // ICMPv6 types that are required for any form of IPv6 connectivity to work. Note that because the
 // fw_dozable chain is called from both INPUT and OUTPUT, this includes both packets that we need
@@ -102,6 +103,7 @@
     res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
     res |= createChain(LOCAL_STANDBY, getFirewallType(STANDBY));
     res |= createChain(LOCAL_POWERSAVE, getFirewallType(POWERSAVE));
+    res |= createChain(LOCAL_ISOLATED, getFirewallType(ISOLATED));
     return res;
 }
 
@@ -156,6 +158,9 @@
         case POWERSAVE:
             name = LOCAL_POWERSAVE;
             break;
+        case ISOLATED:
+            name = LOCAL_ISOLATED;
+            break;
         default:
             return res;
     }
@@ -220,6 +225,8 @@
             return BLACKLIST;
         case POWERSAVE:
             return WHITELIST;
+        case ISOLATED:
+            return BLACKLIST;
         case NONE:
             return mFirewallType;
         default:
@@ -236,7 +243,7 @@
         // When adding, insert RETURN rules at the front, before the catch-all DROP at the end.
         op = (rule == ALLOW)? "-I" : "-D";
     } else { // BLACKLIST mode
-        target = "DROP";
+        target = (chain == ISOLATED) ? "REJECT" : "DROP";
         // When adding, append DROP rules at the end, after the RETURN rule that matches TCP RSTs.
         op = (rule == DENY)? "-A" : "-D";
     }
@@ -252,6 +259,9 @@
         case POWERSAVE:
             chainNames = { LOCAL_POWERSAVE };
             break;
+        case ISOLATED:
+            chainNames = { LOCAL_ISOLATED };
+            break;
         case NONE:
             chainNames = { LOCAL_INPUT, LOCAL_OUTPUT };
             break;
diff --git a/server/FirewallController.h b/server/FirewallController.h
index 43da322..99fe2c4 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -43,6 +43,7 @@
     DOZABLE = INetd::FIREWALL_CHAIN_DOZABLE,
     STANDBY = INetd::FIREWALL_CHAIN_STANDBY,
     POWERSAVE = INetd::FIREWALL_CHAIN_POWERSAVE,
+    ISOLATED = INetd::FIREWALL_CHAIN_ISOLATED,
     INVALID_CHAIN
 };
 
@@ -85,6 +86,7 @@
     static const char* LOCAL_DOZABLE;
     static const char* LOCAL_STANDBY;
     static const char* LOCAL_POWERSAVE;
+    static const char* LOCAL_ISOLATED;
 
     static const char* ICMPV6_TYPES[];
 
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 4b0e76a..ccbe6ef 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -103,6 +103,7 @@
     FLAG_MSG_TRANS(matchType, POWERSAVE_MATCH, match);
     FLAG_MSG_TRANS(matchType, IIF_MATCH, match);
     FLAG_MSG_TRANS(matchType, IF_BLACKLIST, match);
+    FLAG_MSG_TRANS(matchType, ISOLATED_MATCH, match);
     if (match) {
         return StringPrintf("Unknown match: %u", match);
     }
@@ -694,6 +695,9 @@
         case POWERSAVE:
             res = updateOwnerMapEntry(POWERSAVE_MATCH, uid, rule, type);
             break;
+        case ISOLATED:
+            res = updateOwnerMapEntry(ISOLATED_MATCH, uid, rule, type);
+            break;
         case NONE:
         default:
             return -EINVAL;
@@ -825,6 +829,8 @@
         res = replaceRulesInMap(STANDBY_MATCH, uids);
     } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
         res = replaceRulesInMap(POWERSAVE_MATCH, uids);
+    } else if (!name.compare(FirewallController::LOCAL_ISOLATED)) {
+        res = replaceRulesInMap(ISOLATED_MATCH, uids);
     } else {
         ALOGE("unknown chain name: %s", name.c_str());
         return -EINVAL;
@@ -858,6 +864,9 @@
         case POWERSAVE:
             match = POWERSAVE_MATCH;
             break;
+        case ISOLATED:
+            match = ISOLATED_MATCH;
+            break;
         default:
             return -EINVAL;
     }
diff --git a/server/aidl/netd/2/android/net/INetd.aidl b/server/aidl/netd/2/android/net/INetd.aidl
index a5f4f71..becd721 100644
--- a/server/aidl/netd/2/android/net/INetd.aidl
+++ b/server/aidl/netd/2/android/net/INetd.aidl
@@ -152,4 +152,5 @@
   const String IF_FLAG_POINTOPOINT = "point-to-point";
   const String IF_FLAG_RUNNING = "running";
   const String IF_FLAG_MULTICAST = "multicast";
+  const int FIREWALL_CHAIN_ISOLATED = 4;
 }
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 8b5435a..5f58e00 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -1057,6 +1057,10 @@
     const String IF_FLAG_RUNNING = "running";
     const String IF_FLAG_MULTICAST = "multicast";
 
+    // Specify ISOLATED chain (fw_isolated) which is used to unconditionally block all app
+    // network access.
+    const int FIREWALL_CHAIN_ISOLATED = 4;
+
    /**
     * Get interface configuration
     *