diff --git a/framework/src/android/net/NetworkCapabilities.java b/framework/src/android/net/NetworkCapabilities.java index 4254a66c88..feb9fc17db 100644 --- a/framework/src/android/net/NetworkCapabilities.java +++ b/framework/src/android/net/NetworkCapabilities.java @@ -621,22 +621,22 @@ public final class NetworkCapabilities implements Parcelable { * Network capabilities that are expected to be mutable, i.e., can change while a particular * network is connected. */ - private static final long MUTABLE_CAPABILITIES = + private static final long MUTABLE_CAPABILITIES = NetworkCapabilitiesUtils.packBitList( // TRUSTED can change when user explicitly connects to an untrusted network in Settings. // http://b/18206275 - (1 << NET_CAPABILITY_TRUSTED) - | (1 << NET_CAPABILITY_VALIDATED) - | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) - | (1 << NET_CAPABILITY_NOT_ROAMING) - | (1 << NET_CAPABILITY_FOREGROUND) - | (1 << NET_CAPABILITY_NOT_CONGESTED) - | (1 << NET_CAPABILITY_NOT_SUSPENDED) - | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY) - | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED) - | (1 << NET_CAPABILITY_NOT_VCN_MANAGED) + NET_CAPABILITY_TRUSTED, + NET_CAPABILITY_VALIDATED, + NET_CAPABILITY_CAPTIVE_PORTAL, + NET_CAPABILITY_NOT_ROAMING, + NET_CAPABILITY_FOREGROUND, + NET_CAPABILITY_NOT_CONGESTED, + NET_CAPABILITY_NOT_SUSPENDED, + NET_CAPABILITY_PARTIAL_CONNECTIVITY, + NET_CAPABILITY_TEMPORARILY_NOT_METERED, + NET_CAPABILITY_NOT_VCN_MANAGED, // The value of NET_CAPABILITY_HEAD_UNIT is 32, which cannot use int to do bit shift, // otherwise there will be an overflow. Use long to do bit shift instead. - | (1L << NET_CAPABILITY_HEAD_UNIT); + NET_CAPABILITY_HEAD_UNIT); /** * Network capabilities that are not allowed in NetworkRequests. This exists because the @@ -650,25 +650,26 @@ public final class NetworkCapabilities implements Parcelable { // in an infinite loop about these. private static final long NON_REQUESTABLE_CAPABILITIES = MUTABLE_CAPABILITIES - & ~(1 << NET_CAPABILITY_TRUSTED) - & ~(1 << NET_CAPABILITY_NOT_VCN_MANAGED); + & ~(1L << NET_CAPABILITY_TRUSTED) + & ~(1L << NET_CAPABILITY_NOT_VCN_MANAGED); /** * Capabilities that are set by default when the object is constructed. */ - private static final long DEFAULT_CAPABILITIES = - (1 << NET_CAPABILITY_NOT_RESTRICTED) - | (1 << NET_CAPABILITY_TRUSTED) - | (1 << NET_CAPABILITY_NOT_VPN); + private static final long DEFAULT_CAPABILITIES = NetworkCapabilitiesUtils.packBitList( + NET_CAPABILITY_NOT_RESTRICTED, + NET_CAPABILITY_TRUSTED, + NET_CAPABILITY_NOT_VPN); /** * Capabilities that are managed by ConnectivityService. */ private static final long CONNECTIVITY_MANAGED_CAPABILITIES = - (1 << NET_CAPABILITY_VALIDATED) - | (1 << NET_CAPABILITY_CAPTIVE_PORTAL) - | (1 << NET_CAPABILITY_FOREGROUND) - | (1 << NET_CAPABILITY_PARTIAL_CONNECTIVITY); + NetworkCapabilitiesUtils.packBitList( + NET_CAPABILITY_VALIDATED, + NET_CAPABILITY_CAPTIVE_PORTAL, + NET_CAPABILITY_FOREGROUND, + NET_CAPABILITY_PARTIAL_CONNECTIVITY); /** * Capabilities that are allowed for test networks. This list must be set so that it is safe @@ -677,14 +678,15 @@ public final class NetworkCapabilities implements Parcelable { * INTERNET, IMS, SUPL, etc. */ private static final long TEST_NETWORKS_ALLOWED_CAPABILITIES = - (1 << NET_CAPABILITY_NOT_METERED) - | (1 << NET_CAPABILITY_TEMPORARILY_NOT_METERED) - | (1 << NET_CAPABILITY_NOT_RESTRICTED) - | (1 << NET_CAPABILITY_NOT_VPN) - | (1 << NET_CAPABILITY_NOT_ROAMING) - | (1 << NET_CAPABILITY_NOT_CONGESTED) - | (1 << NET_CAPABILITY_NOT_SUSPENDED) - | (1 << NET_CAPABILITY_NOT_VCN_MANAGED); + NetworkCapabilitiesUtils.packBitList( + NET_CAPABILITY_NOT_METERED, + NET_CAPABILITY_TEMPORARILY_NOT_METERED, + NET_CAPABILITY_NOT_RESTRICTED, + NET_CAPABILITY_NOT_VPN, + NET_CAPABILITY_NOT_ROAMING, + NET_CAPABILITY_NOT_CONGESTED, + NET_CAPABILITY_NOT_SUSPENDED, + NET_CAPABILITY_NOT_VCN_MANAGED); /** * Adds the given capability to this {@code NetworkCapability} instance. @@ -1156,12 +1158,13 @@ public final class NetworkCapabilities implements Parcelable { /** * Allowed transports on an unrestricted test network (in addition to TRANSPORT_TEST). */ - private static final int UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS = - 1 << TRANSPORT_TEST - // Test ethernet networks can be created with EthernetManager#setIncludeTestInterfaces - | 1 << TRANSPORT_ETHERNET - // Test VPN networks can be created but their UID ranges must be empty. - | 1 << TRANSPORT_VPN; + private static final long UNRESTRICTED_TEST_NETWORKS_ALLOWED_TRANSPORTS = + NetworkCapabilitiesUtils.packBitList( + TRANSPORT_TEST, + // Test eth networks are created with EthernetManager#setIncludeTestInterfaces + TRANSPORT_ETHERNET, + // Test VPN networks can be created but their UID ranges must be empty. + TRANSPORT_VPN); /** * Adds the given transport type to this {@code NetworkCapability} instance. @@ -3076,4 +3079,4 @@ public final class NetworkCapabilities implements Parcelable { return new NetworkCapabilities(mCaps); } } -} +} \ No newline at end of file diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java index fb9005305c..a9a06e46a5 100644 --- a/service/src/com/android/server/ConnectivityService.java +++ b/service/src/com/android/server/ConnectivityService.java @@ -1338,6 +1338,18 @@ public class ConnectivityService extends IConnectivityManager.Stub return new LocationPermissionChecker(context); } + /** + * @see CarrierPrivilegeAuthenticator + */ + public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator( + @NonNull final Context context, @NonNull final TelephonyManager tm) { + if (SdkLevel.isAtLeastT()) { + return new CarrierPrivilegeAuthenticator(context, tm); + } else { + return null; + } + } + /** * @see DeviceConfigUtils#isFeatureEnabled */ @@ -1426,12 +1438,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE); mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); mLocationPermissionChecker = mDeps.makeLocationPermissionChecker(mContext); - if (SdkLevel.isAtLeastT()) { - mCarrierPrivilegeAuthenticator = - new CarrierPrivilegeAuthenticator(mContext, mTelephonyManager); - } else { - mCarrierPrivilegeAuthenticator = null; - } + mCarrierPrivilegeAuthenticator = + mDeps.makeCarrierPrivilegeAuthenticator(mContext, mTelephonyManager); // To ensure uid state is synchronized with Network Policy, register for // NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService @@ -4157,11 +4165,11 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private boolean hasCarrierPrivilegeForNetworkRequest(int callingUid, - NetworkRequest networkRequest) { + private boolean hasCarrierPrivilegeForNetworkCaps(final int callingUid, + @NonNull final NetworkCapabilities caps) { if (SdkLevel.isAtLeastT() && mCarrierPrivilegeAuthenticator != null) { - return mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(callingUid, - networkRequest); + return mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + callingUid, caps); } return false; } @@ -4205,7 +4213,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } if (req.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) { - if (!hasCarrierPrivilegeForNetworkRequest(nri.mUid, req) + if (!hasCarrierPrivilegeForNetworkCaps(nri.mUid, req.networkCapabilities) && !checkConnectivityRestrictedNetworksPermission( nri.mPid, nri.mUid)) { requestToBeReleased = req; @@ -6140,13 +6148,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void ensureRequestableCapabilities(NetworkCapabilities networkCapabilities) { - final String badCapability = networkCapabilities.describeFirstNonRequestableCapability(); - if (badCapability != null) { - throw new IllegalArgumentException("Cannot request network with " + badCapability); - } - } - // This checks that the passed capabilities either do not request a // specific SSID/SignalStrength, or the calling app has permission to do so. private void ensureSufficientPermissionsForRequest(NetworkCapabilities nc, @@ -6204,7 +6205,7 @@ public class ConnectivityService extends IConnectivityManager.Stub nai.onSignalStrengthThresholdsUpdated(thresholdsArray); } - private void ensureValidNetworkSpecifier(NetworkCapabilities nc) { + private static void ensureValidNetworkSpecifier(NetworkCapabilities nc) { if (nc == null) { return; } @@ -6217,7 +6218,7 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - private void ensureValid(NetworkCapabilities nc) { + private static void ensureListenableCapabilities(@NonNull final NetworkCapabilities nc) { ensureValidNetworkSpecifier(nc); if (nc.isPrivateDnsBroken()) { throw new IllegalArgumentException("Can't request broken private DNS"); @@ -6227,6 +6228,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } } + private void ensureRequestableCapabilities(@NonNull final NetworkCapabilities nc) { + ensureListenableCapabilities(nc); + final String badCapability = nc.describeFirstNonRequestableCapability(); + if (badCapability != null) { + throw new IllegalArgumentException("Cannot request network with " + badCapability); + } + } + // TODO: Set the mini sdk to 31 and remove @TargetApi annotation when b/205923322 is addressed. @TargetApi(Build.VERSION_CODES.S) private boolean isTargetSdkAtleast(int version, int callingUid, @@ -6319,7 +6328,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (timeoutMs < 0) { throw new IllegalArgumentException("Bad timeout specified"); } - ensureValid(networkCapabilities); final NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType, nextNetworkRequestId(), reqType); @@ -6461,7 +6469,6 @@ public class ConnectivityService extends IConnectivityManager.Stub Binder.getCallingPid(), callingUid, callingPackageName); restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities, callingUid, callingPackageName); - ensureValid(networkCapabilities); NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.REQUEST); @@ -6528,7 +6535,7 @@ public class ConnectivityService extends IConnectivityManager.Stub // There is no need to do this for requests because an app without CHANGE_NETWORK_STATE // can't request networks. restrictBackgroundRequestForCaller(nc); - ensureValid(nc); + ensureListenableCapabilities(nc); NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN); @@ -6550,7 +6557,7 @@ public class ConnectivityService extends IConnectivityManager.Stub if (!hasWifiNetworkListenPermission(networkCapabilities)) { enforceAccessPermission(); } - ensureValid(networkCapabilities); + ensureListenableCapabilities(networkCapabilities); ensureSufficientPermissionsForRequest(networkCapabilities, Binder.getCallingPid(), callingUid, callingPackageName); final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities); @@ -7495,7 +7502,8 @@ public class ConnectivityService extends IConnectivityManager.Stub nc.setOwnerUid(nai.networkCapabilities.getOwnerUid()); } nai.declaredCapabilities = new NetworkCapabilities(nc); - NetworkAgentInfo.restrictCapabilitiesFromNetworkAgent(nc, nai.creatorUid); + NetworkAgentInfo.restrictCapabilitiesFromNetworkAgent(nc, nai.creatorUid, + mCarrierPrivilegeAuthenticator); } /** Modifies |newNc| based on the capabilities of |underlyingNetworks| and |agentCaps|. */ diff --git a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java index c5107ade9c..ce955fd6a4 100644 --- a/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java +++ b/service/src/com/android/server/connectivity/CarrierPrivilegeAuthenticator.java @@ -17,6 +17,7 @@ package com.android.server.connectivity; import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS; +import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; import android.annotation.NonNull; import android.content.BroadcastReceiver; @@ -25,7 +26,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; -import android.net.NetworkRequest; +import android.net.NetworkCapabilities; import android.net.NetworkSpecifier; import android.net.TelephonyNetworkSpecifier; import android.os.Build; @@ -235,24 +236,30 @@ public class CarrierPrivilegeAuthenticator extends BroadcastReceiver { } /** - * Check if network request is allowed based upon carrrier service package. + * Check if a UID is the carrier service app of the subscription ID in the provided capabilities * - * Network request for {@link NET_CAPABILITY_CBS} is allowed if the caller has - * carrier privilege and provides the carrier config. This function checks if caller - * has the same and returns true if it has else false. + * This returns whether the passed UID is the carrier service package for the subscription ID + * stored in the telephony network specifier in the passed network capabilities. + * If the capabilities don't code for a cellular network, or if they don't have the + * subscription ID in their specifier, this returns false. * - * @param callingUid user identifier that uniquely identifies the caller. - * @param networkRequest the network request for which the carrier privilege is checked. - * @return true if caller has carrier privilege and provides the carrier config else false. + * This method can be used to check that a network request for {@link NET_CAPABILITY_CBS} is + * allowed for the UID of a caller, which must hold carrier privilege and provide the carrier + * config. + * It can also be used to check that a factory is entitled to grant access to a given network + * to a given UID on grounds that it is the carrier service package. + * + * @param callingUid uid of the app claimed to be the carrier service package. + * @param networkCapabilities the network capabilities for which carrier privilege is checked. + * @return true if uid provides the relevant carrier config else false. */ - public boolean hasCarrierPrivilegeForNetworkRequest(int callingUid, - NetworkRequest networkRequest) { - if (callingUid != Process.INVALID_UID) { - final int subId = getSubIdFromNetworkSpecifier( - networkRequest.getNetworkSpecifier()); - return callingUid == getCarrierServiceUidForSubId(subId); - } - return false; + public boolean hasCarrierPrivilegeForNetworkCapabilities(int callingUid, + @NonNull NetworkCapabilities networkCapabilities) { + if (callingUid == Process.INVALID_UID) return false; + if (!networkCapabilities.hasSingleTransport(TRANSPORT_CELLULAR)) return false; + final int subId = getSubIdFromNetworkSpecifier(networkCapabilities.getNetworkSpecifier()); + if (SubscriptionManager.INVALID_SUBSCRIPTION_ID == subId) return false; + return callingUid == getCarrierServiceUidForSubId(subId); } @VisibleForTesting @@ -286,7 +293,7 @@ public class CarrierPrivilegeAuthenticator extends BroadcastReceiver { if (specifier instanceof TelephonyNetworkSpecifier) { return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId(); } - return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID; + return SubscriptionManager.INVALID_SUBSCRIPTION_ID; } @VisibleForTesting diff --git a/service/src/com/android/server/connectivity/NetworkAgentInfo.java b/service/src/com/android/server/connectivity/NetworkAgentInfo.java index b9e2a5fb97..e917b3f1d6 100644 --- a/service/src/com/android/server/connectivity/NetworkAgentInfo.java +++ b/service/src/com/android/server/connectivity/NetworkAgentInfo.java @@ -60,6 +60,7 @@ import android.util.Pair; import android.util.SparseArray; import com.android.internal.util.WakeupMessage; +import com.android.modules.utils.build.SdkLevel; import com.android.server.ConnectivityService; import java.io.PrintWriter; @@ -1196,21 +1197,26 @@ public class NetworkAgentInfo implements Comparable, NetworkRa * * @param nc the capabilities to sanitize * @param creatorUid the UID of the process creating this network agent + * @param authenticator the carrier privilege authenticator to check for telephony constraints */ public static void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc, - final int creatorUid) { + final int creatorUid, @NonNull final CarrierPrivilegeAuthenticator authenticator) { if (nc.hasTransport(TRANSPORT_TEST)) { nc.restrictCapabilitiesForTestNetwork(creatorUid); } - if (!areAccessUidsAcceptableFromNetworkAgent(nc)) { + if (!areAccessUidsAcceptableFromNetworkAgent(nc, authenticator)) { nc.setAccessUids(new ArraySet<>()); } } private static boolean areAccessUidsAcceptableFromNetworkAgent( - @NonNull final NetworkCapabilities nc) { + @NonNull final NetworkCapabilities nc, + @Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) { // NCs without access UIDs are fine. if (!nc.hasAccessUids()) return true; + // S and below must never accept access UIDs, even if an agent sends them, because netd + // didn't support the required feature in S. + if (!SdkLevel.isAtLeastT()) return false; // On a non-restricted network, access UIDs make no sense if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) return false; @@ -1219,7 +1225,18 @@ public class NetworkAgentInfo implements Comparable, NetworkRa // access UIDs if (nc.hasTransport(TRANSPORT_TEST)) return true; - // TODO : accept more supported cases + // Factories that make cell networks can allow the UID for the carrier service package. + // This can only work in T where there is support for CarrierPrivilegeAuthenticator + if (null != carrierPrivilegeAuthenticator + && nc.hasSingleTransport(TRANSPORT_CELLULAR) + && (1 == nc.getAccessUidsNoCopy().size()) + && (carrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + nc.getAccessUidsNoCopy().valueAt(0), nc))) { + return true; + } + + // TODO : accept Railway callers + return false; } diff --git a/tests/unit/java/com/android/server/ConnectivityServiceTest.java b/tests/unit/java/com/android/server/ConnectivityServiceTest.java index e41a2ac8bb..013252576e 100644 --- a/tests/unit/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/unit/java/com/android/server/ConnectivityServiceTest.java @@ -264,6 +264,7 @@ import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.RouteInfoParcel; import android.net.SocketKeepalive; +import android.net.TelephonyNetworkSpecifier; import android.net.TransportInfo; import android.net.UidRange; import android.net.UidRangeParcel; @@ -334,6 +335,7 @@ import com.android.net.module.util.LocationPermissionChecker; import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo; import com.android.server.ConnectivityService.NetworkRequestInfo; import com.android.server.ConnectivityServiceTest.ConnectivityServiceDependencies.ReportedInterfaces; +import com.android.server.connectivity.CarrierPrivilegeAuthenticator; import com.android.server.connectivity.ConnectivityFlags; import com.android.server.connectivity.MockableSystemProperties; import com.android.server.connectivity.Nat464Xlat; @@ -529,6 +531,7 @@ public class ConnectivityServiceTest { @Mock Resources mResources; @Mock PacProxyManager mPacProxyManager; @Mock BpfNetMaps mBpfNetMaps; + @Mock CarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator; // BatteryStatsManager is final and cannot be mocked with regular mockito, so just mock the // underlying binder calls. @@ -970,8 +973,6 @@ public class ConnectivityServiceTest { * @param hasInternet Indicate if network should pretend to have NET_CAPABILITY_INTERNET. */ public void connect(boolean validated, boolean hasInternet, boolean isStrictMode) { - assertFalse(getNetworkCapabilities().hasCapability(NET_CAPABILITY_INTERNET)); - ConnectivityManager.NetworkCallback callback = null; final ConditionVariable validatedCv = new ConditionVariable(); if (validated) { @@ -1858,6 +1859,12 @@ public class ConnectivityServiceTest { }; } + @Override + public CarrierPrivilegeAuthenticator makeCarrierPrivilegeAuthenticator( + @NonNull final Context context, @NonNull final TelephonyManager tm) { + return SdkLevel.isAtLeastT() ? mCarrierPrivilegeAuthenticator : null; + } + @Override public boolean intentFilterEquals(final PendingIntent a, final PendingIntent b) { return runAsShell(GET_INTENT_SENDER_INTENT, () -> a.intentFilterEquals(b)); @@ -14643,43 +14650,157 @@ public class ConnectivityServiceTest { agent.getNetwork().getNetId(), intToUidRangeStableParcels(uids), preferenceOrder); - inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids200Parcel); + if (SdkLevel.isAtLeastT()) { + inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids200Parcel); + } uids.add(300); uids.add(400); nc.setAccessUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids)); + if (SdkLevel.isAtLeastT()) { + cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids)); + } else { + cb.assertNoCallback(); + } uids.remove(200); final NativeUidRangeConfig uids300400Parcel = new NativeUidRangeConfig( agent.getNetwork().getNetId(), intToUidRangeStableParcels(uids), preferenceOrder); - inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel); + if (SdkLevel.isAtLeastT()) { + inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids300400Parcel); + } nc.setAccessUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids)); - inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel); + if (SdkLevel.isAtLeastT()) { + cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids)); + inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids200Parcel); + } else { + cb.assertNoCallback(); + } uids.clear(); uids.add(600); nc.setAccessUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids)); + if (SdkLevel.isAtLeastT()) { + cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().equals(uids)); + } else { + cb.assertNoCallback(); + } final NativeUidRangeConfig uids600Parcel = new NativeUidRangeConfig( agent.getNetwork().getNetId(), intToUidRangeStableParcels(uids), preferenceOrder); - inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids600Parcel); - inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids300400Parcel); + if (SdkLevel.isAtLeastT()) { + inOrder.verify(mMockNetd, times(1)).networkAddUidRangesParcel(uids600Parcel); + inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids300400Parcel); + } uids.clear(); nc.setAccessUids(uids); agent.setNetworkCapabilities(nc, true /* sendToConnectivityService */); - cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().isEmpty()); - inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel); + if (SdkLevel.isAtLeastT()) { + cb.expectCapabilitiesThat(agent, caps -> caps.getAccessUids().isEmpty()); + inOrder.verify(mMockNetd, times(1)).networkRemoveUidRangesParcel(uids600Parcel); + } else { + cb.assertNoCallback(); + verify(mMockNetd, never()).networkAddUidRangesParcel(any()); + verify(mMockNetd, never()).networkRemoveUidRangesParcel(any()); + } + + } + + @Test + public void testCbsAccessUids() throws Exception { + mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED); + mServiceContext.setPermission(MANAGE_TEST_NETWORKS, PERMISSION_GRANTED); + + // In this test TEST_PACKAGE_UID will be the UID of the carrier service UID. + doReturn(true).when(mCarrierPrivilegeAuthenticator) + .hasCarrierPrivilegeForNetworkCapabilities(eq(TEST_PACKAGE_UID), any()); + + final ArraySet serviceUidSet = new ArraySet<>(); + serviceUidSet.add(TEST_PACKAGE_UID); + final ArraySet nonServiceUidSet = new ArraySet<>(); + nonServiceUidSet.add(TEST_PACKAGE_UID2); + final ArraySet serviceUidSetPlus = new ArraySet<>(); + serviceUidSetPlus.add(TEST_PACKAGE_UID); + serviceUidSetPlus.add(TEST_PACKAGE_UID2); + + final TestNetworkCallback cb = new TestNetworkCallback(); + + // Simulate a restricted telephony network. The telephony factory is entitled to set + // the access UID to the service package on any of its restricted networks. + final NetworkCapabilities.Builder ncb = new NetworkCapabilities.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .addCapability(NET_CAPABILITY_INTERNET) + .addCapability(NET_CAPABILITY_NOT_SUSPENDED) + .addCapability(NET_CAPABILITY_NOT_VCN_MANAGED) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .setNetworkSpecifier(new TelephonyNetworkSpecifier(1 /* subid */)); + + // Cell gets to set the service UID as access UID + mCm.requestNetwork(new NetworkRequest.Builder() + .addTransportType(TRANSPORT_CELLULAR) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .build(), cb); + mCellNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_CELLULAR, + new LinkProperties(), ncb.build()); + mCellNetworkAgent.connect(true); + cb.expectAvailableThenValidatedCallbacks(mCellNetworkAgent); + ncb.setAccessUids(serviceUidSet); + mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + if (SdkLevel.isAtLeastT()) { + cb.expectCapabilitiesThat(mCellNetworkAgent, + caps -> caps.getAccessUids().equals(serviceUidSet)); + } else { + // S must ignore access UIDs. + cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); + } + + // ...but not to some other UID. Rejection sets UIDs to the empty set + ncb.setAccessUids(nonServiceUidSet); + mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + if (SdkLevel.isAtLeastT()) { + cb.expectCapabilitiesThat(mCellNetworkAgent, + caps -> caps.getAccessUids().isEmpty()); + } else { + // S must ignore access UIDs. + cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); + } + + // ...and also not to multiple UIDs even including the service UID + ncb.setAccessUids(serviceUidSetPlus); + mCellNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); + + mCellNetworkAgent.disconnect(); + cb.expectCallback(CallbackEntry.LOST, mCellNetworkAgent); + mCm.unregisterNetworkCallback(cb); + + // Must be unset before touching the transports, because remove and add transport types + // check the specifier on the builder immediately, contradicting normal builder semantics + // TODO : fix the builder + ncb.setNetworkSpecifier(null); + ncb.removeTransportType(TRANSPORT_CELLULAR); + ncb.addTransportType(TRANSPORT_WIFI); + // Wifi does not get to set access UID, even to the correct UID + mCm.requestNetwork(new NetworkRequest.Builder() + .addTransportType(TRANSPORT_WIFI) + .removeCapability(NET_CAPABILITY_NOT_RESTRICTED) + .build(), cb); + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI, + new LinkProperties(), ncb.build()); + mWiFiNetworkAgent.connect(true); + cb.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + ncb.setAccessUids(serviceUidSet); + mWiFiNetworkAgent.setNetworkCapabilities(ncb.build(), true /* sendToCS */); + cb.assertNoCallback(TEST_CALLBACK_TIMEOUT_MS); + mCm.unregisterNetworkCallback(cb); } /** diff --git a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java index d193aa9819..157507bf28 100644 --- a/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java +++ b/tests/unit/java/com/android/server/connectivity/CarrierPrivilegeAuthenticatorTest.java @@ -17,6 +17,7 @@ package com.android.server.connectivity; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.telephony.TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED; import static com.android.testutils.DevSdkIgnoreRuleKt.SC_V2; @@ -40,7 +41,9 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.NetworkRequest; +import android.net.NetworkSpecifier; import android.net.TelephonyNetworkSpecifier; +import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import com.android.networkstack.apishim.TelephonyManagerShimImpl; @@ -66,27 +69,25 @@ import java.util.List; @RunWith(DevSdkIgnoreRunner.class) @IgnoreUpTo(SC_V2) // TODO: Use to Build.VERSION_CODES.SC_V2 when available public class CarrierPrivilegeAuthenticatorTest { - private static final String PACKAGE_NAME = - CarrierPrivilegeAuthenticatorTest.class.getPackage().getName(); - private static final int TEST_SIM_SLOT_INDEX = 0; - private static final int TEST_SUBSCRIPTION_ID_1 = 2; - private static final int TEST_SUBSCRIPTION_ID_2 = 3; + private static final int SUBSCRIPTION_COUNT = 2; + private static final int TEST_SUBSCRIPTION_ID = 1; @NonNull private final Context mContext; @NonNull private final TelephonyManager mTelephonyManager; @NonNull private final TelephonyManagerShimImpl mTelephonyManagerShim; @NonNull private final PackageManager mPackageManager; - @NonNull private CarrierPrivilegeAuthenticatorChild mCarrierPrivilegeAuthenticator; + @NonNull private TestCarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator; private final int mCarrierConfigPkgUid = 12345; private final String mTestPkg = "com.android.server.connectivity.test"; - public class CarrierPrivilegeAuthenticatorChild extends CarrierPrivilegeAuthenticator { - CarrierPrivilegeAuthenticatorChild(@NonNull final Context c, + public class TestCarrierPrivilegeAuthenticator extends CarrierPrivilegeAuthenticator { + TestCarrierPrivilegeAuthenticator(@NonNull final Context c, @NonNull final TelephonyManager t) { super(c, t, mTelephonyManagerShim); } @Override protected int getSlotIndex(int subId) { + if (SubscriptionManager.DEFAULT_SUBSCRIPTION_ID == subId) return TEST_SUBSCRIPTION_ID; return subId; } } @@ -100,7 +101,7 @@ public class CarrierPrivilegeAuthenticatorTest { @Before public void setUp() throws Exception { - doReturn(2).when(mTelephonyManager).getActiveModemCount(); + doReturn(SUBSCRIPTION_COUNT).when(mTelephonyManager).getActiveModemCount(); doReturn(mTestPkg).when(mTelephonyManagerShim) .getCarrierServicePackageNameForLogicalSlot(anyInt()); doReturn(mPackageManager).when(mContext).getPackageManager(); @@ -109,7 +110,7 @@ public class CarrierPrivilegeAuthenticatorTest { doReturn(applicationInfo).when(mPackageManager) .getApplicationInfo(eq(mTestPkg), anyInt()); mCarrierPrivilegeAuthenticator = - new CarrierPrivilegeAuthenticatorChild(mContext, mTelephonyManager); + new TestCarrierPrivilegeAuthenticator(mContext, mTelephonyManager); } private IntentFilter getIntentFilter() { @@ -126,7 +127,6 @@ public class CarrierPrivilegeAuthenticatorTest { verify(mTelephonyManagerShim, atLeastOnce()) .addCarrierPrivilegesListener(anyInt(), any(), captor.capture()); } catch (UnsupportedApiLevelException e) { - } return captor.getAllValues(); } @@ -160,10 +160,10 @@ public class CarrierPrivilegeAuthenticatorTest { networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR); networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier); - assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest( - mCarrierConfigPkgUid, networkRequestBuilder.build())); - assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest( - mCarrierConfigPkgUid + 1, networkRequestBuilder.build())); + assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities)); + assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid + 1, networkRequestBuilder.build().networkCapabilities)); } @Test @@ -192,10 +192,10 @@ public class CarrierPrivilegeAuthenticatorTest { final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR); networkRequestBuilder.setNetworkSpecifier(telephonyNetworkSpecifier); - assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest( - mCarrierConfigPkgUid, networkRequestBuilder.build())); - assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest( - mCarrierConfigPkgUid + 1, networkRequestBuilder.build())); + assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities)); + assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid + 1, networkRequestBuilder.build().networkCapabilities)); } @Test @@ -215,9 +215,30 @@ public class CarrierPrivilegeAuthenticatorTest { .getApplicationInfo(eq(mTestPkg), anyInt()); listener.onCarrierPrivilegesChanged(Collections.emptyList(), new int[] {}); - assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest( - mCarrierConfigPkgUid, networkRequestBuilder.build())); - assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest( - mCarrierConfigPkgUid + 1, networkRequestBuilder.build())); + assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities)); + assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid + 1, networkRequestBuilder.build().networkCapabilities)); + } + + @Test + public void testDefaultSubscription() throws Exception { + final NetworkRequest.Builder networkRequestBuilder = new NetworkRequest.Builder(); + networkRequestBuilder.addTransportType(TRANSPORT_CELLULAR); + assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities)); + + networkRequestBuilder.setNetworkSpecifier(new TelephonyNetworkSpecifier(0)); + assertTrue(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities)); + + // The builder for NetworkRequest doesn't allow removing the transport as long as a + // specifier is set, so unset it first. TODO : fix the builder + networkRequestBuilder.setNetworkSpecifier((NetworkSpecifier) null); + networkRequestBuilder.removeTransportType(TRANSPORT_CELLULAR); + networkRequestBuilder.addTransportType(TRANSPORT_WIFI); + networkRequestBuilder.setNetworkSpecifier(new TelephonyNetworkSpecifier(0)); + assertFalse(mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities( + mCarrierConfigPkgUid, networkRequestBuilder.build().networkCapabilities)); } }