1 //
2 // Copyright (C) 2018 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
17 #include <errno.h>
18 #include <inttypes.h>
19 #include <limits.h>
20 #include <linux/inet_diag.h>
21 #include <linux/netlink.h>
22 #include <linux/sock_diag.h>
23 #include <linux/unistd.h>
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30
31 #include <gtest/gtest.h>
32
33 #include <cutils/qtaguid.h>
34
35 #include <netdutils/Misc.h>
36 #include <netdutils/Syscalls.h>
37 #include "NetlinkListener.h"
38 #include "TrafficController.h"
39 #include "bpf/BpfMap.h"
40 #include "bpf/BpfUtils.h"
41 #include "netdutils/Netlink.h"
42
43 // A test uid that is large enough so normal apps are not likely to take,
44 constexpr uid_t TEST_UID = UID_MAX - 2;
45 // A test tag arbitrarily selected.
46 constexpr uint32_t TEST_TAG = 0xFF0F0F0F;
47
48 constexpr uint32_t SOCK_CLOSE_WAIT_US = 30 * 1000;
49 constexpr uint32_t ENOBUFS_POLL_WAIT_US = 10 * 1000;
50
51 using android::base::Result;
52 using android::base::ResultError;
53
54 // This test set up a SkDestroyListener that is runing parallel with the production
55 // SkDestroyListener. The test will create thousands of sockets and tag them on the
56 // production cookieUidTagMap and close them in a short time. When the number of
57 // sockets get closed exceeds the buffer size, it will start to return ENOBUFF
58 // error. The error will be ignored by the production SkDestroyListener and the
59 // test will clean up the tags in tearDown if there is any remains.
60
61 // TODO: Instead of test the ENOBUFF error, we can test the production
62 // SkDestroyListener to see if it failed to delete a tagged socket when ENOBUFF
63 // triggerred.
64 class NetlinkListenerTest : public testing::Test {
65 protected:
NetlinkListenerTest()66 NetlinkListenerTest() {}
67 BpfMap<uint64_t, UidTagValue> mCookieTagMap;
68
SetUp()69 void SetUp() {
70 mCookieTagMap.reset(android::bpf::mapRetrieveRW(COOKIE_TAG_MAP_PATH));
71 ASSERT_TRUE(mCookieTagMap.isValid());
72 }
73
TearDown()74 void TearDown() {
75 const auto deleteTestCookieEntries = [](const uint64_t& key, const UidTagValue& value,
76 BpfMap<uint64_t, UidTagValue>& map) {
77 if ((value.uid == TEST_UID) && (value.tag == TEST_TAG)) {
78 Result<void> res = map.deleteValue(key);
79 if (res.ok() || (res.error().code() == ENOENT)) {
80 return Result<void>();
81 }
82 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
83 strerror(res.error().code()));
84 }
85 // Move forward to next cookie in the map.
86 return Result<void>();
87 };
88 EXPECT_RESULT_OK(mCookieTagMap.iterateWithValue(deleteTestCookieEntries));
89 }
90
checkNoGarbageTagsExist()91 Result<void> checkNoGarbageTagsExist() {
92 const auto checkGarbageTags = [](const uint64_t&, const UidTagValue& value,
93 const BpfMap<uint64_t, UidTagValue>&) -> Result<void> {
94 if ((TEST_UID == value.uid) && (TEST_TAG == value.tag)) {
95 return ResultError("Closed socket is not untagged", EUCLEAN);
96 }
97 return Result<void>();
98 };
99 return mCookieTagMap.iterateWithValue(checkGarbageTags);
100 }
101
checkMassiveSocketDestroy(int totalNumber,bool expectError)102 bool checkMassiveSocketDestroy(int totalNumber, bool expectError) {
103 std::unique_ptr<android::net::NetlinkListenerInterface> skDestroyListener;
104 auto result = android::net::TrafficController::makeSkDestroyListener();
105 if (!isOk(result)) {
106 ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
107 } else {
108 skDestroyListener = std::move(result.value());
109 }
110 int rxErrorCount = 0;
111 // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
112 const auto rxErrorHandler = [&rxErrorCount](const int, const int) { rxErrorCount++; };
113 skDestroyListener->registerSkErrorHandler(rxErrorHandler);
114 int fds[totalNumber];
115 for (int i = 0; i < totalNumber; i++) {
116 fds[i] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
117 // The likely reason for a failure is running out of available file descriptors.
118 EXPECT_LE(0, fds[i]) << i << " of " << totalNumber;
119 if (fds[i] < 0) {
120 // EXPECT_LE already failed above, so test case is a failure, but we don't
121 // want potentially tens of thousands of extra failures creating and then
122 // closing all these fds cluttering up the logs.
123 totalNumber = i;
124 break;
125 };
126 qtaguid_tagSocket(fds[i], TEST_TAG, TEST_UID);
127 }
128
129 // TODO: Use a separate thread that has it's own fd table so we can
130 // close sockets even faster simply by terminating that thread.
131 for (int i = 0; i < totalNumber; i++) {
132 EXPECT_EQ(0, close(fds[i]));
133 }
134 // wait a bit for netlink listener to handle all the messages.
135 usleep(SOCK_CLOSE_WAIT_US);
136 if (expectError) {
137 // If ENOBUFS triggered, check it only called into the handler once, ie.
138 // that the netlink handler is not spinning.
139 int currentErrorCount = rxErrorCount;
140 // 0 error count is acceptable because the system has chances to close all sockets
141 // normally.
142 EXPECT_LE(0, rxErrorCount);
143 if (!rxErrorCount) return true;
144
145 usleep(ENOBUFS_POLL_WAIT_US);
146 EXPECT_EQ(currentErrorCount, rxErrorCount);
147 } else {
148 EXPECT_RESULT_OK(checkNoGarbageTagsExist());
149 EXPECT_EQ(0, rxErrorCount);
150 }
151 return false;
152 }
153 };
154
TEST_F(NetlinkListenerTest,TestAllSocketUntagged)155 TEST_F(NetlinkListenerTest, TestAllSocketUntagged) {
156 checkMassiveSocketDestroy(10, false);
157 checkMassiveSocketDestroy(100, false);
158 }
159
160 // Disabled because flaky on blueline-userdebug; this test relies on the main thread
161 // winning a race against the NetlinkListener::run() thread. There's no way to ensure
162 // things will be scheduled the same way across all architectures and test environments.
TEST_F(NetlinkListenerTest,DISABLED_TestSkDestroyError)163 TEST_F(NetlinkListenerTest, DISABLED_TestSkDestroyError) {
164 bool needRetry = false;
165 int retryCount = 0;
166 do {
167 needRetry = checkMassiveSocketDestroy(32500, true);
168 if (needRetry) retryCount++;
169 } while (needRetry && retryCount < 3);
170 // Should review test if it can always close all sockets correctly.
171 EXPECT_GT(3, retryCount);
172 }
173