• 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 = 20 * 1000;
49 constexpr uint32_t ENOBUFS_POLL_WAIT_US = 10 * 1000;
50 
51 using android::netdutils::Status;
52 using android::netdutils::statusFromErrno;
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, UidTag> mCookieTagMap;
68 
SetUp()69     void SetUp() {
70         SKIP_IF_BPF_NOT_SUPPORTED;
71 
72         mCookieTagMap.reset(android::bpf::mapRetrieve(COOKIE_TAG_MAP_PATH, 0));
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 UidTag& value,
80                                                 BpfMap<uint64_t, UidTag>& map) {
81             if ((value.uid == TEST_UID) && (value.tag == TEST_TAG)) {
82                 Status res = map.deleteValue(key);
83                 if (isOk(res) || (res.code() == ENOENT)) {
84                     return android::netdutils::status::ok;
85                 }
86                 ALOGE("Failed to delete data(cookie = %" PRIu64 "): %s\n", key,
87                       strerror(res.code()));
88             }
89             // Move forward to next cookie in the map.
90             return android::netdutils::status::ok;
91         };
92         EXPECT_OK(mCookieTagMap.iterateWithValue(deleteTestCookieEntries));
93     }
94 
checkNoGarbageTagsExist()95     Status checkNoGarbageTagsExist() {
96         const auto checkGarbageTags = [](const uint64_t&, const UidTag& value,
97                                          const BpfMap<uint64_t, UidTag>&) {
98             if ((TEST_UID == value.uid) && (TEST_TAG == value.tag)) {
99                 return statusFromErrno(EUCLEAN, "Closed socket is not untagged");
100             }
101             return android::netdutils::status::ok;
102         };
103         return mCookieTagMap.iterateWithValue(checkGarbageTags);
104     }
105 
checkMassiveSocketDestroy(const int totalNumber,bool expectError)106     void checkMassiveSocketDestroy(const 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             EXPECT_LE(0, fds[i]);
122             qtaguid_tagSocket(fds[i], TEST_TAG, TEST_UID);
123         }
124 
125         // TODO: Use a separate thread that have it's own fd table so we can
126         // close socket faster by terminating that threads.
127         for (int i = 0; i < totalNumber; i++) {
128             EXPECT_EQ(0, close(fds[i]));
129         }
130         // wait a bit for netlink listner to handle all the messages.
131         usleep(SOCK_CLOSE_WAIT_US);
132         if (expectError) {
133             // If ENOBUFS triggered, check it only called into the handler once, ie.
134             // that the netlink handler is not spinning.
135             int currentErrorCount = rxErrorCount;
136             EXPECT_LT(0, rxErrorCount);
137             usleep(ENOBUFS_POLL_WAIT_US);
138             EXPECT_EQ(currentErrorCount, rxErrorCount);
139         } else {
140             EXPECT_TRUE(isOk(checkNoGarbageTagsExist()));
141             EXPECT_EQ(0, rxErrorCount);
142         }
143     }
144 };
145 
TEST_F(NetlinkListenerTest,TestAllSocketUntagged)146 TEST_F(NetlinkListenerTest, TestAllSocketUntagged) {
147     SKIP_IF_BPF_NOT_SUPPORTED;
148 
149     checkMassiveSocketDestroy(10, false);
150     checkMassiveSocketDestroy(100, false);
151 }
152 
TEST_F(NetlinkListenerTest,TestSkDestroyError)153 TEST_F(NetlinkListenerTest, TestSkDestroyError) {
154     SKIP_IF_BPF_NOT_SUPPORTED;
155 
156     checkMassiveSocketDestroy(20000, true);
157 }
158