Accept accessUids from telephony when it's the carrier config app

Test: FrameworksNetTests, new test in this patch
Change-Id: I50fab91e107c51d33a5e529c73b83db198a88d2c
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index fb90053..9cf582c 100644
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -1339,6 +1339,18 @@
         }
 
         /**
+         * @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
          */
         public boolean isFeatureEnabled(Context context, String name, boolean defaultEnabled) {
@@ -1426,12 +1438,8 @@
         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 @@
         }
     }
 
-    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 @@
                     }
                 }
                 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;
@@ -7495,7 +7503,8 @@
             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 c5107ad..ce955fd 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.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 @@
     }
 
     /**
-     * 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 @@
         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 b9e2a5f..e917b3f 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.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 @@
      *
      * @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 @@
         // 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;
     }