am eb3c0d9a: am 1aad3ad4: Merge "Fix support for simultaneous VPN tuns" into klp-dev

* commit 'eb3c0d9ac387bb0aea5b4956daac1403253bc76d':
  Fix support for simultaneous VPN tuns
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 0a58552..376414b 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -352,6 +352,12 @@
             Binder.restoreCallingIdentity(token);
         }
 
+        // Save the old config in case we need to go back.
+        VpnConfig oldConfig = mConfig;
+        String oldInterface = mInterface;
+        Connection oldConnection = mConnection;
+        SparseBooleanArray oldUsers = mVpnUsers;
+
         // Configure the interface. Abort if any of these steps fails.
         ParcelFileDescriptor tun = ParcelFileDescriptor.adoptFd(jniCreate(config.mtu));
         try {
@@ -371,12 +377,7 @@
                         new UserHandle(mUserId))) {
                 throw new IllegalStateException("Cannot bind " + config.user);
             }
-            if (mConnection != null) {
-                mContext.unbindService(mConnection);
-            }
-            if (mInterface != null && !mInterface.equals(interfaze)) {
-                jniReset(mInterface);
-            }
+
             mConnection = connection;
             mInterface = interfaze;
 
@@ -385,50 +386,74 @@
             config.interfaze = mInterface;
             config.startTime = SystemClock.elapsedRealtime();
             mConfig = config;
+
             // Set up forwarding and DNS rules.
             mVpnUsers = new SparseBooleanArray();
             token = Binder.clearCallingIdentity();
             try {
                 mCallback.setMarkedForwarding(mInterface);
-                mCallback.setRoutes(interfaze, config.routes);
+                mCallback.setRoutes(mInterface, config.routes);
                 mCallback.override(mInterface, config.dnsServers, config.searchDomains);
                 addVpnUserLocked(mUserId);
-
-            } finally {
-                Binder.restoreCallingIdentity(token);
-            }
-
-        } catch (RuntimeException e) {
-            updateState(DetailedState.FAILED, "establish");
-            IoUtils.closeQuietly(tun);
-            // make sure marked forwarding is cleared if it was set
-            try {
-                mCallback.clearMarkedForwarding(mInterface);
-            } catch (Exception ingored) {
-                // ignored
-            }
-            throw e;
-        }
-        Log.i(TAG, "Established by " + config.user + " on " + mInterface);
-
-
-        // If we are owner assign all Restricted Users to this VPN
-        if (mUserId == UserHandle.USER_OWNER) {
-            token = Binder.clearCallingIdentity();
-            try {
-                for (UserInfo user : mgr.getUsers()) {
-                    if (user.isRestricted()) {
-                        try {
-                            addVpnUserLocked(user.id);
-                        } catch (Exception e) {
-                            Log.wtf(TAG, "Failed to add user " + user.id + " to owner's VPN");
+                // If we are owner assign all Restricted Users to this VPN
+                if (mUserId == UserHandle.USER_OWNER) {
+                    for (UserInfo user : mgr.getUsers()) {
+                        if (user.isRestricted()) {
+                            try {
+                                addVpnUserLocked(user.id);
+                            } catch (Exception e) {
+                                Log.wtf(TAG, "Failed to add user " + user.id + " to owner's VPN");
+                            }
                         }
                     }
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
+
+            if (oldConnection != null) {
+                mContext.unbindService(oldConnection);
+            }
+            if (oldInterface != null && !oldInterface.equals(interfaze)) {
+                // Remove the old tun's user forwarding rules
+                // The new tun's user rules have already been added so they will take over
+                // as rules are deleted. This prevents data leakage as the rules are moved over.
+                token = Binder.clearCallingIdentity();
+                try {
+                        final int size = oldUsers.size();
+                        final boolean forwardDns = (oldConfig.dnsServers != null &&
+                                oldConfig.dnsServers.size() != 0);
+                        for (int i = 0; i < size; i++) {
+                            int user = oldUsers.keyAt(i);
+                            mCallback.clearUserForwarding(oldInterface, user, forwardDns);
+                        }
+                        mCallback.clearMarkedForwarding(oldInterface);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
+                jniReset(oldInterface);
+            }
+        } catch (RuntimeException e) {
+            updateState(DetailedState.FAILED, "establish");
+            IoUtils.closeQuietly(tun);
+            // make sure marked forwarding is cleared if it was set
+            token = Binder.clearCallingIdentity();
+            try {
+                mCallback.clearMarkedForwarding(mInterface);
+            } catch (Exception ingored) {
+                // ignored
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            // restore old state
+            mConfig = oldConfig;
+            mConnection = oldConnection;
+            mVpnUsers = oldUsers;
+            mInterface = oldInterface;
+            throw e;
         }
+        Log.i(TAG, "Established by " + config.user + " on " + mInterface);
+
         // TODO: ensure that contract class eventually marks as connected
         updateState(DetailedState.AUTHENTICATING, "establish");
         return tun;