From 72bc600be2e552e202a8e038f5a00f1a568819e7 Mon Sep 17 00:00:00 2001 From: Yuyang Huang Date: Fri, 17 Feb 2023 17:29:01 +0900 Subject: [PATCH] Verify the access to the mdnsd socket is blocked from Android U The untrusted apps should not directly access /dev/socket/mdnsd since Android U(SDK 34). For untrusted apps built with target SDK 33 or less, it should still be able to access the mdnsd socket. Fix the mts test suits from mts-networking to mts-tethering. If the test suits is marked as mts-networking, it would run in NetworkStack MTS, which isn't really what is tested in the tests. Test: atest CtsNetTestCases CtsNetTestCasesMaxTargetSdk33 Bug: 267102290 Change-Id: I851c181fa7489115fb1f335a369830078f5a5c14 --- TEST_MAPPING | 22 ++++++ tests/cts/net/Android.bp | 35 ++++++---- .../net/src/android/net/cts/NsdManagerTest.kt | 70 +++++++++++++++++++ 3 files changed, 112 insertions(+), 15 deletions(-) diff --git a/TEST_MAPPING b/TEST_MAPPING index 34646e2068..4d3ecdfaf0 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -57,6 +57,17 @@ } ] }, + { + "name": "CtsNetTestCasesMaxTargetSdk33", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + }, + { + "exclude-annotation": "androidx.test.filters.RequiresDevice" + } + ] + }, { "name": "bpf_existence_test" }, @@ -143,6 +154,17 @@ } ] }, + { + "name": "CtsNetTestCasesMaxTargetSdk33[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]", + "options": [ + { + "exclude-annotation": "com.android.testutils.SkipPresubmit" + }, + { + "exclude-annotation": "androidx.test.filters.RequiresDevice" + } + ] + }, // Test with APK modules only, in cases where APEX is not supported, or the other modules // were simply not updated { diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp index 23cb15c6bc..f9fe5b011e 100644 --- a/tests/cts/net/Android.bp +++ b/tests/cts/net/Android.bp @@ -114,34 +114,39 @@ android_test { ], } -android_test { - name: "CtsNetTestCasesMaxTargetSdk31", // Must match CtsNetTestCasesMaxTargetSdk31 annotation. +java_defaults { + name: "CtsNetTestCasesMaxTargetSdkDefaults", defaults: [ "CtsNetTestCasesDefaults", "CtsNetTestCasesApiStableDefaults", ], - target_sdk_version: "31", - package_name: "android.net.cts.maxtargetsdk31", // CTS package names must be unique. - instrumentation_target_package: "android.net.cts.maxtargetsdk31", test_suites: [ "cts", "general-tests", - "mts-networking", + "mts-tethering", ], } +android_test { + name: "CtsNetTestCasesMaxTargetSdk33", // Must match CtsNetTestCasesMaxTargetSdk33 annotation. + defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"], + target_sdk_version: "33", + package_name: "android.net.cts.maxtargetsdk33", + instrumentation_target_package: "android.net.cts.maxtargetsdk33", +} + +android_test { + name: "CtsNetTestCasesMaxTargetSdk31", // Must match CtsNetTestCasesMaxTargetSdk31 annotation. + defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"], + target_sdk_version: "31", + package_name: "android.net.cts.maxtargetsdk31", // CTS package names must be unique. + instrumentation_target_package: "android.net.cts.maxtargetsdk31", +} + android_test { name: "CtsNetTestCasesMaxTargetSdk30", // Must match CtsNetTestCasesMaxTargetSdk30 annotation. - defaults: [ - "CtsNetTestCasesDefaults", - "CtsNetTestCasesApiStableDefaults", - ], + defaults: ["CtsNetTestCasesMaxTargetSdkDefaults"], target_sdk_version: "30", package_name: "android.net.cts.maxtargetsdk30", // CTS package names must be unique. instrumentation_target_package: "android.net.cts.maxtargetsdk30", - test_suites: [ - "cts", - "general-tests", - "mts-networking", - ], } diff --git a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt index 093c7f84ac..de5e46f319 100644 --- a/tests/cts/net/src/android/net/cts/NsdManagerTest.kt +++ b/tests/cts/net/src/android/net/cts/NsdManagerTest.kt @@ -20,6 +20,8 @@ import android.app.compat.CompatChanges import android.net.ConnectivityManager import android.net.ConnectivityManager.NetworkCallback import android.net.LinkProperties +import android.net.LocalSocket +import android.net.LocalSocketAddress import android.net.Network import android.net.NetworkAgentConfig import android.net.NetworkCapabilities @@ -63,6 +65,8 @@ import android.platform.test.annotations.AppModeFull import android.util.Log import androidx.test.platform.app.InstrumentationRegistry import androidx.test.runner.AndroidJUnit4 +import com.android.compatibility.common.util.PollingCheck +import com.android.compatibility.common.util.PropertyUtil import com.android.net.module.util.ArrayTrackRecord import com.android.net.module.util.TrackRecord import com.android.networkstack.apishim.NsdShimImpl @@ -72,14 +76,17 @@ import com.android.testutils.DevSdkIgnoreRule import com.android.testutils.TestableNetworkAgent import com.android.testutils.TestableNetworkCallback import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk30 +import com.android.testutils.filters.CtsNetTestCasesMaxTargetSdk33 import com.android.testutils.runAsShell import com.android.testutils.tryTest import com.android.testutils.waitForIdle import java.io.File +import java.io.IOException import java.net.ServerSocket import java.nio.charset.StandardCharsets import java.util.Random import java.util.concurrent.Executor +import kotlin.math.min import kotlin.test.assertEquals import kotlin.test.assertFailsWith import kotlin.test.assertNotNull @@ -763,6 +770,69 @@ class NsdManagerTest { } } + private fun checkConnectSocketToMdnsd(shouldFail: Boolean) { + val discoveryRecord = NsdDiscoveryRecord() + val localSocket = LocalSocket() + tryTest { + // Discover any service from NsdManager to enforce NsdService to start the mdnsd. + nsdManager.discoverServices(serviceType, NsdManager.PROTOCOL_DNS_SD, discoveryRecord) + discoveryRecord.expectCallback() + + // Checks the /dev/socket/mdnsd is created. + val socket = File("/dev/socket/mdnsd") + val doesSocketExist = PollingCheck.waitFor( + TIMEOUT_MS, + { + socket.exists() + }, + { doesSocketExist -> + doesSocketExist + }, + ) + + // If the socket is not created, then no need to check the access. + if (doesSocketExist) { + // Create a LocalSocket and try to connect to mdnsd. + assertFalse("LocalSocket is connected.", localSocket.isConnected) + val address = LocalSocketAddress("mdnsd", LocalSocketAddress.Namespace.RESERVED) + if (shouldFail) { + assertFailsWith("Expect fail but socket connected") { + localSocket.connect(address) + } + } else { + localSocket.connect(address) + assertTrue("LocalSocket is not connected.", localSocket.isConnected) + } + } + } cleanup { + localSocket.close() + nsdManager.stopServiceDiscovery(discoveryRecord) + discoveryRecord.expectCallback() + } + } + + /** + * Starting from Android U, the access to the /dev/socket/mdnsd is blocked by the + * sepolicy(b/265364111). + */ + @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.TIRAMISU) + @Test + fun testCannotConnectSocketToMdnsd() { + val targetSdkVersion = context.packageManager + .getTargetSdkVersion(context.applicationInfo.packageName) + assumeTrue(targetSdkVersion > Build.VERSION_CODES.TIRAMISU) + val firstApiLevel = min(PropertyUtil.getFirstApiLevel(), PropertyUtil.getVendorApiLevel()) + // The sepolicy is implemented in the vendor image, so the access may not be blocked if + // the vendor image is not update to date. + assumeTrue(firstApiLevel > Build.VERSION_CODES.TIRAMISU) + checkConnectSocketToMdnsd(shouldFail = true) + } + + @Test @CtsNetTestCasesMaxTargetSdk33("mdnsd socket is accessible up to target SDK 33") + fun testCanConnectSocketToMdnsd() { + checkConnectSocketToMdnsd(shouldFail = false) + } + @Test @CtsNetTestCasesMaxTargetSdk30("Socket is started with the service up to target SDK 30") fun testManagerCreatesLegacySocket() { nsdManager // Ensure the lazy-init member is initialized, so NsdManager is created