diff --git a/services/java/com/android/server/connectivity/Vpn.java b/services/java/com/android/server/connectivity/Vpn.java index 03405e7c0cbcf..8f25860172dea 100644 --- a/services/java/com/android/server/connectivity/Vpn.java +++ b/services/java/com/android/server/connectivity/Vpn.java @@ -352,6 +352,12 @@ public class Vpn extends BaseNetworkStateTracker { 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 @@ public class Vpn extends BaseNetworkStateTracker { 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 @@ public class Vpn extends BaseNetworkStateTracker { 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;