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 = 20 * 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         SKIP_IF_BPF_NOT_SUPPORTED;
71 
72         mCookieTagMap.reset(android::bpf::mapRetrieveRW(COOKIE_TAG_MAP_PATH));
73         ASSERT_TRUE(mCookieTagMap.isValid());
74     }
75 
TearDown()76     void TearDown() {
77         SKIP_IF_BPF_NOT_SUPPORTED;
78 
79         const auto deleteTestCookieEntries = [](const uint64_t& key, const UidTagValue& value,
80                                                 BpfMap<uint64_t, UidTagValue>& map) {
81             if ((value.uid == TEST_UID) && (value.tag == TEST_TAG)) {
82                 Result<void> res = map.deleteValue(key);
83                 if (res.ok() || (res.error().code() == ENOENT)) {
84                     return Result<void>();
85                 }
86                 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
87                       strerror(res.error().code()));
88             }
89             // Move forward to next cookie in the map.
90             return Result<void>();
91         };
92         EXPECT_RESULT_OK(mCookieTagMap.iterateWithValue(deleteTestCookieEntries));
93     }
94 
checkNoGarbageTagsExist()95     Result<void> checkNoGarbageTagsExist() {
96         const auto checkGarbageTags = [](const uint64_t&, const UidTagValue& value,
97                                          const BpfMap<uint64_t, UidTagValue>&) -> Result<void> {
98             if ((TEST_UID == value.uid) && (TEST_TAG == value.tag)) {
99                 return ResultError("Closed socket is not untagged", EUCLEAN);
100             }
101             return Result<void>();
102         };
103         return mCookieTagMap.iterateWithValue(checkGarbageTags);
104     }
105 
checkMassiveSocketDestroy(int totalNumber,bool expectError)106     void checkMassiveSocketDestroy(int totalNumber, bool expectError) {
107         std::unique_ptr<android::net::NetlinkListenerInterface> skDestroyListener;
108         auto result = android::net::TrafficController::makeSkDestroyListener();
109         if (!isOk(result)) {
110             ALOGE("Unable to create SkDestroyListener: %s", toString(result).c_str());
111         } else {
112             skDestroyListener = std::move(result.value());
113         }
114         int rxErrorCount = 0;
115         // Rx handler extracts nfgenmsg looks up and invokes registered dispatch function.
116         const auto rxErrorHandler = [&rxErrorCount](const int, const int) { rxErrorCount++; };
117         skDestroyListener->registerSkErrorHandler(rxErrorHandler);
118         int fds[totalNumber];
119         for (int i = 0; i < totalNumber; i++) {
120             fds[i] = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
121             // The likely reason for a failure is running out of available file descriptors.
122             EXPECT_LE(0, fds[i]) << i << " of " << totalNumber;
123             if (fds[i] < 0) {
124                 // EXPECT_LE already failed above, so test case is a failure, but we don't
125                 // want potentially tens of thousands of extra failures creating and then
126                 // closing all these fds cluttering up the logs.
127                 totalNumber = i;
128                 break;
129             };
130             qtaguid_tagSocket(fds[i], TEST_TAG, TEST_UID);
131         }
132 
133         // TODO: Use a separate thread that has it's own fd table so we can
134         // close sockets even faster simply by terminating that thread.
135         for (int i = 0; i < totalNumber; i++) {
136             EXPECT_EQ(0, close(fds[i]));
137         }
138         // wait a bit for netlink listener to handle all the messages.
139         usleep(SOCK_CLOSE_WAIT_US);
140         if (expectError) {
141             // If ENOBUFS triggered, check it only called into the handler once, ie.
142             // that the netlink handler is not spinning.
143             int currentErrorCount = rxErrorCount;
144             EXPECT_LT(0, rxErrorCount);
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     }
152 };
153 
TEST_F(NetlinkListenerTest,TestAllSocketUntagged)154 TEST_F(NetlinkListenerTest, TestAllSocketUntagged) {
155     SKIP_IF_BPF_NOT_SUPPORTED;
156 
157     checkMassiveSocketDestroy(10, false);
158     checkMassiveSocketDestroy(100, false);
159 }
160 
TEST_F(NetlinkListenerTest,TestSkDestroyError)161 TEST_F(NetlinkListenerTest, TestSkDestroyError) {
162     SKIP_IF_BPF_NOT_SUPPORTED;
163 
164     checkMassiveSocketDestroy(32500, true);
165 }
166