blob: e34f6447be7c2066f1675b058d19e3b3365a7b8f [file] [log] [blame]
Narayan Kamatha5ace892017-01-06 15:10:02 +00001/*
2 * Copyright 2017 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 <string>
Lorenzo Colitti173da322017-02-05 01:56:40 +090018#include <fcntl.h>
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +090019#include <sys/file.h>
Lorenzo Colittia701afb2017-02-28 01:47:11 +090020#include <sys/socket.h>
21#include <sys/un.h>
Narayan Kamatha5ace892017-01-06 15:10:02 +000022
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090023#include <gmock/gmock.h>
Narayan Kamatha5ace892017-01-06 15:10:02 +000024#include <gtest/gtest.h>
25
Lorenzo Colitti173da322017-02-05 01:56:40 +090026#define LOG_TAG "IptablesRestoreControllerTest"
Logan Chien3f461482018-04-23 14:31:32 +080027#include <log/log.h>
Lorenzo Colitti173da322017-02-05 01:56:40 +090028#include <android-base/stringprintf.h>
Lorenzo Colitticd283772017-01-31 19:00:49 +090029#include <android-base/strings.h>
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090030#include <netdutils/MockSyscalls.h>
Lorenzo Colitti173da322017-02-05 01:56:40 +090031
Narayan Kamatha5ace892017-01-06 15:10:02 +000032#include "IptablesRestoreController.h"
33#include "NetdConstants.h"
Lorenzo Colittia7357652017-04-25 00:16:36 +090034#include "Stopwatch.h"
Chenbo Feng89c12f12018-03-21 10:29:18 -070035#include "bpf/BpfUtils.h"
Narayan Kamatha5ace892017-01-06 15:10:02 +000036
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +090037#define XT_LOCK_NAME "/system/etc/xtables.lock"
38#define XT_LOCK_ATTEMPTS 10
39#define XT_LOCK_POLL_INTERVAL_MS 100
Lorenzo Colittia701afb2017-02-28 01:47:11 +090040
Lorenzo Colitticd283772017-01-31 19:00:49 +090041using android::base::Join;
Lorenzo Colitti173da322017-02-05 01:56:40 +090042using android::base::StringPrintf;
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090043using android::netdutils::ScopedMockSyscalls;
44using testing::Return;
45using testing::StrictMock;
Narayan Kamatha5ace892017-01-06 15:10:02 +000046
Lorenzo Colitti173da322017-02-05 01:56:40 +090047class IptablesRestoreControllerTest : public ::testing::Test {
48public:
49 IptablesRestoreController con;
Lorenzo Colittia701afb2017-02-28 01:47:11 +090050 int mDefaultMaxRetries = con.MAX_RETRIES;
51 int mDefaultPollTimeoutMs = con.POLL_TIMEOUT_MS;
52 int mIptablesLock = -1;
53 std::string mChainName;
54
Lorenzo Colitti839d7d62017-04-03 15:37:19 +090055 static void SetUpTestCase() {
56 blockSigpipe();
57 }
58
Lorenzo Colittia701afb2017-02-28 01:47:11 +090059 void SetUp() {
60 ASSERT_EQ(0, createTestChain());
61 }
62
63 void TearDown() {
64 con.MAX_RETRIES = mDefaultMaxRetries;
65 con.POLL_TIMEOUT_MS = mDefaultPollTimeoutMs;
66 deleteTestChain();
67 }
Lorenzo Colitti173da322017-02-05 01:56:40 +090068
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090069 void Init() {
70 con.Init();
71 }
72
Lorenzo Colitti173da322017-02-05 01:56:40 +090073 pid_t getIpRestorePid(const IptablesRestoreController::IptablesProcessType type) {
74 return con.getIpRestorePid(type);
75 };
76
77 void expectNoIptablesRestoreProcess(pid_t pid) {
78 // We can't readlink /proc/PID/exe, because zombie processes don't have it.
79 // Parse /proc/PID/stat instead.
80 std::string statPath = StringPrintf("/proc/%d/stat", pid);
Bernie Innocenti15bb55c2018-06-03 16:19:51 +090081 int fd = open(statPath.c_str(), O_RDONLY | O_CLOEXEC);
Lorenzo Colitti173da322017-02-05 01:56:40 +090082 if (fd == -1) {
83 // ENOENT means the process is gone (expected).
84 ASSERT_EQ(errno, ENOENT)
85 << "Unexpected error opening " << statPath << ": " << strerror(errno);
86 return;
87 }
88
89 // If the PID exists, it's possible (though very unlikely) that the PID was reused. Check the
90 // binary name as well, to ensure the test isn't flaky.
91 char statBuf[1024];
92 ASSERT_NE(-1, read(fd, statBuf, sizeof(statBuf)))
93 << "Could not read from " << statPath << ": " << strerror(errno);
94 close(fd);
95
96 std::string statString(statBuf);
97 EXPECT_FALSE(statString.find("iptables-restor") || statString.find("ip6tables-resto"))
98 << "Previous iptables-restore pid " << pid << " still alive: " << statString;
99 }
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900100
101 int createTestChain() {
102 mChainName = StringPrintf("netd_unit_test_%u", arc4random_uniform(10000)).c_str();
103
104 // Create a chain to list.
105 std::vector<std::string> createCommands = {
106 "*filter",
107 StringPrintf(":%s -", mChainName.c_str()),
108 StringPrintf("-A %s -j RETURN", mChainName.c_str()),
109 "COMMIT",
110 ""
111 };
112
113 int ret = con.execute(V4V6, Join(createCommands, "\n"), nullptr);
114 if (ret) mChainName = "";
115 return ret;
116 }
117
118 void deleteTestChain() {
119 std::vector<std::string> deleteCommands = {
120 "*filter",
121 StringPrintf(":%s -", mChainName.c_str()), // Flush chain (otherwise we can't delete it).
122 StringPrintf("-X %s", mChainName.c_str()), // Delete it.
123 "COMMIT",
124 ""
125 };
126 con.execute(V4V6, Join(deleteCommands, "\n"), nullptr);
127 mChainName = "";
128 }
129
130 int acquireIptablesLock() {
Bernie Innocenti15bb55c2018-06-03 16:19:51 +0900131 mIptablesLock = open(XT_LOCK_NAME, O_CREAT | O_CLOEXEC, 0600);
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +0900132 if (mIptablesLock == -1) return mIptablesLock;
133 int attempts;
134 for (attempts = 0; attempts < XT_LOCK_ATTEMPTS; attempts++) {
135 if (flock(mIptablesLock, LOCK_EX | LOCK_NB) == 0) {
136 return 0;
137 }
138 usleep(XT_LOCK_POLL_INTERVAL_MS * 1000);
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900139 }
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +0900140 EXPECT_LT(attempts, XT_LOCK_ATTEMPTS) <<
141 "Could not acquire iptables lock after " << XT_LOCK_ATTEMPTS << " attempts " <<
142 XT_LOCK_POLL_INTERVAL_MS << "ms apart";
143 return -1;
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900144 }
145
146 void releaseIptablesLock() {
147 if (mIptablesLock != -1) {
148 close(mIptablesLock);
149 }
150 }
151
152 void setRetryParameters(int maxRetries, int pollTimeoutMs) {
153 con.MAX_RETRIES = maxRetries;
154 con.POLL_TIMEOUT_MS = pollTimeoutMs;
155 }
Narayan Kamatha5ace892017-01-06 15:10:02 +0000156};
157
Lorenzo Colitti173da322017-02-05 01:56:40 +0900158TEST_F(IptablesRestoreControllerTest, TestBasicCommand) {
Lorenzo Colitticd283772017-01-31 19:00:49 +0900159 std::string output;
160
161 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", nullptr));
Lorenzo Colitti173da322017-02-05 01:56:40 +0900162
163 pid_t pid4 = getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS);
164 pid_t pid6 = getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS);
165
Lorenzo Colitticd283772017-01-31 19:00:49 +0900166 EXPECT_EQ(0, con.execute(IptablesTarget::V6, "#Test\n", nullptr));
167 EXPECT_EQ(0, con.execute(IptablesTarget::V4, "#Test\n", nullptr));
168
169 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", &output));
170 EXPECT_EQ("#Test\n#Test\n", output); // One for IPv4 and one for IPv6.
Lorenzo Colitti173da322017-02-05 01:56:40 +0900171
172 // Check the PIDs are the same as they were before. If they're not, the child processes were
173 // restarted, which causes a 30-60ms delay.
174 EXPECT_EQ(pid4, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
175 EXPECT_EQ(pid6, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
Narayan Kamatha5ace892017-01-06 15:10:02 +0000176}
177
Lorenzo Colitti173da322017-02-05 01:56:40 +0900178TEST_F(IptablesRestoreControllerTest, TestRestartOnMalformedCommand) {
Lorenzo Colitticd283772017-01-31 19:00:49 +0900179 std::string buffer;
Lorenzo Colitti173da322017-02-05 01:56:40 +0900180 for (int i = 0; i < 50; i++) {
181 IptablesTarget target = (IptablesTarget) (i % 3);
Lorenzo Colitticd283772017-01-31 19:00:49 +0900182 std::string *output = (i % 2) ? &buffer : nullptr;
183 ASSERT_EQ(-1, con.execute(target, "malformed command\n", output)) <<
Lorenzo Colitti173da322017-02-05 01:56:40 +0900184 "Malformed command did not fail at iteration " << i;
Lorenzo Colitticd283772017-01-31 19:00:49 +0900185 ASSERT_EQ(0, con.execute(target, "#Test\n", output)) <<
Lorenzo Colitti173da322017-02-05 01:56:40 +0900186 "No-op command did not succeed at iteration " << i;
187 }
188}
189
190TEST_F(IptablesRestoreControllerTest, TestRestartOnProcessDeath) {
Lorenzo Colitticd283772017-01-31 19:00:49 +0900191 std::string output;
192
Lorenzo Colitti173da322017-02-05 01:56:40 +0900193 // Run a command to ensure that the processes are running.
Lorenzo Colitticd283772017-01-31 19:00:49 +0900194 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", &output));
Lorenzo Colitti173da322017-02-05 01:56:40 +0900195
196 pid_t pid4 = getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS);
197 pid_t pid6 = getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS);
198
199 ASSERT_EQ(0, kill(pid4, 0)) << "iptables-restore pid " << pid4 << " does not exist";
200 ASSERT_EQ(0, kill(pid6, 0)) << "ip6tables-restore pid " << pid6 << " does not exist";
201 ASSERT_EQ(0, kill(pid4, SIGTERM)) << "Failed to send SIGTERM to iptables-restore pid " << pid4;
202 ASSERT_EQ(0, kill(pid6, SIGTERM)) << "Failed to send SIGTERM to ip6tables-restore pid " << pid6;
203
204 // Wait 100ms for processes to terminate.
205 TEMP_FAILURE_RETRY(usleep(100 * 1000));
206
207 // Ensure that running a new command properly restarts the processes.
Lorenzo Colitticd283772017-01-31 19:00:49 +0900208 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", nullptr));
Lorenzo Colitti173da322017-02-05 01:56:40 +0900209 EXPECT_NE(pid4, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
210 EXPECT_NE(pid6, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
211
212 // Check there are no zombies.
213 expectNoIptablesRestoreProcess(pid4);
214 expectNoIptablesRestoreProcess(pid6);
Narayan Kamatha5ace892017-01-06 15:10:02 +0000215}
Lorenzo Colitticd283772017-01-31 19:00:49 +0900216
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900217TEST_F(IptablesRestoreControllerTest, TestCommandTimeout) {
218 // Don't wait 10 seconds for this test to fail.
219 setRetryParameters(3, 50);
Lorenzo Colitticd283772017-01-31 19:00:49 +0900220
221 // Expected contents of the chain.
222 std::vector<std::string> expectedLines = {
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900223 StringPrintf("Chain %s (0 references)", mChainName.c_str()),
Lorenzo Colitticd283772017-01-31 19:00:49 +0900224 "target prot opt source destination ",
225 "RETURN all -- 0.0.0.0/0 0.0.0.0/0 ",
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900226 StringPrintf("Chain %s (0 references)", mChainName.c_str()),
Lorenzo Colitticd283772017-01-31 19:00:49 +0900227 "target prot opt source destination ",
228 "RETURN all ::/0 ::/0 ",
229 ""
230 };
231 std::string expected = Join(expectedLines, "\n");
232
Lorenzo Colitticd283772017-01-31 19:00:49 +0900233 std::vector<std::string> listCommands = {
234 "*filter",
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900235 StringPrintf("-n -L %s", mChainName.c_str()), // List chain.
Lorenzo Colitticd283772017-01-31 19:00:49 +0900236 "COMMIT",
237 ""
238 };
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900239 std::string commandString = Join(listCommands, "\n");
Lorenzo Colitticd283772017-01-31 19:00:49 +0900240 std::string output;
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900241
242 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, commandString, &output));
243 EXPECT_EQ(expected, output);
244
245 ASSERT_EQ(0, acquireIptablesLock());
246 EXPECT_EQ(-1, con.execute(IptablesTarget::V4V6, commandString, &output));
247 EXPECT_EQ(-1, con.execute(IptablesTarget::V4V6, commandString, &output));
248 releaseIptablesLock();
249
250 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, commandString, &output));
Lorenzo Colitticd283772017-01-31 19:00:49 +0900251 EXPECT_EQ(expected, output);
252}
Lorenzo Colittia7357652017-04-25 00:16:36 +0900253
Chenbo Feng89c12f12018-03-21 10:29:18 -0700254
Lorenzo Colittia7357652017-04-25 00:16:36 +0900255TEST_F(IptablesRestoreControllerTest, TestUidRuleBenchmark) {
256 const std::vector<int> ITERATIONS = { 1, 5, 10 };
257
258 const std::string IPTABLES_RESTORE_ADD =
Chenbo Feng89c12f12018-03-21 10:29:18 -0700259 StringPrintf("*filter\n-I %s -m owner --uid-owner 2000000000 -j RETURN\nCOMMIT\n",
260 mChainName.c_str());
Lorenzo Colittia7357652017-04-25 00:16:36 +0900261 const std::string IPTABLES_RESTORE_DEL =
Chenbo Feng89c12f12018-03-21 10:29:18 -0700262 StringPrintf("*filter\n-D %s -m owner --uid-owner 2000000000 -j RETURN\nCOMMIT\n",
263 mChainName.c_str());
Lorenzo Colittia7357652017-04-25 00:16:36 +0900264
265 for (const int iterations : ITERATIONS) {
266 Stopwatch s;
267 for (int i = 0; i < iterations; i++) {
268 EXPECT_EQ(0, con.execute(V4V6, IPTABLES_RESTORE_ADD, nullptr));
269 EXPECT_EQ(0, con.execute(V4V6, IPTABLES_RESTORE_DEL, nullptr));
270 }
271 float timeTaken = s.getTimeAndReset();
272 fprintf(stderr, " Add/del %d UID rules via restore: %.1fms (%.2fms per operation)\n",
273 iterations, timeTaken, timeTaken / 2 / iterations);
Lorenzo Colittia7357652017-04-25 00:16:36 +0900274 }
275}
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +0900276
277TEST_F(IptablesRestoreControllerTest, TestStartup) {
278 // Tests that IptablesRestoreController::Init never sets its processes to null pointers if
279 // fork() succeeds.
280 {
281 // Mock fork(), and check that initializing 100 times never results in a null pointer.
282 constexpr int NUM_ITERATIONS = 100; // Takes 100-150ms on angler.
283 constexpr pid_t FAKE_PID = 2000000001;
284 StrictMock<ScopedMockSyscalls> sys;
285
286 EXPECT_CALL(sys, fork()).Times(NUM_ITERATIONS * 2).WillRepeatedly(Return(FAKE_PID));
287 for (int i = 0; i < NUM_ITERATIONS; i++) {
288 Init();
289 EXPECT_NE(0, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
290 EXPECT_NE(0, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
291 }
292 }
293
294 // The controller is now in an invalid state: the pipes are connected to working iptables
295 // processes, but the PIDs are set to FAKE_PID. Send a malformed command to ensure that the
296 // processes terminate and close the pipes, then send a valid command to have the controller
297 // re-initialize properly now that fork() is no longer mocked.
298 EXPECT_EQ(-1, con.execute(V4V6, "malformed command\n", nullptr));
299 EXPECT_EQ(0, con.execute(V4V6, "#Test\n", nullptr));
300}