From d4876dec06ef5d0718d236749e9583c0a4cd535b Mon Sep 17 00:00:00 2001 From: Ken Chen Date: Wed, 13 Sep 2023 00:53:52 +0800 Subject: [PATCH] [Test] for libcom.android.tethering.dns_helper.so Exercise the BpfReader::isUidNetworkingBlocked(). Bug: 288340533 Test: atest dns_helper_unit_test Change-Id: Icc889a6a9649e991cba222427f9b8d4f5ee3b325 --- DnsResolver/Android.bp | 29 +++++++ DnsResolver/DnsBpfHelper.h | 3 + DnsResolver/DnsBpfHelperTest.cpp | 141 +++++++++++++++++++++++++++++++ 3 files changed, 173 insertions(+) create mode 100644 DnsResolver/DnsBpfHelperTest.cpp diff --git a/DnsResolver/Android.bp b/DnsResolver/Android.bp index 4779995373..d1330343f3 100644 --- a/DnsResolver/Android.bp +++ b/DnsResolver/Android.bp @@ -52,3 +52,32 @@ cc_library { apex_available: ["com.android.tethering"], min_sdk_version: "30", } + +cc_test { + name: "dns_helper_unit_test", + defaults: ["netd_defaults"], + test_suites: ["general-tests", "mts-tethering"], + test_config_template: ":net_native_test_config_template", + header_libs: [ + "bpf_connectivity_headers", + ], + srcs: [ + "DnsBpfHelperTest.cpp", + ], + static_libs: [ + "libcom.android.tethering.dns_helper", + ], + shared_libs: [ + "libbase", + "libcutils", + ], + compile_multilib: "both", + multilib: { + lib32: { + suffix: "32", + }, + lib64: { + suffix: "64", + }, + }, +} diff --git a/DnsResolver/DnsBpfHelper.h b/DnsResolver/DnsBpfHelper.h index fdf9b01869..5520d2998d 100644 --- a/DnsResolver/DnsBpfHelper.h +++ b/DnsResolver/DnsBpfHelper.h @@ -36,6 +36,9 @@ class DnsBpfHelper { private: android::bpf::BpfMapRO mConfigurationMap; android::bpf::BpfMapRO mUidOwnerMap; + + // For testing + friend class DnsBpfHelperTest; }; } // namespace net diff --git a/DnsResolver/DnsBpfHelperTest.cpp b/DnsResolver/DnsBpfHelperTest.cpp new file mode 100644 index 0000000000..9bea72903b --- /dev/null +++ b/DnsResolver/DnsBpfHelperTest.cpp @@ -0,0 +1,141 @@ +/* + * 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. + */ + +#include +#include + +#define BPF_MAP_MAKE_VISIBLE_FOR_TESTING +#include "DnsBpfHelper.h" + +using namespace android::bpf; // NOLINT(google-build-using-namespace): exempted + +namespace android { +namespace net { + +constexpr int TEST_MAP_SIZE = 2; + +#define ASSERT_VALID(x) ASSERT_TRUE((x).isValid()) + +class DnsBpfHelperTest : public ::testing::Test { + protected: + DnsBpfHelper mDnsBpfHelper; + BpfMap mFakeConfigurationMap; + BpfMap mFakeUidOwnerMap; + + void SetUp() { + mFakeConfigurationMap.resetMap(BPF_MAP_TYPE_ARRAY, CONFIGURATION_MAP_SIZE); + ASSERT_VALID(mFakeConfigurationMap); + + mFakeUidOwnerMap.resetMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE); + ASSERT_VALID(mFakeUidOwnerMap); + + mDnsBpfHelper.mConfigurationMap = mFakeConfigurationMap; + ASSERT_VALID(mDnsBpfHelper.mConfigurationMap); + mDnsBpfHelper.mUidOwnerMap = mFakeUidOwnerMap; + ASSERT_VALID(mDnsBpfHelper.mUidOwnerMap); + } + + void ResetAllMaps() { + mDnsBpfHelper.mConfigurationMap.reset(); + mDnsBpfHelper.mUidOwnerMap.reset(); + } +}; + +TEST_F(DnsBpfHelperTest, IsUidNetworkingBlocked) { + struct TestConfig { + const uid_t uid; + const uint32_t enabledRules; + const uint32_t uidRules; + const int expectedResult; + std::string toString() const { + return fmt::format( + "uid: {}, enabledRules: {}, uidRules: {}, expectedResult: {}", + uid, enabledRules, uidRules, expectedResult); + } + } testConfigs[] = { + // clang-format off + // No rule enabled: + // uid, enabledRules, uidRules, expectedResult + {AID_APP_START, NO_MATCH, NO_MATCH, false}, + + // An allowlist rule: + {AID_APP_START, NO_MATCH, DOZABLE_MATCH, false}, + {AID_APP_START, DOZABLE_MATCH, NO_MATCH, true}, + {AID_APP_START, DOZABLE_MATCH, DOZABLE_MATCH, false}, + // A denylist rule + {AID_APP_START, NO_MATCH, STANDBY_MATCH, false}, + {AID_APP_START, STANDBY_MATCH, NO_MATCH, false}, + {AID_APP_START, STANDBY_MATCH, STANDBY_MATCH, true}, + + // Multiple rules enabled: + // Match only part of the enabled allowlist rules. + {AID_APP_START, DOZABLE_MATCH|POWERSAVE_MATCH, DOZABLE_MATCH, true}, + {AID_APP_START, DOZABLE_MATCH|POWERSAVE_MATCH, POWERSAVE_MATCH, true}, + // Match all of the enabled allowlist rules. + {AID_APP_START, DOZABLE_MATCH|POWERSAVE_MATCH, DOZABLE_MATCH|POWERSAVE_MATCH, false}, + // Match allowlist. + {AID_APP_START, DOZABLE_MATCH|STANDBY_MATCH, DOZABLE_MATCH, false}, + // Match no rule. + {AID_APP_START, DOZABLE_MATCH|STANDBY_MATCH, NO_MATCH, true}, + {AID_APP_START, DOZABLE_MATCH|POWERSAVE_MATCH, NO_MATCH, true}, + + // System UID: always unblocked. + {AID_SYSTEM, NO_MATCH, NO_MATCH, false}, + {AID_SYSTEM, NO_MATCH, DOZABLE_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH, NO_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH, DOZABLE_MATCH, false}, + {AID_SYSTEM, NO_MATCH, STANDBY_MATCH, false}, + {AID_SYSTEM, STANDBY_MATCH, NO_MATCH, false}, + {AID_SYSTEM, STANDBY_MATCH, STANDBY_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH|POWERSAVE_MATCH, DOZABLE_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH|POWERSAVE_MATCH, POWERSAVE_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH|POWERSAVE_MATCH, DOZABLE_MATCH|POWERSAVE_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH|STANDBY_MATCH, DOZABLE_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH|STANDBY_MATCH, NO_MATCH, false}, + {AID_SYSTEM, DOZABLE_MATCH|POWERSAVE_MATCH, NO_MATCH, false}, + // clang-format on + }; + + for (const auto& config : testConfigs) { + SCOPED_TRACE(config.toString()); + + // Setup maps. + EXPECT_RESULT_OK(mFakeConfigurationMap.writeValue(UID_RULES_CONFIGURATION_KEY, + config.enabledRules, BPF_EXIST)); + EXPECT_RESULT_OK(mFakeUidOwnerMap.writeValue(config.uid, {.iif = 0, .rule = config.uidRules}, + BPF_ANY)); + + // Verify the function. + auto result = mDnsBpfHelper.isUidNetworkingBlocked(config.uid, /*metered=*/false); + EXPECT_TRUE(result.ok()); + EXPECT_EQ(config.expectedResult, result.value()); + } +} + +TEST_F(DnsBpfHelperTest, IsUidNetworkingBlocked_uninitialized) { + ResetAllMaps(); + + auto result = mDnsBpfHelper.isUidNetworkingBlocked(AID_APP_START, /*metered=*/false); + EXPECT_FALSE(result.ok()); + EXPECT_EQ(EUNATCH, result.error().code()); + + result = mDnsBpfHelper.isUidNetworkingBlocked(AID_SYSTEM, /*metered=*/false); + EXPECT_TRUE(result.ok()); + EXPECT_FALSE(result.value()); +} + +} // namespace net +} // namespace android