blob: 20f6183566d8895f7bd015cc0066bb528a0dbb27 [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
Lorenzo Colitti173da322017-02-05 01:56:40 +090017#include <fcntl.h>
Bernie Innocenti196f1b82019-05-20 16:34:16 +090018#include <gmock/gmock.h>
19#include <gtest/gtest.h>
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +090020#include <sys/file.h>
Lorenzo Colittia701afb2017-02-28 01:47:11 +090021#include <sys/socket.h>
22#include <sys/un.h>
Narayan Kamatha5ace892017-01-06 15:10:02 +000023
Bernie Innocenti196f1b82019-05-20 16:34:16 +090024#include <cinttypes>
25#include <iostream>
26#include <string>
Narayan Kamatha5ace892017-01-06 15:10:02 +000027
Lorenzo Colitti173da322017-02-05 01:56:40 +090028#define LOG_TAG "IptablesRestoreControllerTest"
Lorenzo Colitti173da322017-02-05 01:56:40 +090029#include <android-base/stringprintf.h>
Lorenzo Colitticd283772017-01-31 19:00:49 +090030#include <android-base/strings.h>
Mike Yue7e332f2019-03-13 17:15:48 +080031#include <log/log.h>
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090032#include <netdutils/MockSyscalls.h>
Mike Yue7e332f2019-03-13 17:15:48 +080033#include <netdutils/Stopwatch.h>
Lorenzo Colitti173da322017-02-05 01:56:40 +090034
Narayan Kamatha5ace892017-01-06 15:10:02 +000035#include "IptablesRestoreController.h"
36#include "NetdConstants.h"
Chenbo Feng89c12f12018-03-21 10:29:18 -070037#include "bpf/BpfUtils.h"
Narayan Kamatha5ace892017-01-06 15:10:02 +000038
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +090039#define XT_LOCK_NAME "/system/etc/xtables.lock"
40#define XT_LOCK_ATTEMPTS 10
41#define XT_LOCK_POLL_INTERVAL_MS 100
Lorenzo Colittia701afb2017-02-28 01:47:11 +090042
Lorenzo Colitticd283772017-01-31 19:00:49 +090043using android::base::Join;
Lorenzo Colitti173da322017-02-05 01:56:40 +090044using android::base::StringPrintf;
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090045using android::netdutils::ScopedMockSyscalls;
Mike Yue7e332f2019-03-13 17:15:48 +080046using android::netdutils::Stopwatch;
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090047using testing::Return;
48using testing::StrictMock;
Narayan Kamatha5ace892017-01-06 15:10:02 +000049
Lorenzo Colitti173da322017-02-05 01:56:40 +090050class IptablesRestoreControllerTest : public ::testing::Test {
51public:
52 IptablesRestoreController con;
Lorenzo Colittia701afb2017-02-28 01:47:11 +090053 int mDefaultMaxRetries = con.MAX_RETRIES;
54 int mDefaultPollTimeoutMs = con.POLL_TIMEOUT_MS;
55 int mIptablesLock = -1;
56 std::string mChainName;
57
Nick Desaulniers485a4772019-10-11 09:25:59 -070058 static void SetUpTestSuite() { blockSigpipe(); }
Lorenzo Colitti839d7d62017-04-03 15:37:19 +090059
Lorenzo Colittia701afb2017-02-28 01:47:11 +090060 void SetUp() {
61 ASSERT_EQ(0, createTestChain());
62 }
63
64 void TearDown() {
65 con.MAX_RETRIES = mDefaultMaxRetries;
66 con.POLL_TIMEOUT_MS = mDefaultPollTimeoutMs;
67 deleteTestChain();
68 }
Lorenzo Colitti173da322017-02-05 01:56:40 +090069
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +090070 void Init() {
71 con.Init();
72 }
73
Lorenzo Colitti173da322017-02-05 01:56:40 +090074 pid_t getIpRestorePid(const IptablesRestoreController::IptablesProcessType type) {
75 return con.getIpRestorePid(type);
76 };
77
78 void expectNoIptablesRestoreProcess(pid_t pid) {
79 // We can't readlink /proc/PID/exe, because zombie processes don't have it.
80 // Parse /proc/PID/stat instead.
81 std::string statPath = StringPrintf("/proc/%d/stat", pid);
Bernie Innocenti15bb55c2018-06-03 16:19:51 +090082 int fd = open(statPath.c_str(), O_RDONLY | O_CLOEXEC);
Lorenzo Colitti173da322017-02-05 01:56:40 +090083 if (fd == -1) {
84 // ENOENT means the process is gone (expected).
85 ASSERT_EQ(errno, ENOENT)
86 << "Unexpected error opening " << statPath << ": " << strerror(errno);
87 return;
88 }
89
90 // If the PID exists, it's possible (though very unlikely) that the PID was reused. Check the
91 // binary name as well, to ensure the test isn't flaky.
92 char statBuf[1024];
93 ASSERT_NE(-1, read(fd, statBuf, sizeof(statBuf)))
94 << "Could not read from " << statPath << ": " << strerror(errno);
95 close(fd);
96
97 std::string statString(statBuf);
98 EXPECT_FALSE(statString.find("iptables-restor") || statString.find("ip6tables-resto"))
99 << "Previous iptables-restore pid " << pid << " still alive: " << statString;
100 }
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900101
102 int createTestChain() {
103 mChainName = StringPrintf("netd_unit_test_%u", arc4random_uniform(10000)).c_str();
104
105 // Create a chain to list.
106 std::vector<std::string> createCommands = {
107 "*filter",
108 StringPrintf(":%s -", mChainName.c_str()),
109 StringPrintf("-A %s -j RETURN", mChainName.c_str()),
110 "COMMIT",
111 ""
112 };
113
114 int ret = con.execute(V4V6, Join(createCommands, "\n"), nullptr);
115 if (ret) mChainName = "";
116 return ret;
117 }
118
119 void deleteTestChain() {
120 std::vector<std::string> deleteCommands = {
121 "*filter",
122 StringPrintf(":%s -", mChainName.c_str()), // Flush chain (otherwise we can't delete it).
123 StringPrintf("-X %s", mChainName.c_str()), // Delete it.
124 "COMMIT",
125 ""
126 };
127 con.execute(V4V6, Join(deleteCommands, "\n"), nullptr);
128 mChainName = "";
129 }
130
131 int acquireIptablesLock() {
Bernie Innocenti15bb55c2018-06-03 16:19:51 +0900132 mIptablesLock = open(XT_LOCK_NAME, O_CREAT | O_CLOEXEC, 0600);
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +0900133 if (mIptablesLock == -1) return mIptablesLock;
134 int attempts;
135 for (attempts = 0; attempts < XT_LOCK_ATTEMPTS; attempts++) {
136 if (flock(mIptablesLock, LOCK_EX | LOCK_NB) == 0) {
137 return 0;
138 }
139 usleep(XT_LOCK_POLL_INTERVAL_MS * 1000);
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900140 }
Lorenzo Colitti2bd804a2017-03-10 12:19:08 +0900141 EXPECT_LT(attempts, XT_LOCK_ATTEMPTS) <<
142 "Could not acquire iptables lock after " << XT_LOCK_ATTEMPTS << " attempts " <<
143 XT_LOCK_POLL_INTERVAL_MS << "ms apart";
144 return -1;
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900145 }
146
147 void releaseIptablesLock() {
148 if (mIptablesLock != -1) {
149 close(mIptablesLock);
150 }
151 }
152
153 void setRetryParameters(int maxRetries, int pollTimeoutMs) {
154 con.MAX_RETRIES = maxRetries;
155 con.POLL_TIMEOUT_MS = pollTimeoutMs;
156 }
Narayan Kamatha5ace892017-01-06 15:10:02 +0000157};
158
Lorenzo Colitti173da322017-02-05 01:56:40 +0900159TEST_F(IptablesRestoreControllerTest, TestBasicCommand) {
Lorenzo Colitticd283772017-01-31 19:00:49 +0900160 std::string output;
161
162 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", nullptr));
Lorenzo Colitti173da322017-02-05 01:56:40 +0900163
164 pid_t pid4 = getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS);
165 pid_t pid6 = getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS);
166
Lorenzo Colitticd283772017-01-31 19:00:49 +0900167 EXPECT_EQ(0, con.execute(IptablesTarget::V6, "#Test\n", nullptr));
168 EXPECT_EQ(0, con.execute(IptablesTarget::V4, "#Test\n", nullptr));
169
170 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", &output));
171 EXPECT_EQ("#Test\n#Test\n", output); // One for IPv4 and one for IPv6.
Lorenzo Colitti173da322017-02-05 01:56:40 +0900172
173 // Check the PIDs are the same as they were before. If they're not, the child processes were
174 // restarted, which causes a 30-60ms delay.
175 EXPECT_EQ(pid4, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
176 EXPECT_EQ(pid6, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
Narayan Kamatha5ace892017-01-06 15:10:02 +0000177}
178
Lorenzo Colitti173da322017-02-05 01:56:40 +0900179TEST_F(IptablesRestoreControllerTest, TestRestartOnMalformedCommand) {
Lorenzo Colitticd283772017-01-31 19:00:49 +0900180 std::string buffer;
Lorenzo Colitti173da322017-02-05 01:56:40 +0900181 for (int i = 0; i < 50; i++) {
182 IptablesTarget target = (IptablesTarget) (i % 3);
Lorenzo Colitticd283772017-01-31 19:00:49 +0900183 std::string *output = (i % 2) ? &buffer : nullptr;
184 ASSERT_EQ(-1, con.execute(target, "malformed command\n", output)) <<
Lorenzo Colitti173da322017-02-05 01:56:40 +0900185 "Malformed command did not fail at iteration " << i;
Lorenzo Colitticd283772017-01-31 19:00:49 +0900186 ASSERT_EQ(0, con.execute(target, "#Test\n", output)) <<
Lorenzo Colitti173da322017-02-05 01:56:40 +0900187 "No-op command did not succeed at iteration " << i;
188 }
189}
190
191TEST_F(IptablesRestoreControllerTest, TestRestartOnProcessDeath) {
Lorenzo Colitticd283772017-01-31 19:00:49 +0900192 std::string output;
193
Lorenzo Colitti173da322017-02-05 01:56:40 +0900194 // Run a command to ensure that the processes are running.
Lorenzo Colitticd283772017-01-31 19:00:49 +0900195 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", &output));
Lorenzo Colitti173da322017-02-05 01:56:40 +0900196
197 pid_t pid4 = getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS);
198 pid_t pid6 = getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS);
199
200 ASSERT_EQ(0, kill(pid4, 0)) << "iptables-restore pid " << pid4 << " does not exist";
201 ASSERT_EQ(0, kill(pid6, 0)) << "ip6tables-restore pid " << pid6 << " does not exist";
202 ASSERT_EQ(0, kill(pid4, SIGTERM)) << "Failed to send SIGTERM to iptables-restore pid " << pid4;
203 ASSERT_EQ(0, kill(pid6, SIGTERM)) << "Failed to send SIGTERM to ip6tables-restore pid " << pid6;
204
205 // Wait 100ms for processes to terminate.
206 TEMP_FAILURE_RETRY(usleep(100 * 1000));
207
208 // Ensure that running a new command properly restarts the processes.
Lorenzo Colitticd283772017-01-31 19:00:49 +0900209 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, "#Test\n", nullptr));
Lorenzo Colitti173da322017-02-05 01:56:40 +0900210 EXPECT_NE(pid4, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
211 EXPECT_NE(pid6, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
212
213 // Check there are no zombies.
214 expectNoIptablesRestoreProcess(pid4);
215 expectNoIptablesRestoreProcess(pid6);
Narayan Kamatha5ace892017-01-06 15:10:02 +0000216}
Lorenzo Colitticd283772017-01-31 19:00:49 +0900217
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900218TEST_F(IptablesRestoreControllerTest, TestCommandTimeout) {
219 // Don't wait 10 seconds for this test to fail.
220 setRetryParameters(3, 50);
Lorenzo Colitticd283772017-01-31 19:00:49 +0900221
222 // Expected contents of the chain.
223 std::vector<std::string> expectedLines = {
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900224 StringPrintf("Chain %s (0 references)", mChainName.c_str()),
Lorenzo Colitticd283772017-01-31 19:00:49 +0900225 "target prot opt source destination ",
226 "RETURN all -- 0.0.0.0/0 0.0.0.0/0 ",
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900227 StringPrintf("Chain %s (0 references)", mChainName.c_str()),
Lorenzo Colitticd283772017-01-31 19:00:49 +0900228 "target prot opt source destination ",
229 "RETURN all ::/0 ::/0 ",
230 ""
231 };
232 std::string expected = Join(expectedLines, "\n");
233
Lorenzo Colitticd283772017-01-31 19:00:49 +0900234 std::vector<std::string> listCommands = {
235 "*filter",
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900236 StringPrintf("-n -L %s", mChainName.c_str()), // List chain.
Lorenzo Colitticd283772017-01-31 19:00:49 +0900237 "COMMIT",
238 ""
239 };
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900240 std::string commandString = Join(listCommands, "\n");
Lorenzo Colitticd283772017-01-31 19:00:49 +0900241 std::string output;
Lorenzo Colittia701afb2017-02-28 01:47:11 +0900242
243 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, commandString, &output));
244 EXPECT_EQ(expected, output);
245
246 ASSERT_EQ(0, acquireIptablesLock());
247 EXPECT_EQ(-1, con.execute(IptablesTarget::V4V6, commandString, &output));
248 EXPECT_EQ(-1, con.execute(IptablesTarget::V4V6, commandString, &output));
249 releaseIptablesLock();
250
251 EXPECT_EQ(0, con.execute(IptablesTarget::V4V6, commandString, &output));
Lorenzo Colitticd283772017-01-31 19:00:49 +0900252 EXPECT_EQ(expected, output);
253}
Lorenzo Colittia7357652017-04-25 00:16:36 +0900254
Chenbo Feng89c12f12018-03-21 10:29:18 -0700255
Lorenzo Colittia7357652017-04-25 00:16:36 +0900256TEST_F(IptablesRestoreControllerTest, TestUidRuleBenchmark) {
257 const std::vector<int> ITERATIONS = { 1, 5, 10 };
258
259 const std::string IPTABLES_RESTORE_ADD =
Chenbo Feng89c12f12018-03-21 10:29:18 -0700260 StringPrintf("*filter\n-I %s -m owner --uid-owner 2000000000 -j RETURN\nCOMMIT\n",
261 mChainName.c_str());
Lorenzo Colittia7357652017-04-25 00:16:36 +0900262 const std::string IPTABLES_RESTORE_DEL =
Chenbo Feng89c12f12018-03-21 10:29:18 -0700263 StringPrintf("*filter\n-D %s -m owner --uid-owner 2000000000 -j RETURN\nCOMMIT\n",
264 mChainName.c_str());
Lorenzo Colittia7357652017-04-25 00:16:36 +0900265
266 for (const int iterations : ITERATIONS) {
267 Stopwatch s;
268 for (int i = 0; i < iterations; i++) {
269 EXPECT_EQ(0, con.execute(V4V6, IPTABLES_RESTORE_ADD, nullptr));
270 EXPECT_EQ(0, con.execute(V4V6, IPTABLES_RESTORE_DEL, nullptr));
271 }
Bernie Innocenti196f1b82019-05-20 16:34:16 +0900272 int64_t timeTaken = s.getTimeAndResetUs();
273 std::cerr << " Add/del " << iterations << " UID rules via restore: " << timeTaken
274 << "us (" << (timeTaken / 2 / iterations) << "us per operation)" << std::endl;
Lorenzo Colittia7357652017-04-25 00:16:36 +0900275 }
276}
Lorenzo Colitti2103b6b2017-08-14 11:38:18 +0900277
278TEST_F(IptablesRestoreControllerTest, TestStartup) {
279 // Tests that IptablesRestoreController::Init never sets its processes to null pointers if
280 // fork() succeeds.
281 {
282 // Mock fork(), and check that initializing 100 times never results in a null pointer.
283 constexpr int NUM_ITERATIONS = 100; // Takes 100-150ms on angler.
284 constexpr pid_t FAKE_PID = 2000000001;
285 StrictMock<ScopedMockSyscalls> sys;
286
287 EXPECT_CALL(sys, fork()).Times(NUM_ITERATIONS * 2).WillRepeatedly(Return(FAKE_PID));
288 for (int i = 0; i < NUM_ITERATIONS; i++) {
289 Init();
290 EXPECT_NE(0, getIpRestorePid(IptablesRestoreController::IPTABLES_PROCESS));
291 EXPECT_NE(0, getIpRestorePid(IptablesRestoreController::IP6TABLES_PROCESS));
292 }
293 }
294
295 // The controller is now in an invalid state: the pipes are connected to working iptables
296 // processes, but the PIDs are set to FAKE_PID. Send a malformed command to ensure that the
297 // processes terminate and close the pipes, then send a valid command to have the controller
298 // re-initialize properly now that fork() is no longer mocked.
299 EXPECT_EQ(-1, con.execute(V4V6, "malformed command\n", nullptr));
300 EXPECT_EQ(0, con.execute(V4V6, "#Test\n", nullptr));
301}