blob: 443cefa0a87a95a8fd3267794c83c746692bf84a [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>
39#include <android-base/unique_fd.h>
Chenbo Feng05393d82018-01-09 15:18:43 -080040#include <logwrap/logwrap.h>
Chenbo Fengc10a8a42017-12-15 13:56:33 -080041#include <netdutils/StatusOr.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070042
Chenbo Feng116d0552017-12-04 17:25:19 -080043#include <netdutils/Misc.h>
44#include <netdutils/Syscalls.h>
Chenbo Fengf2759682017-10-10 17:31:57 -070045#include "TrafficController.h"
Chenbo Fengc10a8a42017-12-15 13:56:33 -080046#include "bpf/BpfUtils.h"
Chenbo Feng89c12f12018-03-21 10:29:18 -070047#include "bpf/bpf_shared.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080048
Chenbo Feng89c12f12018-03-21 10:29:18 -070049#include "FirewallController.h"
Chenbo Feng7e974052018-02-28 22:57:21 -080050#include "InterfaceController.h"
Chenbo Feng116d0552017-12-04 17:25:19 -080051#include "NetlinkListener.h"
Chenbo Feng33cc1032017-10-23 15:16:37 -070052#include "qtaguid/qtaguid.h"
Chenbo Fengf2759682017-10-10 17:31:57 -070053
Chenbo Fengc10a8a42017-12-15 13:56:33 -080054using namespace android::bpf;
Chenbo Fengf2759682017-10-10 17:31:57 -070055
56namespace android {
57namespace net {
58
Chenbo Fengc10a8a42017-12-15 13:56:33 -080059using base::StringPrintf;
60using base::unique_fd;
Chenbo Feng116d0552017-12-04 17:25:19 -080061using netdutils::extract;
62using netdutils::Slice;
63using netdutils::sSyscalls;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080064using netdutils::Status;
65using netdutils::statusFromErrno;
66using netdutils::StatusOr;
Chenbo Feng116d0552017-12-04 17:25:19 -080067using netdutils::status::ok;
Chenbo Fengc10a8a42017-12-15 13:56:33 -080068
Chenbo Feng116d0552017-12-04 17:25:19 -080069constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
70constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
71
72StatusOr<std::unique_ptr<NetlinkListenerInterface>> makeSkDestroyListener() {
73 const auto& sys = sSyscalls.get();
74 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
75 const int domain = AF_NETLINK;
76 const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
77 const int protocol = NETLINK_INET_DIAG;
78 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
79
80 sockaddr_nl addr = {
81 .nl_family = AF_NETLINK,
82 .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
83 1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
84 RETURN_IF_NOT_OK(sys.bind(sock, addr));
85
86 const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
87 RETURN_IF_NOT_OK(sys.connect(sock, kernel));
88
89 std::unique_ptr<NetlinkListenerInterface> listener =
90 std::make_unique<NetlinkListener>(std::move(event), std::move(sock));
91
92 return listener;
93}
94
Chenbo Feng89c12f12018-03-21 10:29:18 -070095Status changeOwnerAndMode(const char* path, gid_t group, const char* debugName, bool netdOnly) {
96 int ret = chown(path, AID_ROOT, group);
97 if (ret != 0) return statusFromErrno(errno, StringPrintf("change %s group failed", debugName));
98
99 if (netdOnly) {
100 ret = chmod(path, S_IRWXU);
101 } else {
102 // Allow both netd and system server to obtain map fd from the path.
103 // chmod doesn't grant permission to all processes in that group to
104 // read/write the bpf map. They still need correct sepolicy to
105 // read/write the map.
106 ret = chmod(path, S_IRWXU | S_IRGRP);
107 }
108 if (ret != 0) return statusFromErrno(errno, StringPrintf("change %s mode failed", debugName));
109 return netdutils::status::ok;
110}
111
112TrafficController::TrafficController() {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800113 ebpfSupported = hasBpfSupport();
Chenbo Feng89c12f12018-03-21 10:29:18 -0700114}
115
116Status initialOwnerMap(const unique_fd& map_fd, const std::string mapName) {
117 uint32_t mapSettingKey = UID_MAP_ENABLED;
118 uint32_t defaultMapState = 0;
119 int ret = writeToMapEntry(map_fd, &mapSettingKey, &defaultMapState, BPF_NOEXIST);
120 // If it is already exist, it might be a runtime restart and we just keep
121 // the old state.
122 if (ret && errno != EEXIST) {
123 return statusFromErrno(errno, "Fail to set the initial state of " + mapName);
124 }
125 return netdutils::status::ok;
126}
127
128Status TrafficController::initMaps() {
129 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
130 ASSIGN_OR_RETURN(mCookieTagMap,
131 setUpBPFMap(sizeof(uint64_t), sizeof(struct UidTag), COOKIE_UID_MAP_SIZE,
132 COOKIE_TAG_MAP_PATH, BPF_MAP_TYPE_HASH));
133
134 RETURN_IF_NOT_OK(changeOwnerAndMode(COOKIE_TAG_MAP_PATH, AID_NET_BW_ACCT, "CookieTagMap",
135 false));
136
137 ASSIGN_OR_RETURN(mUidCounterSetMap,
138 setUpBPFMap(sizeof(uint32_t), sizeof(uint32_t), UID_COUNTERSET_MAP_SIZE,
139 UID_COUNTERSET_MAP_PATH, BPF_MAP_TYPE_HASH));
140 RETURN_IF_NOT_OK(changeOwnerAndMode(UID_COUNTERSET_MAP_PATH, AID_NET_BW_ACCT,
141 "UidCounterSetMap", false));
142
143 ASSIGN_OR_RETURN(mUidStatsMap,
144 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
145 UID_STATS_MAP_SIZE, UID_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
146 RETURN_IF_NOT_OK(changeOwnerAndMode(UID_STATS_MAP_PATH, AID_NET_BW_STATS, "UidStatsMap",
147 false));
148
149 ASSIGN_OR_RETURN(mTagStatsMap,
150 setUpBPFMap(sizeof(struct StatsKey), sizeof(struct StatsValue),
151 TAG_STATS_MAP_SIZE, TAG_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
152 RETURN_IF_NOT_OK(changeOwnerAndMode(TAG_STATS_MAP_PATH, AID_NET_BW_STATS, "TagStatsMap",
153 false));
154
155 ASSIGN_OR_RETURN(mIfaceIndexNameMap,
156 setUpBPFMap(sizeof(uint32_t), IFNAMSIZ, IFACE_INDEX_NAME_MAP_SIZE,
157 IFACE_INDEX_NAME_MAP_PATH, BPF_MAP_TYPE_HASH));
158 RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_INDEX_NAME_MAP_PATH, AID_NET_BW_STATS,
159 "IfaceIndexNameMap", false));
160
161 ASSIGN_OR_RETURN(mDozableUidMap,
162 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
163 DOZABLE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
164 RETURN_IF_NOT_OK(changeOwnerAndMode(DOZABLE_UID_MAP_PATH, AID_ROOT, "DozableUidMap", true));
165 RETURN_IF_NOT_OK(initialOwnerMap(mDozableUidMap, "DozableUidMap"));
166
167 ASSIGN_OR_RETURN(mStandbyUidMap,
168 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
169 STANDBY_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
170 RETURN_IF_NOT_OK(changeOwnerAndMode(STANDBY_UID_MAP_PATH, AID_ROOT, "StandbyUidMap", true));
171 RETURN_IF_NOT_OK(initialOwnerMap(mStandbyUidMap, "StandbyUidMap"));
172
173 ASSIGN_OR_RETURN(mPowerSaveUidMap,
174 setUpBPFMap(sizeof(uint32_t), sizeof(uint8_t), UID_OWNER_MAP_SIZE,
175 POWERSAVE_UID_MAP_PATH, BPF_MAP_TYPE_HASH));
176 RETURN_IF_NOT_OK(changeOwnerAndMode(POWERSAVE_UID_MAP_PATH, AID_ROOT, "PowerSaveUidMap", true));
177 RETURN_IF_NOT_OK(initialOwnerMap(mPowerSaveUidMap, "PowerSaveUidMap"));
178
179 ASSIGN_OR_RETURN(mIfaceStatsMap,
180 setUpBPFMap(sizeof(uint32_t), sizeof(struct StatsValue), IFACE_STATS_MAP_SIZE,
181 IFACE_STATS_MAP_PATH, BPF_MAP_TYPE_HASH));
182 RETURN_IF_NOT_OK(changeOwnerAndMode(IFACE_STATS_MAP_PATH, AID_NET_BW_STATS, "IfaceStatsMap",
183 false));
184 return netdutils::status::ok;
185}
186
187Status TrafficController::start() {
188
Chenbo Fengf43bf812017-12-15 18:27:22 -0800189 if (!ebpfSupported) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800190 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700191 }
192
193 /* When netd restart from a crash without total system reboot, the program
194 * is still attached to the cgroup, detach it so the program can be freed
195 * and we can load and attach new program into the target cgroup.
196 *
197 * TODO: Scrape existing socket when run-time restart and clean up the map
198 * if the socket no longer exist
199 */
200
Chenbo Feng89c12f12018-03-21 10:29:18 -0700201 RETURN_IF_NOT_OK(initMaps());
Chenbo Feng7e974052018-02-28 22:57:21 -0800202
203 // Fetch the list of currently-existing interfaces. At this point NetlinkHandler is
204 // already running, so it will call addInterface() when any new interface appears.
205 std::map<std::string, uint32_t> ifacePairs;
206 ASSIGN_OR_RETURN(ifacePairs, InterfaceController::getIfaceList());
207 for (const auto& ifacePair:ifacePairs) {
208 addInterface(ifacePair.first.c_str(), ifacePair.second);
209 }
210
Chenbo Feng5ed17992018-03-13 21:30:49 -0700211
Chenbo Feng116d0552017-12-04 17:25:19 -0800212 auto result = makeSkDestroyListener();
213 if (!isOk(result)) {
214 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
215 } else {
216 mSkDestroyListener = std::move(result.value());
217 }
218 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
219 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
220 inet_diag_msg diagmsg = {};
221 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
222 ALOGE("unrecognized netlink message: %s", toString(msg).c_str());
223 return;
224 }
225 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
226 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
227
228 deleteMapEntry(mCookieTagMap, &sock_cookie);
229 };
230 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
231
232 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
233 // properly.
234 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
235 // Ignore NLMSG_DONE messages
236 inet_diag_msg diagmsg = {};
237 extract(msg, diagmsg);
238 };
239 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
240
Chenbo Feng05393d82018-01-09 15:18:43 -0800241 int* status = nullptr;
242
243 std::vector<const char*> prog_args{
244 "/system/bin/bpfloader",
245 };
Chenbo Feng89c12f12018-03-21 10:29:18 -0700246 int ret = access(BPF_INGRESS_PROG_PATH, R_OK);
Chenbo Feng05393d82018-01-09 15:18:43 -0800247 if (ret != 0 && errno == ENOENT) {
248 prog_args.push_back((char*)"-i");
249 }
250 ret = access(BPF_EGRESS_PROG_PATH, R_OK);
251 if (ret != 0 && errno == ENOENT) {
252 prog_args.push_back((char*)"-e");
253 }
Chenbo Feng5ed17992018-03-13 21:30:49 -0700254 ret = access(XT_BPF_INGRESS_PROG_PATH, R_OK);
255 if (ret != 0 && errno == ENOENT) {
256 prog_args.push_back((char*)"-p");
257 }
258 ret = access(XT_BPF_EGRESS_PROG_PATH, R_OK);
259 if (ret != 0 && errno == ENOENT) {
260 prog_args.push_back((char*)"-m");
261 }
Chenbo Feng05393d82018-01-09 15:18:43 -0800262
263 if (prog_args.size() == 1) {
Chenbo Feng5ed17992018-03-13 21:30:49 -0700264 // all program are loaded already.
Chenbo Feng05393d82018-01-09 15:18:43 -0800265 return netdutils::status::ok;
266 }
267
268 prog_args.push_back(nullptr);
269 ret = android_fork_execvp(prog_args.size(), (char**)prog_args.data(), status, false, true);
270 if (ret) {
271 ret = errno;
272 ALOGE("failed to execute %s: %s", prog_args[0], strerror(errno));
273 return statusFromErrno(ret, "run bpf loader failed");
274 }
275 return netdutils::status::ok;
Chenbo Fengf2759682017-10-10 17:31:57 -0700276}
277
Chenbo Fengf2759682017-10-10 17:31:57 -0700278int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800279 if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
280 if (!ebpfSupported) return 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700281
Chenbo Fengf2759682017-10-10 17:31:57 -0700282 uint64_t sock_cookie = getSocketCookie(sockFd);
283 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
284 UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
285
286 // Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
287 // flag so it will insert a new entry to the map if that value doesn't exist
288 // yet. And update the tag if there is already a tag stored. Since the eBPF
289 // program in kernel only read this map, and is protected by rcu read lock. It
290 // should be fine to cocurrently update the map while eBPF program is running.
291 int res = writeToMapEntry(mCookieTagMap, &sock_cookie, &newKey, BPF_ANY);
292 if (res < 0) {
293 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800294 ALOGE("Failed to tag the socket: %s, fd: %d", strerror(errno), mCookieTagMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700295 }
296
297 return res;
298}
299
300int TrafficController::untagSocket(int sockFd) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800301 if (legacy_untagSocket(sockFd)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700302 if (!ebpfSupported) return 0;
Chenbo Fengf2759682017-10-10 17:31:57 -0700303 uint64_t sock_cookie = getSocketCookie(sockFd);
304
305 if (sock_cookie == INET_DIAG_NOCOOKIE) return -errno;
306 int res = deleteMapEntry(mCookieTagMap, &sock_cookie);
307 if (res) {
308 res = -errno;
309 ALOGE("Failed to untag socket: %s\n", strerror(errno));
310 }
311 return res;
312}
313
314int TrafficController::setCounterSet(int counterSetNum, uid_t uid) {
315 if (counterSetNum < 0 || counterSetNum >= COUNTERSETS_LIMIT) return -EINVAL;
Chenbo Fengf2759682017-10-10 17:31:57 -0700316 int res;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800317 if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
318 if (!ebpfSupported) return 0;
319
320 // The default counter set for all uid is 0, so deleting the current counterset for that uid
321 // will automatically set it to 0.
Chenbo Fengf2759682017-10-10 17:31:57 -0700322 if (counterSetNum == 0) {
323 res = deleteMapEntry(mUidCounterSetMap, &uid);
324 if (res == 0 || (res == -1 && errno == ENOENT)) {
325 return 0;
326 } else {
327 ALOGE("Failed to delete the counterSet: %s\n", strerror(errno));
328 return -errno;
329 }
330 }
331
332 res = writeToMapEntry(mUidCounterSetMap, &uid, &counterSetNum, BPF_ANY);
333 if (res < 0) {
334 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800335 ALOGE("Failed to set the counterSet: %s, fd: %d", strerror(errno), mUidCounterSetMap.get());
Chenbo Fengf2759682017-10-10 17:31:57 -0700336 }
337 return res;
338}
339
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800340// TODO: Add a lock for delete tag Data so when several request for different uid comes in, they do
341// not race with each other.
Chenbo Fengf2759682017-10-10 17:31:57 -0700342int TrafficController::deleteTagData(uint32_t tag, uid_t uid) {
343 int res = 0;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700344
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800345 if (legacy_deleteTagData(tag, uid)) return -errno;
Chenbo Feng33cc1032017-10-23 15:16:37 -0700346 if (!ebpfSupported) return 0;
347
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800348 uint64_t curCookie = NONEXIST_COOKIE;
Chenbo Fengf2759682017-10-10 17:31:57 -0700349 uint64_t nextCookie = 0;
350 UidTag tmp_uidtag;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800351 std::vector<uint64_t> cookieList;
352 // First we go through the cookieTagMap to delete the target uid tag combination. Or delete all
353 // the tags related to the uid if the tag is 0, we start the map iteration with a cookie of
354 // INET_DIAG_NOCOOKIE because it's guaranteed that that will not be in the map.
355 while (getNextMapKey(mCookieTagMap, &curCookie, &nextCookie) != -1) {
356 res = findMapEntry(mCookieTagMap, &nextCookie, &tmp_uidtag);
Chenbo Fengf2759682017-10-10 17:31:57 -0700357 if (res < 0) {
358 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800359 ALOGE("Failed to get tag info(cookie = %" PRIu64 ": %s\n", nextCookie, strerror(errno));
360 // Continue to look for next entry.
361 curCookie = nextCookie;
362 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700363 }
364
365 if (tmp_uidtag.uid == uid && (tmp_uidtag.tag == tag || tag == 0)) {
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800366 res = deleteMapEntry(mCookieTagMap, &nextCookie);
367 if (res < 0 && errno != ENOENT) {
Chenbo Fengf2759682017-10-10 17:31:57 -0700368 res = -errno;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800369 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", nextCookie,
370 strerror(errno));
Chenbo Fengf2759682017-10-10 17:31:57 -0700371 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800372 } else {
373 // Move forward to next cookie in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700374 curCookie = nextCookie;
375 }
376 }
377
378 // 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 -0800379 // combination. Or all tag stats under that uid if the target tag is 0. The initial key is
380 // set to the nonexist_statskey because it will never be in the map, and thus getNextMapKey will
381 // return 0 and set nextKey to the first key in the map.
Chenbo Fengf2759682017-10-10 17:31:57 -0700382 struct StatsKey curKey, nextKey;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800383 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800384 while (getNextMapKey(mTagStatsMap, &curKey, &nextKey) != -1) {
385 if (nextKey.uid == uid && (nextKey.tag == tag || tag == 0)) {
386 res = deleteMapEntry(mTagStatsMap, &nextKey);
387 if (res < 0 && errno != ENOENT) {
388 // Skip the current entry if unexpected error happened.
389 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
390 strerror(errno));
391 curKey = nextKey;
Chenbo Fengf2759682017-10-10 17:31:57 -0700392 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800393 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700394 curKey = nextKey;
395 }
396 }
397
398 // 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 -0800399 // need to delete the stats stored in uidStatsMap and counterSet map.
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800400 if (tag != 0) return 0;
401
402 res = deleteMapEntry(mUidCounterSetMap, &uid);
403 if (res < 0 && errno != ENOENT) {
404 ALOGE("Failed to delete counterSet data(uid=%u, tag=%u): %s\n", uid, tag, strerror(errno));
405 }
406
407 // For the uid stats deleted from the map, move them into a special
408 // removed uid entry. The removed uid is stored in uid 0, tag 0 and
409 // counterSet as COUNTERSETS_LIMIT.
410 StatsKey removedStatsKey = {0, 0, COUNTERSETS_LIMIT, 0};
Chenbo Fengf43bf812017-12-15 18:27:22 -0800411 StatsValue removedStatsTotal = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800412 res = findMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal);
413 if (res < 0 && errno != ENOENT) {
414 ALOGE("Failed to get stats of removed uid: %s", strerror(errno));
415 }
416
Chenbo Fengf43bf812017-12-15 18:27:22 -0800417 curKey = android::bpf::NONEXISTENT_STATSKEY;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800418 while (getNextMapKey(mUidStatsMap, &curKey, &nextKey) != -1) {
419 if (nextKey.uid == uid) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800420 StatsValue old_stats = {};
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800421 res = findMapEntry(mUidStatsMap, &nextKey, &old_stats);
422 if (res < 0) {
423 if (errno != ENOENT) {
424 // if errno is ENOENT Somebody else deleted nextKey. Lookup the next key from
425 // curKey. If we have other error. Skip this key to avoid an infinite loop.
426 curKey = nextKey;
427 }
428 continue;
Chenbo Fengf2759682017-10-10 17:31:57 -0700429 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800430 res = deleteMapEntry(mUidStatsMap, &nextKey);
431 if (res < 0 && errno != ENOENT) {
432 ALOGE("Failed to delete data(uid=%u, tag=%u): %s\n", nextKey.uid, nextKey.tag,
433 strerror(errno));
434 curKey = nextKey;
435 continue;
436 }
Chenbo Fengeac6c472018-02-05 15:06:23 -0800437 removedStatsTotal.rxPackets += old_stats.rxPackets;
438 removedStatsTotal.rxBytes += old_stats.rxBytes;
439 removedStatsTotal.txPackets += old_stats.txPackets;
440 removedStatsTotal.txBytes += old_stats.txBytes;
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800441 } else {
Chenbo Fengf2759682017-10-10 17:31:57 -0700442 curKey = nextKey;
443 }
444 }
Chenbo Fengc10a8a42017-12-15 13:56:33 -0800445
446 res = writeToMapEntry(mUidStatsMap, &removedStatsKey, &removedStatsTotal, BPF_ANY);
447 if (res) {
448 res = -errno;
449 ALOGE("Failed to add deleting stats to removed uid: %s", strerror(errno));
450 }
Chenbo Fengf2759682017-10-10 17:31:57 -0700451 return res;
452}
453
Chenbo Feng7e974052018-02-28 22:57:21 -0800454int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
455 int res = 0;
456 if (!ebpfSupported) return res;
457
458 char ifaceName[IFNAMSIZ];
459 if (ifaceIndex == 0) {
460 ALOGE("Unknow interface %s(%d)", name, ifaceIndex);
461 return -1;
462 }
463
464 strlcpy(ifaceName, name, sizeof(ifaceName));
465 res = writeToMapEntry(mIfaceIndexNameMap, &ifaceIndex, ifaceName, BPF_ANY);
466 if (res) {
467 res = -errno;
468 ALOGE("Failed to add iface %s(%d): %s", name, ifaceIndex, strerror(errno));
469 }
470 return res;
471}
472
Chenbo Feng89c12f12018-03-21 10:29:18 -0700473int TrafficController::updateOwnerMapEntry(const base::unique_fd& map_fd, uid_t uid,
474 FirewallRule rule, FirewallType type) {
475 int res = 0;
476 if (uid == NONEXISTENT_UID) {
477 ALOGE("This uid should never exist in maps: %u", uid);
478 return -EINVAL;
479 }
480
481 if (uid == UID_MAP_ENABLED) {
482 ALOGE("This uid is reserved for map state");
483 return -EINVAL;
484 }
485
486 if ((rule == ALLOW && type == WHITELIST) || (rule == DENY && type == BLACKLIST)) {
487 uint8_t flag = (type == WHITELIST) ? BPF_PASS : BPF_DROP;
488 res = writeToMapEntry(map_fd, &uid, &flag, BPF_ANY);
489 if (res) {
490 res = -errno;
491 ALOGE("Failed to add owner rule(uid: %u): %s", uid, strerror(errno));
492 }
493 } else if ((rule == ALLOW && type == BLACKLIST) || (rule == DENY && type == WHITELIST)) {
494 res = deleteMapEntry(map_fd, &uid);
495 if (res) {
496 res = -errno;
497 ALOGE("Failed to delete owner rule(uid: %u): %s", uid, strerror(errno));
498 }
499 } else {
500 //Cannot happen.
501 return -EINVAL;
502 }
503 return res;
504}
505
506int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
507 FirewallType type) {
508 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
509 if (!ebpfSupported) {
510 ALOGE("bpf is not set up, should use iptables rule");
511 return -ENOSYS;
512 }
513 switch (chain) {
514 case DOZABLE:
515 return updateOwnerMapEntry(mDozableUidMap, uid, rule, type);
516 case STANDBY:
517 return updateOwnerMapEntry(mStandbyUidMap, uid, rule, type);
518 case POWERSAVE:
519 return updateOwnerMapEntry(mPowerSaveUidMap, uid, rule, type);
520 case NONE:
521 default:
522 return -EINVAL;
523 }
524}
525
526int TrafficController::replaceUidsInMap(const base::unique_fd& map_fd,
527 const std::vector<int32_t> &uids,
528 FirewallRule rule, FirewallType type) {
529 std::set<int32_t> uidSet(uids.begin(), uids.end());
530 std::vector<uint32_t> uidsToDelete;
531 auto getUidsToDelete = [&uidsToDelete, &uidSet](void *key, const base::unique_fd&) {
532 uint32_t uid = *(uint32_t *)key;
533 if (uid != UID_MAP_ENABLED && uidSet.find((int32_t)uid) == uidSet.end()) {
534 uidsToDelete.push_back(uid);
535 }
536 return 0;
537 };
538 uint32_t nonExistentKey = NONEXISTENT_UID;
539 uint8_t dummyValue;
540 int ret = bpfIterateMap(nonExistentKey, dummyValue, map_fd, getUidsToDelete);
541
542 if (ret) return ret;
543
544 for(auto uid : uidsToDelete) {
545 if(deleteMapEntry(map_fd, &uid)) {
546 ret = -errno;
547 ALOGE("Delete uid(%u) from owner Map %d failed: %s", uid, map_fd.get(),
548 strerror(errno));
549 return -errno;
550 }
551 }
552
553 for (auto uid : uids) {
554 ret = updateOwnerMapEntry(map_fd, uid, rule, type);
555 if (ret) {
556 ALOGE("Failed to add owner rule(uid: %u, map: %d)", uid, map_fd.get());
557 return ret;
558 }
559 }
560 return 0;
561}
562
563int TrafficController::replaceUidOwnerMap(const std::string& name, bool isWhitelist,
564 const std::vector<int32_t>& uids) {
565 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
566 FirewallRule rule;
567 FirewallType type;
568 if (isWhitelist) {
569 type = WHITELIST;
570 rule = ALLOW;
571 } else {
572 type = BLACKLIST;
573 rule = DENY;
574 }
575 int ret;
576 if (!name.compare(FirewallController::LOCAL_DOZABLE)) {
577 ret = replaceUidsInMap(mDozableUidMap, uids, rule, type);
578 } else if (!name.compare(FirewallController::LOCAL_STANDBY)) {
579 ret = replaceUidsInMap(mStandbyUidMap, uids, rule, type);
580 } else if (!name.compare(FirewallController::LOCAL_POWERSAVE)) {
581 ret = replaceUidsInMap(mPowerSaveUidMap, uids, rule, type);
582 } else {
583 ALOGE("unknown chain name: %s", name.c_str());
584 return -EINVAL;
585 }
586 if (ret) {
587 ALOGE("Failed to clean up chain: %s: %s", name.c_str(), strerror(ret));
588 return ret;
589 }
590 return 0;
591}
592
593int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
594 std::lock_guard<std::mutex> guard(mOwnerMatchMutex);
595 uint32_t keyUid = UID_MAP_ENABLED;
596 uint8_t mapState = enable ? 1 : 0;
597 int ret;
598 switch (chain) {
599 case DOZABLE:
600 ret = writeToMapEntry(mDozableUidMap, &keyUid, &mapState, BPF_EXIST);
601 break;
602 case STANDBY:
603 ret = writeToMapEntry(mStandbyUidMap, &keyUid, &mapState, BPF_EXIST);
604 break;
605 case POWERSAVE:
606 ret = writeToMapEntry(mPowerSaveUidMap, &keyUid, &mapState, BPF_EXIST);
607 break;
608 default:
609 return -EINVAL;
610 }
611 if (ret) {
612 ret = -errno;
613 ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, strerror(errno));
614 }
615 return ret;
616}
617
Chenbo Feng07d43fe2017-12-21 14:38:51 -0800618bool TrafficController::checkBpfStatsEnable() {
619 return ebpfSupported;
620}
621
Chenbo Fengf2759682017-10-10 17:31:57 -0700622} // namespace net
623} // namespace android