Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5729afcb authored by Luke Huang's avatar Luke Huang
Browse files

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
parent 6024824b
Loading
Loading
Loading
Loading
+2 −8
Original line number Diff line number Diff line
@@ -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;
+49 −24
Original line number Diff line number Diff line
@@ -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 @@ class ScopedSystemProperties {
    std::string mStoredValue;
};

const bool isAtLeastR = (getApiLevel() >= 30);

}  // namespace

class ResolverTest : public ::testing::Test {
@@ -4119,17 +4122,24 @@ TEST_F(ResolverTest, BlockDnsQueryWithUidRule) {
    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);

    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 @@ TEST_F(ResolverTest, EnforceDnsUid) {
    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 @@ TEST_F(ResolverTest, BlockDnsQueryUidDoesNotLeadToBadServer) {
        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);
}

+20 −0
Original line number Diff line number Diff line
@@ -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);
}