Keep track of users allowed to call protect() explicitly.

This is an API change between ConnectivityService and Netd.

The ownerUid was meant for this purpose, but it's insufficient, as apps need to
call protect() _before_ they create a VPN.

Bug: 15409918
Change-Id: If804aa106002e96d5ffb623d32db35fd76928367
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 7e408f0..9c91910 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -1644,17 +1644,16 @@
     //    0      1       2          3
     // network create <netId> [<permission> ...]
     //
-    //    0      1       2     3      4
-    // network create <netId> vpn <ownerUid>
+    //    0      1       2     3
+    // network create <netId> vpn
     if (!strcmp(argv[1], "create")) {
         if (argc < 3) {
             return syntaxError(client, "Missing argument");
         }
         // strtoul() returns 0 on errors, which is fine because 0 is an invalid netId.
         unsigned netId = strtoul(argv[2], NULL, 0);
-        if (argc == 5 && !strcmp(argv[3], "vpn")) {
-            uid_t ownerUid = strtoul(argv[4], NULL, 0);
-            if (int ret = sNetCtrl->createVpn(netId, ownerUid)) {
+        if (argc == 4 && !strcmp(argv[3], "vpn")) {
+            if (int ret = sNetCtrl->createVpn(netId)) {
                 return operationError(client, "createVpn() failed", ret);
             }
         } else {
@@ -1774,6 +1773,27 @@
         return success(client);
     }
 
+    //    0       1      2     3
+    // network protect allow <uid> ...
+    // network protect  deny <uid> ...
+    if (!strcmp(argv[1], "protect")) {
+        if (argc < 4) {
+            return syntaxError(client, "Missing argument");
+        }
+        std::vector<uid_t> uids;
+        for (int i = 3; i < argc; ++i) {
+            uids.push_back(strtoul(argv[i], NULL, 0));
+        }
+        if (!strcmp(argv[2], "allow")) {
+            sNetCtrl->allowProtect(uids);
+        } else if (!strcmp(argv[2], "deny")) {
+            sNetCtrl->denyProtect(uids);
+        } else {
+            return syntaxError(client, "Unknown argument");
+        }
+        return success(client);
+    }
+
     // TODO:
     //   o tethering
     //   o p2p
diff --git a/server/Network.cpp b/server/Network.cpp
index 5c4bd0e..d22f42d 100644
--- a/server/Network.cpp
+++ b/server/Network.cpp
@@ -19,9 +19,6 @@
 #define LOG_TAG "Netd"
 #include "log/log.h"
 
-Network::Network(unsigned netId) : mNetId(netId) {
-}
-
 Network::~Network() {
     if (!mInterfaces.empty()) {
         ALOGE("deleting network with netId %u without clearing its interfaces", mNetId);
@@ -43,3 +40,6 @@
     }
     return 0;
 }
+
+Network::Network(unsigned netId) : mNetId(netId) {
+}
diff --git a/server/Network.h b/server/Network.h
index 6ef0c3a..b10cb17 100644
--- a/server/Network.h
+++ b/server/Network.h
@@ -30,8 +30,6 @@
         VIRTUAL,
     };
 
-    explicit Network(unsigned netId);
-
     // You MUST ensure that no interfaces are still assigned to this network, say by calling
     // clearInterfaces(), before deleting it. This is because interface removal may fail. If we
     // automatically removed interfaces in the destructor, you wouldn't know if it failed.
@@ -47,6 +45,8 @@
     int clearInterfaces() WARN_UNUSED_RESULT;
 
 protected:
+    explicit Network(unsigned netId);
+
     const unsigned mNetId;
     std::set<std::string> mInterfaces;
 };
diff --git a/server/NetworkController.cpp b/server/NetworkController.cpp
index f062dcf..0e341e5 100644
--- a/server/NetworkController.cpp
+++ b/server/NetworkController.cpp
@@ -177,7 +177,7 @@
     return 0;
 }
 
-int NetworkController::createVpn(unsigned netId, uid_t ownerUid) {
+int NetworkController::createVpn(unsigned netId) {
     if (netId < MIN_NET_ID || netId > MAX_NET_ID) {
         ALOGE("invalid netId %u", netId);
         return -EINVAL;
@@ -189,7 +189,7 @@
     }
 
     android::RWLock::AutoWLock lock(mRWLock);
-    mNetworks[netId] = new VirtualNetwork(netId, ownerUid);
+    mNetworks[netId] = new VirtualNetwork(netId);
     return 0;
 }
 
@@ -331,6 +331,18 @@
     return modifyRoute(netId, interface, destination, nexthop, false, legacy, uid);
 }
 
+void NetworkController::allowProtect(const std::vector<uid_t>& uids) {
+    android::RWLock::AutoWLock lock(mRWLock);
+    mProtectableUsers.insert(uids.begin(), uids.end());
+}
+
+void NetworkController::denyProtect(const std::vector<uid_t>& uids) {
+    android::RWLock::AutoWLock lock(mRWLock);
+    for (uid_t uid : uids) {
+        mProtectableUsers.erase(uid);
+    }
+}
+
 Network* NetworkController::getNetworkLocked(unsigned netId) const {
     auto iter = mNetworks.find(netId);
     return iter == mNetworks.end() ? NULL : iter->second;
diff --git a/server/NetworkController.h b/server/NetworkController.h
index 1968ab5..735704c 100644
--- a/server/NetworkController.h
+++ b/server/NetworkController.h
@@ -24,6 +24,7 @@
 
 #include <list>
 #include <map>
+#include <set>
 #include <sys/types.h>
 #include <vector>
 
@@ -55,7 +56,7 @@
     bool isValidNetwork(unsigned netId) const;
 
     int createNetwork(unsigned netId, Permission permission) WARN_UNUSED_RESULT;
-    int createVpn(unsigned netId, uid_t ownerUid) WARN_UNUSED_RESULT;
+    int createVpn(unsigned netId) WARN_UNUSED_RESULT;
     int destroyNetwork(unsigned netId) WARN_UNUSED_RESULT;
 
     int addInterfaceToNetwork(unsigned netId, const char* interface) WARN_UNUSED_RESULT;
@@ -77,6 +78,9 @@
     int removeRoute(unsigned netId, const char* interface, const char* destination,
                     const char* nexthop, bool legacy, uid_t uid) WARN_UNUSED_RESULT;
 
+    void allowProtect(const std::vector<uid_t>& uids);
+    void denyProtect(const std::vector<uid_t>& uids);
+
 private:
     Network* getNetworkLocked(unsigned netId) const;
 
@@ -92,12 +96,14 @@
         UidEntry(uid_t uidStart, uid_t uidEnd, unsigned netId, bool forwardDns);
     };
 
-    // mRWLock guards all accesses to mUidMap, mDefaultNetId, mNetworks and mUsers.
+    // mRWLock guards all accesses to mUidMap, mDefaultNetId, mNetworks, mUsers and
+    // mProtectableUsers.
     mutable android::RWLock mRWLock;
     std::list<UidEntry> mUidMap;
     unsigned mDefaultNetId;
     std::map<unsigned, Network*> mNetworks;  // Map keys are NetIds.
     std::map<uid_t, Permission> mUsers;
+    std::set<uid_t> mProtectableUsers;
 };
 
 #endif  // NETD_SERVER_NETWORK_CONTROLLER_H
diff --git a/server/VirtualNetwork.cpp b/server/VirtualNetwork.cpp
index 37f9644..5ffee6e 100644
--- a/server/VirtualNetwork.cpp
+++ b/server/VirtualNetwork.cpp
@@ -21,7 +21,7 @@
 #define LOG_TAG "Netd"
 #include "log/log.h"
 
-VirtualNetwork::VirtualNetwork(unsigned netId, uid_t /*ownerUid*/) : Network(netId) {
+VirtualNetwork::VirtualNetwork(unsigned netId): Network(netId) {
 }
 
 VirtualNetwork::~VirtualNetwork() {
diff --git a/server/VirtualNetwork.h b/server/VirtualNetwork.h
index cf1147b..54b4926 100644
--- a/server/VirtualNetwork.h
+++ b/server/VirtualNetwork.h
@@ -22,7 +22,7 @@
 
 class VirtualNetwork : public Network {
 public:
-    VirtualNetwork(unsigned netId, uid_t ownerUid);
+    explicit VirtualNetwork(unsigned netId);
     virtual ~VirtualNetwork();
 
     int addUsers(const UidRanges& uidRanges) WARN_UNUSED_RESULT;