Enforce structural NetworkAgent constraints
Avoid network agents trying to do things that the stack
does not support.
Test: new test in this change
Change-Id: I3ffa1c3ddbb0b648b06862dc0a44f8525d358acc
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index f52a1a2..3dc5692 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -4156,7 +4156,14 @@
switch (msg.what) {
case NetworkAgent.EVENT_NETWORK_CAPABILITIES_CHANGED: {
- nai.setDeclaredCapabilities((NetworkCapabilities) arg.second);
+ final NetworkCapabilities proposed = (NetworkCapabilities) arg.second;
+ if (!nai.respectsNcStructuralConstraints(proposed)) {
+ Log.wtf(TAG, "Agent " + nai + " violates nc structural constraints : "
+ + nai.networkCapabilities + " -> " + proposed);
+ disconnectAndDestroyNetwork(nai);
+ return;
+ }
+ nai.setDeclaredCapabilities(proposed);
final NetworkCapabilities sanitized =
nai.getDeclaredCapabilitiesSanitized(mCarrierPrivilegeAuthenticator);
maybeUpdateWifiRoamTimestamp(nai, sanitized);
diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
index b0ad978..dacae20 100644
--- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
@@ -428,12 +429,28 @@
private final boolean mHasAutomotiveFeature;
/**
+ * Checks that a proposed update to the NCs of this NAI satisfies structural constraints.
+ *
+ * Some changes to NetworkCapabilities are structurally not supported by the stack, and
+ * NetworkAgents are absolutely never allowed to try and do them. When one of these is
+ * violated, this method returns false, which has ConnectivityService disconnect the network ;
+ * this is meant to guarantee that no implementor ever tries to do this.
+ */
+ public boolean respectsNcStructuralConstraints(@NonNull final NetworkCapabilities proposedNc) {
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_LOCAL_NETWORK)
+ != proposedNc.hasCapability(NET_CAPABILITY_LOCAL_NETWORK)) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
* Sets the capabilities sent by the agent for later retrieval.
- *
- * This method does not sanitize the capabilities ; instead, use
- * {@link #getDeclaredCapabilitiesSanitized} to retrieve a sanitized
- * copy of the capabilities as they were passed here.
- *
+ * <p>
+ * This method does not sanitize the capabilities before storing them ; instead, use
+ * {@link #getDeclaredCapabilitiesSanitized} to retrieve a sanitized copy of the capabilities
+ * as they were passed here.
+ * <p>
* This method makes a defensive copy to avoid issues where the passed object is later mutated.
*
* @param caps the caps sent by the agent
diff --git a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
index bd3efa9..d9f7f9f 100644
--- a/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/CSLocalAgentTests.kt
@@ -32,11 +32,11 @@
import android.os.Build
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
-import com.android.testutils.RecorderCallback
import com.android.testutils.RecorderCallback.CallbackEntry.Available
import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus
import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
+import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.TestableNetworkCallback
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,6 +65,8 @@
class CSLocalAgentTests : CSTest() {
@Test
fun testBadAgents() {
+ deps.setBuildSdk(VERSION_V)
+
assertFailsWith<IllegalArgumentException> {
Agent(nc = NetworkCapabilities.Builder()
.addCapability(NET_CAPABILITY_LOCAL_NETWORK)
@@ -78,6 +80,41 @@
}
@Test
+ fun testStructuralConstraintViolation() {
+ deps.setBuildSdk(VERSION_V)
+
+ val cb = TestableNetworkCallback()
+ cm.requestNetwork(NetworkRequest.Builder()
+ .clearCapabilities()
+ .build(),
+ cb)
+ val agent = Agent(nc = NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_LOCAL_NETWORK)
+ .build(),
+ lnc = LocalNetworkConfig.Builder().build())
+ agent.connect()
+ cb.expect<Available>(agent.network)
+ cb.expect<CapabilitiesChanged>(agent.network)
+ cb.expect<LinkPropertiesChanged>(agent.network)
+ cb.expect<BlockedStatus>(agent.network)
+ agent.sendNetworkCapabilities(NetworkCapabilities.Builder().build())
+ cb.expect<Lost>(agent.network)
+
+ val agent2 = Agent(nc = NetworkCapabilities.Builder()
+ .build(),
+ lnc = null)
+ agent2.connect()
+ cb.expect<Available>(agent2.network)
+ cb.expect<CapabilitiesChanged>(agent2.network)
+ cb.expect<LinkPropertiesChanged>(agent2.network)
+ cb.expect<BlockedStatus>(agent2.network)
+ agent2.sendNetworkCapabilities(NetworkCapabilities.Builder()
+ .addCapability(NET_CAPABILITY_LOCAL_NETWORK)
+ .build())
+ cb.expect<Lost>(agent2.network)
+ }
+
+ @Test
fun testUpdateLocalAgentConfig() {
deps.setBuildSdk(VERSION_V)
diff --git a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
index 8860895..f903e51 100644
--- a/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
+++ b/tests/unit/java/com/android/server/connectivityservice/base/CSAgentWrapper.kt
@@ -169,4 +169,5 @@
fun unregisterAfterReplacement(timeoutMs: Int) = agent.unregisterAfterReplacement(timeoutMs)
fun sendLocalNetworkConfig(lnc: LocalNetworkConfig) = agent.sendLocalNetworkConfig(lnc)
+ fun sendNetworkCapabilities(nc: NetworkCapabilities) = agent.sendNetworkCapabilities(nc)
}