blob: 3db5265f85cade12b86504cce528148ec07a87de [file] [log] [blame]
Tyler Wearb37f5512021-10-01 13:22:00 -07001/*
2 * Copyright (C) 2022 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
Tyler Wear4e7aced2022-04-19 17:50:04 -070017#include <aidl/android/net/connectivity/aidl/ConnectivityNative.h>
18#include <android/binder_manager.h>
19#include <android/binder_process.h>
Tyler Wearb37f5512021-10-01 13:22:00 -070020#include <android-modules-utils/sdk_level.h>
21#include <cutils/misc.h> // FIRST_APPLICATION_UID
22#include <gtest/gtest.h>
23#include <netinet/in.h>
Tyler Wearb37f5512021-10-01 13:22:00 -070024
Tyler Wear4e7aced2022-04-19 17:50:04 -070025#include "bpf/BpfUtils.h"
Tyler Wearb37f5512021-10-01 13:22:00 -070026
27using aidl::android::net::connectivity::aidl::IConnectivityNative;
28
29class ConnectivityNativeBinderTest : public ::testing::Test {
30 public:
31 std::vector<int32_t> mActualBlockedPorts;
32
33 ConnectivityNativeBinderTest() {
34 AIBinder* binder = AServiceManager_getService("connectivity_native");
35 ndk::SpAIBinder sBinder = ndk::SpAIBinder(binder);
36 mService = aidl::android::net::connectivity::aidl::IConnectivityNative::fromBinder(sBinder);
37 }
38
39 void SetUp() override {
40 // Skip test case if not on T.
41 if (!android::modules::sdklevel::IsAtLeastT()) GTEST_SKIP() <<
42 "Should be at least T device.";
43
Tyler Wear4e7aced2022-04-19 17:50:04 -070044 // Skip test case if not on 5.4 kernel which is required by bpf prog.
45 if (!android::bpf::isAtLeastKernelVersion(5, 4, 0)) GTEST_SKIP() <<
46 "Kernel should be at least 5.4.";
47
Tyler Wearb37f5512021-10-01 13:22:00 -070048 ASSERT_NE(nullptr, mService.get());
49
50 // If there are already ports being blocked on device unblockAllPortsForBind() store
51 // the currently blocked ports and add them back at the end of the test. Do this for
52 // every test case so additional test cases do not forget to add ports back.
53 ndk::ScopedAStatus status = mService->getPortsBlockedForBind(&mActualBlockedPorts);
54 EXPECT_TRUE(status.isOk()) << status.getDescription ();
55
56 }
57
58 void TearDown() override {
59 ndk::ScopedAStatus status;
60 if (mActualBlockedPorts.size() > 0) {
61 for (int i : mActualBlockedPorts) {
62 mService->blockPortForBind(i);
63 EXPECT_TRUE(status.isOk()) << status.getDescription ();
64 }
65 }
66 }
67
68 protected:
69 std::shared_ptr<IConnectivityNative> mService;
70
71 void runSocketTest (sa_family_t family, const int type, bool blockPort) {
72 ndk::ScopedAStatus status;
73 in_port_t port = 0;
74 int sock, sock2;
75 // Open two sockets with SO_REUSEADDR and expect they can both bind to port.
76 sock = openSocket(&port, family, type, false /* expectBindFail */);
77 sock2 = openSocket(&port, family, type, false /* expectBindFail */);
78
79 int blockedPort = 0;
80 if (blockPort) {
81 blockedPort = ntohs(port);
82 status = mService->blockPortForBind(blockedPort);
83 EXPECT_TRUE(status.isOk()) << status.getDescription ();
84 }
85
86 int sock3 = openSocket(&port, family, type, blockPort /* expectBindFail */);
87
88 if (blockPort) {
89 EXPECT_EQ(-1, sock3);
90 status = mService->unblockPortForBind(blockedPort);
91 EXPECT_TRUE(status.isOk()) << status.getDescription ();
92 } else {
93 EXPECT_NE(-1, sock3);
94 }
95
96 close(sock);
97 close(sock2);
98 close(sock3);
99 }
100
101 /*
102 * Open the socket and update the port.
103 */
104 int openSocket(in_port_t* port, sa_family_t family, const int type, bool expectBindFail) {
105 int ret = 0;
106 int enable = 1;
107 const int sock = socket(family, type, 0);
108 ret = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
109 EXPECT_EQ(0, ret);
110
111 if (family == AF_INET) {
112 struct sockaddr_in addr4 = { .sin_family = family, .sin_port = htons(*port) };
113 ret = bind(sock, (struct sockaddr*) &addr4, sizeof(addr4));
114 } else {
115 struct sockaddr_in6 addr6 = { .sin6_family = family, .sin6_port = htons(*port) };
116 ret = bind(sock, (struct sockaddr*) &addr6, sizeof(addr6));
117 }
118
119 if (expectBindFail) {
120 EXPECT_NE(0, ret);
121 // If port is blocked, return here since the port is not needed
122 // for subsequent sockets.
123 close(sock);
124 return -1;
125 }
126 EXPECT_EQ(0, ret) << "bind unexpectedly failed, errno: " << errno;
127
128 if (family == AF_INET) {
129 struct sockaddr_in sin;
130 socklen_t len = sizeof(sin);
131 EXPECT_NE(-1, getsockname(sock, (struct sockaddr *)&sin, &len));
132 EXPECT_NE(0, ntohs(sin.sin_port));
133 if (*port != 0) EXPECT_EQ(*port, ntohs(sin.sin_port));
134 *port = ntohs(sin.sin_port);
135 } else {
136 struct sockaddr_in6 sin;
137 socklen_t len = sizeof(sin);
138 EXPECT_NE(-1, getsockname(sock, (struct sockaddr *)&sin, &len));
139 EXPECT_NE(0, ntohs(sin.sin6_port));
140 if (*port != 0) EXPECT_EQ(*port, ntohs(sin.sin6_port));
141 *port = ntohs(sin.sin6_port);
142 }
143 return sock;
144 }
145};
146
147TEST_F(ConnectivityNativeBinderTest, PortUnblockedV4Udp) {
148 runSocketTest(AF_INET, SOCK_DGRAM, false);
149}
150
151TEST_F(ConnectivityNativeBinderTest, PortUnblockedV4Tcp) {
152 runSocketTest(AF_INET, SOCK_STREAM, false);
153}
154
155TEST_F(ConnectivityNativeBinderTest, PortUnblockedV6Udp) {
156 runSocketTest(AF_INET6, SOCK_DGRAM, false);
157}
158
159TEST_F(ConnectivityNativeBinderTest, PortUnblockedV6Tcp) {
160 runSocketTest(AF_INET6, SOCK_STREAM, false);
161}
162
163TEST_F(ConnectivityNativeBinderTest, BlockPort4Udp) {
164 runSocketTest(AF_INET, SOCK_DGRAM, true);
165}
166
167TEST_F(ConnectivityNativeBinderTest, BlockPort4Tcp) {
168 runSocketTest(AF_INET, SOCK_STREAM, true);
169}
170
171TEST_F(ConnectivityNativeBinderTest, BlockPort6Udp) {
172 runSocketTest(AF_INET6, SOCK_DGRAM, true);
173}
174
175TEST_F(ConnectivityNativeBinderTest, BlockPort6Tcp) {
176 runSocketTest(AF_INET6, SOCK_STREAM, true);
177}
178
179TEST_F(ConnectivityNativeBinderTest, BlockPortTwice) {
180 ndk::ScopedAStatus status = mService->blockPortForBind(5555);
181 EXPECT_TRUE(status.isOk()) << status.getDescription ();
182 status = mService->blockPortForBind(5555);
183 EXPECT_TRUE(status.isOk()) << status.getDescription ();
184 status = mService->unblockPortForBind(5555);
185 EXPECT_TRUE(status.isOk()) << status.getDescription ();
186}
187
188TEST_F(ConnectivityNativeBinderTest, GetBlockedPorts) {
189 ndk::ScopedAStatus status;
190 std::vector<int> blockedPorts{1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
191 for (int i : blockedPorts) {
192 status = mService->blockPortForBind(i);
193 EXPECT_TRUE(status.isOk()) << status.getDescription ();
194 }
195 std::vector<int32_t> actualBlockedPorts;
196 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
197 EXPECT_TRUE(status.isOk()) << status.getDescription ();
198 EXPECT_FALSE(actualBlockedPorts.empty());
199 EXPECT_EQ(blockedPorts, actualBlockedPorts);
200
201 // Remove the ports we added.
202 status = mService->unblockAllPortsForBind();
203 EXPECT_TRUE(status.isOk()) << status.getDescription ();
204 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
205 EXPECT_TRUE(status.isOk()) << status.getDescription ();
206 EXPECT_TRUE(actualBlockedPorts.empty());
207}
208
209TEST_F(ConnectivityNativeBinderTest, UnblockAllPorts) {
210 ndk::ScopedAStatus status;
211 std::vector<int> blockedPorts{1, 100, 1220, 1333, 2700, 5555, 5600, 65000};
212
213 if (mActualBlockedPorts.size() > 0) {
214 status = mService->unblockAllPortsForBind();
215 }
216
217 for (int i : blockedPorts) {
218 status = mService->blockPortForBind(i);
219 EXPECT_TRUE(status.isOk()) << status.getDescription ();
220 }
221
222 std::vector<int32_t> actualBlockedPorts;
223 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
224 EXPECT_TRUE(status.isOk()) << status.getDescription ();
225 EXPECT_FALSE(actualBlockedPorts.empty());
226
227 status = mService->unblockAllPortsForBind();
228 EXPECT_TRUE(status.isOk()) << status.getDescription ();
229 status = mService->getPortsBlockedForBind(&actualBlockedPorts);
230 EXPECT_TRUE(status.isOk()) << status.getDescription ();
231 EXPECT_TRUE(actualBlockedPorts.empty());
232 // If mActualBlockedPorts is not empty, ports will be added back in teardown.
233}
234
235TEST_F(ConnectivityNativeBinderTest, BlockNegativePort) {
Steven Moreland5d0843b2022-06-22 20:27:15 +0000236 int retry = 0;
237 ndk::ScopedAStatus status;
238 do {
239 status = mService->blockPortForBind(-1);
240 // TODO: find out why transaction failed is being thrown on the first attempt.
241 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
Tyler Wearb37f5512021-10-01 13:22:00 -0700242 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
243}
244
245TEST_F(ConnectivityNativeBinderTest, UnblockNegativePort) {
Steven Moreland5d0843b2022-06-22 20:27:15 +0000246 int retry = 0;
247 ndk::ScopedAStatus status;
248 do {
249 status = mService->unblockPortForBind(-1);
250 // TODO: find out why transaction failed is being thrown on the first attempt.
251 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
Tyler Wearb37f5512021-10-01 13:22:00 -0700252 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
253}
254
255TEST_F(ConnectivityNativeBinderTest, BlockMaxPort) {
Steven Moreland5d0843b2022-06-22 20:27:15 +0000256 int retry = 0;
257 ndk::ScopedAStatus status;
258 do {
259 status = mService->blockPortForBind(65536);
260 // TODO: find out why transaction failed is being thrown on the first attempt.
261 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
Tyler Wearb37f5512021-10-01 13:22:00 -0700262 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
263}
264
265TEST_F(ConnectivityNativeBinderTest, UnblockMaxPort) {
Steven Moreland5d0843b2022-06-22 20:27:15 +0000266 int retry = 0;
267 ndk::ScopedAStatus status;
268 do {
269 status = mService->unblockPortForBind(65536);
270 // TODO: find out why transaction failed is being thrown on the first attempt.
271 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
Tyler Wearb37f5512021-10-01 13:22:00 -0700272 EXPECT_EQ(EX_ILLEGAL_ARGUMENT, status.getExceptionCode());
273}
274
275TEST_F(ConnectivityNativeBinderTest, CheckPermission) {
Steven Moreland5d0843b2022-06-22 20:27:15 +0000276 int retry = 0;
Tyler Wearb37f5512021-10-01 13:22:00 -0700277 int curUid = getuid();
278 EXPECT_EQ(0, seteuid(FIRST_APPLICATION_UID + 2000)) << "seteuid failed: " << strerror(errno);
Steven Moreland5d0843b2022-06-22 20:27:15 +0000279 ndk::ScopedAStatus status;
280 do {
281 status = mService->blockPortForBind(5555);
282 // TODO: find out why transaction failed is being thrown on the first attempt.
283 } while (status.getExceptionCode() == EX_TRANSACTION_FAILED && retry++ < 5);
Tyler Wearb37f5512021-10-01 13:22:00 -0700284 EXPECT_EQ(EX_SECURITY, status.getExceptionCode());
285 EXPECT_EQ(0, seteuid(curUid)) << "seteuid failed: " << strerror(errno);
286}