Don't call into system_server for permissions check
With the recently added permission information in traffic controller,
netd can check if the calling process has permission UPDATE_DEVICE_STATS
without calling into system_server. Update the code path and add some
test cases for it.
Bug: 111560570
Bug: 111560739
Test: netd_unit_test, netd_integration_test
Change-Id: I79eee1321f32154e91466f023f7952db23df8494
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
index 7f32988..541738b 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -124,14 +124,16 @@
mTc.mConfigurationMap.reset(mFakeConfigurationMap.getMap());
mTc.mUidOwnerMap.reset(mFakeUidOwnerMap.getMap());
mTc.mUidPermissionMap.reset(mFakeUidPermissionMap.getMap());
+ mTc.mPrivilegedUser.clear();
}
- int setUpSocketAndTag(int protocol, uint64_t* cookie, uint32_t tag, uid_t uid) {
+ int setUpSocketAndTag(int protocol, uint64_t* cookie, uint32_t tag, uid_t uid,
+ uid_t callingUid) {
int sock = socket(protocol, SOCK_STREAM | SOCK_CLOEXEC, 0);
EXPECT_LE(0, sock);
*cookie = getSocketCookie(sock);
EXPECT_NE(NONEXISTENT_COOKIE, *cookie);
- EXPECT_EQ(0, mTc.tagSocket(sock, tag, uid));
+ EXPECT_EQ(0, mTc.tagSocket(sock, tag, uid, callingUid));
return sock;
}
@@ -257,13 +259,47 @@
}
void expectPrivilegedUserSetEmpty() { EXPECT_TRUE(mTc.mPrivilegedUser.empty()); }
+
+ void addPrivilegedUid(uid_t uid) {
+ std::vector privilegedUid = {uid};
+ mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, privilegedUid);
+ }
+
+ void removePrivilegedUid(uid_t uid) {
+ std::vector privilegedUid = {uid};
+ mTc.setPermissionForUids(INetd::NO_PERMISSIONS, privilegedUid);
+ }
+
+ void expectFakeStatsUnchanged(uint64_t cookie, uint32_t tag, uint32_t uid,
+ StatsKey tagStatsMapKey) {
+ StatusOr<UidTag> cookieMapResult = mFakeCookieTagMap.readValue(cookie);
+ EXPECT_TRUE(isOk(cookieMapResult));
+ EXPECT_EQ(uid, cookieMapResult.value().uid);
+ EXPECT_EQ(tag, cookieMapResult.value().tag);
+ StatusOr<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
+ EXPECT_TRUE(isOk(counterSetResult));
+ EXPECT_EQ(TEST_COUNTERSET, counterSetResult.value());
+ StatusOr<StatsValue> statsMapResult = mFakeTagStatsMap.readValue(tagStatsMapKey);
+ EXPECT_TRUE(isOk(statsMapResult));
+ EXPECT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
+ EXPECT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
+ tagStatsMapKey.tag = 0;
+ statsMapResult = mFakeUidStatsMap.readValue(tagStatsMapKey);
+ EXPECT_TRUE(isOk(statsMapResult));
+ EXPECT_EQ((uint64_t)1, statsMapResult.value().rxPackets);
+ EXPECT_EQ((uint64_t)100, statsMapResult.value().rxBytes);
+ auto appStatsResult = mFakeAppUidStatsMap.readValue(uid);
+ EXPECT_TRUE(isOk(appStatsResult));
+ EXPECT_EQ((uint64_t)1, appStatsResult.value().rxPackets);
+ EXPECT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
+ }
};
TEST_F(TrafficControllerTest, TestTagSocketV4) {
SKIP_IF_BPF_NOT_SUPPORTED;
uint64_t sockCookie;
- int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID);
+ int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie, TEST_UID, TEST_TAG);
ASSERT_EQ(0, mTc.untagSocket(v4socket));
expectNoTag(sockCookie);
@@ -274,9 +310,9 @@
SKIP_IF_BPF_NOT_SUPPORTED;
uint64_t sockCookie;
- int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID);
+ int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie, TEST_UID, TEST_TAG);
- ASSERT_EQ(0, mTc.tagSocket(v4socket, TEST_TAG + 1, TEST_UID + 1));
+ ASSERT_EQ(0, mTc.tagSocket(v4socket, TEST_TAG + 1, TEST_UID + 1, TEST_UID + 1));
expectUidTag(sockCookie, TEST_UID + 1, TEST_TAG + 1);
}
@@ -285,8 +321,8 @@
uint64_t sockCookie1;
uint64_t sockCookie2;
- int v4socket1 = setUpSocketAndTag(AF_INET, &sockCookie1, TEST_TAG, TEST_UID);
- setUpSocketAndTag(AF_INET, &sockCookie2, TEST_TAG, TEST_UID);
+ int v4socket1 = setUpSocketAndTag(AF_INET, &sockCookie1, TEST_TAG, TEST_UID, TEST_UID);
+ setUpSocketAndTag(AF_INET, &sockCookie2, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie1, TEST_UID, TEST_TAG);
expectUidTag(sockCookie2, TEST_UID, TEST_TAG);
ASSERT_EQ(0, mTc.untagSocket(v4socket1));
@@ -299,7 +335,7 @@
SKIP_IF_BPF_NOT_SUPPORTED;
uint64_t sockCookie;
- int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID);
+ int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID, TEST_UID);
expectUidTag(sockCookie, TEST_UID, TEST_TAG);
ASSERT_EQ(0, mTc.untagSocket(v6socket));
expectNoTag(sockCookie);
@@ -310,10 +346,39 @@
SKIP_IF_BPF_NOT_SUPPORTED;
int invalidSocket = -1;
- ASSERT_GT(0, mTc.tagSocket(invalidSocket, TEST_TAG, TEST_UID));
+ ASSERT_GT(0, mTc.tagSocket(invalidSocket, TEST_TAG, TEST_UID, TEST_UID));
expectMapEmpty(mFakeCookieTagMap);
}
+TEST_F(TrafficControllerTest, TestTagSocketWithoutPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_NE(-1, sock);
+ ASSERT_EQ(-EPERM, mTc.tagSocket(sock, TEST_TAG, TEST_UID, TEST_UID2));
+ expectMapEmpty(mFakeCookieTagMap);
+}
+
+TEST_F(TrafficControllerTest, TestTagSocketWithPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ // Grant permission to calling uid.
+ std::vector<uid_t> callingUid = {TEST_UID2};
+ mTc.setPermissionForUids(INetd::PERMISSION_UPDATE_DEVICE_STATS, callingUid);
+
+ // Tag a socket to a different uid other then callingUid.
+ uint64_t sockCookie;
+ int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID, TEST_UID2);
+ expectUidTag(sockCookie, TEST_UID, TEST_TAG);
+ EXPECT_EQ(0, mTc.untagSocket(v6socket));
+ expectNoTag(sockCookie);
+ expectMapEmpty(mFakeCookieTagMap);
+
+ // Clean up the permission
+ mTc.setPermissionForUids(INetd::NO_PERMISSIONS, callingUid);
+ expectPrivilegedUserSetEmpty();
+}
+
TEST_F(TrafficControllerTest, TestUntagInvalidSocket) {
SKIP_IF_BPF_NOT_SUPPORTED;
@@ -327,12 +392,23 @@
TEST_F(TrafficControllerTest, TestSetCounterSet) {
SKIP_IF_BPF_NOT_SUPPORTED;
- ASSERT_EQ(0, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID));
+ uid_t callingUid = TEST_UID2;
+ addPrivilegedUid(callingUid);
+ ASSERT_EQ(0, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, callingUid));
uid_t uid = TEST_UID;
StatusOr<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
ASSERT_TRUE(isOk(counterSetResult));
ASSERT_EQ(TEST_COUNTERSET, counterSetResult.value());
- ASSERT_EQ(0, mTc.setCounterSet(DEFAULT_COUNTERSET, TEST_UID));
+ ASSERT_EQ(0, mTc.setCounterSet(DEFAULT_COUNTERSET, TEST_UID, callingUid));
+ ASSERT_FALSE(isOk(mFakeUidCounterSetMap.readValue(uid)));
+ expectMapEmpty(mFakeUidCounterSetMap);
+}
+
+TEST_F(TrafficControllerTest, TestSetCounterSetWithoutPermission) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ ASSERT_EQ(-EPERM, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID, TEST_UID2));
+ uid_t uid = TEST_UID;
ASSERT_FALSE(isOk(mFakeUidCounterSetMap.readValue(uid)));
expectMapEmpty(mFakeUidCounterSetMap);
}
@@ -340,13 +416,15 @@
TEST_F(TrafficControllerTest, TestSetInvalidCounterSet) {
SKIP_IF_BPF_NOT_SUPPORTED;
- ASSERT_GT(0, mTc.setCounterSet(OVERFLOW_COUNTERSET, TEST_UID));
+ uid_t callingUid = TEST_UID2;
+ addPrivilegedUid(callingUid);
+ ASSERT_GT(0, mTc.setCounterSet(OVERFLOW_COUNTERSET, TEST_UID, callingUid));
uid_t uid = TEST_UID;
ASSERT_FALSE(isOk(mFakeUidCounterSetMap.readValue(uid)));
expectMapEmpty(mFakeUidCounterSetMap);
}
-TEST_F(TrafficControllerTest, TestDeleteTagData) {
+TEST_F(TrafficControllerTest, TestDeleteTagDataWithoutPermission) {
SKIP_IF_BPF_NOT_SUPPORTED;
uint64_t cookie = 1;
@@ -354,7 +432,22 @@
uint32_t tag = TEST_TAG;
StatsKey tagStatsMapKey;
populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
- ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID));
+ ASSERT_EQ(-EPERM, mTc.deleteTagData(0, TEST_UID, TEST_UID2));
+
+ expectFakeStatsUnchanged(cookie, tag, uid, tagStatsMapKey);
+}
+
+TEST_F(TrafficControllerTest, TestDeleteTagData) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ uid_t callingUid = TEST_UID2;
+ addPrivilegedUid(callingUid);
+ uint64_t cookie = 1;
+ uid_t uid = TEST_UID;
+ uint32_t tag = TEST_TAG;
+ StatsKey tagStatsMapKey;
+ populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
+ ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID, callingUid));
ASSERT_FALSE(isOk(mFakeCookieTagMap.readValue(cookie)));
StatusOr<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid);
ASSERT_TRUE(isOk(counterSetResult));
@@ -374,12 +467,14 @@
TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
SKIP_IF_BPF_NOT_SUPPORTED;
+ uid_t callingUid = TEST_UID2;
+ addPrivilegedUid(callingUid);
uint64_t cookie = 1;
uid_t uid = TEST_UID;
uint32_t tag = TEST_TAG;
StatsKey tagStatsMapKey;
populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
- ASSERT_EQ(0, mTc.deleteTagData(0, TEST_UID));
+ ASSERT_EQ(0, mTc.deleteTagData(0, TEST_UID, callingUid));
ASSERT_FALSE(isOk(mFakeCookieTagMap.readValue(cookie)));
ASSERT_FALSE(isOk(mFakeUidCounterSetMap.readValue(uid)));
ASSERT_FALSE(isOk(mFakeTagStatsMap.readValue(tagStatsMapKey)));
@@ -391,6 +486,8 @@
TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
SKIP_IF_BPF_NOT_SUPPORTED;
+ uid_t callingUid = TEST_UID2;
+ addPrivilegedUid(callingUid);
uint64_t cookie1 = 1;
uint64_t cookie2 = 2;
uid_t uid = TEST_UID;
@@ -400,7 +497,7 @@
StatsKey tagStatsMapKey2;
populateFakeStats(cookie1, uid, tag1, &tagStatsMapKey1);
populateFakeStats(cookie2, uid, tag2, &tagStatsMapKey2);
- ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID));
+ ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID, callingUid));
ASSERT_FALSE(isOk(mFakeCookieTagMap.readValue(cookie1)));
StatusOr<UidTag> cookieMapResult = mFakeCookieTagMap.readValue(cookie2);
ASSERT_TRUE(isOk(cookieMapResult));
@@ -419,6 +516,8 @@
TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
SKIP_IF_BPF_NOT_SUPPORTED;
+ uid_t callingUid = TEST_UID2;
+ addPrivilegedUid(callingUid);
uint64_t cookie1 = 1;
uint64_t cookie2 = 2;
uid_t uid1 = TEST_UID;
@@ -431,7 +530,7 @@
// Delete the stats of one of the uid. Check if it is properly collected by
// removedStats.
- ASSERT_EQ(0, mTc.deleteTagData(0, uid2));
+ ASSERT_EQ(0, mTc.deleteTagData(0, uid2, callingUid));
ASSERT_FALSE(isOk(mFakeCookieTagMap.readValue(cookie2)));
StatusOr<uint8_t> counterSetResult = mFakeUidCounterSetMap.readValue(uid1);
ASSERT_TRUE(isOk(counterSetResult));
@@ -452,7 +551,7 @@
ASSERT_EQ((uint64_t)100, appStatsResult.value().rxBytes);
// Delete the stats of the other uid.
- ASSERT_EQ(0, mTc.deleteTagData(0, uid1));
+ ASSERT_EQ(0, mTc.deleteTagData(0, uid1, callingUid));
ASSERT_FALSE(isOk(mFakeUidStatsMap.readValue(tagStatsMapKey1)));
ASSERT_FALSE(isOk(mFakeAppUidStatsMap.readValue(uid1)));
}