blob: 8cd698e47fc6709e259a93ca94368906c9cc3a0a [file] [log] [blame]
Wayne Ma4d692332022-01-19 16:04:04 +08001/*
Wayne Maa9716ff2022-01-12 10:37:04 +08002 * Copyright (C) 2022 The Android Open Source Project
Wayne Ma4d692332022-01-19 16:04:04 +08003 *
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
17#define LOG_TAG "TrafficController"
18#include <inttypes.h>
Wayne Ma4d692332022-01-19 16:04:04 +080019#include <linux/if_ether.h>
20#include <linux/in.h>
21#include <linux/inet_diag.h>
22#include <linux/netlink.h>
23#include <linux/sock_diag.h>
24#include <linux/unistd.h>
25#include <net/if.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/socket.h>
29#include <sys/stat.h>
30#include <sys/types.h>
31#include <sys/utsname.h>
32#include <sys/wait.h>
Wayne Maa9716ff2022-01-12 10:37:04 +080033#include <map>
Wayne Ma4d692332022-01-19 16:04:04 +080034#include <mutex>
35#include <unordered_set>
36#include <vector>
37
38#include <android-base/stringprintf.h>
39#include <android-base/strings.h>
40#include <android-base/unique_fd.h>
41#include <netdutils/StatusOr.h>
Wayne Ma4d692332022-01-19 16:04:04 +080042#include <netdutils/Syscalls.h>
Ken Chenf426b2b2022-01-23 15:39:13 +080043#include <netdutils/UidConstants.h>
Wayne Ma4d692332022-01-19 16:04:04 +080044#include <netdutils/Utils.h>
Wayne Maa9716ff2022-01-12 10:37:04 +080045#include <private/android_filesystem_config.h>
46
Wayne Ma4d692332022-01-19 16:04:04 +080047#include "TrafficController.h"
48#include "bpf/BpfMap.h"
Wayne Ma4d692332022-01-19 16:04:04 +080049
50namespace android {
51namespace net {
52
53using base::StringPrintf;
54using base::unique_fd;
55using bpf::BpfMap;
Wayne Ma4d692332022-01-19 16:04:04 +080056using bpf::synchronizeKernelRCU;
Wayne Ma4d692332022-01-19 16:04:04 +080057using netdutils::NetlinkListener;
58using netdutils::NetlinkListenerInterface;
Wayne Ma4d692332022-01-19 16:04:04 +080059using netdutils::Slice;
60using netdutils::sSyscalls;
61using netdutils::Status;
62using netdutils::statusFromErrno;
63using netdutils::StatusOr;
Wayne Ma4d692332022-01-19 16:04:04 +080064
65constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
66constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
Wayne Ma4d692332022-01-19 16:04:04 +080067
68const char* TrafficController::LOCAL_DOZABLE = "fw_dozable";
69const char* TrafficController::LOCAL_STANDBY = "fw_standby";
70const char* TrafficController::LOCAL_POWERSAVE = "fw_powersave";
71const char* TrafficController::LOCAL_RESTRICTED = "fw_restricted";
Robert Horvathd945bf02022-01-27 19:55:16 +010072const char* TrafficController::LOCAL_LOW_POWER_STANDBY = "fw_low_power_standby";
Motomu Utsumid9801492022-06-01 13:57:27 +000073const char* TrafficController::LOCAL_OEM_DENY_1 = "fw_oem_deny_1";
74const char* TrafficController::LOCAL_OEM_DENY_2 = "fw_oem_deny_2";
Motomu Utsumi1d9054b2022-06-06 07:44:05 +000075const char* TrafficController::LOCAL_OEM_DENY_3 = "fw_oem_deny_3";
Wayne Ma4d692332022-01-19 16:04:04 +080076
77static_assert(BPF_PERMISSION_INTERNET == INetd::PERMISSION_INTERNET,
78 "Mismatch between BPF and AIDL permissions: PERMISSION_INTERNET");
79static_assert(BPF_PERMISSION_UPDATE_DEVICE_STATS == INetd::PERMISSION_UPDATE_DEVICE_STATS,
80 "Mismatch between BPF and AIDL permissions: PERMISSION_UPDATE_DEVICE_STATS");
Wayne Ma4d692332022-01-19 16:04:04 +080081
82#define FLAG_MSG_TRANS(result, flag, value) \
83 do { \
84 if ((value) & (flag)) { \
85 (result).append(" " #flag); \
86 (value) &= ~(flag); \
87 } \
88 } while (0)
89
Motomu Utsumi42edc602022-05-12 13:57:42 +000090const std::string uidMatchTypeToString(uint32_t match) {
Wayne Ma4d692332022-01-19 16:04:04 +080091 std::string matchType;
92 FLAG_MSG_TRANS(matchType, HAPPY_BOX_MATCH, match);
93 FLAG_MSG_TRANS(matchType, PENALTY_BOX_MATCH, match);
94 FLAG_MSG_TRANS(matchType, DOZABLE_MATCH, match);
95 FLAG_MSG_TRANS(matchType, STANDBY_MATCH, match);
96 FLAG_MSG_TRANS(matchType, POWERSAVE_MATCH, match);
97 FLAG_MSG_TRANS(matchType, RESTRICTED_MATCH, match);
Robert Horvathd945bf02022-01-27 19:55:16 +010098 FLAG_MSG_TRANS(matchType, LOW_POWER_STANDBY_MATCH, match);
Wayne Ma4d692332022-01-19 16:04:04 +080099 FLAG_MSG_TRANS(matchType, IIF_MATCH, match);
Motomu Utsumib08654c2022-05-11 05:56:26 +0000100 FLAG_MSG_TRANS(matchType, LOCKDOWN_VPN_MATCH, match);
Motomu Utsumid9801492022-06-01 13:57:27 +0000101 FLAG_MSG_TRANS(matchType, OEM_DENY_1_MATCH, match);
102 FLAG_MSG_TRANS(matchType, OEM_DENY_2_MATCH, match);
Motomu Utsumi1d9054b2022-06-06 07:44:05 +0000103 FLAG_MSG_TRANS(matchType, OEM_DENY_3_MATCH, match);
Wayne Ma4d692332022-01-19 16:04:04 +0800104 if (match) {
105 return StringPrintf("Unknown match: %u", match);
106 }
107 return matchType;
108}
109
Wayne Ma4d692332022-01-19 16:04:04 +0800110const std::string UidPermissionTypeToString(int permission) {
111 if (permission == INetd::PERMISSION_NONE) {
112 return "PERMISSION_NONE";
113 }
114 if (permission == INetd::PERMISSION_UNINSTALLED) {
115 // This should never appear in the map, complain loudly if it does.
116 return "PERMISSION_UNINSTALLED error!";
117 }
118 std::string permissionType;
119 FLAG_MSG_TRANS(permissionType, BPF_PERMISSION_INTERNET, permission);
120 FLAG_MSG_TRANS(permissionType, BPF_PERMISSION_UPDATE_DEVICE_STATS, permission);
121 if (permission) {
122 return StringPrintf("Unknown permission: %u", permission);
123 }
124 return permissionType;
125}
126
127StatusOr<std::unique_ptr<NetlinkListenerInterface>> TrafficController::makeSkDestroyListener() {
128 const auto& sys = sSyscalls.get();
129 ASSIGN_OR_RETURN(auto event, sys.eventfd(0, EFD_CLOEXEC));
130 const int domain = AF_NETLINK;
131 const int type = SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
132 const int protocol = NETLINK_INET_DIAG;
133 ASSIGN_OR_RETURN(auto sock, sys.socket(domain, type, protocol));
134
135 // TODO: if too many sockets are closed too quickly, we can overflow the socket buffer, and
136 // some entries in mCookieTagMap will not be freed. In order to fix this we would need to
137 // periodically dump all sockets and remove the tag entries for sockets that have been closed.
138 // For now, set a large-enough buffer that we can close hundreds of sockets without getting
139 // ENOBUFS and leaking mCookieTagMap entries.
140 int rcvbuf = 512 * 1024;
141 auto ret = sys.setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf));
142 if (!ret.ok()) {
143 ALOGW("Failed to set SkDestroyListener buffer size to %d: %s", rcvbuf, ret.msg().c_str());
144 }
145
146 sockaddr_nl addr = {
147 .nl_family = AF_NETLINK,
148 .nl_groups = 1 << (SKNLGRP_INET_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET_UDP_DESTROY - 1) |
149 1 << (SKNLGRP_INET6_TCP_DESTROY - 1) | 1 << (SKNLGRP_INET6_UDP_DESTROY - 1)};
150 RETURN_IF_NOT_OK(sys.bind(sock, addr));
151
152 const sockaddr_nl kernel = {.nl_family = AF_NETLINK};
153 RETURN_IF_NOT_OK(sys.connect(sock, kernel));
154
155 std::unique_ptr<NetlinkListenerInterface> listener =
156 std::make_unique<NetlinkListener>(std::move(event), std::move(sock), "SkDestroyListen");
157
158 return listener;
159}
160
Wayne Ma4d692332022-01-19 16:04:04 +0800161Status TrafficController::initMaps() {
162 std::lock_guard guard(mMutex);
163
164 RETURN_IF_NOT_OK(mCookieTagMap.init(COOKIE_TAG_MAP_PATH));
165 RETURN_IF_NOT_OK(mUidCounterSetMap.init(UID_COUNTERSET_MAP_PATH));
166 RETURN_IF_NOT_OK(mAppUidStatsMap.init(APP_UID_STATS_MAP_PATH));
167 RETURN_IF_NOT_OK(mStatsMapA.init(STATS_MAP_A_PATH));
168 RETURN_IF_NOT_OK(mStatsMapB.init(STATS_MAP_B_PATH));
169 RETURN_IF_NOT_OK(mIfaceIndexNameMap.init(IFACE_INDEX_NAME_MAP_PATH));
170 RETURN_IF_NOT_OK(mIfaceStatsMap.init(IFACE_STATS_MAP_PATH));
171
172 RETURN_IF_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
Wayne Ma4d692332022-01-19 16:04:04 +0800173
174 RETURN_IF_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH));
Wayne Ma4d692332022-01-19 16:04:04 +0800175 RETURN_IF_NOT_OK(mUidPermissionMap.init(UID_PERMISSION_MAP_PATH));
Ken Chen322ffcb2022-05-23 22:27:40 +0800176 ALOGI("%s successfully", __func__);
Wayne Ma4d692332022-01-19 16:04:04 +0800177
178 return netdutils::status::ok;
179}
180
Motomu Utsumi3af8f0e2022-09-02 23:42:13 +0900181Status TrafficController::start(bool startSkDestroyListener) {
Wayne Ma4d692332022-01-19 16:04:04 +0800182 RETURN_IF_NOT_OK(initMaps());
183
Motomu Utsumi3af8f0e2022-09-02 23:42:13 +0900184 if (!startSkDestroyListener) {
185 return netdutils::status::ok;
186 }
187
Wayne Ma4d692332022-01-19 16:04:04 +0800188 auto result = makeSkDestroyListener();
189 if (!isOk(result)) {
190 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
191 } else {
192 mSkDestroyListener = std::move(result.value());
193 }
194 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
195 const auto rxHandler = [this](const nlmsghdr&, const Slice msg) {
196 std::lock_guard guard(mMutex);
197 inet_diag_msg diagmsg = {};
198 if (extract(msg, diagmsg) < sizeof(inet_diag_msg)) {
199 ALOGE("Unrecognized netlink message: %s", toString(msg).c_str());
200 return;
201 }
202 uint64_t sock_cookie = static_cast<uint64_t>(diagmsg.id.idiag_cookie[0]) |
203 (static_cast<uint64_t>(diagmsg.id.idiag_cookie[1]) << 32);
204
205 Status s = mCookieTagMap.deleteValue(sock_cookie);
206 if (!isOk(s) && s.code() != ENOENT) {
207 ALOGE("Failed to delete cookie %" PRIx64 ": %s", sock_cookie, toString(s).c_str());
208 return;
209 }
210 };
211 expectOk(mSkDestroyListener->subscribe(kSockDiagMsgType, rxHandler));
212
213 // In case multiple netlink message comes in as a stream, we need to handle the rxDone message
214 // properly.
215 const auto rxDoneHandler = [](const nlmsghdr&, const Slice msg) {
216 // Ignore NLMSG_DONE messages
217 inet_diag_msg diagmsg = {};
218 extract(msg, diagmsg);
219 };
220 expectOk(mSkDestroyListener->subscribe(kSockDiagDoneMsgType, rxDoneHandler));
221
222 return netdutils::status::ok;
223}
224
Wayne Ma4d692332022-01-19 16:04:04 +0800225Status TrafficController::updateOwnerMapEntry(UidOwnerMatchType match, uid_t uid, FirewallRule rule,
226 FirewallType type) {
227 std::lock_guard guard(mMutex);
228 if ((rule == ALLOW && type == ALLOWLIST) || (rule == DENY && type == DENYLIST)) {
229 RETURN_IF_NOT_OK(addRule(uid, match));
230 } else if ((rule == ALLOW && type == DENYLIST) || (rule == DENY && type == ALLOWLIST)) {
231 RETURN_IF_NOT_OK(removeRule(uid, match));
232 } else {
233 //Cannot happen.
234 return statusFromErrno(EINVAL, "");
235 }
236 return netdutils::status::ok;
237}
238
239Status TrafficController::removeRule(uint32_t uid, UidOwnerMatchType match) {
240 auto oldMatch = mUidOwnerMap.readValue(uid);
241 if (oldMatch.ok()) {
242 UidOwnerValue newMatch = {
243 .iif = (match == IIF_MATCH) ? 0 : oldMatch.value().iif,
Motomu Utsumi42edc602022-05-12 13:57:42 +0000244 .rule = oldMatch.value().rule & ~match,
Wayne Ma4d692332022-01-19 16:04:04 +0800245 };
246 if (newMatch.rule == 0) {
247 RETURN_IF_NOT_OK(mUidOwnerMap.deleteValue(uid));
248 } else {
249 RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
250 }
251 } else {
252 return statusFromErrno(ENOENT, StringPrintf("uid: %u does not exist in map", uid));
253 }
254 return netdutils::status::ok;
255}
256
257Status TrafficController::addRule(uint32_t uid, UidOwnerMatchType match, uint32_t iif) {
Motomu Utsumib08654c2022-05-11 05:56:26 +0000258 if (match != IIF_MATCH && iif != 0) {
Wayne Ma4d692332022-01-19 16:04:04 +0800259 return statusFromErrno(EINVAL, "Non-interface match must have zero interface index");
260 }
261 auto oldMatch = mUidOwnerMap.readValue(uid);
262 if (oldMatch.ok()) {
263 UidOwnerValue newMatch = {
Motomu Utsumib08654c2022-05-11 05:56:26 +0000264 .iif = (match == IIF_MATCH) ? iif : oldMatch.value().iif,
Motomu Utsumi42edc602022-05-12 13:57:42 +0000265 .rule = oldMatch.value().rule | match,
Wayne Ma4d692332022-01-19 16:04:04 +0800266 };
267 RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
268 } else {
269 UidOwnerValue newMatch = {
270 .iif = iif,
Motomu Utsumi42edc602022-05-12 13:57:42 +0000271 .rule = match,
Wayne Ma4d692332022-01-19 16:04:04 +0800272 };
273 RETURN_IF_NOT_OK(mUidOwnerMap.writeValue(uid, newMatch, BPF_ANY));
274 }
275 return netdutils::status::ok;
276}
277
Wayne Maa9716ff2022-01-12 10:37:04 +0800278Status TrafficController::updateUidOwnerMap(const uint32_t uid,
Wayne Ma4d692332022-01-19 16:04:04 +0800279 UidOwnerMatchType matchType, IptOp op) {
280 std::lock_guard guard(mMutex);
Wayne Maa9716ff2022-01-12 10:37:04 +0800281 if (op == IptOpDelete) {
282 RETURN_IF_NOT_OK(removeRule(uid, matchType));
283 } else if (op == IptOpInsert) {
284 RETURN_IF_NOT_OK(addRule(uid, matchType));
285 } else {
286 // Cannot happen.
287 return statusFromErrno(EINVAL, StringPrintf("invalid IptOp: %d, %d", op, matchType));
Wayne Ma4d692332022-01-19 16:04:04 +0800288 }
289 return netdutils::status::ok;
290}
291
292FirewallType TrafficController::getFirewallType(ChildChain chain) {
293 switch (chain) {
294 case DOZABLE:
295 return ALLOWLIST;
296 case STANDBY:
297 return DENYLIST;
298 case POWERSAVE:
299 return ALLOWLIST;
300 case RESTRICTED:
301 return ALLOWLIST;
Robert Horvathd945bf02022-01-27 19:55:16 +0100302 case LOW_POWER_STANDBY:
303 return ALLOWLIST;
Motomu Utsumid9801492022-06-01 13:57:27 +0000304 case OEM_DENY_1:
305 return DENYLIST;
306 case OEM_DENY_2:
307 return DENYLIST;
Motomu Utsumi1d9054b2022-06-06 07:44:05 +0000308 case OEM_DENY_3:
309 return DENYLIST;
Wayne Ma4d692332022-01-19 16:04:04 +0800310 case NONE:
311 default:
312 return DENYLIST;
313 }
314}
315
316int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
317 FirewallType type) {
318 Status res;
319 switch (chain) {
320 case DOZABLE:
321 res = updateOwnerMapEntry(DOZABLE_MATCH, uid, rule, type);
322 break;
323 case STANDBY:
324 res = updateOwnerMapEntry(STANDBY_MATCH, uid, rule, type);
325 break;
326 case POWERSAVE:
327 res = updateOwnerMapEntry(POWERSAVE_MATCH, uid, rule, type);
328 break;
329 case RESTRICTED:
330 res = updateOwnerMapEntry(RESTRICTED_MATCH, uid, rule, type);
331 break;
Robert Horvathd945bf02022-01-27 19:55:16 +0100332 case LOW_POWER_STANDBY:
333 res = updateOwnerMapEntry(LOW_POWER_STANDBY_MATCH, uid, rule, type);
334 break;
Motomu Utsumid9801492022-06-01 13:57:27 +0000335 case OEM_DENY_1:
336 res = updateOwnerMapEntry(OEM_DENY_1_MATCH, uid, rule, type);
337 break;
338 case OEM_DENY_2:
339 res = updateOwnerMapEntry(OEM_DENY_2_MATCH, uid, rule, type);
340 break;
Motomu Utsumi1d9054b2022-06-06 07:44:05 +0000341 case OEM_DENY_3:
342 res = updateOwnerMapEntry(OEM_DENY_3_MATCH, uid, rule, type);
343 break;
Wayne Ma4d692332022-01-19 16:04:04 +0800344 case NONE:
345 default:
346 ALOGW("Unknown child chain: %d", chain);
347 return -EINVAL;
348 }
349 if (!isOk(res)) {
350 ALOGE("change uid(%u) rule of %d failed: %s, rule: %d, type: %d", uid, chain,
351 res.msg().c_str(), rule, type);
352 return -res.code();
353 }
354 return 0;
355}
356
357Status TrafficController::replaceRulesInMap(const UidOwnerMatchType match,
358 const std::vector<int32_t>& uids) {
359 std::lock_guard guard(mMutex);
360 std::set<int32_t> uidSet(uids.begin(), uids.end());
361 std::vector<uint32_t> uidsToDelete;
362 auto getUidsToDelete = [&uidsToDelete, &uidSet](const uint32_t& key,
363 const BpfMap<uint32_t, UidOwnerValue>&) {
364 if (uidSet.find((int32_t) key) == uidSet.end()) {
365 uidsToDelete.push_back(key);
366 }
367 return base::Result<void>();
368 };
369 RETURN_IF_NOT_OK(mUidOwnerMap.iterate(getUidsToDelete));
370
371 for(auto uid : uidsToDelete) {
372 RETURN_IF_NOT_OK(removeRule(uid, match));
373 }
374
375 for (auto uid : uids) {
376 RETURN_IF_NOT_OK(addRule(uid, match));
377 }
378 return netdutils::status::ok;
379}
380
381Status TrafficController::addUidInterfaceRules(const int iif,
382 const std::vector<int32_t>& uidsToAdd) {
Wayne Ma4d692332022-01-19 16:04:04 +0800383 std::lock_guard guard(mMutex);
384
385 for (auto uid : uidsToAdd) {
386 netdutils::Status result = addRule(uid, IIF_MATCH, iif);
387 if (!isOk(result)) {
388 ALOGW("addRule failed(%d): uid=%d iif=%d", result.code(), uid, iif);
389 }
390 }
391 return netdutils::status::ok;
392}
393
394Status TrafficController::removeUidInterfaceRules(const std::vector<int32_t>& uidsToDelete) {
395 std::lock_guard guard(mMutex);
396
397 for (auto uid : uidsToDelete) {
398 netdutils::Status result = removeRule(uid, IIF_MATCH);
399 if (!isOk(result)) {
400 ALOGW("removeRule failed(%d): uid=%d", result.code(), uid);
401 }
402 }
403 return netdutils::status::ok;
404}
405
Motomu Utsumi8b42e6d2022-05-19 06:23:40 +0000406Status TrafficController::updateUidLockdownRule(const uid_t uid, const bool add) {
407 std::lock_guard guard(mMutex);
408
409 netdutils::Status result = add ? addRule(uid, LOCKDOWN_VPN_MATCH)
410 : removeRule(uid, LOCKDOWN_VPN_MATCH);
411 if (!isOk(result)) {
412 ALOGW("%s Lockdown rule failed(%d): uid=%d",
413 (add ? "add": "remove"), result.code(), uid);
414 }
415 return result;
416}
417
Wayne Ma4d692332022-01-19 16:04:04 +0800418int TrafficController::replaceUidOwnerMap(const std::string& name, bool isAllowlist __unused,
419 const std::vector<int32_t>& uids) {
420 // FirewallRule rule = isAllowlist ? ALLOW : DENY;
421 // FirewallType type = isAllowlist ? ALLOWLIST : DENYLIST;
422 Status res;
423 if (!name.compare(LOCAL_DOZABLE)) {
424 res = replaceRulesInMap(DOZABLE_MATCH, uids);
425 } else if (!name.compare(LOCAL_STANDBY)) {
426 res = replaceRulesInMap(STANDBY_MATCH, uids);
427 } else if (!name.compare(LOCAL_POWERSAVE)) {
428 res = replaceRulesInMap(POWERSAVE_MATCH, uids);
429 } else if (!name.compare(LOCAL_RESTRICTED)) {
430 res = replaceRulesInMap(RESTRICTED_MATCH, uids);
Robert Horvathd945bf02022-01-27 19:55:16 +0100431 } else if (!name.compare(LOCAL_LOW_POWER_STANDBY)) {
432 res = replaceRulesInMap(LOW_POWER_STANDBY_MATCH, uids);
Motomu Utsumid9801492022-06-01 13:57:27 +0000433 } else if (!name.compare(LOCAL_OEM_DENY_1)) {
434 res = replaceRulesInMap(OEM_DENY_1_MATCH, uids);
435 } else if (!name.compare(LOCAL_OEM_DENY_2)) {
436 res = replaceRulesInMap(OEM_DENY_2_MATCH, uids);
Motomu Utsumi1d9054b2022-06-06 07:44:05 +0000437 } else if (!name.compare(LOCAL_OEM_DENY_3)) {
438 res = replaceRulesInMap(OEM_DENY_3_MATCH, uids);
Wayne Ma4d692332022-01-19 16:04:04 +0800439 } else {
440 ALOGE("unknown chain name: %s", name.c_str());
441 return -EINVAL;
442 }
443 if (!isOk(res)) {
444 ALOGE("Failed to clean up chain: %s: %s", name.c_str(), res.msg().c_str());
445 return -res.code();
446 }
447 return 0;
448}
449
Motomu Utsumi114cd9c2022-08-01 02:08:35 +0000450int TrafficController::toggleUidOwnerMap(ChildChain chain, bool enable) {
451 std::lock_guard guard(mMutex);
452 uint32_t key = UID_RULES_CONFIGURATION_KEY;
453 auto oldConfigure = mConfigurationMap.readValue(key);
454 if (!oldConfigure.ok()) {
455 ALOGE("Cannot read the old configuration from map: %s",
456 oldConfigure.error().message().c_str());
457 return -oldConfigure.error().code();
458 }
459 uint32_t match;
460 switch (chain) {
461 case DOZABLE:
462 match = DOZABLE_MATCH;
463 break;
464 case STANDBY:
465 match = STANDBY_MATCH;
466 break;
467 case POWERSAVE:
468 match = POWERSAVE_MATCH;
469 break;
470 case RESTRICTED:
471 match = RESTRICTED_MATCH;
472 break;
473 case LOW_POWER_STANDBY:
474 match = LOW_POWER_STANDBY_MATCH;
475 break;
476 case OEM_DENY_1:
477 match = OEM_DENY_1_MATCH;
478 break;
479 case OEM_DENY_2:
480 match = OEM_DENY_2_MATCH;
481 break;
482 case OEM_DENY_3:
483 match = OEM_DENY_3_MATCH;
484 break;
485 default:
486 return -EINVAL;
487 }
488 BpfConfig newConfiguration =
489 enable ? (oldConfigure.value() | match) : (oldConfigure.value() & ~match);
490 Status res = mConfigurationMap.writeValue(key, newConfiguration, BPF_EXIST);
491 if (!isOk(res)) {
492 ALOGE("Failed to toggleUidOwnerMap(%d): %s", chain, res.msg().c_str());
493 }
494 return -res.code();
495}
496
Wayne Ma4d692332022-01-19 16:04:04 +0800497Status TrafficController::swapActiveStatsMap() {
498 std::lock_guard guard(mMutex);
499
500 uint32_t key = CURRENT_STATS_MAP_CONFIGURATION_KEY;
Lorenzo Colitti60cbed32022-03-03 17:49:01 +0900501 auto oldConfigure = mConfigurationMap.readValue(key);
502 if (!oldConfigure.ok()) {
Wayne Ma4d692332022-01-19 16:04:04 +0800503 ALOGE("Cannot read the old configuration from map: %s",
Lorenzo Colitti60cbed32022-03-03 17:49:01 +0900504 oldConfigure.error().message().c_str());
505 return Status(oldConfigure.error().code(), oldConfigure.error().message());
Wayne Ma4d692332022-01-19 16:04:04 +0800506 }
507
508 // Write to the configuration map to inform the kernel eBPF program to switch
509 // from using one map to the other. Use flag BPF_EXIST here since the map should
510 // be already populated in initMaps.
Lorenzo Colitti60cbed32022-03-03 17:49:01 +0900511 uint32_t newConfigure = (oldConfigure.value() == SELECT_MAP_A) ? SELECT_MAP_B : SELECT_MAP_A;
Wayne Ma4d692332022-01-19 16:04:04 +0800512 auto res = mConfigurationMap.writeValue(CURRENT_STATS_MAP_CONFIGURATION_KEY, newConfigure,
513 BPF_EXIST);
514 if (!res.ok()) {
515 ALOGE("Failed to toggle the stats map: %s", strerror(res.error().code()));
516 return res;
517 }
518 // After changing the config, we need to make sure all the current running
519 // eBPF programs are finished and all the CPUs are aware of this config change
520 // before we modify the old map. So we do a special hack here to wait for
521 // the kernel to do a synchronize_rcu(). Once the kernel called
522 // synchronize_rcu(), the config we just updated will be available to all cores
523 // and the next eBPF programs triggered inside the kernel will use the new
524 // map configuration. So once this function returns we can safely modify the
525 // old stats map without concerning about race between the kernel and
526 // userspace.
527 int ret = synchronizeKernelRCU();
528 if (ret) {
529 ALOGE("map swap synchronize_rcu() ended with failure: %s", strerror(-ret));
530 return statusFromErrno(-ret, "map swap synchronize_rcu() failed");
531 }
532 return netdutils::status::ok;
533}
534
535void TrafficController::setPermissionForUids(int permission, const std::vector<uid_t>& uids) {
536 std::lock_guard guard(mMutex);
537 if (permission == INetd::PERMISSION_UNINSTALLED) {
538 for (uid_t uid : uids) {
539 // Clean up all permission information for the related uid if all the
540 // packages related to it are uninstalled.
541 mPrivilegedUser.erase(uid);
542 Status ret = mUidPermissionMap.deleteValue(uid);
543 if (!isOk(ret) && ret.code() != ENOENT) {
544 ALOGE("Failed to clean up the permission for %u: %s", uid, strerror(ret.code()));
545 }
546 }
547 return;
548 }
549
550 bool privileged = (permission & INetd::PERMISSION_UPDATE_DEVICE_STATS);
551
552 for (uid_t uid : uids) {
553 if (privileged) {
554 mPrivilegedUser.insert(uid);
555 } else {
556 mPrivilegedUser.erase(uid);
557 }
558
559 // The map stores all the permissions that the UID has, except if the only permission
560 // the UID has is the INTERNET permission, then the UID should not appear in the map.
561 if (permission != INetd::PERMISSION_INTERNET) {
562 Status ret = mUidPermissionMap.writeValue(uid, permission, BPF_ANY);
563 if (!isOk(ret)) {
564 ALOGE("Failed to set permission: %s of uid(%u) to permission map: %s",
565 UidPermissionTypeToString(permission).c_str(), uid, strerror(ret.code()));
566 }
567 } else {
568 Status ret = mUidPermissionMap.deleteValue(uid);
569 if (!isOk(ret) && ret.code() != ENOENT) {
570 ALOGE("Failed to remove uid %u from permission map: %s", uid, strerror(ret.code()));
571 }
572 }
573 }
574}
575
Wayne Ma4d692332022-01-19 16:04:04 +0800576} // namespace net
577} // namespace android