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

Commit 2c11878c authored by Sehee Park's avatar Sehee Park Committed by Lorenzo Colitti
Browse files

fchown DNS lookup sockets to UID of the app that sent the DNS lookup.



Currently DNS lookups are all sent as AID_DNS. A seperate UID of the
app that sent the DNS lookup allows us to account for and route DNS
traffic differently from AID_DNS.
Also, currently DNS over TLS lookups are all sent as UID 0.
A seperate UID(AID_DNS) allows us to account for and route DNS over
TLS traffic differently from other UID 0 traffic.

Bug: 132125333
Test: system/netd && atest resolv_integration_test

Change-Id: I47a8d41d2a9bfd9af44efe291b56b46c7da9c346
Signed-off-by: default avatarSehee Park <sehee32.park@samsung.com>
parent a025619d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@
#include <openssl/sha.h>
#include <sys/eventfd.h>
#include <sys/poll.h>
#include <unistd.h>
#include <algorithm>

#include "DnsTlsSessionCache.h"
@@ -34,6 +35,7 @@
#include <android-base/logging.h>

#include "netdutils/SocketOption.h"
#include "private/android_filesystem_config.h"  // AID_DNS

namespace android {

@@ -80,6 +82,10 @@ Status DnsTlsSocket::tcpConnect() {
        return Status(errno);
    }

    if (fchown(mSslFd.get(), AID_DNS, -1) == -1) {
        LOG(WARNING) << "Failed to chown socket: %s" << strerror(errno);
    }

    const socklen_t len = sizeof(mMark);
    if (setsockopt(mSslFd.get(), SOL_SOCKET, SO_MARK, &mMark, len) == -1) {
        LOG(ERROR) << "Failed to set socket mark";
+1 −0
Original line number Diff line number Diff line
@@ -313,6 +313,7 @@ void res_setnetcontext(res_state statp, const struct android_net_context* netcon
                       android::net::NetworkDnsEventReported* _Nonnull event) {
    if (statp != NULL) {
        statp->netid = netcontext->dns_netid;
        statp->uid = netcontext->uid;
        statp->_mark = netcontext->dns_mark;
        if (netcontext->flags & NET_CONTEXT_FLAG_USE_EDNS) {
            statp->options |= RES_USE_EDNS0 | RES_USE_DNSSEC;
+6 −2
Original line number Diff line number Diff line
@@ -772,7 +772,9 @@ same_ns:
                    return -1;
            }
        }
        fchown(statp->_vcsock, AID_DNS, -1);
        if (fchown(statp->_vcsock, statp->uid, -1) == -1) {
            PLOG(WARNING) << __func__ << ": Failed to chown socket";
        }
        if (statp->_mark != MARK_UNSET) {
            if (setsockopt(statp->_vcsock, SOL_SOCKET, SO_MARK, &statp->_mark,
                           sizeof(statp->_mark)) < 0) {
@@ -1015,7 +1017,9 @@ static int send_dg(res_state statp, res_params* params, const u_char* buf, int b
            }
        }

        fchown(statp->_u._ext.nssocks[ns], AID_DNS, -1);
        if (fchown(statp->_u._ext.nssocks[ns], statp->uid, -1) == -1) {
            PLOG(WARNING) << __func__ << ": Failed to chown socket";
        }
        if (statp->_mark != MARK_UNSET) {
            if (setsockopt(statp->_u._ext.nssocks[ns], SOL_SOCKET, SO_MARK, &(statp->_mark),
                           sizeof(statp->_mark)) < 0) {
+1 −0
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ struct res_state_ext;

struct __res_state {
    unsigned netid;                        /* NetId: cache key and socket mark */
    uid_t uid;                             /* uid of the app that sent the DNS lookup */
    u_long options;                        /* option flags - see below. */
    int nscount;                           /* number of name srvers */
    struct sockaddr_in nsaddr_list[MAXNS]; /* address of name server */
+60 −0
Original line number Diff line number Diff line
@@ -66,6 +66,9 @@
constexpr int TEST_VPN_NETID = 65502;
constexpr int MAXPACKET = (8 * 1024);

// Use maximum reserved appId for applications to avoid conflict with existing uids.
static const int TEST_UID = 99999;

// Semi-public Bionic hook used by the NDK (frameworks/base/native/android/net.c)
// Tested here for convenience.
extern "C" int android_getaddrinfofornet(const char* hostname, const char* servname,
@@ -75,6 +78,7 @@ extern "C" int android_getaddrinfofornet(const char* hostname, const char* servn
using android::base::ParseInt;
using android::base::StringPrintf;
using android::base::unique_fd;
using android::net::INetd;
using android::net::ResolverStats;
using android::net::metrics::DnsMetricsListener;
using android::netdutils::enableSockopt;
@@ -3440,3 +3444,59 @@ TEST_F(ResolverTest, getDnsNetId) {
    // Keep in sync with FrameworkListener.cpp (500, "Command not recognized")
    EXPECT_EQ(500, readResponseCode(fd));
}

TEST_F(ResolverTest, BlockDnsQueryWithUidRule) {
    constexpr char listen_addr1[] = "127.0.0.4";
    constexpr char listen_addr2[] = "::1";
    constexpr char host_name[] = "howdy.example.com.";
    const std::vector<DnsRecord> records = {
            {host_name, ns_type::ns_t_a, "1.2.3.4"},
            {host_name, ns_type::ns_t_aaaa, "::1.2.3.4"},
    };

    test::DNSResponder dns1(listen_addr1);
    test::DNSResponder dns2(listen_addr2);
    StartDns(dns1, records);
    StartDns(dns2, records);

    std::vector<std::string> servers = {listen_addr1, listen_addr2};
    ASSERT_TRUE(mDnsClient.SetResolversForNetwork(servers));
    dns1.clearQueries();
    dns2.clearQueries();

    // Add drop Rule for Uid
    EXPECT_TRUE(mDnsClient.netdService()
                        ->firewallSetUidRule(INetd::FIREWALL_CHAIN_STANDBY, TEST_UID,
                                             INetd::FIREWALL_RULE_DENY)
                        .isOk());

    // Save uid
    int suid = getuid();

    // Switch to TEST_UID
    EXPECT_TRUE(seteuid(TEST_UID) == 0);

    // Dns Query
    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);
    EXPECT_TRUE(fd1 != -1);
    EXPECT_TRUE(fd2 != -1);

    uint8_t buf[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);

    // Restore uid
    EXPECT_TRUE(seteuid(suid) == 0);

    // Remove drop Rule for Uid
    EXPECT_TRUE(mDnsClient.netdService()
                        ->firewallSetUidRule(INetd::FIREWALL_CHAIN_STANDBY, TEST_UID,
                                             INetd::FIREWALL_RULE_ALLOW)
                        .isOk());
}