diff --git a/framework/api/system-current.txt b/framework/api/system-current.txt index 7a574268cc..db1d7e9e50 100644 --- a/framework/api/system-current.txt +++ b/framework/api/system-current.txt @@ -340,7 +340,7 @@ package android.net { 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); method @NonNull public android.net.NetworkCapabilities.Builder setTransportInfo(@Nullable android.net.TransportInfo); - method @NonNull public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List); + method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public android.net.NetworkCapabilities.Builder setUnderlyingNetworks(@Nullable java.util.List); 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 f7f2f57f6e..97b1f32671 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java @@ -863,8 +863,11 @@ public final class NetworkCapabilities implements Parcelable { } /** - * 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
  • If the list is null, this network hasn't declared underlying networks.
  • *
  • If the list is empty, this network has declared that it has no underlying @@ -2650,7 +2653,7 @@ public final class NetworkCapabilities implements Parcelable { /** * 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 @@ public final class NetworkCapabilities implements Parcelable { /** * Set the underlying networks of this network. * + *

    This API is mainly for {@link NetworkAgent}s who hold + * {@link android.Manifest.permission.NETWORK_FACTORY} to set its underlying networks. + * + *

    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.

    + * * @param networks The underlying networks of this network. */ @NonNull + @RequiresPermission(android.Manifest.permission.NETWORK_FACTORY) public Builder setUnderlyingNetworks(@Nullable List 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 b4cc41a94d..0528f292e6 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -2238,6 +2238,13 @@ public class ConnectivityService extends IConnectivityManager.Stub 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) { @@ -2250,8 +2257,6 @@ public class ConnectivityService extends IConnectivityManager.Stub 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()); @@ -2265,6 +2270,7 @@ public class ConnectivityService extends IConnectivityManager.Stub newNc.setAllowedUids(new ArraySet<>()); newNc.setSubscriptionIds(Collections.emptySet()); } + redactUnderlyingNetworksForCapabilities(newNc, callerPid, callerUid); return newNc; } @@ -2877,6 +2883,15 @@ public class ConnectivityService extends IConnectivityManager.Stub 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,