summaryrefslogtreecommitdiffstats
path: root/server/TrafficController.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'server/TrafficController.cpp')
-rw-r--r--server/TrafficController.cpp34
1 files changed, 34 insertions, 0 deletions
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index 04eee315c..1f3b557f8 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -72,6 +72,7 @@ using netdutils::status::ok;
constexpr int kSockDiagMsgType = SOCK_DIAG_BY_FAMILY;
constexpr int kSockDiagDoneMsgType = NLMSG_DONE;
+constexpr int PER_UID_STATS_ENTRY_LIMIT = 1024;
static_assert(BPF_PERMISSION_INTERNET == INetd::PERMISSION_INTERNET,
"Mismatch between BPF and AIDL permissions: PERMISSION_INTERNET");
@@ -329,6 +330,7 @@ Status TrafficController::start() {
}
int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t callingUid) {
+ std::lock_guard guard(mOwnerMatchMutex);
if (uid != callingUid && !hasUpdateDeviceStatsPermission(callingUid)) {
return -EPERM;
}
@@ -342,6 +344,38 @@ int TrafficController::tagSocket(int sockFd, uint32_t tag, uid_t uid, uid_t call
if (sock_cookie == NONEXISTENT_COOKIE) return -errno;
UidTag newKey = {.uid = (uint32_t)uid, .tag = tag};
+ uint32_t totalEntryCount = 0;
+ // Now we go through the stats map and count how many entries are associated
+ // with target uid. If the uid entry hit the limit for each uid, we block
+ // the request to prevent the map from overflow. It is safe here to iterate
+ // over the map since when mOwnerMatchMutex is hold, system server cannot toggle
+ // the live stats map and clean it. So nobody can delete entries from the map.
+ const auto countUidStatsEntries = [uid, &totalEntryCount](const StatsKey& key,
+ BpfMap<StatsKey, StatsValue>&) {
+ if (key.uid == uid) {
+ totalEntryCount++;
+ }
+ return netdutils::status::ok;
+ };
+ auto configuration = mConfigurationMap.readValue(CURRENT_STATS_MAP_CONFIGURATION_KEY);
+ if (!isOk(configuration.status())) {
+ ALOGE("Failed to get current configuration: %s, fd: %d",
+ strerror(configuration.status().code()), mConfigurationMap.getMap().get());
+ return -configuration.status().code();
+ }
+ if (configuration.value() == SELECT_MAP_A) {
+ mStatsMapA.iterate(countUidStatsEntries).ignoreError();
+ } else if (configuration.value() == SELECT_MAP_B) {
+ mStatsMapB.iterate(countUidStatsEntries).ignoreError();
+ } else {
+ ALOGE("unknown configuration value: %d", configuration.value());
+ return -EINVAL;
+ }
+ if (totalEntryCount > PER_UID_STATS_ENTRY_LIMIT) {
+ ALOGE("Too many stats entry for this uid: %u, block tag request to prevent map overflow",
+ uid);
+ return -EMFILE;
+ }
// Update the tag information of a socket to the cookieUidMap. Use BPF_ANY
// flag so it will insert a new entry to the map if that value doesn't exist
// yet. And update the tag if there is already a tag stored. Since the eBPF