blob: 29cffd450722e1f29851f0a9d8c5400c1001729f [file] [log] [blame]
Chenbo Fengf2759682017-10-10 17:31:57 -07001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Chenbo Fengc10a8a42017-12-15 13:56:33 -080017#define LOG_TAG "TrafficController"
Chenbo Feng33cc1032017-10-23 15:16:37 -070018#include <inttypes.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070019#include <linux/bpf.h>
20#include <linux/if_ether.h>
21#include <linux/in.h>
22#include <linux/inet_diag.h>
Chenbo Feng116d0552017-12-04 17:25:19 -080023#include <linux/netlink.h>
24#include <linux/sock_diag.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070025#include <linux/unistd.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080026#include <net/if.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070027#include <stdlib.h>
28#include <string.h>
29#include <sys/socket.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080030#include <sys/stat.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080031#include <sys/types.h>
Chenbo Feng33cc1032017-10-23 15:16:37 -070032#include <sys/utsname.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080033#include <sys/wait.h>
Chenbo Feng89c12f12018-03-21 10:29:18 -070034#include <mutex>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080035#include <unordered_set>
36#include <vector>
37
38#include <android-base/stringprintf.h>
Chenbo Fengef297172018-03-26 10:53:33 -070039#include <android-base/strings.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080040#include <android-base/unique_fd.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080041#include <logwrap/logwrap.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080042#include <netdutils/StatusOr.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070043
Chenbo Feng116d0552017-12-04 17:25:19 -080044#include <netdutils/Misc.h>
45#include <netdutils/Syscalls.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070046#include "TrafficController.h"
Chenbo Fengc10a8a42017-12-15 13:56:33 -080047#include "bpf/BpfUtils.h"
Chenbo Feng89c12f12018-03-21 10:29:18 -070048#include "bpf/bpf_shared.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080049
Chenbo Fengef297172018-03-26 10:53:33 -070050#include "DumpWriter.h"
Chenbo Feng89c12f12018-03-21 10:29:18 -070051#include "FirewallController.h"
Chenbo Feng7e974052018-02-28 22:57:21 -080052#include "InterfaceController.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080053#include "NetlinkListener.h"
Chenbo Feng33cc1032017-10-23 15:16:37 -070054#include "qtaguid/qtaguid.h"
Chenbo Fengf2759682017-10-10 17:31:57 -070055
Chenbo Fengc10a8a42017-12-15 13:56:33 -080056using namespace android::bpf;
Chenbo Fengf2759682017-10-10 17:31:57 -070057
58namespace android {
59namespace net {
60
Chenbo Fengc10a8a42017-12-15 13:56:33 -080061using base::StringPrintf;
62using base::unique_fd;
Chenbo Fengef297172018-03-26 10:53:33 -070063using base::Join;
Chenbo Feng116d0552017-12-04 17:25:19 -080064using netdutils::extract;
65using netdutils::Slice;
66using netdutils::sSyscalls;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080067using netdutils::Status;
68using netdutils::statusFromErrno;
69using netdutils::StatusOr;
Chenbo Feng116d0552017-12-04 17:25:19 -080070using netdutils::status::ok;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080071
Chenbo Feng116d0552017-12-04 17:25:19 -080072constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
73constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
74
75StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener() {
76 const auto& sys = sSyscalls.get();
77 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
78 const int domain = AF_NETLINK;
79 const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
80 const int protocol = NETLINK_INET_DIAG;
81 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
82
83 sockaddr_nl addr = {
84 .nl_family = AF_NETLINK,
85 .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
86 1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
87 RETURN_IF_NOT_OK(sys.bind(sock, addr));
88
89 const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
90 RETURN_IF_NOT_OK(sys.connect(sock, kernel));
91
92 std::unique_ptr<NetlinkListenerInterface> listener =
93 std::make_unique<NetlinkListener>(std::move(event), std::move(sock));
94
95 return listener;
96}
97
Chenbo Feng89c12f12018-03-21 10:29:18 -070098Status changeOwnerAndMode(const char* path, gid_t group, const char* debugName, bool netdOnly) {
99 int ret = chown(path, AID_ROOT, group);
100 if (ret != 0) return statusFromErrno(errno, StringPrintf("change %s group failed", debugName));
101
102 if (netdOnly) {
103 ret = chmod(path, S_IRWXU);
104 } else {
105 // Allow both netd and system server to obtain map fd from the path.
106 // chmod doesn't grant permission to all processes in that group to
107 // read/write the bpf map. They still need correct sepolicy to
108 // read/write the map.
109 ret = chmod(path, S_IRWXU | S_IRGRP);
110 }
111 if (ret != 0) return statusFromErrno(errno, StringPrintf("change %s mode failed", debugName));
112 return netdutils::status::ok;
113}
114
115TrafficController::TrafficController() {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800116 ebpfSupported = hasBpfSupport();
Chenbo Feng89c12f12018-03-21 10:29:18 -0700117}
118
119Status initialOwnerMap(const unique_fd& map_fd, const std::string mapName) {
120 uint32_t mapSettingKey = UID_MAP_ENABLED;
121 uint32_t defaultMapState = 0;
122 int ret = writeToMapEntry(map_fd, &mapSettingKey, &defaultMapState, BPF_NOEXIST);
123 // If it is already exist, it might be a runtime restart and we just keep
124 // the old state.
125 if (ret && errno != EEXIST) {
126 return statusFromErrno(errno, "Fail to set the initial state of " + mapName);
127 }
128 return netdutils::status::ok;
129}
130
131Status TrafficController::initMaps() {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700132 std::lock_guard<std::mutex> ownerMapGuard(mOwnerMatchMutex);
133 std::lock_guard<std::mutex> statsMapGuard(mDeleteStatsMutex);
Chenbo Feng89c12f12018-03-21 10:29:18 -0700134 ASSIGN_OR_RETURN(mCookieTagMap,
135 setUpBPFMap(sizeof(uint64_t), sizeof(struct UidTag), COOKIE_UID_MAP_SIZE,
136 COOKIE_TAG_MAP_PATH, BPF_MAP_TYPE_HASH));
137
138 RETURN_IF_NOT_OK(changeOwnerAndMode(COOKIE_TAG_MAP_PATH, AID_NET_BW_ACCT, "CookieTagMap",
139 false));
140
141 ASSIGN_OR_RETURN(mUidCounterSetMap,
142 setUpBPFMap(sizeof(uint32_t), sizeof(uint32_t), UID_COUNTERSET_MAP_SIZE,
143 UID_COUNTERSET_MAP_PATH, BPF_MAP_TYPE_HASH));
144 RETURN_IF_NOT_OK(changeOwnerAndMode(UID_COUNTERSET_MAP_PATH, AID_NET_BW_ACCT,
145 "UidCounterSetMap", false));
146
147 ASSIGN_OR_RETURN(mUidStatsMap,
148 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
149 UID_STATS_MAP_SIZE, UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
150 RETURN_IF_NOT_OK(changeOwnerAndMode(UID_STATS_MAP_PATH, AID_NET_BW_STATS, "UidStatsMap",
151 false));
152
153 ASSIGN_OR_RETURN(mTagStatsMap,
154 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
155 TAG_STATS_MAP_SIZE, TAG_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
156 RETURN_IF_NOT_OK(changeOwnerAndMode(TAG_STATS_MAP_PATH, AID_NET_BW_STATS, "TagStatsMap",
157 false));
158
159 ASSIGN_OR_RETURN(mIfaceIndexNameMap,
160 setUpBPFMap(sizeof(uint32_t), IFNAMSIZ, IFACE_INDEX_NAME_MAP_SIZE,
161 IFACE_INDEX_NAME_MAP_PATH, BPF_MAP_TYPE_HASH));
162 RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_INDEX_NAME_MAP_PATH, AID_NET_BW_STATS,
163 "IfaceIndexNameMap", false));
164
165 ASSIGN_OR_RETURN(mDozableUidMap,
166 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
167 DOZABLE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
168 RETURN_IF_NOT_OK(changeOwnerAndMode(DOZABLE_UID_MAP_PATH, AID_ROOT, "DozableUidMap", true));
169 RETURN_IF_NOT_OK(initialOwnerMap(mDozableUidMap, "DozableUidMap"));
170
171 ASSIGN_OR_RETURN(mStandbyUidMap,
172 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
173 STANDBY_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
174 RETURN_IF_NOT_OK(changeOwnerAndMode(STANDBY_UID_MAP_PATH, AID_ROOT, "StandbyUidMap", true));
175 RETURN_IF_NOT_OK(initialOwnerMap(mStandbyUidMap, "StandbyUidMap"));
176
177 ASSIGN_OR_RETURN(mPowerSaveUidMap,
178 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
179 POWERSAVE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
180 RETURN_IF_NOT_OK(changeOwnerAndMode(POWERSAVE_UID_MAP_PATH, AID_ROOT, "PowerSaveUidMap", true));
181 RETURN_IF_NOT_OK(initialOwnerMap(mPowerSaveUidMap, "PowerSaveUidMap"));
182
183 ASSIGN_OR_RETURN(mIfaceStatsMap,
184 setUpBPFMap(sizeof(uint32_t), sizeof(struct StatsValue), IFACE_STATS_MAP_SIZE,
185 IFACE_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
186 RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_STATS_MAP_PATH, AID_NET_BW_STATS, "IfaceStatsMap",
187 false));
188 return netdutils::status::ok;
189}
190
191Status TrafficController::start() {
192
Chenbo Fengf43bf812017-12-15 18:27:22 -0800193 if (!ebpfSupported) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800194 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700195 }
196
197 /* When netd restart from a crash without total system reboot, the program
198 * is still attached to the cgroup, detach it so the program can be freed
199 * and we can load and attach new program into the target cgroup.
200 *
201 * TODO: Scrape existing socket when run-time restart and clean up the map
202 * if the socket no longer exist
203 */
204
Chenbo Feng89c12f12018-03-21 10:29:18 -0700205 RETURN_IF_NOT_OK(initMaps());
Chenbo Feng7e974052018-02-28 22:57:21 -0800206
207 // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
208 // already running, so it will call addInterface() when any new interface appears.
209 std::map<std::string, uint32_t> ifacePairs;
210 ASSIGN_OR_RETURN(ifacePairs, InterfaceController::getIfaceList());
211 for (const auto& ifacePair:ifacePairs) {
212 addInterface(ifacePair.first.c_str(), ifacePair.second);
213 }
214
Chenbo Feng5ed17992018-03-13 21:30:49 -0700215
Chenbo Feng116d0552017-12-04 17:25:19 -0800216 auto result = makeSkDestroyListener();
217 if (!isOk(result)) {
218 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
219 } else {
220 mSkDestroyListener = std::move(result.value());
221 }
222 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
223 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
224 inet_diag_msg diagmsg = {};
225 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
226 ALOGE("unrecognized netlink message: %s", toString(msg).c_str());
227 return;
228 }
229 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
230 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
231
232 deleteMapEntry(mCookieTagMap, &sock_cookie);
233 };
234 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
235
236 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
237 // properly.
238 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
239 // Ignore NLMSG_DONE messages
240 inet_diag_msg diagmsg = {};
241 extract(msg, diagmsg);
242 };
243 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
244
Chenbo Feng05393d82018-01-09 15:18:43 -0800245 int* status = nullptr;
246
247 std::vector<const char*> prog_args{
248 "/system/bin/bpfloader",
249 };
Chenbo Feng89c12f12018-03-21 10:29:18 -0700250 int ret = access(BPF_INGRESS_PROG_PATH, R_OK);
Chenbo Feng05393d82018-01-09 15:18:43 -0800251 if (ret != 0 && errno == ENOENT) {
252 prog_args.push_back((char*)"-i");
253 }
254 ret = access(BPF_EGRESS_PROG_PATH, R_OK);
255 if (ret != 0 && errno == ENOENT) {
256 prog_args.push_back((char*)"-e");
257 }
Chenbo Feng5ed17992018-03-13 21:30:49 -0700258 ret = access(XT_BPF_INGRESS_PROG_PATH, R_OK);
259 if (ret != 0 && errno == ENOENT) {
260 prog_args.push_back((char*)"-p");
261 }
262 ret = access(XT_BPF_EGRESS_PROG_PATH, R_OK);
263 if (ret != 0 && errno == ENOENT) {
264 prog_args.push_back((char*)"-m");
265 }
Chenbo Feng05393d82018-01-09 15:18:43 -0800266
267 if (prog_args.size() == 1) {
Chenbo Feng5ed17992018-03-13 21:30:49 -0700268 // all program are loaded already.
Chenbo Feng05393d82018-01-09 15:18:43 -0800269 return netdutils::status::ok;
270 }
271
272 prog_args.push_back(nullptr);
273 ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
274 if (ret) {
275 ret = errno;
276 ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
277 return statusFromErrno(ret, "run bpf loader failed");
278 }
279 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700280}
281
Chenbo Fengf2759682017-10-10 17:31:57 -0700282int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700283 if (!ebpfSupported) {
284 if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
285 return 0;
286 }
Chenbo Feng33cc1032017-10-23 15:16:37 -0700287
Chenbo Fengf2759682017-10-10 17:31:57 -0700288 uint64_t sock_cookie = getSocketCookie(sockFd);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700289 if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
Chenbo Fengf2759682017-10-10 17:31:57 -0700290 UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
291
292 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
293 // flag so it will insert a new entry to the map if that value doesn't exist
294 // yet. And update the tag if there is already a tag stored. Since the eBPF
295 // program in kernel only read this map, and is protected by rcu read lock. It
296 // should be fine to cocurrently update the map while eBPF program is running.
297 int res = writeToMapEntry(mCookieTagMap, &sock_cookie, &newKey, BPF_ANY);
298 if (res < 0) {
299 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800300 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(errno), mCookieTagMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700301 }
302
303 return res;
304}
305
306int TrafficController::untagSocket(int sockFd) {
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700307 if (!ebpfSupported) {
308 if (legacy_untagSocket(sockFd)) return -errno;
309 return 0;
310 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700311 uint64_t sock_cookie = getSocketCookie(sockFd);
312
Chenbo Fengef1cab32018-04-13 19:50:49 -0700313 if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
Chenbo Fengf2759682017-10-10 17:31:57 -0700314 int res = deleteMapEntry(mCookieTagMap, &sock_cookie);
315 if (res) {
316 res = -errno;
317 ALOGE("Failed to untag socket: %s\n", strerror(errno));
318 }
319 return res;
320}
321
322int TrafficController::setCounterSet(int counterSetNum, uid_t uid) {
323 if (counterSetNum < 0 || counterSetNum >= COUNTERSETS_LIMIT) return -EINVAL;
Chenbo Fengf2759682017-10-10 17:31:57 -0700324 int res;
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700325 if (!ebpfSupported) {
326 if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
327 return 0;
328 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800329
330 // The default counter set for all uid is 0, so deleting the current counterset for that uid
331 // will automatically set it to 0.
Chenbo Fengf2759682017-10-10 17:31:57 -0700332 if (counterSetNum == 0) {
333 res = deleteMapEntry(mUidCounterSetMap, &uid);
334 if (res == 0 || (res == -1 && errno == ENOENT)) {
335 return 0;
336 } else {
337 ALOGE("Failed to delete the counterSet: %s\n", strerror(errno));
338 return -errno;
339 }
340 }
341
342 res = writeToMapEntry(mUidCounterSetMap, &uid, &counterSetNum, BPF_ANY);
343 if (res < 0) {
344 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800345 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(errno), mUidCounterSetMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700346 }
347 return res;
348}
349
350int TrafficController::deleteTagData(uint32_t tag, uid_t uid) {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700351 std::lock_guard<std::mutex> guard(mDeleteStatsMutex);
Chenbo Fengf2759682017-10-10 17:31:57 -0700352 int res = 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700353
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700354 if (!ebpfSupported) {
355 if (legacy_deleteTagData(tag, uid)) return -errno;
356 return 0;
357 }
Chenbo Feng33cc1032017-10-23 15:16:37 -0700358
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700359 uint64_t dummyCookie;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800360 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
Chenbo Fengef1cab32018-04-13 19:50:49 -0700361 // the tags related to the uid if the tag is 0.
362 struct UidTag dummyUidTag;
363 auto deleteMatchedCookieEntry = [&uid, &tag](void *key, void *value,
364 const base::unique_fd& map_fd) {
365 UidTag *tmp_uidtag = (UidTag *) value;
366 uint64_t cookie = *(uint64_t *)key;
367 if (tmp_uidtag->uid == uid && (tmp_uidtag->tag == tag || tag == 0)) {
368 int res = deleteMapEntry(map_fd, &cookie);
369 if (res == 0 || (res && errno == ENOENT)) {
370 return BPF_DELETED;
Chenbo Fengf2759682017-10-10 17:31:57 -0700371 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700372 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", cookie,
373 strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700374 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700375 // Move forward to next cookie in the map.
376 return BPF_CONTINUE;
377 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700378 res = bpfIterateMapWithValue(dummyCookie, dummyUidTag, mCookieTagMap, deleteMatchedCookieEntry);
Chenbo Fengf2759682017-10-10 17:31:57 -0700379 // Now we go through the Tag stats map and delete the data entry with correct uid and tag
Chenbo Fengef1cab32018-04-13 19:50:49 -0700380 // combination. Or all tag stats under that uid if the target tag is 0.
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700381 struct StatsKey dummyStatsKey;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700382 auto deleteMatchedUidTagEntry = [&uid, &tag](void *key, const base::unique_fd& map_fd) {
383 StatsKey *keyInfo = (StatsKey *) key;
384 if (keyInfo->uid == uid && (keyInfo->tag == tag || tag == 0)) {
385 int res = deleteMapEntry(map_fd, key);
386 if (res == 0 || (res && (errno == ENOENT))) {
387 //Entry is deleted, use the current key to get a new nextKey;
388 return BPF_DELETED;
Chenbo Fengf2759682017-10-10 17:31:57 -0700389 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700390 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", keyInfo->uid,
391 keyInfo->tag, strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700392 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700393 return BPF_CONTINUE;
394 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700395 res = bpfIterateMap(dummyStatsKey, mTagStatsMap, deleteMatchedUidTagEntry);
Chenbo Fengf2759682017-10-10 17:31:57 -0700396 // If the tag is not zero, we already deleted all the data entry required. If tag is 0, we also
Chenbo Fenged37fea2017-12-13 19:35:01 -0800397 // need to delete the stats stored in uidStatsMap and counterSet map.
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800398 if (tag != 0) return 0;
399
400 res = deleteMapEntry(mUidCounterSetMap, &uid);
401 if (res < 0 && errno != ENOENT) {
402 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
403 }
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700404 return bpfIterateMap(dummyStatsKey, mUidStatsMap, deleteMatchedUidTagEntry);
Chenbo Fengf2759682017-10-10 17:31:57 -0700405}
406
Chenbo Feng7e974052018-02-28 22:57:21 -0800407int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
408 int res = 0;
409 if (!ebpfSupported) return res;
410
411 char ifaceName[IFNAMSIZ];
412 if (ifaceIndex == 0) {
413 ALOGE("Unknow interface %s(%d)", name, ifaceIndex);
414 return -1;
415 }
416
417 strlcpy(ifaceName, name, sizeof(ifaceName));
418 res = writeToMapEntry(mIfaceIndexNameMap, &ifaceIndex, ifaceName, BPF_ANY);
419 if (res) {
420 res = -errno;
421 ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(errno));
422 }
423 return res;
424}
425
Chenbo Feng89c12f12018-03-21 10:29:18 -0700426int TrafficController::updateOwnerMapEntry(const base::unique_fd& map_fd, uid_t uid,
427 FirewallRule rule, FirewallType type) {
428 int res = 0;
Chenbo Feng89c12f12018-03-21 10:29:18 -0700429
430 if (uid == UID_MAP_ENABLED) {
431 ALOGE("This uid is reserved for map state");
432 return -EINVAL;
433 }
434
435 if ((rule == ALLOW && type == WHITELIST) || (rule == DENY && type == BLACKLIST)) {
436 uint8_t flag = (type == WHITELIST) ? BPF_PASS : BPF_DROP;
437 res = writeToMapEntry(map_fd, &uid, &flag, BPF_ANY);
438 if (res) {
439 res = -errno;
440 ALOGE("Failed to add owner rule(uid: %u): %s", uid, strerror(errno));
441 }
442 } else if ((rule == ALLOW && type == BLACKLIST) || (rule == DENY && type == WHITELIST)) {
443 res = deleteMapEntry(map_fd, &uid);
444 if (res) {
445 res = -errno;
446 ALOGE("Failed to delete owner rule(uid: %u): %s", uid, strerror(errno));
447 }
448 } else {
449 //Cannot happen.
450 return -EINVAL;
451 }
452 return res;
453}
454
455int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
456 FirewallType type) {
457 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
458 if (!ebpfSupported) {
459 ALOGE("bpf is not set up, should use iptables rule");
460 return -ENOSYS;
461 }
462 switch (chain) {
463 case DOZABLE:
464 return updateOwnerMapEntry(mDozableUidMap, uid, rule, type);
465 case STANDBY:
466 return updateOwnerMapEntry(mStandbyUidMap, uid, rule, type);
467 case POWERSAVE:
468 return updateOwnerMapEntry(mPowerSaveUidMap, uid, rule, type);
469 case NONE:
470 default:
471 return -EINVAL;
472 }
473}
474
475int TrafficController::replaceUidsInMap(const base::unique_fd& map_fd,
476 const std::vector<int32_t> &uids,
477 FirewallRule rule, FirewallType type) {
478 std::set<int32_t> uidSet(uids.begin(), uids.end());
479 std::vector<uint32_t> uidsToDelete;
480 auto getUidsToDelete = [&uidsToDelete, &uidSet](void *key, const base::unique_fd&) {
481 uint32_t uid = *(uint32_t *)key;
482 if (uid != UID_MAP_ENABLED && uidSet.find((int32_t)uid) == uidSet.end()) {
483 uidsToDelete.push_back(uid);
484 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700485 return BPF_CONTINUE;
Chenbo Feng89c12f12018-03-21 10:29:18 -0700486 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700487 uint32_t dummyKey;
488 int ret = bpfIterateMap(dummyKey, map_fd, getUidsToDelete);
Chenbo Feng89c12f12018-03-21 10:29:18 -0700489
490 if (ret) return ret;
491
492 for(auto uid : uidsToDelete) {
493 if(deleteMapEntry(map_fd, &uid)) {
494 ret = -errno;
495 ALOGE("Delete uid(%u) from owner Map %d failed: %s", uid, map_fd.get(),
496 strerror(errno));
497 return -errno;
498 }
499 }
500
501 for (auto uid : uids) {
502 ret = updateOwnerMapEntry(map_fd, uid, rule, type);
503 if (ret) {
504 ALOGE("Failed to add owner rule(uid: %u, map: %d)", uid, map_fd.get());
505 return ret;
506 }
507 }
508 return 0;
509}
510
511int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist,
512 const std::vector<int32_t>& uids) {
513 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
514 FirewallRule rule;
515 FirewallType type;
516 if (isWhitelist) {
517 type = WHITELIST;
518 rule = ALLOW;
519 } else {
520 type = BLACKLIST;
521 rule = DENY;
522 }
523 int ret;
524 if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
525 ret = replaceUidsInMap(mDozableUidMap, uids, rule, type);
526 } else if (!name.compare(FirewallController::LOCAL_STANDBY)) {
527 ret = replaceUidsInMap(mStandbyUidMap, uids, rule, type);
528 } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
529 ret = replaceUidsInMap(mPowerSaveUidMap, uids, rule, type);
530 } else {
531 ALOGE("unknown chain name: %s", name.c_str());
532 return -EINVAL;
533 }
534 if (ret) {
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700535 ALOGE("Failed to clean up chain: %s: %s", name.c_str(), strerror(-ret));
Chenbo Feng89c12f12018-03-21 10:29:18 -0700536 return ret;
537 }
538 return 0;
539}
540
541int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
542 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
543 uint32_t keyUid = UID_MAP_ENABLED;
544 uint8_t mapState = enable ? 1 : 0;
545 int ret;
546 switch (chain) {
547 case DOZABLE:
548 ret = writeToMapEntry(mDozableUidMap, &keyUid, &mapState, BPF_EXIST);
549 break;
550 case STANDBY:
551 ret = writeToMapEntry(mStandbyUidMap, &keyUid, &mapState, BPF_EXIST);
552 break;
553 case POWERSAVE:
554 ret = writeToMapEntry(mPowerSaveUidMap, &keyUid, &mapState, BPF_EXIST);
555 break;
556 default:
557 return -EINVAL;
558 }
559 if (ret) {
560 ret = -errno;
561 ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, strerror(errno));
562 }
563 return ret;
564}
565
Chenbo Feng07d43fe2017-12-21 14:38:51 -0800566bool TrafficController::checkBpfStatsEnable() {
567 return ebpfSupported;
568}
569
Chenbo Fengef297172018-03-26 10:53:33 -0700570std::string getProgramStatus(const char *path) {
571 int ret = access(path, R_OK);
572 if (ret == 0) {
573 return StringPrintf("OK");
574 }
575 if (ret != 0 && errno == ENOENT) {
576 return StringPrintf("program is missing at: %s", path);
577 }
578 return StringPrintf("check Program %s error: %s", path, strerror(errno));
579}
580
581std::string getMapStatus(const unique_fd& map_fd, const char *path) {
582 if (map_fd.get() < 0) {
583 return StringPrintf("map fd lost");
584 }
585 if (access(path, F_OK) != 0) {
586 return StringPrintf("map not pinned to location: %s", path);
587 }
588 return StringPrintf("OK");
589}
590
591void dumpBpfMap(std::string mapName, DumpWriter& dw, const std::string& header) {
592 dw.blankline();
593 dw.println("%s:", mapName.c_str());
594 if(!header.empty()) {
595 dw.println(header.c_str());
596 }
597}
598
599const String16 TrafficController::DUMP_KEYWORD = String16("trafficcontroller");
600
601void TrafficController::dump(DumpWriter& dw, bool verbose) {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700602 std::lock_guard<std::mutex> ownerMapGuard(mOwnerMatchMutex);
603 std::lock_guard<std::mutex> statsMapGuard(mDeleteStatsMutex);
Chenbo Fengef297172018-03-26 10:53:33 -0700604 dw.incIndent();
605 dw.println("TrafficController");
606
607 dw.incIndent();
608 dw.println("BPF module status: %s", ebpfSupported? "ON" : "OFF");
609
610 if (!ebpfSupported)
611 return;
612
613 dw.blankline();
614 dw.println("mCookieTagMap status: %s",
615 getMapStatus(mCookieTagMap, COOKIE_TAG_MAP_PATH).c_str());
616 dw.println("mUidCounterSetMap status: %s",
617 getMapStatus(mUidCounterSetMap, UID_COUNTERSET_MAP_PATH).c_str());
618 dw.println("mUidStatsMap status: %s", getMapStatus(mUidStatsMap, UID_STATS_MAP_PATH).c_str());
619 dw.println("mTagStatsMap status: %s", getMapStatus(mTagStatsMap, TAG_STATS_MAP_PATH).c_str());
620 dw.println("mIfaceIndexNameMap status: %s",
621 getMapStatus(mIfaceIndexNameMap, IFACE_INDEX_NAME_MAP_PATH).c_str());
622 dw.println("mIfaceStatsMap status: %s",
623 getMapStatus(mIfaceStatsMap, IFACE_STATS_MAP_PATH).c_str());
624 dw.println("mDozableUidMap status: %s",
625 getMapStatus(mDozableUidMap, DOZABLE_UID_MAP_PATH).c_str());
626 dw.println("mStandbyUidMap status: %s",
627 getMapStatus(mStandbyUidMap, STANDBY_UID_MAP_PATH).c_str());
628 dw.println("mPowerSaveUidMap status: %s",
629 getMapStatus(mPowerSaveUidMap, POWERSAVE_UID_MAP_PATH).c_str());
630
631 dw.blankline();
632 dw.println("Cgroup ingress program status: %s",
633 getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
634 dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
635 dw.println("xt_bpf ingress program status: %s",
636 getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
637 dw.println("xt_bpf egress program status: %s",
638 getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
639
640 if(!verbose) return;
641
642 dw.blankline();
643 dw.println("BPF map content:");
644
645 dw.incIndent();
646
647 // Print CookieTagMap content.
648 dumpBpfMap("mCookieTagMap", dw, "");
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700649 uint64_t dummyCookie;
Chenbo Fengef297172018-03-26 10:53:33 -0700650 UidTag dummyUidTag;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700651 auto printCookieTagInfo = [&dw](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700652 UidTag uidTagEntry = *(UidTag *) value;
653 uint64_t cookie = *(uint64_t *) key;
654 dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", cookie, uidTagEntry.tag, uidTagEntry.uid);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700655 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700656 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700657 int ret = bpfIterateMapWithValue(dummyCookie, dummyUidTag, mCookieTagMap, printCookieTagInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700658 if (ret) {
659 dw.println("mCookieTagMap print end with error: %s", strerror(-ret));
660 }
661
662 // Print UidCounterSetMap Content
663 dumpBpfMap("mUidCounterSetMap", dw, "");
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700664 uint32_t dummyUid;
Chenbo Fengef297172018-03-26 10:53:33 -0700665 uint32_t dummyUidInfo;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700666 auto printUidInfo = [&dw](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700667 uint8_t setting = *(uint8_t *) value;
668 uint32_t uid = *(uint32_t *) key;
669 dw.println("%u %u", uid, setting);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700670 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700671 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700672 ret = bpfIterateMapWithValue(dummyUid, dummyUidInfo, mUidCounterSetMap, printUidInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700673 if (ret) {
674 dw.println("mUidCounterSetMap print end with error: %s", strerror(-ret));
675 }
676
677 // Print uidStatsMap content
678 std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
679 " rxPackets txBytes txPackets");
680 dumpBpfMap("mUidStatsMap", dw, statsHeader);
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700681 struct StatsKey dummyStatsKey;
Chenbo Fengef297172018-03-26 10:53:33 -0700682 struct StatsValue dummyStatsValue;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700683 auto printStatsInfo = [&dw, this](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700684 StatsValue statsEntry = *(StatsValue *) value;
685 StatsKey keyInfo = *(StatsKey *) key;
686 char ifname[IFNAMSIZ];
687 uint32_t ifIndex = keyInfo.ifaceIndex;
688 if (bpf::findMapEntry(mIfaceIndexNameMap, &ifIndex, &ifname) < 0) {
689 strlcpy(ifname, "unknown", sizeof(ifname));
690 }
691 dw.println("%u %s 0x%x %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifIndex, ifname,
692 keyInfo.tag, keyInfo.uid, keyInfo.counterSet, statsEntry.rxBytes,
693 statsEntry.rxPackets, statsEntry.txBytes, statsEntry.txPackets);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700694 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700695 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700696 ret = bpfIterateMapWithValue(dummyStatsKey, dummyStatsValue, mUidStatsMap, printStatsInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700697 if (ret) {
698 dw.println("mUidStatsMap print end with error: %s", strerror(-ret));
699 }
700
701 // Print TagStatsMap content.
702 dumpBpfMap("mTagStatsMap", dw, statsHeader);
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700703 ret = bpfIterateMapWithValue(dummyStatsKey, dummyStatsValue, mTagStatsMap, printStatsInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700704 if (ret) {
705 dw.println("mTagStatsMap print end with error: %s", strerror(-ret));
706 }
707
708 // Print ifaceIndexToNameMap content.
709 dumpBpfMap("mIfaceIndexNameMap", dw, "");
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700710 uint32_t dummyKey;
Chenbo Fengef297172018-03-26 10:53:33 -0700711 char dummyIface[IFNAMSIZ];
Chenbo Fengef1cab32018-04-13 19:50:49 -0700712 auto printIfaceNameInfo = [&dw](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700713 char *ifname = (char *) value;
714 uint32_t ifaceIndex = *(uint32_t *)key;
715 dw.println("ifaceIndex=%u ifaceName=%s", ifaceIndex, ifname);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700716 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700717 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700718 ret = bpfIterateMapWithValue(dummyKey, dummyIface, mIfaceIndexNameMap, printIfaceNameInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700719 if (ret) {
720 dw.println("mIfaceIndexNameMap print end with error: %s", strerror(-ret));
721 }
722
723 // Print ifaceStatsMap content
724 std::string ifaceStatsHeader = StringPrintf("ifaceIndex ifaceName rxBytes rxPackets txBytes"
725 " txPackets");
726 dumpBpfMap("mIfaceStatsMap:", dw, ifaceStatsHeader);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700727 auto printIfaceStatsInfo = [&dw, this] (void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700728 StatsValue statsEntry = *(StatsValue *) value;
729 uint32_t ifaceIndex = *(uint32_t *) key;
730 char ifname[IFNAMSIZ];
731 if (bpf::findMapEntry(mIfaceIndexNameMap, key, ifname) < 0) {
732 strlcpy(ifname, "unknown", sizeof(ifname));
733 }
734 dw.println("%u %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifaceIndex, ifname,
735 statsEntry.rxBytes, statsEntry.rxPackets, statsEntry.txBytes,
736 statsEntry.txPackets);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700737 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700738 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700739 ret = bpfIterateMapWithValue(dummyKey, dummyStatsValue, mIfaceStatsMap, printIfaceStatsInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700740 if (ret) {
741 dw.println("mIfaceStatsMap print end with error: %s", strerror(-ret));
742 }
743
744 // Print owner match uid maps
745 uint8_t dummyOwnerInfo;
746 dumpBpfMap("mDozableUidMap", dw, "");
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700747 ret = bpfIterateMapWithValue(dummyUid, dummyOwnerInfo, mDozableUidMap, printUidInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700748 if (ret) {
749 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
750 }
751
752 dumpBpfMap("mStandbyUidMap", dw, "");
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700753 ret = bpfIterateMapWithValue(dummyUid, dummyOwnerInfo, mStandbyUidMap, printUidInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700754 if (ret) {
755 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
756 }
757
758 dumpBpfMap("mPowerSaveUidMap", dw, "");
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700759 ret = bpfIterateMapWithValue(dummyUid, dummyOwnerInfo, mPowerSaveUidMap, printUidInfo);
Chenbo Fengef297172018-03-26 10:53:33 -0700760 if (ret) {
761 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
762 }
763
764 dw.decIndent();
765
766 dw.decIndent();
767
768 dw.decIndent();
769
770}
771
Chenbo Fengf2759682017-10-10 17:31:57 -0700772} // namespace net
773} // namespace android