Let network requests see VPNs.
Test: runtest frameworks-net
Test: also tested with VPN app
Test: also cts passing
Change-Id: I3b16caad7787c3c1f2921ca1583815c89efbadc5
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index 6e80f02..31516fd 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -895,6 +895,17 @@
private Set<UidRange> mUids = null;
/**
+ * Convenience method to set the UIDs this network applies to to a single UID.
+ * @hide
+ */
+ public NetworkCapabilities setSingleUid(int uid) {
+ final ArraySet<UidRange> identity = new ArraySet<>(1);
+ identity.add(new UidRange(uid, uid));
+ setUids(identity);
+ return this;
+ }
+
+ /**
* Set the list of UIDs this network applies to.
* This makes a copy of the set so that callers can't modify it after the call.
* @hide
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 216e19b..6dbf538 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -30,6 +30,7 @@
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
import static android.net.NetworkCapabilities.TRANSPORT_VPN;
@@ -711,12 +712,12 @@
mSystemProperties = getSystemProperties();
mMetricsLog = logger;
- mDefaultRequest = createInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
+ mDefaultRequest = createDefaultInternetRequestForTransport(-1, NetworkRequest.Type.REQUEST);
NetworkRequestInfo defaultNRI = new NetworkRequestInfo(null, mDefaultRequest, new Binder());
mNetworkRequests.put(mDefaultRequest, defaultNRI);
mNetworkRequestInfoLogs.log("REGISTER " + defaultNRI);
- mDefaultMobileDataRequest = createInternetRequestForTransport(
+ mDefaultMobileDataRequest = createDefaultInternetRequestForTransport(
NetworkCapabilities.TRANSPORT_CELLULAR, NetworkRequest.Type.BACKGROUND_REQUEST);
mHandlerThread = new HandlerThread("ConnectivityServiceThread");
@@ -881,7 +882,7 @@
deps);
}
- private NetworkRequest createInternetRequestForTransport(
+ private NetworkRequest createDefaultInternetRequestForTransport(
int transportType, NetworkRequest.Type type) {
NetworkCapabilities netCap = new NetworkCapabilities();
netCap.addCapability(NET_CAPABILITY_INTERNET);
@@ -1259,7 +1260,11 @@
for (Network network : networks) {
nai = getNetworkAgentInfoForNetwork(network);
nc = getNetworkCapabilitiesInternal(nai);
+ // nc is a copy of the capabilities in nai, so it's fine to mutate it
+ // TODO : don't remove the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
if (nc != null) {
+ nc.setSingleUid(userId);
result.put(network, nc);
}
}
@@ -4190,6 +4195,7 @@
// the system default network.
if (type == NetworkRequest.Type.TRACK_DEFAULT) {
networkCapabilities = new NetworkCapabilities(mDefaultRequest.networkCapabilities);
+ networkCapabilities.removeCapability(NET_CAPABILITY_NOT_VPN);
enforceAccessPermission();
} else {
networkCapabilities = new NetworkCapabilities(networkCapabilities);
@@ -4200,6 +4206,13 @@
enforceMeteredApnPolicy(networkCapabilities);
}
ensureRequestableCapabilities(networkCapabilities);
+ // Set the UID range for this request to the single UID of the requester.
+ // This will overwrite any allowed UIDs in the requested capabilities. Though there
+ // are no visible methods to set the UIDs, an app could use reflection to try and get
+ // networks for other apps so it's essential that the UIDs are overwritten.
+ // TODO : don't forcefully set the UID when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ networkCapabilities.setSingleUid(Binder.getCallingUid());
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
@@ -4273,6 +4286,9 @@
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
ensureValidNetworkSpecifier(networkCapabilities);
+ // TODO : don't forcefully set the UID when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ networkCapabilities.setSingleUid(Binder.getCallingUid());
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4326,6 +4342,9 @@
}
NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ // TODO : don't forcefully set the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ nc.setSingleUid(Binder.getCallingUid());
if (!ConnectivityManager.checkChangePermission(mContext)) {
// Apps without the CHANGE_NETWORK_STATE permission can't use background networks, so
// make all their listens include NET_CAPABILITY_FOREGROUND. That way, they will get
@@ -4354,8 +4373,12 @@
}
ensureValidNetworkSpecifier(networkCapabilities);
- NetworkRequest networkRequest = new NetworkRequest(
- new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
+ final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
+ // TODO : don't forcefully set the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ nc.setSingleUid(Binder.getCallingUid());
+
+ NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
NetworkRequestInfo nri = new NetworkRequestInfo(networkRequest, operation);
if (VDBG) log("pendingListenForNetwork for " + nri);
@@ -4904,7 +4927,12 @@
break;
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
- putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
+ final NetworkCapabilities nc =
+ new NetworkCapabilities(networkAgent.networkCapabilities);
+ // TODO : don't remove the UIDs when communicating with processes
+ // that have the NETWORK_SETTINGS permission.
+ nc.setSingleUid(nri.mUid);
+ putParcelable(bundle, nc);
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
diff --git a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
index 397d8c1..24865bc 100644
--- a/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
+++ b/services/core/java/com/android/server/connectivity/ConnectivityConstants.java
@@ -46,4 +46,7 @@
// This ensures that a) the explicitly selected network is never trumped by anything else, and
// b) the explicitly selected network is never torn down.
public static final int MAXIMUM_NETWORK_SCORE = 100;
+ // VPNs typically have priority over other networks. Give them a score that will
+ // let them win every single time.
+ public static final int VPN_DEFAULT_SCORE = 101;
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index e93f311..bb46d5e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -850,7 +850,8 @@
long token = Binder.clearCallingIdentity();
try {
mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */,
- mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) {
+ mNetworkInfo, mNetworkCapabilities, lp,
+ ConnectivityConstants.VPN_DEFAULT_SCORE, networkMisc) {
@Override
public void unwanted() {
// We are user controlled, not driven by NetworkRequest.
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 4733deb..6e643a3 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -128,11 +128,13 @@
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.connectivity.ConnectivityConstants;
import com.android.server.connectivity.DefaultNetworkMetrics;
import com.android.server.connectivity.IpConnectivityMetrics;
import com.android.server.connectivity.MockableSystemProperties;
import com.android.server.connectivity.NetworkAgentInfo;
import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.Vpn;
import com.android.server.net.NetworkPinner;
import com.android.server.net.NetworkPolicyManagerInternal;
@@ -380,7 +382,7 @@
mScore = 20;
break;
case TRANSPORT_VPN:
- mScore = 0;
+ mScore = ConnectivityConstants.VPN_DEFAULT_SCORE;
break;
default:
throw new UnsupportedOperationException("unimplemented network type");