Allow Carrier app to request for CBS capability
Test: unit test and CTS Bug: 194332512 Change-Id: I29680b56d790106ad082f1a398c2bddb030f834a
This commit is contained in:
@@ -249,6 +249,7 @@ import com.android.net.module.util.NetworkCapabilitiesUtils;
|
||||
import com.android.net.module.util.PermissionUtils;
|
||||
import com.android.net.module.util.netlink.InetDiagMessage;
|
||||
import com.android.server.connectivity.AutodestructReference;
|
||||
import com.android.server.connectivity.CarrierPrivilegeAuthenticator;
|
||||
import com.android.server.connectivity.ConnectivityFlags;
|
||||
import com.android.server.connectivity.DnsManager;
|
||||
import com.android.server.connectivity.DnsManager.PrivateDnsValidationUpdate;
|
||||
@@ -593,6 +594,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
// Handle private DNS validation status updates.
|
||||
private static final int EVENT_PRIVATE_DNS_VALIDATION_UPDATE = 38;
|
||||
|
||||
/**
|
||||
* used to remove a network request, either a listener or a real request and call unavailable
|
||||
* arg1 = UID of caller
|
||||
* obj = NetworkRequest
|
||||
*/
|
||||
private static final int EVENT_RELEASE_NETWORK_REQUEST_AND_CALL_UNAVAILABLE = 39;
|
||||
|
||||
/**
|
||||
* Event for NetworkMonitor/NetworkAgentInfo to inform ConnectivityService that the network has
|
||||
* been tested.
|
||||
@@ -760,6 +768,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
private Set<String> mWolSupportedInterfaces;
|
||||
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
private final CarrierPrivilegeAuthenticator mCarrierPrivilegeAuthenticator;
|
||||
private final AppOpsManager mAppOpsManager;
|
||||
|
||||
private final LocationPermissionChecker mLocationPermissionChecker;
|
||||
@@ -1406,6 +1415,12 @@ 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;
|
||||
}
|
||||
|
||||
// To ensure uid state is synchronized with Network Policy, register for
|
||||
// NetworkPolicyManagerService events must happen prior to NetworkPolicyManagerService
|
||||
@@ -4140,6 +4155,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasCarrierPrivilegeForNetworkRequest(int callingUid,
|
||||
NetworkRequest networkRequest) {
|
||||
if (SdkLevel.isAtLeastT() && mCarrierPrivilegeAuthenticator != null) {
|
||||
return mCarrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkRequest(callingUid,
|
||||
networkRequest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void handleRegisterNetworkRequestWithIntent(@NonNull final Message msg) {
|
||||
final NetworkRequestInfo nri = (NetworkRequestInfo) (msg.obj);
|
||||
// handleRegisterNetworkRequestWithIntent() doesn't apply to multilayer requests.
|
||||
@@ -4163,6 +4187,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
|
||||
private void handleRegisterNetworkRequests(@NonNull final Set<NetworkRequestInfo> nris) {
|
||||
ensureRunningOnConnectivityServiceThread();
|
||||
NetworkRequest requestToBeReleased = null;
|
||||
for (final NetworkRequestInfo nri : nris) {
|
||||
mNetworkRequestInfoLogs.log("REGISTER " + nri);
|
||||
checkNrisConsistency(nri);
|
||||
@@ -4177,7 +4202,15 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
}
|
||||
}
|
||||
if (req.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
|
||||
if (!hasCarrierPrivilegeForNetworkRequest(nri.mUid, req)
|
||||
&& !checkConnectivityRestrictedNetworksPermission(
|
||||
nri.mPid, nri.mUid)) {
|
||||
requestToBeReleased = req;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If this NRI has a satisfier already, it is replacing an older request that
|
||||
// has been removed. Track it.
|
||||
final NetworkRequest activeRequest = nri.getActiveRequest();
|
||||
@@ -4187,6 +4220,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
}
|
||||
}
|
||||
|
||||
if (requestToBeReleased != null) {
|
||||
releaseNetworkRequestAndCallOnUnavailable(requestToBeReleased);
|
||||
return;
|
||||
}
|
||||
|
||||
if (mFlags.noRematchAllRequestsOnRegister()) {
|
||||
rematchNetworksAndRequests(nris);
|
||||
} else {
|
||||
@@ -5026,6 +5064,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
/* callOnUnavailable */ false);
|
||||
break;
|
||||
}
|
||||
case EVENT_RELEASE_NETWORK_REQUEST_AND_CALL_UNAVAILABLE: {
|
||||
handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1,
|
||||
/* callOnUnavailable */ true);
|
||||
break;
|
||||
}
|
||||
case EVENT_SET_ACCEPT_UNVALIDATED: {
|
||||
Network network = (Network) msg.obj;
|
||||
handleSetAcceptUnvalidated(network, toBool(msg.arg1), toBool(msg.arg2));
|
||||
@@ -6330,12 +6373,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
private void enforceNetworkRequestPermissions(NetworkCapabilities networkCapabilities,
|
||||
String callingPackageName, String callingAttributionTag) {
|
||||
if (networkCapabilities.hasCapability(NET_CAPABILITY_NOT_RESTRICTED) == false) {
|
||||
enforceConnectivityRestrictedNetworksPermission();
|
||||
if (!networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_CBS)) {
|
||||
enforceConnectivityRestrictedNetworksPermission();
|
||||
}
|
||||
} else {
|
||||
enforceChangePermission(callingPackageName, callingAttributionTag);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkConnectivityRestrictedNetworksPermission(int callerPid, int callerUid) {
|
||||
if (checkAnyPermissionOf(callerPid, callerUid,
|
||||
android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS)
|
||||
|| checkAnyPermissionOf(callerPid, callerUid,
|
||||
android.Manifest.permission.CONNECTIVITY_INTERNAL)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestBandwidthUpdate(Network network) {
|
||||
enforceAccessPermission();
|
||||
@@ -6402,7 +6457,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
ensureValidNetworkSpecifier(networkCapabilities);
|
||||
restrictRequestUidsForCallerAndSetRequestorInfo(networkCapabilities,
|
||||
callingUid, callingPackageName);
|
||||
|
||||
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
|
||||
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
|
||||
NetworkRequestInfo nri = new NetworkRequestInfo(callingUid, networkRequest, operation,
|
||||
@@ -6518,6 +6572,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
||||
EVENT_RELEASE_NETWORK_REQUEST, mDeps.getCallingUid(), 0, networkRequest));
|
||||
}
|
||||
|
||||
private void releaseNetworkRequestAndCallOnUnavailable(NetworkRequest networkRequest) {
|
||||
ensureNetworkRequestHasType(networkRequest);
|
||||
mHandler.sendMessage(mHandler.obtainMessage(
|
||||
EVENT_RELEASE_NETWORK_REQUEST_AND_CALL_UNAVAILABLE, mDeps.getCallingUid(), 0,
|
||||
networkRequest));
|
||||
}
|
||||
|
||||
private void handleRegisterNetworkProvider(NetworkProviderInfo npi) {
|
||||
if (mNetworkProviderInfos.containsKey(npi.messenger)) {
|
||||
// Avoid creating duplicates. even if an app makes a direct AIDL call.
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.connectivity;
|
||||
|
||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
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.NetworkSpecifier;
|
||||
import android.net.TelephonyNetworkSpecifier;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Process;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.networkstack.apishim.TelephonyManagerShimImpl;
|
||||
import com.android.networkstack.apishim.common.TelephonyManagerShim;
|
||||
import com.android.networkstack.apishim.common.TelephonyManagerShim.CarrierPrivilegesListenerShim;
|
||||
import com.android.networkstack.apishim.common.UnsupportedApiLevelException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
|
||||
/**
|
||||
* Tracks the uid of the carrier privileged app that provides the carrier config.
|
||||
* Authenticates if the caller has same uid as
|
||||
* carrier privileged app that provides the carrier config
|
||||
* @hide
|
||||
*/
|
||||
public class CarrierPrivilegeAuthenticator extends BroadcastReceiver {
|
||||
private static final String TAG = CarrierPrivilegeAuthenticator.class.getSimpleName();
|
||||
private static final boolean DBG = true;
|
||||
|
||||
// The context is for the current user (system server)
|
||||
private final Context mContext;
|
||||
private final TelephonyManagerShim mTelephonyManagerShim;
|
||||
private final TelephonyManager mTelephonyManager;
|
||||
@GuardedBy("mLock")
|
||||
private int[] mCarrierServiceUid;
|
||||
@GuardedBy("mLock")
|
||||
private int mModemCount = 0;
|
||||
private final Object mLock = new Object();
|
||||
private final HandlerThread mThread;
|
||||
private final Handler mHandler;
|
||||
@NonNull
|
||||
private final List<CarrierPrivilegesListenerShim> mCarrierPrivilegesChangedListeners =
|
||||
new ArrayList<>();
|
||||
|
||||
public CarrierPrivilegeAuthenticator(@NonNull final Context c,
|
||||
@NonNull final TelephonyManager t,
|
||||
@NonNull final TelephonyManagerShimImpl telephonyManagerShim) {
|
||||
mContext = c;
|
||||
mTelephonyManager = t;
|
||||
mTelephonyManagerShim = telephonyManagerShim;
|
||||
mThread = new HandlerThread(TAG);
|
||||
mThread.start();
|
||||
mHandler = new Handler(mThread.getLooper()) {};
|
||||
synchronized (mLock) {
|
||||
mModemCount = mTelephonyManager.getActiveModemCount();
|
||||
registerForCarrierChanges();
|
||||
updateCarrierServiceUid();
|
||||
}
|
||||
}
|
||||
|
||||
public CarrierPrivilegeAuthenticator(@NonNull final Context c,
|
||||
@NonNull final TelephonyManager t) {
|
||||
mContext = c;
|
||||
mTelephonyManager = t;
|
||||
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S) {
|
||||
mTelephonyManagerShim = new TelephonyManagerShimImpl(mTelephonyManager);
|
||||
} else {
|
||||
mTelephonyManagerShim = null;
|
||||
}
|
||||
mThread = new HandlerThread(TAG);
|
||||
mThread.start();
|
||||
mHandler = new Handler(mThread.getLooper()) {};
|
||||
synchronized (mLock) {
|
||||
mModemCount = mTelephonyManager.getActiveModemCount();
|
||||
registerForCarrierChanges();
|
||||
updateCarrierServiceUid();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An adapter {@link Executor} that posts all executed tasks onto the given
|
||||
* {@link Handler}.
|
||||
*
|
||||
* TODO : migrate to the version in frameworks/libs/net when it's ready
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class HandlerExecutor implements Executor {
|
||||
private final Handler mHandler;
|
||||
public HandlerExecutor(@NonNull Handler handler) {
|
||||
mHandler = handler;
|
||||
}
|
||||
@Override
|
||||
public void execute(Runnable command) {
|
||||
if (!mHandler.post(command)) {
|
||||
throw new RejectedExecutionException(mHandler + " is shutting down");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast receiver for ACTION_MULTI_SIM_CONFIG_CHANGED
|
||||
*
|
||||
* <p>The broadcast receiver is registered with mHandler
|
||||
*/
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
switch (intent.getAction()) {
|
||||
case TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED:
|
||||
handleActionMultiSimConfigChanged(context, intent);
|
||||
break;
|
||||
default:
|
||||
Log.d(TAG, "Unknown intent received with action: " + intent.getAction());
|
||||
}
|
||||
}
|
||||
|
||||
private void handleActionMultiSimConfigChanged(Context context, Intent intent) {
|
||||
unregisterCarrierPrivilegesListeners();
|
||||
synchronized (mLock) {
|
||||
mModemCount = mTelephonyManager.getActiveModemCount();
|
||||
}
|
||||
registerCarrierPrivilegesListeners();
|
||||
updateCarrierServiceUid();
|
||||
}
|
||||
|
||||
private void registerForCarrierChanges() {
|
||||
final IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(TelephonyManager.ACTION_MULTI_SIM_CONFIG_CHANGED);
|
||||
mContext.registerReceiver(this, filter, null, mHandler);
|
||||
registerCarrierPrivilegesListeners();
|
||||
}
|
||||
|
||||
private void registerCarrierPrivilegesListeners() {
|
||||
final HandlerExecutor executor = new HandlerExecutor(mHandler);
|
||||
int modemCount;
|
||||
synchronized (mLock) {
|
||||
modemCount = mModemCount;
|
||||
}
|
||||
try {
|
||||
for (int i = 0; i < modemCount; i++) {
|
||||
CarrierPrivilegesListenerShim carrierPrivilegesListener =
|
||||
new CarrierPrivilegesListenerShim() {
|
||||
@Override
|
||||
public void onCarrierPrivilegesChanged(
|
||||
@NonNull List<String> privilegedPackageNames,
|
||||
@NonNull int[] privilegedUids) {
|
||||
// Re-trigger the synchronous check (which is also very cheap due
|
||||
// to caching in CarrierPrivilegesTracker). This allows consistency
|
||||
// with the onSubscriptionsChangedListener and broadcasts.
|
||||
updateCarrierServiceUid();
|
||||
}
|
||||
};
|
||||
addCarrierPrivilegesListener(i, executor, carrierPrivilegesListener);
|
||||
mCarrierPrivilegesChangedListeners.add(carrierPrivilegesListener);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "Encountered exception registering carrier privileges listeners", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCarrierPrivilegesListener(int logicalSlotIndex, Executor executor,
|
||||
CarrierPrivilegesListenerShim listener) {
|
||||
if (mTelephonyManagerShim == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mTelephonyManagerShim.addCarrierPrivilegesListener(
|
||||
logicalSlotIndex, executor, listener);
|
||||
} catch (UnsupportedApiLevelException unsupportedApiLevelException) {
|
||||
Log.e(TAG, "addCarrierPrivilegesListener API is not available");
|
||||
}
|
||||
}
|
||||
|
||||
private void removeCarrierPrivilegesListener(CarrierPrivilegesListenerShim listener) {
|
||||
if (mTelephonyManagerShim == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
mTelephonyManagerShim.removeCarrierPrivilegesListener(listener);
|
||||
} catch (UnsupportedApiLevelException unsupportedApiLevelException) {
|
||||
Log.e(TAG, "removeCarrierPrivilegesListener API is not available");
|
||||
}
|
||||
}
|
||||
|
||||
private String getCarrierServicePackageNameForLogicalSlot(int logicalSlotIndex) {
|
||||
if (mTelephonyManagerShim == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return mTelephonyManagerShim.getCarrierServicePackageNameForLogicalSlot(
|
||||
logicalSlotIndex);
|
||||
} catch (UnsupportedApiLevelException unsupportedApiLevelException) {
|
||||
Log.e(TAG, "getCarrierServicePackageNameForLogicalSlot API is not available");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void unregisterCarrierPrivilegesListeners() {
|
||||
for (CarrierPrivilegesListenerShim carrierPrivilegesListener :
|
||||
mCarrierPrivilegesChangedListeners) {
|
||||
removeCarrierPrivilegesListener(carrierPrivilegesListener);
|
||||
}
|
||||
mCarrierPrivilegesChangedListeners.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if network request is allowed based upon carrrier service package.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @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.
|
||||
*/
|
||||
public boolean hasCarrierPrivilegeForNetworkRequest(int callingUid,
|
||||
NetworkRequest networkRequest) {
|
||||
if (callingUid != Process.INVALID_UID) {
|
||||
final int subId = getSubIdFromNetworkSpecifier(
|
||||
networkRequest.getNetworkSpecifier());
|
||||
return callingUid == getCarrierServiceUidForSubId(subId);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void updateCarrierServiceUid() {
|
||||
synchronized (mLock) {
|
||||
mCarrierServiceUid = new int[mModemCount];
|
||||
for (int i = 0; i < mModemCount; i++) {
|
||||
mCarrierServiceUid[i] = getCarrierServicePackageUidForSlot(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getCarrierServiceUidForSubId(int subId) {
|
||||
final int slotId = getSlotIndex(subId);
|
||||
synchronized (mLock) {
|
||||
if (slotId != SubscriptionManager.INVALID_SIM_SLOT_INDEX && slotId < mModemCount) {
|
||||
return mCarrierServiceUid[slotId];
|
||||
}
|
||||
}
|
||||
return Process.INVALID_UID;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected int getSlotIndex(int subId) {
|
||||
return SubscriptionManager.getSlotIndex(subId);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getSubIdFromNetworkSpecifier(NetworkSpecifier specifier) {
|
||||
if (specifier instanceof TelephonyNetworkSpecifier) {
|
||||
return ((TelephonyNetworkSpecifier) specifier).getSubscriptionId();
|
||||
}
|
||||
return SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getUidForPackage(String pkgName) {
|
||||
if (pkgName == null) {
|
||||
return Process.INVALID_UID;
|
||||
}
|
||||
try {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
if (pm != null) {
|
||||
ApplicationInfo applicationInfo = pm.getApplicationInfo(pkgName, 0);
|
||||
if (applicationInfo != null) {
|
||||
return applicationInfo.uid;
|
||||
}
|
||||
}
|
||||
} catch (PackageManager.NameNotFoundException exception) {
|
||||
// Didn't find package. Try other users
|
||||
Log.i(TAG, "Unable to find uid for package " + pkgName);
|
||||
}
|
||||
return Process.INVALID_UID;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
int getCarrierServicePackageUidForSlot(int slotId) {
|
||||
return getUidForPackage(getCarrierServicePackageNameForLogicalSlot(slotId));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user