blob: 17c8f9a77ff34a73018e7b497eafdb8001ffd4ed [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 Fengef1cab32018-04-13 19:50:49 -0700359 uint64_t nonExistentCookie = NONEXISTENT_COOKIE;
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 };
378 bpfIterateMapWithValue(nonExistentCookie, dummyUidTag, mCookieTagMap,
379 deleteMatchedCookieEntry);
Chenbo Fengf2759682017-10-10 17:31:57 -0700380 // 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 -0700381 // combination. Or all tag stats under that uid if the target tag is 0.
382 struct StatsKey nonExistentStatsKey = NONEXISTENT_STATSKEY;
383 struct StatsValue dummyStatsValue;
384 auto deleteMatchedUidTagEntry = [&uid, &tag](void *key, const base::unique_fd& map_fd) {
385 StatsKey *keyInfo = (StatsKey *) key;
386 if (keyInfo->uid == uid && (keyInfo->tag == tag || tag == 0)) {
387 int res = deleteMapEntry(map_fd, key);
388 if (res == 0 || (res && (errno == ENOENT))) {
389 //Entry is deleted, use the current key to get a new nextKey;
390 return BPF_DELETED;
Chenbo Fengf2759682017-10-10 17:31:57 -0700391 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700392 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", keyInfo->uid,
393 keyInfo->tag, strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700394 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700395 return BPF_CONTINUE;
396 };
397 bpfIterateMap(nonExistentStatsKey, dummyStatsValue, mTagStatsMap,
398 deleteMatchedUidTagEntry);
Chenbo Fengf2759682017-10-10 17:31:57 -0700399 // 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 -0800400 // need to delete the stats stored in uidStatsMap and counterSet map.
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800401 if (tag != 0) return 0;
402
403 res = deleteMapEntry(mUidCounterSetMap, &uid);
404 if (res < 0 && errno != ENOENT) {
405 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
406 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700407 return bpfIterateMap(nonExistentStatsKey, dummyStatsValue, mUidStatsMap,
408 deleteMatchedUidTagEntry);
Chenbo Fengf2759682017-10-10 17:31:57 -0700409}
410
Chenbo Feng7e974052018-02-28 22:57:21 -0800411int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
412 int res = 0;
413 if (!ebpfSupported) return res;
414
415 char ifaceName[IFNAMSIZ];
416 if (ifaceIndex == 0) {
417 ALOGE("Unknow interface %s(%d)", name, ifaceIndex);
418 return -1;
419 }
420
421 strlcpy(ifaceName, name, sizeof(ifaceName));
422 res = writeToMapEntry(mIfaceIndexNameMap, &ifaceIndex, ifaceName, BPF_ANY);
423 if (res) {
424 res = -errno;
425 ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(errno));
426 }
427 return res;
428}
429
Chenbo Feng89c12f12018-03-21 10:29:18 -0700430int TrafficController::updateOwnerMapEntry(const base::unique_fd& map_fd, uid_t uid,
431 FirewallRule rule, FirewallType type) {
432 int res = 0;
433 if (uid == NONEXISTENT_UID) {
434 ALOGE("This uid should never exist in maps: %u", uid);
435 return -EINVAL;
436 }
437
438 if (uid == UID_MAP_ENABLED) {
439 ALOGE("This uid is reserved for map state");
440 return -EINVAL;
441 }
442
443 if ((rule == ALLOW && type == WHITELIST) || (rule == DENY && type == BLACKLIST)) {
444 uint8_t flag = (type == WHITELIST) ? BPF_PASS : BPF_DROP;
445 res = writeToMapEntry(map_fd, &uid, &flag, BPF_ANY);
446 if (res) {
447 res = -errno;
448 ALOGE("Failed to add owner rule(uid: %u): %s", uid, strerror(errno));
449 }
450 } else if ((rule == ALLOW && type == BLACKLIST) || (rule == DENY && type == WHITELIST)) {
451 res = deleteMapEntry(map_fd, &uid);
452 if (res) {
453 res = -errno;
454 ALOGE("Failed to delete owner rule(uid: %u): %s", uid, strerror(errno));
455 }
456 } else {
457 //Cannot happen.
458 return -EINVAL;
459 }
460 return res;
461}
462
463int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
464 FirewallType type) {
465 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
466 if (!ebpfSupported) {
467 ALOGE("bpf is not set up, should use iptables rule");
468 return -ENOSYS;
469 }
470 switch (chain) {
471 case DOZABLE:
472 return updateOwnerMapEntry(mDozableUidMap, uid, rule, type);
473 case STANDBY:
474 return updateOwnerMapEntry(mStandbyUidMap, uid, rule, type);
475 case POWERSAVE:
476 return updateOwnerMapEntry(mPowerSaveUidMap, uid, rule, type);
477 case NONE:
478 default:
479 return -EINVAL;
480 }
481}
482
483int TrafficController::replaceUidsInMap(const base::unique_fd& map_fd,
484 const std::vector<int32_t> &uids,
485 FirewallRule rule, FirewallType type) {
486 std::set<int32_t> uidSet(uids.begin(), uids.end());
487 std::vector<uint32_t> uidsToDelete;
488 auto getUidsToDelete = [&uidsToDelete, &uidSet](void *key, const base::unique_fd&) {
489 uint32_t uid = *(uint32_t *)key;
490 if (uid != UID_MAP_ENABLED && uidSet.find((int32_t)uid) == uidSet.end()) {
491 uidsToDelete.push_back(uid);
492 }
Chenbo Fengef1cab32018-04-13 19:50:49 -0700493 return BPF_CONTINUE;
Chenbo Feng89c12f12018-03-21 10:29:18 -0700494 };
495 uint32_t nonExistentKey = NONEXISTENT_UID;
496 uint8_t dummyValue;
497 int ret = bpfIterateMap(nonExistentKey, dummyValue, map_fd, getUidsToDelete);
498
499 if (ret) return ret;
500
501 for(auto uid : uidsToDelete) {
502 if(deleteMapEntry(map_fd, &uid)) {
503 ret = -errno;
504 ALOGE("Delete uid(%u) from owner Map %d failed: %s", uid, map_fd.get(),
505 strerror(errno));
506 return -errno;
507 }
508 }
509
510 for (auto uid : uids) {
511 ret = updateOwnerMapEntry(map_fd, uid, rule, type);
512 if (ret) {
513 ALOGE("Failed to add owner rule(uid: %u, map: %d)", uid, map_fd.get());
514 return ret;
515 }
516 }
517 return 0;
518}
519
520int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist,
521 const std::vector<int32_t>& uids) {
522 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
523 FirewallRule rule;
524 FirewallType type;
525 if (isWhitelist) {
526 type = WHITELIST;
527 rule = ALLOW;
528 } else {
529 type = BLACKLIST;
530 rule = DENY;
531 }
532 int ret;
533 if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
534 ret = replaceUidsInMap(mDozableUidMap, uids, rule, type);
535 } else if (!name.compare(FirewallController::LOCAL_STANDBY)) {
536 ret = replaceUidsInMap(mStandbyUidMap, uids, rule, type);
537 } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
538 ret = replaceUidsInMap(mPowerSaveUidMap, uids, rule, type);
539 } else {
540 ALOGE("unknown chain name: %s", name.c_str());
541 return -EINVAL;
542 }
543 if (ret) {
544 ALOGE("Failed to clean up chain: %s: %s", name.c_str(), strerror(ret));
545 return ret;
546 }
547 return 0;
548}
549
550int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
551 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
552 uint32_t keyUid = UID_MAP_ENABLED;
553 uint8_t mapState = enable ? 1 : 0;
554 int ret;
555 switch (chain) {
556 case DOZABLE:
557 ret = writeToMapEntry(mDozableUidMap, &keyUid, &mapState, BPF_EXIST);
558 break;
559 case STANDBY:
560 ret = writeToMapEntry(mStandbyUidMap, &keyUid, &mapState, BPF_EXIST);
561 break;
562 case POWERSAVE:
563 ret = writeToMapEntry(mPowerSaveUidMap, &keyUid, &mapState, BPF_EXIST);
564 break;
565 default:
566 return -EINVAL;
567 }
568 if (ret) {
569 ret = -errno;
570 ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, strerror(errno));
571 }
572 return ret;
573}
574
Chenbo Feng07d43fe2017-12-21 14:38:51 -0800575bool TrafficController::checkBpfStatsEnable() {
576 return ebpfSupported;
577}
578
Chenbo Fengef297172018-03-26 10:53:33 -0700579std::string getProgramStatus(const char *path) {
580 int ret = access(path, R_OK);
581 if (ret == 0) {
582 return StringPrintf("OK");
583 }
584 if (ret != 0 && errno == ENOENT) {
585 return StringPrintf("program is missing at: %s", path);
586 }
587 return StringPrintf("check Program %s error: %s", path, strerror(errno));
588}
589
590std::string getMapStatus(const unique_fd& map_fd, const char *path) {
591 if (map_fd.get() < 0) {
592 return StringPrintf("map fd lost");
593 }
594 if (access(path, F_OK) != 0) {
595 return StringPrintf("map not pinned to location: %s", path);
596 }
597 return StringPrintf("OK");
598}
599
600void dumpBpfMap(std::string mapName, DumpWriter& dw, const std::string& header) {
601 dw.blankline();
602 dw.println("%s:", mapName.c_str());
603 if(!header.empty()) {
604 dw.println(header.c_str());
605 }
606}
607
608const String16 TrafficController::DUMP_KEYWORD = String16("trafficcontroller");
609
610void TrafficController::dump(DumpWriter& dw, bool verbose) {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700611 std::lock_guard<std::mutex> ownerMapGuard(mOwnerMatchMutex);
612 std::lock_guard<std::mutex> statsMapGuard(mDeleteStatsMutex);
Chenbo Fengef297172018-03-26 10:53:33 -0700613 dw.incIndent();
614 dw.println("TrafficController");
615
616 dw.incIndent();
617 dw.println("BPF module status: %s", ebpfSupported? "ON" : "OFF");
618
619 if (!ebpfSupported)
620 return;
621
622 dw.blankline();
623 dw.println("mCookieTagMap status: %s",
624 getMapStatus(mCookieTagMap, COOKIE_TAG_MAP_PATH).c_str());
625 dw.println("mUidCounterSetMap status: %s",
626 getMapStatus(mUidCounterSetMap, UID_COUNTERSET_MAP_PATH).c_str());
627 dw.println("mUidStatsMap status: %s", getMapStatus(mUidStatsMap, UID_STATS_MAP_PATH).c_str());
628 dw.println("mTagStatsMap status: %s", getMapStatus(mTagStatsMap, TAG_STATS_MAP_PATH).c_str());
629 dw.println("mIfaceIndexNameMap status: %s",
630 getMapStatus(mIfaceIndexNameMap, IFACE_INDEX_NAME_MAP_PATH).c_str());
631 dw.println("mIfaceStatsMap status: %s",
632 getMapStatus(mIfaceStatsMap, IFACE_STATS_MAP_PATH).c_str());
633 dw.println("mDozableUidMap status: %s",
634 getMapStatus(mDozableUidMap, DOZABLE_UID_MAP_PATH).c_str());
635 dw.println("mStandbyUidMap status: %s",
636 getMapStatus(mStandbyUidMap, STANDBY_UID_MAP_PATH).c_str());
637 dw.println("mPowerSaveUidMap status: %s",
638 getMapStatus(mPowerSaveUidMap, POWERSAVE_UID_MAP_PATH).c_str());
639
640 dw.blankline();
641 dw.println("Cgroup ingress program status: %s",
642 getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
643 dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
644 dw.println("xt_bpf ingress program status: %s",
645 getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
646 dw.println("xt_bpf egress program status: %s",
647 getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
648
649 if(!verbose) return;
650
651 dw.blankline();
652 dw.println("BPF map content:");
653
654 dw.incIndent();
655
656 // Print CookieTagMap content.
657 dumpBpfMap("mCookieTagMap", dw, "");
Chenbo Fengef1cab32018-04-13 19:50:49 -0700658 const uint64_t nonExistentCookie = NONEXISTENT_COOKIE;
Chenbo Fengef297172018-03-26 10:53:33 -0700659 UidTag dummyUidTag;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700660 auto printCookieTagInfo = [&dw](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700661 UidTag uidTagEntry = *(UidTag *) value;
662 uint64_t cookie = *(uint64_t *) key;
663 dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", cookie, uidTagEntry.tag, uidTagEntry.uid);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700664 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700665 };
666 int ret = bpfIterateMapWithValue(nonExistentCookie, dummyUidTag, mCookieTagMap,
667 printCookieTagInfo);
668 if (ret) {
669 dw.println("mCookieTagMap print end with error: %s", strerror(-ret));
670 }
671
672 // Print UidCounterSetMap Content
673 dumpBpfMap("mUidCounterSetMap", dw, "");
674 const uint32_t nonExistentUid = NONEXISTENT_UID;
675 uint32_t dummyUidInfo;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700676 auto printUidInfo = [&dw](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700677 uint8_t setting = *(uint8_t *) value;
678 uint32_t uid = *(uint32_t *) key;
679 dw.println("%u %u", uid, setting);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700680 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700681 };
682 ret = bpfIterateMapWithValue(nonExistentUid, dummyUidInfo, mUidCounterSetMap, printUidInfo);
683 if (ret) {
684 dw.println("mUidCounterSetMap print end with error: %s", strerror(-ret));
685 }
686
687 // Print uidStatsMap content
688 std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
689 " rxPackets txBytes txPackets");
690 dumpBpfMap("mUidStatsMap", dw, statsHeader);
691 const struct StatsKey nonExistentStatsKey = NONEXISTENT_STATSKEY;
692 struct StatsValue dummyStatsValue;
Chenbo Fengef1cab32018-04-13 19:50:49 -0700693 auto printStatsInfo = [&dw, this](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700694 StatsValue statsEntry = *(StatsValue *) value;
695 StatsKey keyInfo = *(StatsKey *) key;
696 char ifname[IFNAMSIZ];
697 uint32_t ifIndex = keyInfo.ifaceIndex;
698 if (bpf::findMapEntry(mIfaceIndexNameMap, &ifIndex, &ifname) < 0) {
699 strlcpy(ifname, "unknown", sizeof(ifname));
700 }
701 dw.println("%u %s 0x%x %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifIndex, ifname,
702 keyInfo.tag, keyInfo.uid, keyInfo.counterSet, statsEntry.rxBytes,
703 statsEntry.rxPackets, statsEntry.txBytes, statsEntry.txPackets);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700704 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700705 };
706 ret = bpfIterateMapWithValue(nonExistentStatsKey, dummyStatsValue, mUidStatsMap,
707 printStatsInfo);
708 if (ret) {
709 dw.println("mUidStatsMap print end with error: %s", strerror(-ret));
710 }
711
712 // Print TagStatsMap content.
713 dumpBpfMap("mTagStatsMap", dw, statsHeader);
714 ret = bpfIterateMapWithValue(nonExistentStatsKey, dummyStatsValue, mTagStatsMap,
715 printStatsInfo);
716 if (ret) {
717 dw.println("mTagStatsMap print end with error: %s", strerror(-ret));
718 }
719
720 // Print ifaceIndexToNameMap content.
721 dumpBpfMap("mIfaceIndexNameMap", dw, "");
722 uint32_t nonExistentIface = NONEXISTENT_IFACE_STATS_KEY;
723 char dummyIface[IFNAMSIZ];
Chenbo Fengef1cab32018-04-13 19:50:49 -0700724 auto printIfaceNameInfo = [&dw](void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700725 char *ifname = (char *) value;
726 uint32_t ifaceIndex = *(uint32_t *)key;
727 dw.println("ifaceIndex=%u ifaceName=%s", ifaceIndex, ifname);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700728 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700729 };
730 ret = bpfIterateMapWithValue(nonExistentIface, dummyIface, mIfaceIndexNameMap,
731 printIfaceNameInfo);
732 if (ret) {
733 dw.println("mIfaceIndexNameMap print end with error: %s", strerror(-ret));
734 }
735
736 // Print ifaceStatsMap content
737 std::string ifaceStatsHeader = StringPrintf("ifaceIndex ifaceName rxBytes rxPackets txBytes"
738 " txPackets");
739 dumpBpfMap("mIfaceStatsMap:", dw, ifaceStatsHeader);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700740 auto printIfaceStatsInfo = [&dw, this] (void *key, void *value, const base::unique_fd&) {
Chenbo Fengef297172018-03-26 10:53:33 -0700741 StatsValue statsEntry = *(StatsValue *) value;
742 uint32_t ifaceIndex = *(uint32_t *) key;
743 char ifname[IFNAMSIZ];
744 if (bpf::findMapEntry(mIfaceIndexNameMap, key, ifname) < 0) {
745 strlcpy(ifname, "unknown", sizeof(ifname));
746 }
747 dw.println("%u %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifaceIndex, ifname,
748 statsEntry.rxBytes, statsEntry.rxPackets, statsEntry.txBytes,
749 statsEntry.txPackets);
Chenbo Fengef1cab32018-04-13 19:50:49 -0700750 return BPF_CONTINUE;
Chenbo Fengef297172018-03-26 10:53:33 -0700751 };
752 ret = bpfIterateMapWithValue(nonExistentIface, dummyStatsValue, mIfaceStatsMap,
753 printIfaceStatsInfo);
754 if (ret) {
755 dw.println("mIfaceStatsMap print end with error: %s", strerror(-ret));
756 }
757
758 // Print owner match uid maps
759 uint8_t dummyOwnerInfo;
760 dumpBpfMap("mDozableUidMap", dw, "");
761 ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mDozableUidMap, printUidInfo);
762 if (ret) {
763 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
764 }
765
766 dumpBpfMap("mStandbyUidMap", dw, "");
767 ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mStandbyUidMap, printUidInfo);
768 if (ret) {
769 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
770 }
771
772 dumpBpfMap("mPowerSaveUidMap", dw, "");
773 ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mPowerSaveUidMap, printUidInfo);
774 if (ret) {
775 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
776 }
777
778 dw.decIndent();
779
780 dw.decIndent();
781
782 dw.decIndent();
783
784}
785
Chenbo Fengf2759682017-10-10 17:31:57 -0700786} // namespace net
787} // namespace android