blob: 0039d25070364ac420cfda5c7f588aaa199d9abf [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() {
132 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
133 ASSIGN_OR_RETURN(mCookieTagMap,
134 setUpBPFMap(sizeof(uint64_t), sizeof(struct UidTag), COOKIE_UID_MAP_SIZE,
135 COOKIE_TAG_MAP_PATH, BPF_MAP_TYPE_HASH));
136
137 RETURN_IF_NOT_OK(changeOwnerAndMode(COOKIE_TAG_MAP_PATH, AID_NET_BW_ACCT, "CookieTagMap",
138 false));
139
140 ASSIGN_OR_RETURN(mUidCounterSetMap,
141 setUpBPFMap(sizeof(uint32_t), sizeof(uint32_t), UID_COUNTERSET_MAP_SIZE,
142 UID_COUNTERSET_MAP_PATH, BPF_MAP_TYPE_HASH));
143 RETURN_IF_NOT_OK(changeOwnerAndMode(UID_COUNTERSET_MAP_PATH, AID_NET_BW_ACCT,
144 "UidCounterSetMap", false));
145
146 ASSIGN_OR_RETURN(mUidStatsMap,
147 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
148 UID_STATS_MAP_SIZE, UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
149 RETURN_IF_NOT_OK(changeOwnerAndMode(UID_STATS_MAP_PATH, AID_NET_BW_STATS, "UidStatsMap",
150 false));
151
152 ASSIGN_OR_RETURN(mTagStatsMap,
153 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
154 TAG_STATS_MAP_SIZE, TAG_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
155 RETURN_IF_NOT_OK(changeOwnerAndMode(TAG_STATS_MAP_PATH, AID_NET_BW_STATS, "TagStatsMap",
156 false));
157
158 ASSIGN_OR_RETURN(mIfaceIndexNameMap,
159 setUpBPFMap(sizeof(uint32_t), IFNAMSIZ, IFACE_INDEX_NAME_MAP_SIZE,
160 IFACE_INDEX_NAME_MAP_PATH, BPF_MAP_TYPE_HASH));
161 RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_INDEX_NAME_MAP_PATH, AID_NET_BW_STATS,
162 "IfaceIndexNameMap", false));
163
164 ASSIGN_OR_RETURN(mDozableUidMap,
165 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
166 DOZABLE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
167 RETURN_IF_NOT_OK(changeOwnerAndMode(DOZABLE_UID_MAP_PATH, AID_ROOT, "DozableUidMap", true));
168 RETURN_IF_NOT_OK(initialOwnerMap(mDozableUidMap, "DozableUidMap"));
169
170 ASSIGN_OR_RETURN(mStandbyUidMap,
171 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
172 STANDBY_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
173 RETURN_IF_NOT_OK(changeOwnerAndMode(STANDBY_UID_MAP_PATH, AID_ROOT, "StandbyUidMap", true));
174 RETURN_IF_NOT_OK(initialOwnerMap(mStandbyUidMap, "StandbyUidMap"));
175
176 ASSIGN_OR_RETURN(mPowerSaveUidMap,
177 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
178 POWERSAVE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
179 RETURN_IF_NOT_OK(changeOwnerAndMode(POWERSAVE_UID_MAP_PATH, AID_ROOT, "PowerSaveUidMap", true));
180 RETURN_IF_NOT_OK(initialOwnerMap(mPowerSaveUidMap, "PowerSaveUidMap"));
181
182 ASSIGN_OR_RETURN(mIfaceStatsMap,
183 setUpBPFMap(sizeof(uint32_t), sizeof(struct StatsValue), IFACE_STATS_MAP_SIZE,
184 IFACE_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
185 RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_STATS_MAP_PATH, AID_NET_BW_STATS, "IfaceStatsMap",
186 false));
187 return netdutils::status::ok;
188}
189
190Status TrafficController::start() {
191
Chenbo Fengf43bf812017-12-15 18:27:22 -0800192 if (!ebpfSupported) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800193 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700194 }
195
196 /* When netd restart from a crash without total system reboot, the program
197 * is still attached to the cgroup, detach it so the program can be freed
198 * and we can load and attach new program into the target cgroup.
199 *
200 * TODO: Scrape existing socket when run-time restart and clean up the map
201 * if the socket no longer exist
202 */
203
Chenbo Feng89c12f12018-03-21 10:29:18 -0700204 RETURN_IF_NOT_OK(initMaps());
Chenbo Feng7e974052018-02-28 22:57:21 -0800205
206 // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
207 // already running, so it will call addInterface() when any new interface appears.
208 std::map<std::string, uint32_t> ifacePairs;
209 ASSIGN_OR_RETURN(ifacePairs, InterfaceController::getIfaceList());
210 for (const auto& ifacePair:ifacePairs) {
211 addInterface(ifacePair.first.c_str(), ifacePair.second);
212 }
213
Chenbo Feng5ed17992018-03-13 21:30:49 -0700214
Chenbo Feng116d0552017-12-04 17:25:19 -0800215 auto result = makeSkDestroyListener();
216 if (!isOk(result)) {
217 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
218 } else {
219 mSkDestroyListener = std::move(result.value());
220 }
221 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
222 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
223 inet_diag_msg diagmsg = {};
224 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
225 ALOGE("unrecognized netlink message: %s", toString(msg).c_str());
226 return;
227 }
228 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
229 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
230
231 deleteMapEntry(mCookieTagMap, &sock_cookie);
232 };
233 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
234
235 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
236 // properly.
237 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
238 // Ignore NLMSG_DONE messages
239 inet_diag_msg diagmsg = {};
240 extract(msg, diagmsg);
241 };
242 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
243
Chenbo Feng05393d82018-01-09 15:18:43 -0800244 int* status = nullptr;
245
246 std::vector<const char*> prog_args{
247 "/system/bin/bpfloader",
248 };
Chenbo Feng89c12f12018-03-21 10:29:18 -0700249 int ret = access(BPF_INGRESS_PROG_PATH, R_OK);
Chenbo Feng05393d82018-01-09 15:18:43 -0800250 if (ret != 0 && errno == ENOENT) {
251 prog_args.push_back((char*)"-i");
252 }
253 ret = access(BPF_EGRESS_PROG_PATH, R_OK);
254 if (ret != 0 && errno == ENOENT) {
255 prog_args.push_back((char*)"-e");
256 }
Chenbo Feng5ed17992018-03-13 21:30:49 -0700257 ret = access(XT_BPF_INGRESS_PROG_PATH, R_OK);
258 if (ret != 0 && errno == ENOENT) {
259 prog_args.push_back((char*)"-p");
260 }
261 ret = access(XT_BPF_EGRESS_PROG_PATH, R_OK);
262 if (ret != 0 && errno == ENOENT) {
263 prog_args.push_back((char*)"-m");
264 }
Chenbo Feng05393d82018-01-09 15:18:43 -0800265
266 if (prog_args.size() == 1) {
Chenbo Feng5ed17992018-03-13 21:30:49 -0700267 // all program are loaded already.
Chenbo Feng05393d82018-01-09 15:18:43 -0800268 return netdutils::status::ok;
269 }
270
271 prog_args.push_back(nullptr);
272 ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
273 if (ret) {
274 ret = errno;
275 ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
276 return statusFromErrno(ret, "run bpf loader failed");
277 }
278 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700279}
280
Chenbo Fengf2759682017-10-10 17:31:57 -0700281int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700282 if (!ebpfSupported) {
283 if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
284 return 0;
285 }
Chenbo Feng33cc1032017-10-23 15:16:37 -0700286
Chenbo Fengf2759682017-10-10 17:31:57 -0700287 uint64_t sock_cookie = getSocketCookie(sockFd);
288 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
289 UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
290
291 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
292 // flag so it will insert a new entry to the map if that value doesn't exist
293 // yet. And update the tag if there is already a tag stored. Since the eBPF
294 // program in kernel only read this map, and is protected by rcu read lock. It
295 // should be fine to cocurrently update the map while eBPF program is running.
296 int res = writeToMapEntry(mCookieTagMap, &sock_cookie, &newKey, BPF_ANY);
297 if (res < 0) {
298 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800299 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(errno), mCookieTagMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700300 }
301
302 return res;
303}
304
305int TrafficController::untagSocket(int sockFd) {
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700306 if (!ebpfSupported) {
307 if (legacy_untagSocket(sockFd)) return -errno;
308 return 0;
309 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700310 uint64_t sock_cookie = getSocketCookie(sockFd);
311
312 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
313 int res = deleteMapEntry(mCookieTagMap, &sock_cookie);
314 if (res) {
315 res = -errno;
316 ALOGE("Failed to untag socket: %s\n", strerror(errno));
317 }
318 return res;
319}
320
321int TrafficController::setCounterSet(int counterSetNum, uid_t uid) {
322 if (counterSetNum < 0 || counterSetNum >= COUNTERSETS_LIMIT) return -EINVAL;
Chenbo Fengf2759682017-10-10 17:31:57 -0700323 int res;
Chenbo Fengbc6d4702018-04-11 18:27:19 -0700324 if (!ebpfSupported) {
325 if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
326 return 0;
327 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800328
329 // The default counter set for all uid is 0, so deleting the current counterset for that uid
330 // will automatically set it to 0.
Chenbo Fengf2759682017-10-10 17:31:57 -0700331 if (counterSetNum == 0) {
332 res = deleteMapEntry(mUidCounterSetMap, &uid);
333 if (res == 0 || (res == -1 && errno == ENOENT)) {
334 return 0;
335 } else {
336 ALOGE("Failed to delete the counterSet: %s\n", strerror(errno));
337 return -errno;
338 }
339 }
340
341 res = writeToMapEntry(mUidCounterSetMap, &uid, &counterSetNum, BPF_ANY);
342 if (res < 0) {
343 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800344 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(errno), mUidCounterSetMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700345 }
346 return res;
347}
348
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800349// TODO: Add a lock for delete tag Data so when several request for different uid comes in, they do
350// not race with each other.
Chenbo Fengf2759682017-10-10 17:31:57 -0700351int TrafficController::deleteTagData(uint32_t tag, uid_t uid) {
352 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 Fengc10a8a42017-12-15 13:56:33 -0800359 uint64_t curCookie = NONEXIST_COOKIE;
Chenbo Fengf2759682017-10-10 17:31:57 -0700360 uint64_t nextCookie = 0;
361 UidTag tmp_uidtag;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800362 std::vector<uint64_t> cookieList;
363 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
364 // the tags related to the uid if the tag is 0, we start the map iteration with a cookie of
365 // INET_DIAG_NOCOOKIE because it's guaranteed that that will not be in the map.
366 while (getNextMapKey(mCookieTagMap, &curCookie, &nextCookie) != -1) {
367 res = findMapEntry(mCookieTagMap, &nextCookie, &tmp_uidtag);
Chenbo Fengf2759682017-10-10 17:31:57 -0700368 if (res < 0) {
369 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800370 ALOGE("Failed to get tag info(cookie = %" PRIu64 ": %s\n", nextCookie, strerror(errno));
371 // Continue to look for next entry.
372 curCookie = nextCookie;
373 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700374 }
375
376 if (tmp_uidtag.uid == uid && (tmp_uidtag.tag == tag || tag == 0)) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800377 res = deleteMapEntry(mCookieTagMap, &nextCookie);
378 if (res < 0 && errno != ENOENT) {
Chenbo Fengf2759682017-10-10 17:31:57 -0700379 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800380 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", nextCookie,
381 strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700382 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800383 } else {
384 // Move forward to next cookie in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700385 curCookie = nextCookie;
386 }
387 }
388
389 // Now we go through the Tag stats map and delete the data entry with correct uid and tag
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800390 // combination. Or all tag stats under that uid if the target tag is 0. The initial key is
391 // set to the nonexist_statskey because it will never be in the map, and thus getNextMapKey will
392 // return 0 and set nextKey to the first key in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700393 struct StatsKey curKey, nextKey;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800394 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800395 while (getNextMapKey(mTagStatsMap, &curKey, &nextKey) != -1) {
396 if (nextKey.uid == uid && (nextKey.tag == tag || tag == 0)) {
397 res = deleteMapEntry(mTagStatsMap, &nextKey);
398 if (res < 0 && errno != ENOENT) {
399 // Skip the current entry if unexpected error happened.
400 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
401 strerror(errno));
402 curKey = nextKey;
Chenbo Fengf2759682017-10-10 17:31:57 -0700403 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800404 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700405 curKey = nextKey;
406 }
407 }
408
409 // 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 -0800410 // need to delete the stats stored in uidStatsMap and counterSet map.
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800411 if (tag != 0) return 0;
412
413 res = deleteMapEntry(mUidCounterSetMap, &uid);
414 if (res < 0 && errno != ENOENT) {
415 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
416 }
417
418 // For the uid stats deleted from the map, move them into a special
419 // removed uid entry. The removed uid is stored in uid 0, tag 0 and
420 // counterSet as COUNTERSETS_LIMIT.
421 StatsKey removedStatsKey = {0, 0, COUNTERSETS_LIMIT, 0};
Chenbo Fengf43bf812017-12-15 18:27:22 -0800422 StatsValue removedStatsTotal = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800423 res = findMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal);
424 if (res < 0 && errno != ENOENT) {
425 ALOGE("Failed to get stats of removed uid: %s", strerror(errno));
426 }
427
Chenbo Fengf43bf812017-12-15 18:27:22 -0800428 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800429 while (getNextMapKey(mUidStatsMap, &curKey, &nextKey) != -1) {
430 if (nextKey.uid == uid) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800431 StatsValue old_stats = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800432 res = findMapEntry(mUidStatsMap, &nextKey, &old_stats);
433 if (res < 0) {
434 if (errno != ENOENT) {
435 // if errno is ENOENT Somebody else deleted nextKey. Lookup the next key from
436 // curKey. If we have other error. Skip this key to avoid an infinite loop.
437 curKey = nextKey;
438 }
439 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700440 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800441 res = deleteMapEntry(mUidStatsMap, &nextKey);
442 if (res < 0 && errno != ENOENT) {
443 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
444 strerror(errno));
445 curKey = nextKey;
446 continue;
447 }
Chenbo Fengeac6c472018-02-05 15:06:23 -0800448 removedStatsTotal.rxPackets += old_stats.rxPackets;
449 removedStatsTotal.rxBytes += old_stats.rxBytes;
450 removedStatsTotal.txPackets += old_stats.txPackets;
451 removedStatsTotal.txBytes += old_stats.txBytes;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800452 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700453 curKey = nextKey;
454 }
455 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800456
457 res = writeToMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal, BPF_ANY);
458 if (res) {
459 res = -errno;
460 ALOGE("Failed to add deleting stats to removed uid: %s", strerror(errno));
461 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700462 return res;
463}
464
Chenbo Feng7e974052018-02-28 22:57:21 -0800465int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
466 int res = 0;
467 if (!ebpfSupported) return res;
468
469 char ifaceName[IFNAMSIZ];
470 if (ifaceIndex == 0) {
471 ALOGE("Unknow interface %s(%d)", name, ifaceIndex);
472 return -1;
473 }
474
475 strlcpy(ifaceName, name, sizeof(ifaceName));
476 res = writeToMapEntry(mIfaceIndexNameMap, &ifaceIndex, ifaceName, BPF_ANY);
477 if (res) {
478 res = -errno;
479 ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(errno));
480 }
481 return res;
482}
483
Chenbo Feng89c12f12018-03-21 10:29:18 -0700484int TrafficController::updateOwnerMapEntry(const base::unique_fd& map_fd, uid_t uid,
485 FirewallRule rule, FirewallType type) {
486 int res = 0;
487 if (uid == NONEXISTENT_UID) {
488 ALOGE("This uid should never exist in maps: %u", uid);
489 return -EINVAL;
490 }
491
492 if (uid == UID_MAP_ENABLED) {
493 ALOGE("This uid is reserved for map state");
494 return -EINVAL;
495 }
496
497 if ((rule == ALLOW && type == WHITELIST) || (rule == DENY && type == BLACKLIST)) {
498 uint8_t flag = (type == WHITELIST) ? BPF_PASS : BPF_DROP;
499 res = writeToMapEntry(map_fd, &uid, &flag, BPF_ANY);
500 if (res) {
501 res = -errno;
502 ALOGE("Failed to add owner rule(uid: %u): %s", uid, strerror(errno));
503 }
504 } else if ((rule == ALLOW && type == BLACKLIST) || (rule == DENY && type == WHITELIST)) {
505 res = deleteMapEntry(map_fd, &uid);
506 if (res) {
507 res = -errno;
508 ALOGE("Failed to delete owner rule(uid: %u): %s", uid, strerror(errno));
509 }
510 } else {
511 //Cannot happen.
512 return -EINVAL;
513 }
514 return res;
515}
516
517int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
518 FirewallType type) {
519 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
520 if (!ebpfSupported) {
521 ALOGE("bpf is not set up, should use iptables rule");
522 return -ENOSYS;
523 }
524 switch (chain) {
525 case DOZABLE:
526 return updateOwnerMapEntry(mDozableUidMap, uid, rule, type);
527 case STANDBY:
528 return updateOwnerMapEntry(mStandbyUidMap, uid, rule, type);
529 case POWERSAVE:
530 return updateOwnerMapEntry(mPowerSaveUidMap, uid, rule, type);
531 case NONE:
532 default:
533 return -EINVAL;
534 }
535}
536
537int TrafficController::replaceUidsInMap(const base::unique_fd& map_fd,
538 const std::vector<int32_t> &uids,
539 FirewallRule rule, FirewallType type) {
540 std::set<int32_t> uidSet(uids.begin(), uids.end());
541 std::vector<uint32_t> uidsToDelete;
542 auto getUidsToDelete = [&uidsToDelete, &uidSet](void *key, const base::unique_fd&) {
543 uint32_t uid = *(uint32_t *)key;
544 if (uid != UID_MAP_ENABLED && uidSet.find((int32_t)uid) == uidSet.end()) {
545 uidsToDelete.push_back(uid);
546 }
547 return 0;
548 };
549 uint32_t nonExistentKey = NONEXISTENT_UID;
550 uint8_t dummyValue;
551 int ret = bpfIterateMap(nonExistentKey, dummyValue, map_fd, getUidsToDelete);
552
553 if (ret) return ret;
554
555 for(auto uid : uidsToDelete) {
556 if(deleteMapEntry(map_fd, &uid)) {
557 ret = -errno;
558 ALOGE("Delete uid(%u) from owner Map %d failed: %s", uid, map_fd.get(),
559 strerror(errno));
560 return -errno;
561 }
562 }
563
564 for (auto uid : uids) {
565 ret = updateOwnerMapEntry(map_fd, uid, rule, type);
566 if (ret) {
567 ALOGE("Failed to add owner rule(uid: %u, map: %d)", uid, map_fd.get());
568 return ret;
569 }
570 }
571 return 0;
572}
573
574int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist,
575 const std::vector<int32_t>& uids) {
576 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
577 FirewallRule rule;
578 FirewallType type;
579 if (isWhitelist) {
580 type = WHITELIST;
581 rule = ALLOW;
582 } else {
583 type = BLACKLIST;
584 rule = DENY;
585 }
586 int ret;
587 if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
588 ret = replaceUidsInMap(mDozableUidMap, uids, rule, type);
589 } else if (!name.compare(FirewallController::LOCAL_STANDBY)) {
590 ret = replaceUidsInMap(mStandbyUidMap, uids, rule, type);
591 } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
592 ret = replaceUidsInMap(mPowerSaveUidMap, uids, rule, type);
593 } else {
594 ALOGE("unknown chain name: %s", name.c_str());
595 return -EINVAL;
596 }
597 if (ret) {
598 ALOGE("Failed to clean up chain: %s: %s", name.c_str(), strerror(ret));
599 return ret;
600 }
601 return 0;
602}
603
604int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
605 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
606 uint32_t keyUid = UID_MAP_ENABLED;
607 uint8_t mapState = enable ? 1 : 0;
608 int ret;
609 switch (chain) {
610 case DOZABLE:
611 ret = writeToMapEntry(mDozableUidMap, &keyUid, &mapState, BPF_EXIST);
612 break;
613 case STANDBY:
614 ret = writeToMapEntry(mStandbyUidMap, &keyUid, &mapState, BPF_EXIST);
615 break;
616 case POWERSAVE:
617 ret = writeToMapEntry(mPowerSaveUidMap, &keyUid, &mapState, BPF_EXIST);
618 break;
619 default:
620 return -EINVAL;
621 }
622 if (ret) {
623 ret = -errno;
624 ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, strerror(errno));
625 }
626 return ret;
627}
628
Chenbo Feng07d43fe2017-12-21 14:38:51 -0800629bool TrafficController::checkBpfStatsEnable() {
630 return ebpfSupported;
631}
632
Chenbo Fengef297172018-03-26 10:53:33 -0700633std::string getProgramStatus(const char *path) {
634 int ret = access(path, R_OK);
635 if (ret == 0) {
636 return StringPrintf("OK");
637 }
638 if (ret != 0 && errno == ENOENT) {
639 return StringPrintf("program is missing at: %s", path);
640 }
641 return StringPrintf("check Program %s error: %s", path, strerror(errno));
642}
643
644std::string getMapStatus(const unique_fd& map_fd, const char *path) {
645 if (map_fd.get() < 0) {
646 return StringPrintf("map fd lost");
647 }
648 if (access(path, F_OK) != 0) {
649 return StringPrintf("map not pinned to location: %s", path);
650 }
651 return StringPrintf("OK");
652}
653
654void dumpBpfMap(std::string mapName, DumpWriter& dw, const std::string& header) {
655 dw.blankline();
656 dw.println("%s:", mapName.c_str());
657 if(!header.empty()) {
658 dw.println(header.c_str());
659 }
660}
661
662const String16 TrafficController::DUMP_KEYWORD = String16("trafficcontroller");
663
664void TrafficController::dump(DumpWriter& dw, bool verbose) {
665 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
666 dw.incIndent();
667 dw.println("TrafficController");
668
669 dw.incIndent();
670 dw.println("BPF module status: %s", ebpfSupported? "ON" : "OFF");
671
672 if (!ebpfSupported)
673 return;
674
675 dw.blankline();
676 dw.println("mCookieTagMap status: %s",
677 getMapStatus(mCookieTagMap, COOKIE_TAG_MAP_PATH).c_str());
678 dw.println("mUidCounterSetMap status: %s",
679 getMapStatus(mUidCounterSetMap, UID_COUNTERSET_MAP_PATH).c_str());
680 dw.println("mUidStatsMap status: %s", getMapStatus(mUidStatsMap, UID_STATS_MAP_PATH).c_str());
681 dw.println("mTagStatsMap status: %s", getMapStatus(mTagStatsMap, TAG_STATS_MAP_PATH).c_str());
682 dw.println("mIfaceIndexNameMap status: %s",
683 getMapStatus(mIfaceIndexNameMap, IFACE_INDEX_NAME_MAP_PATH).c_str());
684 dw.println("mIfaceStatsMap status: %s",
685 getMapStatus(mIfaceStatsMap, IFACE_STATS_MAP_PATH).c_str());
686 dw.println("mDozableUidMap status: %s",
687 getMapStatus(mDozableUidMap, DOZABLE_UID_MAP_PATH).c_str());
688 dw.println("mStandbyUidMap status: %s",
689 getMapStatus(mStandbyUidMap, STANDBY_UID_MAP_PATH).c_str());
690 dw.println("mPowerSaveUidMap status: %s",
691 getMapStatus(mPowerSaveUidMap, POWERSAVE_UID_MAP_PATH).c_str());
692
693 dw.blankline();
694 dw.println("Cgroup ingress program status: %s",
695 getProgramStatus(BPF_INGRESS_PROG_PATH).c_str());
696 dw.println("Cgroup egress program status: %s", getProgramStatus(BPF_EGRESS_PROG_PATH).c_str());
697 dw.println("xt_bpf ingress program status: %s",
698 getProgramStatus(XT_BPF_INGRESS_PROG_PATH).c_str());
699 dw.println("xt_bpf egress program status: %s",
700 getProgramStatus(XT_BPF_EGRESS_PROG_PATH).c_str());
701
702 if(!verbose) return;
703
704 dw.blankline();
705 dw.println("BPF map content:");
706
707 dw.incIndent();
708
709 // Print CookieTagMap content.
710 dumpBpfMap("mCookieTagMap", dw, "");
711 const uint64_t nonExistentCookie = NONEXIST_COOKIE;
712 UidTag dummyUidTag;
713 auto printCookieTagInfo = [&dw](void *key, void *value) {
714 UidTag uidTagEntry = *(UidTag *) value;
715 uint64_t cookie = *(uint64_t *) key;
716 dw.println("cookie=%" PRIu64 " tag=0x%x uid=%u", cookie, uidTagEntry.tag, uidTagEntry.uid);
717 return 0;
718 };
719 int ret = bpfIterateMapWithValue(nonExistentCookie, dummyUidTag, mCookieTagMap,
720 printCookieTagInfo);
721 if (ret) {
722 dw.println("mCookieTagMap print end with error: %s", strerror(-ret));
723 }
724
725 // Print UidCounterSetMap Content
726 dumpBpfMap("mUidCounterSetMap", dw, "");
727 const uint32_t nonExistentUid = NONEXISTENT_UID;
728 uint32_t dummyUidInfo;
729 auto printUidInfo = [&dw](void *key, void *value) {
730 uint8_t setting = *(uint8_t *) value;
731 uint32_t uid = *(uint32_t *) key;
732 dw.println("%u %u", uid, setting);
733 return 0;
734 };
735 ret = bpfIterateMapWithValue(nonExistentUid, dummyUidInfo, mUidCounterSetMap, printUidInfo);
736 if (ret) {
737 dw.println("mUidCounterSetMap print end with error: %s", strerror(-ret));
738 }
739
740 // Print uidStatsMap content
741 std::string statsHeader = StringPrintf("ifaceIndex ifaceName tag_hex uid_int cnt_set rxBytes"
742 " rxPackets txBytes txPackets");
743 dumpBpfMap("mUidStatsMap", dw, statsHeader);
744 const struct StatsKey nonExistentStatsKey = NONEXISTENT_STATSKEY;
745 struct StatsValue dummyStatsValue;
746 auto printStatsInfo = [&dw, this](void *key, void *value) {
747 StatsValue statsEntry = *(StatsValue *) value;
748 StatsKey keyInfo = *(StatsKey *) key;
749 char ifname[IFNAMSIZ];
750 uint32_t ifIndex = keyInfo.ifaceIndex;
751 if (bpf::findMapEntry(mIfaceIndexNameMap, &ifIndex, &ifname) < 0) {
752 strlcpy(ifname, "unknown", sizeof(ifname));
753 }
754 dw.println("%u %s 0x%x %u %u %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifIndex, ifname,
755 keyInfo.tag, keyInfo.uid, keyInfo.counterSet, statsEntry.rxBytes,
756 statsEntry.rxPackets, statsEntry.txBytes, statsEntry.txPackets);
757 return 0;
758 };
759 ret = bpfIterateMapWithValue(nonExistentStatsKey, dummyStatsValue, mUidStatsMap,
760 printStatsInfo);
761 if (ret) {
762 dw.println("mUidStatsMap print end with error: %s", strerror(-ret));
763 }
764
765 // Print TagStatsMap content.
766 dumpBpfMap("mTagStatsMap", dw, statsHeader);
767 ret = bpfIterateMapWithValue(nonExistentStatsKey, dummyStatsValue, mTagStatsMap,
768 printStatsInfo);
769 if (ret) {
770 dw.println("mTagStatsMap print end with error: %s", strerror(-ret));
771 }
772
773 // Print ifaceIndexToNameMap content.
774 dumpBpfMap("mIfaceIndexNameMap", dw, "");
775 uint32_t nonExistentIface = NONEXISTENT_IFACE_STATS_KEY;
776 char dummyIface[IFNAMSIZ];
777 auto printIfaceNameInfo = [&dw](void *key, void *value) {
778 char *ifname = (char *) value;
779 uint32_t ifaceIndex = *(uint32_t *)key;
780 dw.println("ifaceIndex=%u ifaceName=%s", ifaceIndex, ifname);
781 return 0;
782 };
783 ret = bpfIterateMapWithValue(nonExistentIface, dummyIface, mIfaceIndexNameMap,
784 printIfaceNameInfo);
785 if (ret) {
786 dw.println("mIfaceIndexNameMap print end with error: %s", strerror(-ret));
787 }
788
789 // Print ifaceStatsMap content
790 std::string ifaceStatsHeader = StringPrintf("ifaceIndex ifaceName rxBytes rxPackets txBytes"
791 " txPackets");
792 dumpBpfMap("mIfaceStatsMap:", dw, ifaceStatsHeader);
793 auto printIfaceStatsInfo = [&dw, this] (void *key, void *value) {
794 StatsValue statsEntry = *(StatsValue *) value;
795 uint32_t ifaceIndex = *(uint32_t *) key;
796 char ifname[IFNAMSIZ];
797 if (bpf::findMapEntry(mIfaceIndexNameMap, key, ifname) < 0) {
798 strlcpy(ifname, "unknown", sizeof(ifname));
799 }
800 dw.println("%u %s %" PRIu64 " %" PRIu64 " %" PRIu64 " %" PRIu64, ifaceIndex, ifname,
801 statsEntry.rxBytes, statsEntry.rxPackets, statsEntry.txBytes,
802 statsEntry.txPackets);
803 return 0;
804 };
805 ret = bpfIterateMapWithValue(nonExistentIface, dummyStatsValue, mIfaceStatsMap,
806 printIfaceStatsInfo);
807 if (ret) {
808 dw.println("mIfaceStatsMap print end with error: %s", strerror(-ret));
809 }
810
811 // Print owner match uid maps
812 uint8_t dummyOwnerInfo;
813 dumpBpfMap("mDozableUidMap", dw, "");
814 ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mDozableUidMap, printUidInfo);
815 if (ret) {
816 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
817 }
818
819 dumpBpfMap("mStandbyUidMap", dw, "");
820 ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mStandbyUidMap, printUidInfo);
821 if (ret) {
822 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
823 }
824
825 dumpBpfMap("mPowerSaveUidMap", dw, "");
826 ret = bpfIterateMapWithValue(nonExistentUid, dummyOwnerInfo, mPowerSaveUidMap, printUidInfo);
827 if (ret) {
828 dw.println("mDozableUidMap print end with error: %s", strerror(-ret));
829 }
830
831 dw.decIndent();
832
833 dw.decIndent();
834
835 dw.decIndent();
836
837}
838
Chenbo Fengf2759682017-10-10 17:31:57 -0700839} // namespace net
840} // namespace android