summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-05-03 07:21:23 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-05-03 07:21:23 +0000
commit2b3e1648467ed93bc4e4a553086d6a08391d6f13 (patch)
tree748b939f1cf3826538b33b8545297a481a4fe08c
parentec6783fe545870553875034a645d726149277e74 (diff)
parente2d7ab91d79f5b9807ff24e1b813b982167f9e6f (diff)
downloadnetd-2b3e1648467ed93bc4e4a553086d6a08391d6f13.tar.gz
Snap for 4759746 from e2d7ab91d79f5b9807ff24e1b813b982167f9e6f to pi-release
Change-Id: If31d2a886c2f12d17d6f84ba5a4d89c69a1d3378
-rw-r--r--bpfloader/bpf_kern.h12
-rw-r--r--bpfloader/bpf_kern.obin6232 -> 6264 bytes
-rw-r--r--libbpf/BpfNetworkStats.cpp47
-rw-r--r--libbpf/BpfNetworkStatsTest.cpp33
-rw-r--r--libbpf/include/bpf/BpfNetworkStats.h6
-rw-r--r--server/DnsProxyListener.cpp32
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
index 32d8e876..7b60514e 100644
--- a/bpfloader/bpf_kern.o
+++ b/bpfloader/bpf_kern.o
Binary files differ
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