diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-03 07:21:23 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-03 07:21:23 +0000 |
commit | 2b3e1648467ed93bc4e4a553086d6a08391d6f13 (patch) | |
tree | 748b939f1cf3826538b33b8545297a481a4fe08c | |
parent | ec6783fe545870553875034a645d726149277e74 (diff) | |
parent | e2d7ab91d79f5b9807ff24e1b813b982167f9e6f (diff) | |
download | netd-2b3e1648467ed93bc4e4a553086d6a08391d6f13.tar.gz |
Snap for 4759746 from e2d7ab91d79f5b9807ff24e1b813b982167f9e6f to pi-release
Change-Id: If31d2a886c2f12d17d6f84ba5a4d89c69a1d3378
-rw-r--r-- | bpfloader/bpf_kern.h | 12 | ||||
-rw-r--r-- | bpfloader/bpf_kern.o | bin | 6232 -> 6264 bytes | |||
-rw-r--r-- | libbpf/BpfNetworkStats.cpp | 47 | ||||
-rw-r--r-- | libbpf/BpfNetworkStatsTest.cpp | 33 | ||||
-rw-r--r-- | libbpf/include/bpf/BpfNetworkStats.h | 6 | ||||
-rw-r--r-- | server/DnsProxyListener.cpp | 32 |
6 files changed, 120 insertions, 10 deletions
diff --git a/bpfloader/bpf_kern.h b/bpfloader/bpf_kern.h index 8fb6046f..975f4655 100644 --- a/bpfloader/bpf_kern.h +++ b/bpfloader/bpf_kern.h @@ -150,6 +150,14 @@ static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid) { } static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction) { + uint32_t sock_uid = get_socket_uid(skb); + int match = bpf_owner_match(skb, sock_uid); + if ((direction == BPF_EGRESS) && (match == BPF_DROP)) { + // If an outbound packet is going to be dropped, we do not count that + // traffic. + return match; + } + uint64_t cookie = get_socket_cookie(skb); struct uid_tag* utag = find_map_entry(COOKIE_TAG_MAP, &cookie); uint32_t uid, tag; @@ -157,7 +165,7 @@ static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int uid = utag->uid; tag = utag->tag; } else { - uid = get_socket_uid(skb); + uid = sock_uid; tag = 0; } @@ -174,5 +182,5 @@ static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int key.tag = 0; bpf_update_stats(skb, UID_STATS_MAP, direction, &key); - return bpf_owner_match(skb, uid); + return match; } diff --git a/bpfloader/bpf_kern.o b/bpfloader/bpf_kern.o Binary files differindex 32d8e876..7b60514e 100644 --- a/bpfloader/bpf_kern.o +++ b/bpfloader/bpf_kern.o diff --git a/libbpf/BpfNetworkStats.cpp b/libbpf/BpfNetworkStats.cpp index bc9a932f..acde1e65 100644 --- a/libbpf/BpfNetworkStats.cpp +++ b/libbpf/BpfNetworkStats.cpp @@ -123,9 +123,9 @@ stats_line populateStatsEntry(const StatsKey& statsKey, const StatsValue& statsE const char* ifname) { stats_line newLine; strlcpy(newLine.iface, ifname, sizeof(newLine.iface)); - newLine.uid = statsKey.uid; - newLine.set = statsKey.counterSet; - newLine.tag = statsKey.tag; + newLine.uid = (int32_t)statsKey.uid; + newLine.set = (int32_t)statsKey.counterSet; + newLine.tag = (int32_t)statsKey.tag; newLine.rxPackets = statsEntry.rxPackets; newLine.txPackets = statsEntry.txPackets; newLine.rxBytes = statsEntry.rxBytes; @@ -240,6 +240,47 @@ int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines, return ret; } +int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines, + const base::unique_fd& statsMapFd, + const base::unique_fd& ifaceMapFd) { + int64_t unknownIfaceBytesTotal = 0; + uint32_t nonExistentKey = NONEXISTENT_IFACE_STATS_KEY; + struct StatsValue dummyValue; + auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMapFd]( + void* key, void* value, const base::unique_fd& statsMapFd) { + uint32_t ifIndex = *(uint32_t*)key; + char ifname[IFNAMSIZ]; + if (getIfaceNameFromMap(ifaceMapFd, statsMapFd, ifIndex, ifname, &ifIndex, + &unknownIfaceBytesTotal)) { + return BPF_CONTINUE; + } + StatsValue* statsEntry = (StatsValue*)value; + StatsKey fakeKey = { + .uid = (uint32_t)UID_ALL, .counterSet = (uint32_t)SET_ALL, .tag = (uint32_t)TAG_NONE}; + lines->push_back(populateStatsEntry(fakeKey, *statsEntry, ifname)); + return BPF_CONTINUE; + }; + return bpfIterateMapWithValue(nonExistentKey, dummyValue, statsMapFd, processDetailIfaceStats); +} + +int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) { + int ret = 0; + base::unique_fd ifaceIndexNameMap(bpf::mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS)); + if (ifaceIndexNameMap < 0) { + ret = -errno; + ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno)); + return ret; + } + + base::unique_fd ifaceStatsMap(bpf::mapRetrieve(IFACE_STATS_MAP_PATH, BPF_OPEN_FLAGS)); + if (ifaceStatsMap < 0) { + ret = -errno; + ALOGE("get ifaceStats map fd failed: %s", strerror(errno)); + return ret; + } + return parseBpfNetworkStatsDevInternal(lines, ifaceStatsMap, ifaceIndexNameMap); +} + uint64_t combineUidTag(const uid_t uid, const uint32_t tag) { return (uint64_t)uid << 32 | tag; } diff --git a/libbpf/BpfNetworkStatsTest.cpp b/libbpf/BpfNetworkStatsTest.cpp index cd7a0660..33df0f20 100644 --- a/libbpf/BpfNetworkStatsTest.cpp +++ b/libbpf/BpfNetworkStatsTest.cpp @@ -378,5 +378,38 @@ TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) { expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front()); } +TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) { + updateIfaceMap(IFACE_NAME1, IFACE_INDEX1); + updateIfaceMap(IFACE_NAME2, IFACE_INDEX2); + updateIfaceMap(IFACE_NAME3, IFACE_INDEX3); + StatsValue value1 = { + .rxBytes = TEST_BYTES0, + .rxPackets = TEST_PACKET0, + .txBytes = TEST_BYTES1, + .txPackets = TEST_PACKET1, + }; + StatsValue value2 = { + .rxBytes = TEST_BYTES1, + .rxPackets = TEST_PACKET1, + .txBytes = TEST_BYTES0, + .txPackets = TEST_PACKET0, + }; + uint32_t ifaceStatsKey = IFACE_INDEX1; + EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value1, BPF_ANY)); + ifaceStatsKey = IFACE_INDEX2; + EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value2, BPF_ANY)); + ifaceStatsKey = IFACE_INDEX3; + EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value1, BPF_ANY)); + std::vector<stats_line> lines; + ASSERT_EQ(0, + parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap)); + ASSERT_EQ((unsigned long)3, lines.size()); + std::sort(lines.begin(), lines.end(), [](const auto& line1, const auto& line2)-> bool { + return strcmp(line1.iface, line2.iface) < 0; + }); + expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]); + expectStatsLineEqual(value1, IFACE_NAME3, UID_ALL, SET_ALL, TAG_NONE, lines[1]); + expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[2]); +} } // namespace bpf } // namespace android diff --git a/libbpf/include/bpf/BpfNetworkStats.h b/libbpf/include/bpf/BpfNetworkStats.h index db0c185f..63cf0bc8 100644 --- a/libbpf/include/bpf/BpfNetworkStats.h +++ b/libbpf/include/bpf/BpfNetworkStats.h @@ -53,12 +53,18 @@ int cleanStatsMapInternal(const base::unique_fd& cookieTagMap, const base::uniqu int getIfaceNameFromMap(const base::unique_fd& ifaceMapFd, const base::unique_fd& statsMapFd, uint32_t ifaceIndex, char* ifname, void* curKey, int64_t* unknownIfaceBytesTotal); +// For test only +int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines, + const base::unique_fd& statsMapFd, + const base::unique_fd& ifaceMapFd); int bpfGetUidStats(uid_t uid, struct Stats* stats); int bpfGetIfaceStats(const char* iface, struct Stats* stats); int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines, const std::vector<std::string>& limitIfaces, int limitTag, int limitUid); + +int parseBpfNetworkStatsDev(std::vector<stats_line>* lines); int cleanStatsMap(); } // namespace bpf } // namespace android diff --git a/server/DnsProxyListener.cpp b/server/DnsProxyListener.cpp index 18ffe1cb..dd7b4e2b 100644 --- a/server/DnsProxyListener.cpp +++ b/server/DnsProxyListener.cpp @@ -39,10 +39,13 @@ #include <vector> #include <cutils/log.h> +#include <cutils/misc.h> #include <netdutils/Slice.h> #include <utils/String16.h> #include <sysutils/SocketClient.h> +#include <binder/IServiceManager.h> + #include "Controllers.h" #include "Fwmark.h" #include "DnsProxyListener.h" @@ -65,6 +68,12 @@ namespace net { namespace { +// TODO: move to a separate file (with other constants from FwmarkService and NetdNativeService) +constexpr const char CONNECTIVITY_USE_RESTRICTED_NETWORKS[] = + "android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"; +constexpr const char NETWORK_BYPASS_PRIVATE_DNS[] = + "android.permission.NETWORK_BYPASS_PRIVATE_DNS"; + void logArguments(int argc, char** argv) { for (int i = 0; i < argc; i++) { ALOGD("argv[%i]=%s", i, argv[i]); @@ -189,13 +198,26 @@ inline bool queryingViaTls(unsigned dns_netid) { } } -void maybeFixupNetContext(android_net_context* ctx) { - if (requestingUseLocalNameservers(ctx->flags)) { - if (net::gCtls->netCtrl.getPermissionForUser(ctx->uid) != Permission::PERMISSION_SYSTEM) { - // Not permitted; clear the flag. - ctx->flags &= ~NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS; +bool hasPermissionToBypassPrivateDns(uid_t uid) { + static_assert(AID_SYSTEM >= 0 && AID_SYSTEM < FIRST_APPLICATION_UID, + "Calls from AID_SYSTEM must not result in a permission check to avoid deadlock."); + if (uid >= 0 && uid < FIRST_APPLICATION_UID) { + return true; + } + + for (auto& permission : {CONNECTIVITY_USE_RESTRICTED_NETWORKS, NETWORK_BYPASS_PRIVATE_DNS}) { + if (checkCallingPermission(String16(permission))) { + return true; } } + return false; +} + +void maybeFixupNetContext(android_net_context* ctx) { + if (requestingUseLocalNameservers(ctx->flags) && !hasPermissionToBypassPrivateDns(ctx->uid)) { + // Not permitted; clear the flag. + ctx->flags &= ~NET_CONTEXT_FLAG_USE_LOCAL_NAMESERVERS; + } if (!requestingUseLocalNameservers(ctx->flags)) { // If we're not explicitly bypassing DNS-over-TLS servers, check whether |