Merge "Add more powerful CTS for allowedUids" into main

This commit is contained in:
Jean Chalard 2023-11-20 04:44:22 +00:00 • committed by Gerrit Code Review
commit 51c80a72d8
12 changed files with 455 additions and 41 deletions

View file

@ -1457,6 +1457,18 @@ public final class NetworkCapabilities implements Parcelable {
return mTransportTypes == (1 << transportType);
}
/**
* Returns true iff this NC has the specified transport and no other, ignoring TRANSPORT_TEST.
*
* If this NC has the passed transport and no other, this method returns true.
* If this NC has the passed transport, TRANSPORT_TEST and no other, this method returns true.
* Otherwise, this method returns false.
* @hide
*/
public boolean hasSingleTransportBesidesTest(@Transport int transportType) {
return (mTransportTypes & ~(1 << TRANSPORT_TEST)) == (1 << transportType);
}
private boolean satisfiedByTransportTypes(NetworkCapabilities nc) {
return ((this.mTransportTypes == 0)
|| ((this.mTransportTypes & nc.mTransportTypes) != 0));

View file

@ -2649,6 +2649,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
private boolean canSeeAllowedUids(final int pid, final int uid, final int netOwnerUid) {
return Process.SYSTEM_UID == uid
|| netOwnerUid == uid
|| checkAnyPermissionOf(mContext, pid, uid,
android.Manifest.permission.NETWORK_FACTORY);
}
@VisibleForTesting
NetworkCapabilities networkCapabilitiesRestrictedForCallerPermissions(
NetworkCapabilities nc, int callerPid, int callerUid) {
@ -2670,8 +2677,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)) {
newNc.setAdministratorUids(new int[0]);
}
if (!checkAnyPermissionOf(mContext,
callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
if (!canSeeAllowedUids(callerPid, callerUid, newNc.getOwnerUid())) {
newNc.setAllowedUids(new ArraySet<>());
newNc.setSubscriptionIds(Collections.emptySet());
}
@ -3944,6 +3950,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
pw.println();
dumpBpfProgramStatus(pw);
if (null != mCarrierPrivilegeAuthenticator) {
pw.println();
mCarrierPrivilegeAuthenticator.dump(pw);
}
pw.println();
if (!CollectionUtils.contains(args, SHORT_ARG)) {

View file

@ -41,6 +41,7 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.modules.utils.HandlerExecutor;
import com.android.networkstack.apishim.TelephonyManagerShimImpl;
import com.android.networkstack.apishim.common.TelephonyManagerShim;
@ -125,11 +126,13 @@ public class CarrierPrivilegeAuthenticator {
private class PrivilegeListener implements CarrierPrivilegesListenerShim {
public final int mLogicalSlot;
PrivilegeListener(final int logicalSlot) {
mLogicalSlot = logicalSlot;
}
@Override public void onCarrierPrivilegesChanged(
@Override
public void onCarrierPrivilegesChanged(
@NonNull List<String> privilegedPackageNames,
@NonNull int[] privilegedUids) {
if (mUseCallbacksForServiceChanged) return;
@ -209,7 +212,9 @@ public class CarrierPrivilegeAuthenticator {
public boolean hasCarrierPrivilegeForNetworkCapabilities(int callingUid,
@NonNull NetworkCapabilities networkCapabilities) {
if (callingUid == Process.INVALID_UID) return false;
if (!networkCapabilities.hasSingleTransport(TRANSPORT_CELLULAR)) return false;
if (!networkCapabilities.hasSingleTransportBesidesTest(TRANSPORT_CELLULAR)) {
return false;
}
final int subId = getSubIdFromNetworkSpecifier(networkCapabilities.getNetworkSpecifier());
if (SubscriptionManager.INVALID_SUBSCRIPTION_ID == subId) return false;
return callingUid == getCarrierServiceUidForSubId(subId);
@ -292,4 +297,16 @@ public class CarrierPrivilegeAuthenticator {
Log.e(TAG, "removeCarrierPrivilegesListener API is not available");
}
}
public void dump(IndentingPrintWriter pw) {
pw.println("CarrierPrivilegeAuthenticator:");
synchronized (mLock) {
final int size = mCarrierServiceUid.size();
for (int i = 0; i < size; ++i) {
final int logicalSlot = mCarrierServiceUid.keyAt(i);
final int serviceUid = mCarrierServiceUid.valueAt(i);
pw.println("Logical slot = " + logicalSlot + " : uid = " + serviceUid);
}
}
}
}

View file

@ -17,6 +17,7 @@
package com.android.server.connectivity;
import static android.net.ConnectivityDiagnosticsManager.ConnectivityReport;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@ -1549,7 +1550,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable {
* @param hasAutomotiveFeature true if this device has the automotive feature, false otherwise
* @param authenticator the carrier privilege authenticator to check for telephony constraints
*/
public static void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc,
public void restrictCapabilitiesFromNetworkAgent(@NonNull final NetworkCapabilities nc,
final int creatorUid, final boolean hasAutomotiveFeature,
@NonNull final ConnectivityService.Dependencies deps,
@Nullable final CarrierPrivilegeAuthenticator authenticator) {
@ -1562,7 +1563,7 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable {
}
}
private static boolean areAllowedUidsAcceptableFromNetworkAgent(
private boolean areAllowedUidsAcceptableFromNetworkAgent(
@NonNull final NetworkCapabilities nc, final boolean hasAutomotiveFeature,
@NonNull final ConnectivityService.Dependencies deps,
@Nullable final CarrierPrivilegeAuthenticator carrierPrivilegeAuthenticator) {
@ -1575,19 +1576,25 @@ public class NetworkAgentInfo implements NetworkRanker.Scoreable {
// On a non-restricted network, access UIDs make no sense
if (nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)) return false;
// If this network has TRANSPORT_TEST, then the caller can do whatever they want to
// access UIDs
if (nc.hasTransport(TRANSPORT_TEST)) return true;
// If this network has TRANSPORT_TEST and nothing else, then the caller can do whatever
// they want to access UIDs
if (nc.hasSingleTransport(TRANSPORT_TEST)) return true;
// Factories that make ethernet networks can allow UIDs for automotive devices.
if (nc.hasSingleTransport(TRANSPORT_ETHERNET) && hasAutomotiveFeature) {
return true;
if (nc.hasTransport(TRANSPORT_ETHERNET)) {
// Factories that make ethernet networks can allow UIDs for automotive devices.
if (hasAutomotiveFeature) return true;
// It's also admissible if the ethernet network has TRANSPORT_TEST, as long as it
// doesn't have NET_CAPABILITY_INTERNET so it can't become the default network.
if (nc.hasTransport(TRANSPORT_TEST) && !nc.hasCapability(NET_CAPABILITY_INTERNET)) {
return true;
}
return false;
}
// 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)
&& nc.hasSingleTransportBesidesTest(TRANSPORT_CELLULAR)
&& (1 == nc.getAllowedUidsNoCopy().size())
&& (carrierPrivilegeAuthenticator.hasCarrierPrivilegeForNetworkCapabilities(
nc.getAllowedUidsNoCopy().valueAt(0), nc))) {

View file

@ -62,10 +62,13 @@ java_defaults {
// uncomment when b/13249961 is fixed
// sdk_version: "current",
platform_apis: true,
data: [":ConnectivityTestPreparer"],
per_testcase_directory: true,
host_required: ["net-tests-utils-host-common"],
test_config_template: "AndroidTestTemplate.xml",
data: [
":ConnectivityTestPreparer",
":CtsCarrierServicePackage",
]
}
// Networking CTS tests for development and release. These tests always target the platform SDK
@ -154,3 +157,17 @@ android_test {
package_name: "android.net.cts.maxtargetsdk30", // CTS package names must be unique.
instrumentation_target_package: "android.net.cts.maxtargetsdk30",
}
android_test_helper_app {
name: "CtsCarrierServicePackage",
defaults: ["cts_defaults"],
package_name: "android.net.cts.carrierservicepackage",
manifest: "carrierservicepackage/AndroidManifest.xml",
srcs: ["carrierservicepackage/src/**/*.java"],
min_sdk_version: "30",
// Tag this module as a cts test artifact
test_suites: [
"cts",
"general-tests",
],
}

View file

@ -36,6 +36,7 @@
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
<!-- This test also uses signature permissions through adopting the shell identity.
The permissions acquired that way include (probably not exhaustive) :
@ -46,6 +47,7 @@
android:usesCleartextTraffic="true">
<uses-library android:name="android.test.runner" />
<uses-library android:name="org.apache.http.legacy" android:required="false" />
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
@ -54,4 +56,3 @@
</instrumentation>
</manifest>

View file

@ -27,6 +27,7 @@
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="{MODULE}.apk" />
<option name="test-file-name" value="CtsCarrierServicePackage.apk" />
</target_preparer>
<target_preparer class="com.android.testutils.ConnectivityTestTargetPreparer">
</target_preparer>

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
* Copyright (C) 2023 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
android:versionCode="1"
android:versionName="1.0.0"
package="android.net.cts.carrierservicepackage">
<uses-sdk android:minSdkVersion="30"
android:targetSdkVersion="33" />
<uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
<application android:allowBackup="false"
android:directBootAware="true">
<service android:name=".DummyCarrierConfigService"
android:permission="android.permission.BIND_CARRIER_SERVICES"
android:exported="true">
<intent-filter>
<action android:name="android.service.carrier.CarrierService"/>
</intent-filter>
</service>
</application>
</manifest>

View file

@ -0,0 +1,45 @@
/*
* Copyright (C) 2023 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 android.net.cts.carrierservicepackage;
import android.content.Intent;
import android.os.IBinder;
import android.os.PersistableBundle;
import android.service.carrier.CarrierIdentifier;
import android.service.carrier.CarrierService;
public class DummyCarrierConfigService extends CarrierService {
private static final String TAG = "DummyCarrierConfigService";
public DummyCarrierConfigService() {}
@Override
public PersistableBundle onLoadConfig(CarrierIdentifier id) {
return new PersistableBundle(); // Do nothing
}
@Override
public IBinder onBind(Intent intent) {
return super.onBind(intent);
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}

View file

@ -796,14 +796,15 @@ public class ConnectivityManagerTest {
// Make sure that the NC is null if the package doesn't hold ACCESS_NETWORK_STATE.
assertNull(redactNc(nc, groundedUid, groundedPkg));
// Uids, ssid, underlying networks & subscriptionIds will be redacted if the given uid
// Uids, ssid & underlying networks will be redacted if the given uid
// doesn't hold the associated permissions. The wifi transport info is also suitably
// redacted.
final NetworkCapabilities redactedNormal = redactNc(nc, normalUid, normalPkg);
assertNull(redactedNormal.getUids());
assertNull(redactedNormal.getSsid());
assertNull(redactedNormal.getUnderlyingNetworks());
assertEquals(0, redactedNormal.getSubscriptionIds().size());
// Owner UID is allowed to see the subscription IDs.
assertEquals(2, redactedNormal.getSubscriptionIds().size());
assertEquals(WifiInfo.DEFAULT_MAC_ADDRESS,
((WifiInfo) redactedNormal.getTransportInfo()).getBSSID());
assertEquals(rssi, ((WifiInfo) redactedNormal.getTransportInfo()).getRssi());

View file

@ -15,9 +15,12 @@
*/
package android.net.cts
import android.Manifest.permission.MODIFY_PHONE_STATE
import android.Manifest.permission.NETWORK_SETTINGS
import android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
import android.app.Instrumentation
import android.content.Context
import android.content.pm.PackageManager
import android.net.ConnectivityManager
import android.net.EthernetNetworkSpecifier
import android.net.INetworkAgent
@ -44,7 +47,9 @@ import android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN
import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
import android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH
import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkCapabilities.TRANSPORT_VPN
import android.net.NetworkCapabilities.TRANSPORT_WIFI
@ -53,6 +58,7 @@ import android.net.NetworkProvider
import android.net.NetworkReleasedException
import android.net.NetworkRequest
import android.net.NetworkScore
import android.net.NetworkSpecifier
import android.net.QosCallback
import android.net.QosCallback.QosCallbackRegistrationException
import android.net.QosCallbackException
@ -61,6 +67,7 @@ import android.net.QosSessionAttributes
import android.net.QosSocketInfo
import android.net.RouteInfo
import android.net.SocketKeepalive
import android.net.TelephonyNetworkSpecifier
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
import android.net.Uri
@ -69,21 +76,31 @@ import android.net.VpnTransportInfo
import android.net.cts.NetworkAgentTest.TestableQosCallback.CallbackEntry.OnError
import android.net.cts.NetworkAgentTest.TestableQosCallback.CallbackEntry.OnQosSessionAvailable
import android.net.cts.NetworkAgentTest.TestableQosCallback.CallbackEntry.OnQosSessionLost
import android.net.wifi.WifiInfo
import android.os.Build
import android.os.ConditionVariable
import android.os.Handler
import android.os.HandlerThread
import android.os.Message
import android.os.PersistableBundle
import android.os.Process
import android.os.SystemClock
import android.platform.test.annotations.AppModeFull
import android.system.OsConstants.IPPROTO_TCP
import android.system.OsConstants.IPPROTO_UDP
import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
import android.telephony.TelephonyManager.CarrierPrivilegesCallback
import android.telephony.data.EpsBearerQosSessionAttributes
import android.util.ArraySet
import android.util.DebugUtils.valueToString
import android.util.Log
import androidx.test.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil.runShellCommand
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.ThrowingSupplier
import com.android.compatibility.common.util.UiccUtil
import com.android.modules.utils.build.SdkLevel
import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.CompatUtil
@ -112,23 +129,8 @@ import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnUnregisterQosC
import com.android.testutils.TestableNetworkAgent.CallbackEntry.OnValidationStatus
import com.android.testutils.TestableNetworkCallback
import com.android.testutils.assertThrows
import java.io.Closeable
import java.io.IOException
import java.net.DatagramSocket
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Socket
import java.time.Duration
import java.util.Arrays
import java.util.UUID
import java.util.concurrent.Executors
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.test.fail
import com.android.testutils.runAsShell
import com.android.testutils.tryTest
import org.junit.After
import org.junit.Before
import org.junit.Test
@ -140,7 +142,26 @@ import org.mockito.Mockito.doReturn
import org.mockito.Mockito.mock
import org.mockito.Mockito.timeout
import org.mockito.Mockito.verify
import java.io.Closeable
import java.io.IOException
import java.net.DatagramSocket
import java.net.InetAddress
import java.net.InetSocketAddress
import java.net.Socket
import java.security.MessageDigest
import java.time.Duration
import java.util.Arrays
import java.util.UUID
import java.util.concurrent.Executors
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertFalse
import kotlin.test.assertNotNull
import kotlin.test.assertNull
import kotlin.test.assertTrue
import kotlin.test.fail
private const val TAG = "NetworkAgentTest"
// This test doesn't really have a constraint on how fast the methods should return. If it's
// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio
// without affecting the run time of successful runs. Thus, set a very high timeout.
@ -261,17 +282,18 @@ class NetworkAgentTest {
callbacksToCleanUp.add(callback)
}
private fun makeTestNetworkRequest(specifier: String? = null): NetworkRequest {
return NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.also {
if (specifier != null) {
it.setNetworkSpecifier(CompatUtil.makeEthernetNetworkSpecifier(specifier))
}
}
.build()
}
private fun String?.asEthSpecifier(): NetworkSpecifier? =
if (null == this) null else CompatUtil.makeEthernetNetworkSpecifier(this)
private fun makeTestNetworkRequest(specifier: NetworkSpecifier? = null) =
NetworkRequest.Builder().run {
clearCapabilities()
addTransportType(TRANSPORT_TEST)
if (specifier != null) setNetworkSpecifier(specifier)
build()
}
private fun makeTestNetworkRequest(specifier: String?) =
makeTestNetworkRequest(specifier.asEthSpecifier())
private fun makeTestNetworkCapabilities(
specifier: String? = null,
@ -322,7 +344,7 @@ class NetworkAgentTest {
): Pair<TestableNetworkAgent, TestableNetworkCallback> {
val callback = TestableNetworkCallback()
// Ensure this NetworkAgent is never unneeded by filing a request with its specifier.
requestNetwork(makeTestNetworkRequest(specifier = specifier), callback)
requestNetwork(makeTestNetworkRequest(specifier), callback)
val nc = makeTestNetworkCapabilities(specifier, transports)
val agent = createNetworkAgent(context, initialConfig = initialConfig, initialNc = nc)
agent.setTeardownDelayMillis(0)
@ -543,6 +565,227 @@ class NetworkAgentTest {
.addTransportType(TRANSPORT_TEST)
.setAllowedUids(uids.toSet()).build()
/**
* Get the single element from this ArraySet, or fail() if doesn't contain exactly 1 element.
*/
fun <T> ArraySet<T>.getSingleElement(): T {
if (size != 1) fail("Expected exactly one element, contained $size")
return iterator().next()
}
private fun doTestAllowedUids(
subId: Int,
transport: Int,
uid: Int,
expectUidsPresent: Boolean
) {
doTestAllowedUids(subId, intArrayOf(transport), uid, expectUidsPresent)
}
private fun doTestAllowedUids(
subId: Int,
transports: IntArray,
uid: Int,
expectUidsPresent: Boolean
) {
val callback = TestableNetworkCallback(DEFAULT_TIMEOUT_MS)
val specifier = when {
transports.size != 1 -> null
TRANSPORT_ETHERNET in transports -> EthernetNetworkSpecifier("testInterface")
TRANSPORT_CELLULAR in transports -> TelephonyNetworkSpecifier(subId)
else -> null
}
val agent = createNetworkAgent(initialNc = NetworkCapabilities.Builder().run {
addTransportType(TRANSPORT_TEST)
transports.forEach { addTransportType(it) }
addCapability(NET_CAPABILITY_NOT_VCN_MANAGED)
addCapability(NET_CAPABILITY_NOT_SUSPENDED)
removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
setNetworkSpecifier(specifier)
if (TRANSPORT_WIFI in transports && SdkLevel.isAtLeastV()) {
// setSubscriptionId only exists in V+
setTransportInfo(WifiInfo.Builder().setSubscriptionId(subId).build())
}
setAllowedUids(setOf(uid))
setOwnerUid(Process.myUid())
setAdministratorUids(intArrayOf(Process.myUid()))
build()
})
runWithShellPermissionIdentity {
agent.register()
}
agent.markConnected()
registerNetworkCallback(makeTestNetworkRequest(specifier), callback)
callback.expect<Available>(agent.network!!)
callback.expect<CapabilitiesChanged>(agent.network!!) {
if (expectUidsPresent) {
it.caps.allowedUidsNoCopy.getSingleElement() == uid
} else {
it.caps.allowedUidsNoCopy.isEmpty()
}
}
agent.unregister()
// callback will be unregistered in tearDown()
}
private fun setHoldCarrierPrivilege(hold: Boolean, subId: Int) {
fun getCertHash(): String {
val pkgInfo = realContext.packageManager.getPackageInfo(realContext.opPackageName,
PackageManager.GET_SIGNATURES)
val digest = MessageDigest.getInstance("SHA-256")
val certHash = digest.digest(pkgInfo.signatures!![0]!!.toByteArray())
return UiccUtil.bytesToHexString(certHash)!!
}
val tm = realContext.getSystemService(TelephonyManager::class.java)!!
val ccm = realContext.getSystemService(CarrierConfigManager::class.java)!!
val cv = ConditionVariable()
val cpb = PrivilegeWaiterCallback(cv)
tryTest {
val slotIndex = SubscriptionManager.getSlotIndex(subId)!!
runAsShell(READ_PRIVILEGED_PHONE_STATE) {
tm.registerCarrierPrivilegesCallback(slotIndex, { it.run() }, cpb)
}
// Wait for the callback to be registered
assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't register CarrierPrivilegesCallback")
if (cpb.hasPrivilege == hold) {
if (hold) {
Log.w(TAG, "Package ${realContext.opPackageName} already is privileged")
} else {
Log.w(TAG, "Package ${realContext.opPackageName} already isn't privileged")
}
return@tryTest
}
cv.close()
runAsShell(MODIFY_PHONE_STATE) {
val carrierConfigs = if (hold) {
PersistableBundle().also {
it.putStringArray(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
arrayOf(getCertHash()))
}
} else {
null
}
ccm.overrideConfig(subId, carrierConfigs)
}
assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't change carrier privilege")
} cleanup {
runAsShell(READ_PRIVILEGED_PHONE_STATE) {
tm.unregisterCarrierPrivilegesCallback(cpb)
}
}
}
private fun acquireCarrierPrivilege(subId: Int) = setHoldCarrierPrivilege(true, subId)
private fun dropCarrierPrivilege(subId: Int) = setHoldCarrierPrivilege(false, subId)
private fun setCarrierServicePackageOverride(subId: Int, pkg: String?) {
val tm = realContext.getSystemService(TelephonyManager::class.java)!!
val cv = ConditionVariable()
val cpb = CarrierServiceChangedWaiterCallback(cv)
tryTest {
val slotIndex = SubscriptionManager.getSlotIndex(subId)!!
runAsShell(READ_PRIVILEGED_PHONE_STATE) {
tm.registerCarrierPrivilegesCallback(slotIndex, { it.run() }, cpb)
}
// Wait for the callback to be registered
assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't register CarrierPrivilegesCallback")
if (cpb.pkgName == pkg) {
Log.w(TAG, "Carrier service package was already $pkg")
return@tryTest
}
cv.close()
runAsShell(MODIFY_PHONE_STATE) {
if (null == pkg) {
// There is a bug is clear-carrier-service-package-override where not adding
// the -s argument will use the wrong slot index : b/299604822
runShellCommand("cmd phone clear-carrier-service-package-override" +
" -s $subId")
} else {
// -s could set the subId, but this test works with the default subId.
runShellCommand("cmd phone set-carrier-service-package-override $pkg")
}
}
assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't modify carrier service package")
} cleanup {
runAsShell(READ_PRIVILEGED_PHONE_STATE) {
tm.unregisterCarrierPrivilegesCallback(cpb)
}
}
}
private fun String.execute() = runShellCommand(this).trim()
@Test
@IgnoreUpTo(Build.VERSION_CODES.S)
fun testAllowedUids() {
// Use a different package than this one to make sure that a package that doesn't hold
// carrier service permission can be set as an allowed UID.
val servicePackage = "android.net.cts.carrierservicepackage"
val uid = try {
realContext.packageManager.getApplicationInfo(servicePackage, 0).uid
} catch (e: PackageManager.NameNotFoundException) {
fail("$servicePackage could not be installed, please check the SuiteApkInstaller" +
" installed CtsCarrierServicePackage.apk", e)
}
val tm = realContext.getSystemService(TelephonyManager::class.java)!!
val defaultSubId = SubscriptionManager.getDefaultSubscriptionId()
tryTest {
// This process is not the carrier service UID, so allowedUids should be ignored in all
// the following cases.
doTestAllowedUids(defaultSubId, TRANSPORT_CELLULAR, uid, expectUidsPresent = false)
doTestAllowedUids(defaultSubId, TRANSPORT_WIFI, uid, expectUidsPresent = false)
doTestAllowedUids(defaultSubId, TRANSPORT_BLUETOOTH, uid, expectUidsPresent = false)
// The tools to set the carrier service package override do not exist before U,
// so there is no way to test the rest of this test on < U.
if (!SdkLevel.isAtLeastU()) return@tryTest
// Acquiring carrier privilege is necessary to override the carrier service package.
val defaultSlotIndex = SubscriptionManager.getSlotIndex(defaultSubId)
acquireCarrierPrivilege(defaultSubId)
setCarrierServicePackageOverride(defaultSubId, servicePackage)
val actualServicePackage: String? = runAsShell(READ_PRIVILEGED_PHONE_STATE) {
tm.getCarrierServicePackageNameForLogicalSlot(defaultSlotIndex)
}
assertEquals(servicePackage, actualServicePackage)
// Wait for CarrierServiceAuthenticator to have seen the update of the service package
val timeout = SystemClock.elapsedRealtime() + DEFAULT_TIMEOUT_MS
while (true) {
if (SystemClock.elapsedRealtime() > timeout) {
fail("Couldn't make $servicePackage the service package for $defaultSubId: "
+ "dumpsys connectivity".execute().split("\n")
.filter { it.contains("Logical slot = $defaultSlotIndex.*") })
}
if ("dumpsys connectivity"
.execute()
.split("\n")
.filter { it.contains("Logical slot = $defaultSlotIndex : uid = $uid") }
.isNotEmpty()) {
// Found the configuration
break
}
Thread.sleep(500)
}
// Cell is allowed to set UIDs, but not WIFI/BLUETOOTH or agents with multiple
// transports.
doTestAllowedUids(defaultSubId, TRANSPORT_CELLULAR, uid, expectUidsPresent = true)
doTestAllowedUids(defaultSubId, TRANSPORT_WIFI, uid, expectUidsPresent = false)
doTestAllowedUids(defaultSubId, TRANSPORT_BLUETOOTH, uid, expectUidsPresent = false)
doTestAllowedUids(defaultSubId, intArrayOf(TRANSPORT_CELLULAR, TRANSPORT_WIFI), uid,
expectUidsPresent = false)
} cleanupStep {
if (SdkLevel.isAtLeastU()) setCarrierServicePackageOverride(defaultSubId, null)
} cleanup {
if (SdkLevel.isAtLeastU()) dropCarrierPrivilege(defaultSubId)
}
}
@Test
fun testRejectedUpdates() {
val callback = TestableNetworkCallback(DEFAULT_TIMEOUT_MS)
@ -1497,3 +1740,25 @@ class NetworkAgentTest {
doTestNativeNetworkCreation(expectCreatedImmediately = true, intArrayOf(TRANSPORT_VPN))
}
}
// Subclasses of CarrierPrivilegesCallback can't be inline, or they'll be compiled as
// inner classes of the test class and will fail resolution on R as the test harness
// uses reflection to list all methods and classes
class PrivilegeWaiterCallback(private val cv: ConditionVariable) :
CarrierPrivilegesCallback {
var hasPrivilege = false
override fun onCarrierPrivilegesChanged(p: MutableSet<String>, uids: MutableSet<Int>) {
hasPrivilege = uids.contains(Process.myUid())
cv.open()
}
}
class CarrierServiceChangedWaiterCallback(private val cv: ConditionVariable) :
CarrierPrivilegesCallback {
var pkgName: String? = null
override fun onCarrierPrivilegesChanged(p: MutableSet<String>, u: MutableSet<Int>) {}
override fun onCarrierServiceChanged(pkgName: String?, uid: Int) {
this.pkgName = pkgName
cv.open()
}
}

View file

@ -17385,6 +17385,7 @@ public class ConnectivityServiceTest {
mCm.requestNetwork(new NetworkRequest.Builder()
.clearCapabilities()
.addTransportType(TRANSPORT_TEST)
.addTransportType(TRANSPORT_CELLULAR)
.build(),
cb);