From 704321da7db7edff9bb57c3bb95732f4b37691b3 Mon Sep 17 00:00:00 2001 From: chiachangwang Date: Mon, 22 Aug 2022 02:14:57 +0000 Subject: [PATCH] Skip events on stale Ikev2VpnRunner The exit() of VpnRunner will do exitVpnRunner() and cleanupVpnStateLocked(). But the exitVpnRunner() posts a runnable to the executor. This means that disconnectVpnRunner() might run concurrently with cleanupVpnStateLocked(), and it might even complete after cleanupVpnStateLocked() finishes. After exiting the runner, the states are reset. The remaining events in the executor are irrelavent and should be skipped to prevent accessing any of the outer class's members. Also add missing synchronized block by verifying that there is no other field of the outer Vpn class that is used inside Ikev2VpnRunner implicitly. Bug: 235322391 Test: atest FrameworksNetTests Change-Id: I9eed58b2e96ebaf33e557a42e83525a74a4697d8 Merged-In: I9eed58b2e96ebaf33e557a42e83525a74a4697d8 --- .../com/android/server/connectivity/Vpn.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 8d028037aa60e..b988b5731f9b5 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -2903,6 +2903,9 @@ public class Vpn { final LinkProperties lp; synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != this) return; + mInterface = interfaceName; mConfig.mtu = maxMtu; mConfig.interfaze = mInterface; @@ -3004,6 +3007,9 @@ public class Vpn { try { synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != this) return; + mConfig.underlyingNetworks = new Network[] {network}; mNetworkCapabilities = new NetworkCapabilities.Builder(mNetworkCapabilities) @@ -3093,7 +3099,12 @@ public class Vpn { // Clear mInterface to prevent Ikev2VpnRunner being cleared when // interfaceRemoved() is called. - mInterface = null; + synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != this) return; + + mInterface = null; + } // Without MOBIKE, we have no way to seamlessly migrate. Close on old // (non-default) network, and start the new one. resetIkeState(); @@ -3278,6 +3289,9 @@ public class Vpn { /** Marks the state as FAILED, and disconnects. */ private void markFailedAndDisconnect(Exception exception) { synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != this) return; + updateState(DetailedState.FAILED, exception.getMessage()); } @@ -3316,6 +3330,9 @@ public class Vpn { cancelHandleNetworkLostTimeout(); synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != this) return; + if (exception instanceof IkeProtocolException) { final IkeProtocolException ikeException = (IkeProtocolException) exception; @@ -3436,6 +3453,9 @@ public class Vpn { Log.d(TAG, "Resetting state for token: " + mCurrentToken); synchronized (Vpn.this) { + // Ignore stale runner. + if (mVpnRunner != this) return; + // Since this method handles non-fatal errors only, set mInterface to null to // prevent the NetworkManagementEventObserver from killing this VPN based on the // interface going down (which we expect).