blob: bedb0a4f598ec36357535a7f09787cc11bddf432 [file] [log] [blame]
Narayan Kamatha5ace892017-01-06 15:10:02 +00001/*
2 * Copyright (C) 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 "IptablesRestoreController.h"
18
19#include <poll.h>
20#include <signal.h>
21#include <sys/wait.h>
22#include <unistd.h>
23
24#include <android-base/logging.h>
25#include <android-base/file.h>
26
27#include "Controllers.h"
28
29constexpr char IPTABLES_RESTORE_PATH[] = "/system/bin/iptables-restore";
30constexpr char IP6TABLES_RESTORE_PATH[] = "/system/bin/ip6tables-restore";
31
32constexpr char PING[] = "#PING\n";
33
34constexpr size_t PING_SIZE = sizeof(PING) - 1;
35
36// TODO: This mirrors &gCtls.iptablesRestoreCtrl in production and is duplicated
37// here to aid testing. It allows us to unit-test IptablesRestoreController without
38// needing to construct a fully fledged Controllers object.
39/* static */ IptablesRestoreController* sInstance = nullptr;
40
41class IptablesProcess {
42public:
43 IptablesProcess(pid_t pid, int stdIn, int stdOut, int stdErr) :
44 pid(pid),
45 stdIn(stdIn),
46 processTerminated(false) {
47
48 pollFds[STDOUT_IDX] = { .fd = stdOut, .events = POLLIN };
49 pollFds[STDERR_IDX] = { .fd = stdErr, .events = POLLIN };
50 }
51
52 ~IptablesProcess() {
53 close(stdIn);
54 close(pollFds[STDOUT_IDX].fd);
55 close(pollFds[STDERR_IDX].fd);
56 }
57
58 const pid_t pid;
59 const int stdIn;
60
61 struct pollfd pollFds[2];
62 std::string errBuf;
63
64 bool processTerminated;
65
66 static constexpr size_t STDOUT_IDX = 0;
67 static constexpr size_t STDERR_IDX = 1;
68};
69
70IptablesRestoreController::IptablesRestoreController() :
71 mIpRestore(nullptr),
72 mIp6Restore(nullptr) {
73}
74
75IptablesRestoreController::~IptablesRestoreController() {
76}
77
78/* static */
79IptablesProcess* IptablesRestoreController::forkAndExec(const IptablesProcessType type) {
80 const char* const cmd = (type == IPTABLES_PROCESS) ?
81 IPTABLES_RESTORE_PATH : IP6TABLES_RESTORE_PATH;
82
83 // Create the pipes we'll use for communication with the child
84 // process. One each for the child's in, out and err files.
85 int stdin_pipe[2];
86 int stdout_pipe[2];
87 int stderr_pipe[2];
88
89 if (pipe2(stdin_pipe, 0) == -1 ||
90 pipe2(stdout_pipe, 0) == -1 ||
91 pipe2(stderr_pipe, 0) == -1) {
92
93 PLOG(ERROR) << "pipe2() failed";
94 return nullptr;
95 }
96
97 pid_t child_pid = fork();
98 if (child_pid == 0) {
99 // The child process. Reads from stdin, writes to stderr and stdout.
100
101 // stdin_pipe[1] : The write end of the stdin pipe.
102 // stdout_pipe[0] : The read end of the stdout pipe.
103 // stderr_pipe[0] : The read end of the stderr pipe.
104 if (close(stdin_pipe[1]) == -1 ||
105 close(stdout_pipe[0]) == -1 ||
106 close(stderr_pipe[0]) == -1) {
107
108 PLOG(WARNING) << "close() failed";
109 }
110
111 // stdin_pipe[0] : The read end of the stdin pipe.
112 // stdout_pipe[1] : The write end of the stdout pipe.
113 // stderr_pipe[1] : The write end of the stderr pipe.
114 if (dup2(stdin_pipe[0], 0) == -1 ||
115 dup2(stdout_pipe[1], 1) == -1 ||
116 dup2(stderr_pipe[1], 2) == -1) {
117 PLOG(ERROR) << "dup2() failed";
118 abort();
119 }
120
121 if (execl(cmd,
122 cmd,
123 "--noflush", // Don't flush the whole table.
124 "-w", // Wait instead of failing if the lock is held.
125 "-v", // Verbose mode, to make sure our ping is echoed
126 // back to us.
127 nullptr) == -1) {
128 PLOG(ERROR) << "execl(" << cmd << ", ...) failed";
129 abort();
130 }
131
132 // This statement is unreachable. We abort() upon error, and execl
133 // if everything goes well.
134 return nullptr;
135 }
136
137 // The parent process. Writes to stdout and stderr and reads from stdin.
138 if (child_pid == -1) {
139 PLOG(ERROR) << "fork() failed";
140 return nullptr;
141 }
142
143 // stdin_pipe[0] : The read end of the stdin pipe.
144 // stdout_pipe[1] : The write end of the stdout pipe.
145 // stderr_pipe[1] : The write end of the stderr pipe.
146 if (close(stdin_pipe[0]) == -1 ||
147 close(stdout_pipe[1]) == -1 ||
148 close(stderr_pipe[1]) == -1) {
149 PLOG(WARNING) << "close() failed";
150 }
151
152 return new IptablesProcess(child_pid, stdin_pipe[1], stdout_pipe[0], stderr_pipe[0]);
153}
154
155void sigchldHandler(int /* signal_number */, siginfo_t *siginfo, void* /* context */) {
156 // Save and restore errno to prevent threads from spuriously seeing
157 // incorrect errors due to errors from this signal handler.
158 int saved_errno = errno;
159
160 // Notify the IptablesRestoreController so that it can try to recover. Log
161 // relevant information if it's one of the process we care about. netd
162 // forks other processes as well, so there's no need to spam the logs
163 // every time one of those dies.
164 const pid_t child_pid = siginfo->si_pid;
165 const IptablesRestoreController::IptablesProcessType process =
166 sInstance->notifyChildTermination(child_pid);
167
168 if (process != IptablesRestoreController::INVALID_PROCESS) {
169 // This should return immediately because we've been informed that
170 // |child_pid| just exited.
171 pid_t wait_result = waitpid(child_pid, nullptr, WNOHANG);
172 if (wait_result < 0) {
173 PLOG(WARNING) << "waitpid for child " << child_pid << " unexpectedly failed";
174 }
175
176 if (siginfo->si_code == CLD_EXITED) {
177 LOG(WARNING) << "iptables[6]-restore process exited (pid=" << child_pid
178 << ") exit_status=" << siginfo->si_status
179 << " type=" << process;
180 } else {
181 LOG(WARNING) << "iptables[6]-restore process was signalled (pid=" << child_pid
182 << ") signal=" << siginfo->si_status
183 << " type=" << process;
184 }
185 }
186
187 errno = saved_errno;
188}
189
190/* static */
191void IptablesRestoreController::installSignalHandler(IptablesRestoreController *singleton) {
192 if (singleton == nullptr) {
193 LOG(ERROR) << "installSignalHandler: singleton == nullptr";
194 }
195
196 sInstance = singleton;
197
198 struct sigaction sa = {};
199 sa.sa_flags = SA_SIGINFO;
200 sa.sa_sigaction = sigchldHandler;
201 const int err = sigaction(SIGCHLD, &sa, nullptr);
202 if (err < 0) {
203 PLOG(ERROR) << "Unable to set SIGCHLD handler.";
204 }
205}
206
207IptablesRestoreController::IptablesProcessType
208IptablesRestoreController::notifyChildTermination(pid_t pid) {
209 // We minimize the amount of work that we do from the signal handler, given
210 // that this can be called at any arbitrary point of time.
211
212 if (mIpRestore != nullptr && mIpRestore->pid == pid) {
213 mIpRestore->processTerminated = true;
214 return IPTABLES_PROCESS;
215 }
216
217 if (mIp6Restore != nullptr && mIp6Restore->pid == pid) {
218 mIp6Restore->processTerminated = true;
219 return IP6TABLES_PROCESS;
220 }
221
222 return INVALID_PROCESS;
223}
224
225// TODO: Return -errno on failure instead of -1.
226// TODO: Maybe we should keep a rotating buffer of the last N commands
227// so that they can be dumped on dumpsys.
228int IptablesRestoreController::sendCommand(const IptablesProcessType type,
229 const std::string& command) {
230 std::unique_ptr<IptablesProcess> *process =
231 (type == IPTABLES_PROCESS) ? &mIpRestore : &mIp6Restore;
232
233 // We might need to fork a new process if we haven't forked one yet, or
234 // if the forked process terminated.
235 //
236 // NOTE: For a given command, this is the last point at which we try to
237 // recover from a child death. If the child dies at some later point during
238 // the execution of this method, we will receive an EPIPE and return an
239 // error. The command will then need to be retried at a higher level.
240 if (process->get() == nullptr || (*process)->processTerminated) {
241 // Fork a new iptables[6]-restore process.
242 IptablesProcess *newProcess = IptablesRestoreController::forkAndExec(type);
243 if (newProcess == nullptr) {
244 LOG(ERROR) << "Unable to fork ip[6]tables-restore, type: " << type;
245 return -1;
246 }
247
248 process->reset(newProcess);
249 }
250
251 // TODO: Investigate why this horrible hackery is necessary. We're currently
252 // sending iptables[6]-restore malformed commands. They appear to contain garbage
253 // after the last "\n". They obviously "work" because we fork a new process
254 // for every command so it doesn't matter whether the process chokes after
255 // the last successful COMMIT.
256 const std::string fixedCommand = fixCommandString(command);
257
258 if (!android::base::WriteFully((*process)->stdIn,
259 fixedCommand.data(),
260 fixedCommand.length())) {
261 PLOG(ERROR) << "Unable to send command";
262 }
263
264 if (!android::base::WriteFully((*process)->stdIn, PING, PING_SIZE)) {
265 PLOG(ERROR) << "Unable to send ping command : " << type;
266 return -1;
267 }
268
269 if (!drainAndWaitForAck(*process)) {
270 LOG(ERROR) << "Timed out waiting for response from iptables process: " << (*process)->pid;
271 return -1;
272 }
273
274 return 0;
275}
276
277/* static */
278std::string IptablesRestoreController::fixCommandString(const std::string& command) {
279 std::string commandDup = command;
280 commandDup.erase(commandDup.find_last_of("\n") + 1);
281 return commandDup;
282}
283
284void IptablesRestoreController::maybeLogStderr(const std::unique_ptr<IptablesProcess> &process,
285 const char* buf, ssize_t numBytes) {
286 ssize_t lastNewline = 0;
287 for (ssize_t i = 0; i < numBytes; ++i) {
288 if (buf[i] == '\n') {
289 process->errBuf.append(buf + lastNewline, (i - lastNewline));
290 LOG(ERROR) << "Iptables : " << process->errBuf;
291 process->errBuf.clear();
292 lastNewline = i;
293 }
294 }
295
296 // Append all remaining characters to the buffer so that they're logged the
297 // next time 'round.
298 if (lastNewline < (static_cast<ssize_t>(numBytes) - 1)) {
299 process->errBuf.append(buf + lastNewline,
300 static_cast<ssize_t>(numBytes) - 1 - lastNewline);
301 }
302}
303
304// The maximum number of times we poll(2) for a response on our set of polled
305// fds. Chosen so that the overall timeout is 1s.
306static constexpr int MAX_RETRIES = 10;
307
308// The timeout (in millis) for each call to poll. The maximum wait is
309// |POLL_TIMEOUT_MS * MAX_RETRIES|. Chosen so that the overall timeout is 1s.
310static constexpr int POLL_TIMEOUT_MS = 100;
311
312/* static */
313bool IptablesRestoreController::drainAndWaitForAck(
314 const std::unique_ptr<IptablesProcess> &process) {
315 bool receivedAck = false;
316 int timeout = 0;
317 std::string out;
318 while (!receivedAck && (timeout++ < MAX_RETRIES)) {
319 int numEvents = TEMP_FAILURE_RETRY(
320 poll(process->pollFds, ARRAY_SIZE(process->pollFds), POLL_TIMEOUT_MS));
321 if (numEvents == -1) {
322 PLOG(ERROR) << "Poll failed.";
323 return false;
324 }
325
326 // We've timed out, which means something has gone wrong - we know that stdout should have
327 // become available to read with the ACK message.
328 if (numEvents == 0) {
329 continue;
330 }
331
332 char buffer[256];
333 for (size_t i = 0; i < ARRAY_SIZE(process->pollFds); ++i) {
334 const struct pollfd &pollfd = process->pollFds[i];
335 if (pollfd.revents & POLLIN) {
336 // TODO: We read a maximum of 256 bytes for each call to poll.
337 // We should change this so that we can read as much input as we
338 // can from the descriptor without blocking.
339 const ssize_t size = TEMP_FAILURE_RETRY(read(pollfd.fd, buffer, sizeof(buffer)));
340
341 // This should never happen. Poll just told us that we have
342 // something available.
343 if (size == -1) {
344 PLOG(ERROR) << "Unable to read from descriptor";
345 return false;
346 }
347
348 if (i == IptablesProcess::STDOUT_IDX) {
349 // i == STDOUT_IDX : look for the ping response. We use
350 // a string buffer here because it's possible (but unlikely)
351 // that only a subsection of the PING response is available
352 // on the pipe when poll returns for the first time. We use
353 // find instead of operator== to be robust in the case of
354 // additional stdout logging.
355 out.append(buffer, size);
356 if (out.find(PING) != std::string::npos) {
357 receivedAck = true;
358 }
359 } else {
360 // i == STDERR_IDX implies stderr, log.
361 IptablesRestoreController::maybeLogStderr(process, buffer, size);
362 }
363 }
364 }
365 }
366
367 return receivedAck;
368}
369
370int IptablesRestoreController::execute(const IptablesTarget target, const std::string& command) {
371 std::lock_guard<std::mutex> lock(mLock);
372
373 int res = 0;
374 if (target == V4 || target == V4V6) {
375 res |= sendCommand(IPTABLES_PROCESS, command);
376 }
377 if (target == V6 || target == V4V6) {
378 res |= sendCommand(IP6TABLES_PROCESS, command);
379 }
380 return res;
381}