• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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