Add @RequiresPermission for setUnderlyingNetworks
setUnderlyingNetworks() is mainly for the NetworkAgents who hold
the NETWORK_FACTORY to set its underlying networks.
And the underlying networks are only visible and useful for the
caller of getNetworkCapabilities() or the receiver of
onCapabilitiesChanged() who hold one of NETWORK_FACTORY,
NETWORK_SETTINGS and MAINLINE_NETWORK_STACK permissions.
Otherwise, the underlying networks field will be cleard before
sending.
Bug: 205738644
Test: atest CtsNetTestCases:ConnectivityManagerTest
atest CtsHostsideNetworkTests:HostsideVpnTests
atest FrameworksNetTests
Change-Id: Ife7630d9676a31ee5ab977cb1b87aec3b6fd7080
diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt
index 53d485d..10b5755 100644
--- a/framework/api/system-current.txt
+++ b/framework/api/system-current.txt
@@ -340,7 +340,7 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setSsid(@Nullable String);
method @NonNull public android.net.NetworkCapabilities.Builder setSubscriptionIds(@NonNull java.util.Set<java.lang.Integer>);
method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo);
- method @NonNull public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
+ method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List<android.net.Network>);
method @NonNull public static android.net.NetworkCapabilities.Builder withoutDefaultCapabilities();
}
diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java
index f7f2f57..97b1f32 100644
--- a/framework/src/android/net/NetworkCapabilities.java
+++ b/framework/src/android/net/NetworkCapabilities.java
@@ -863,8 +863,11 @@
}
/**
- * Get the underlying networks of this network. If the caller is not system privileged, this is
- * always redacted to null and it will be never useful to the caller.
+ * Get the underlying networks of this network. If the caller doesn't have one of
+ * {@link android.Manifest.permission.NETWORK_FACTORY},
+ * {@link android.Manifest.permission.NETWORK_SETTINGS} and
+ * {@link NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}, this is always redacted to null and
+ * it will be never useful to the caller.
*
* @return <li>If the list is null, this network hasn't declared underlying networks.</li>
* <li>If the list is empty, this network has declared that it has no underlying
@@ -2650,7 +2653,7 @@
/**
* Builder class for NetworkCapabilities.
*
- * This class is mainly for for {@link NetworkAgent} instances to use. Many fields in
+ * This class is mainly for {@link NetworkAgent} instances to use. Many fields in
* the built class require holding a signature permission to use - mostly
* {@link android.Manifest.permission.NETWORK_FACTORY}, but refer to the specific
* description of each setter. As this class lives entirely in app space it does not
@@ -3058,9 +3061,20 @@
/**
* Set the underlying networks of this network.
*
+ * <p>This API is mainly for {@link NetworkAgent}s who hold
+ * {@link android.Manifest.permission.NETWORK_FACTORY} to set its underlying networks.
+ *
+ * <p>The underlying networks are only visible for the receiver who has one of
+ * {@link android.Manifest.permission.NETWORK_FACTORY},
+ * {@link android.Manifest.permission.NETWORK_SETTINGS} and
+ * {@link NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK}.
+ * If the receiver doesn't have required permissions, the field will be cleared before
+ * sending to the caller.</p>
+ *
* @param networks The underlying networks of this network.
*/
@NonNull
+ @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public Builder setUnderlyingNetworks(@Nullable List<Network> networks) {
mCaps.setUnderlyingNetworks(networks);
return this;
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index e58160a..32d306a 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -2235,6 +2235,13 @@
callingAttributionTag);
}
+ private void redactUnderlyingNetworksForCapabilities(NetworkCapabilities nc, int pid, int uid) {
+ if (nc.getUnderlyingNetworks() != null
+ && !checkNetworkFactoryOrSettingsPermission(pid, uid)) {
+ nc.setUnderlyingNetworks(null);
+ }
+ }
+
@VisibleForTesting
NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
NetworkCapabilities nc, int callerPid, int callerUid) {
@@ -2247,8 +2254,6 @@
if (!checkSettingsPermission(callerPid, callerUid)) {
newNc.setUids(null);
newNc.setSSID(null);
- // TODO: Processes holding NETWORK_FACTORY should be able to see the underlying networks
- newNc.setUnderlyingNetworks(null);
}
if (newNc.getNetworkSpecifier() != null) {
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
@@ -2262,6 +2267,7 @@
newNc.setAllowedUids(new ArraySet<>());
newNc.setSubscriptionIds(Collections.emptySet());
}
+ redactUnderlyingNetworksForCapabilities(newNc, callerPid, callerUid);
return newNc;
}
@@ -2874,6 +2880,15 @@
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
}
+ private boolean checkNetworkFactoryOrSettingsPermission(int pid, int uid) {
+ return PERMISSION_GRANTED == mContext.checkPermission(
+ android.Manifest.permission.NETWORK_FACTORY, pid, uid)
+ || PERMISSION_GRANTED == mContext.checkPermission(
+ android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
+ || PERMISSION_GRANTED == mContext.checkPermission(
+ NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid);
+ }
+
private boolean checkSettingsPermission() {
return checkAnyPermissionOf(
android.Manifest.permission.NETWORK_SETTINGS,