Make uid related tests compatible with Android Q
To be compatible with VPN isolation feature, DnsResolver has
different behavior fchown'ing when query socket.
sdk version >= (R+), fchown to apps' uid, otherwise fchown to AID_DNS
Make relevant tests compatible with it.
Test: atest
Bug: 161509097
Change-Id: I1c0bb4b9f35eaae32977a51c2d0a968092095cd0
diff --git a/DnsResolver.cpp b/DnsResolver.cpp
index 9c569c0..5068aef 100644
--- a/DnsResolver.cpp
+++ b/DnsResolver.cpp
@@ -17,26 +17,20 @@
#include "DnsResolver.h"
#include <android-base/logging.h>
-#include <android-base/properties.h>
#include "DnsProxyListener.h"
#include "DnsResolverService.h"
#include "netd_resolv/resolv.h"
#include "res_debug.h"
+#include "util.h"
bool resolv_init(const ResolverNetdCallbacks* callbacks) {
android::base::InitLogging(/*argv=*/nullptr);
android::base::SetDefaultTag("libnetd_resolv");
LOG(INFO) << __func__ << ": Initializing resolver";
resolv_set_log_severity(android::base::WARNING);
-
- uint64_t buildVersionSdk = android::base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
- uint64_t buildVersionPreviewSdk =
- android::base::GetUintProperty<uint64_t>("ro.build.version.preview_sdk", 0);
- uint64_t firstApiLevel =
- android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
using android::net::gApiLevel;
- gApiLevel = std::max(buildVersionSdk + !!buildVersionPreviewSdk, firstApiLevel);
+ gApiLevel = getApiLevel();
using android::net::gResNetdCallbacks;
gResNetdCallbacks.check_calling_permission = callbacks->check_calling_permission;
gResNetdCallbacks.get_network_context = callbacks->get_network_context;
diff --git a/tests/resolv_integration_test.cpp b/tests/resolv_integration_test.cpp
index 716dc71..2c1dc9d 100644
--- a/tests/resolv_integration_test.cpp
+++ b/tests/resolv_integration_test.cpp
@@ -58,6 +58,7 @@
#include <aidl/android/net/IDnsResolver.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
+#include <util.h> // getApiLevel
#include "NetdClient.h"
#include "ResolverStats.h"
#include "netid_client.h" // NETID_UNSET
@@ -161,6 +162,8 @@
std::string mStoredValue;
};
+const bool isAtLeastR = (getApiLevel() >= 30);
+
} // namespace
class ResolverTest : public ::testing::Test {
@@ -4119,17 +4122,24 @@
EXPECT_TRUE(fd1 != -1);
EXPECT_TRUE(fd2 != -1);
- uint8_t buf[MAXPACKET] = {};
+ uint8_t buf1[MAXPACKET] = {};
+ uint8_t buf2[MAXPACKET] = {};
int rcode;
- int res = getAsyncResponse(fd2, &rcode, buf, MAXPACKET);
- EXPECT_EQ(-ECONNREFUSED, res);
-
- memset(buf, 0, MAXPACKET);
- res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
- EXPECT_EQ(-ECONNREFUSED, res);
-
- ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
- ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
+ int res2 = getAsyncResponse(fd2, &rcode, buf2, MAXPACKET);
+ int res1 = getAsyncResponse(fd1, &rcode, buf1, MAXPACKET);
+ // If API level >= 30 (R+), these queries should be blocked.
+ if (isAtLeastR) {
+ EXPECT_EQ(res2, -ECONNREFUSED);
+ EXPECT_EQ(res1, -ECONNREFUSED);
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
+ ExpectDnsEvent(INetdEventListener::EVENT_RES_NSEND, EAI_SYSTEM, "howdy.example.com", {});
+ } else {
+ EXPECT_GT(res2, 0);
+ EXPECT_EQ("::1.2.3.4", toString(buf2, res2, AF_INET6));
+ EXPECT_GT(res1, 0);
+ EXPECT_EQ("1.2.3.4", toString(buf1, res1, AF_INET));
+ // To avoid flaky test, do not evaluate DnsEvent since event order is not guaranteed.
+ }
}
TEST_F(ResolverTest, EnforceDnsUid) {
@@ -4155,23 +4165,31 @@
ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
uint8_t buf[MAXPACKET] = {};
+ uint8_t buf2[MAXPACKET] = {};
int rcode;
{
ScopeBlockedUIDRule scopeBlockUidRule(netdService, TEST_UID);
// Dns Queries should be blocked
- int fd1 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_a, 0);
- int fd2 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_aaaa, 0);
+ const int fd1 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_a, 0);
+ const int fd2 = resNetworkQuery(TEST_NETID, host_name, ns_c_in, ns_t_aaaa, 0);
EXPECT_TRUE(fd1 != -1);
EXPECT_TRUE(fd2 != -1);
- int res = getAsyncResponse(fd2, &rcode, buf, MAXPACKET);
- EXPECT_EQ(-ECONNREFUSED, res);
-
- memset(buf, 0, MAXPACKET);
- res = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
- EXPECT_EQ(-ECONNREFUSED, res);
+ const int res2 = getAsyncResponse(fd2, &rcode, buf2, MAXPACKET);
+ const int res1 = getAsyncResponse(fd1, &rcode, buf, MAXPACKET);
+ // If API level >= 30 (R+), the query should be blocked.
+ if (isAtLeastR) {
+ EXPECT_EQ(res2, -ECONNREFUSED);
+ EXPECT_EQ(res1, -ECONNREFUSED);
+ } else {
+ EXPECT_GT(res2, 0);
+ EXPECT_EQ("::1.2.3.4", toString(buf2, res2, AF_INET6));
+ EXPECT_GT(res1, 0);
+ EXPECT_EQ("1.2.3.4", toString(buf, res1, AF_INET));
+ }
}
+ memset(buf, 0, MAXPACKET);
parcel.resolverOptions.enforceDnsUid = true;
ASSERT_TRUE(mDnsClient.resolvService()->setResolverConfiguration(parcel).isOk());
{
@@ -5167,16 +5185,23 @@
for (int i = 0; i < 10; i++) {
std::string hostName = fmt::format("blocked{}.com", i);
const addrinfo hints = {.ai_family = AF_INET, .ai_socktype = SOCK_DGRAM};
- EXPECT_EQ(safe_getaddrinfo(hostName.c_str(), nullptr, &hints), nullptr);
+ // The query result between R+ and Q would be different, but we don't really care
+ // about the result here because this test is only used to ensure blocked uid rule
+ // won't cause bad servers.
+ safe_getaddrinfo(hostName.c_str(), nullptr, &hints);
}
}
- // Since all query packets are blocked, we should not see any stats of them.
- const std::vector<NameserverStats> expectedEmptyDnsStats = {
- NameserverStats(listen_addr1),
+ ResolverParamsParcel setupParams = DnsResponderClient::GetDefaultResolverParamsParcel();
+ // If api level >= 30 (R+), expect all query packets to be blocked, hence we should not see any
+ // of their stats show up. Otherwise, all queries should succeed.
+ const std::vector<NameserverStats> expectedDnsStats = {
+ NameserverStats(listen_addr1).setSuccesses(isAtLeastR ? 0 : setupParams.maxSamples),
NameserverStats(listen_addr2),
};
- expectStatsEqualTo(expectedEmptyDnsStats);
- EXPECT_EQ(dns1.queries().size(), 0U);
+ expectStatsEqualTo(expectedDnsStats);
+ // If api level >= 30 (R+), expect server won't receive any queries,
+ // otherwise expect 20 == 10 * (setupParams.domains.size() + 1) queries.
+ EXPECT_EQ(dns1.queries().size(), isAtLeastR ? 0U : 10 * (setupParams.domains.size() + 1));
EXPECT_EQ(dns2.queries().size(), 0U);
}
diff --git a/util.h b/util.h
index d13a032..38f09b8 100644
--- a/util.h
+++ b/util.h
@@ -21,9 +21,29 @@
#include <netinet/in.h>
+#include <android-base/properties.h>
+
socklen_t sockaddrSize(const sockaddr* sa);
socklen_t sockaddrSize(const sockaddr_storage& ss);
// TODO: getExperimentFlagString
// TODO: Migrate it to DnsResolverExperiments.cpp
int getExperimentFlagInt(const std::string& flagName, int defaultValue);
+
+// When sdk X release branch is created, aosp's sdk version would still be X-1,
+// internal would be X. Also there might be some different setting between real devices and
+// CF. Below is the example for the sdk related properties in later R development stage. (internal
+// should be cosidered as S and aosp should be considered as R.)
+// R version is 30, rvc-dev aosp(CF) aosp(non-CF) internal
+// ro.build.version.sdk: [30] [29] [29] [30]
+// Note that, ro.product.first_api_level is device specific - so the value might be various.
+// ro.product.first_api_level: [26-30] [31] [28] [26-30]
+// ro.build.version.preview_sdk: [0] [1] [1] [1]
+inline uint64_t getApiLevel() {
+ uint64_t buildVersionSdk = android::base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ uint64_t buildVersionPreviewSdk =
+ android::base::GetUintProperty<uint64_t>("ro.build.version.preview_sdk", 0);
+ uint64_t firstApiLevel =
+ android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ return std::max(buildVersionSdk + !!buildVersionPreviewSdk, firstApiLevel);
+}