• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 #define DEBUG false
17 #include "Log.h"
18 
19 #include "incidentd_util.h"
20 
21 #include <android/util/EncodedBuffer.h>
22 #include <fcntl.h>
23 #include <sys/prctl.h>
24 #include <wait.h>
25 
26 #include "section_list.h"
27 
28 namespace android {
29 namespace os {
30 namespace incidentd {
31 
get_privacy_of_section(int id)32 const Privacy* get_privacy_of_section(int id) {
33     int l = 0;
34     int r = PRIVACY_POLICY_COUNT - 1;
35     while (l <= r) {
36         int mid = (l + r) >> 1;
37         const Privacy* p = PRIVACY_POLICY_LIST[mid];
38 
39         if (p->field_id < (uint32_t)id) {
40             l = mid + 1;
41         } else if (p->field_id > (uint32_t)id) {
42             r = mid - 1;
43         } else {
44             return p;
45         }
46     }
47     return NULL;
48 }
49 
50 std::vector<sp<EncodedBuffer>> gBufferPool;
51 std::mutex gBufferPoolLock;
52 
get_buffer_from_pool()53 sp<EncodedBuffer> get_buffer_from_pool() {
54     std::scoped_lock<std::mutex> lock(gBufferPoolLock);
55     if (gBufferPool.size() == 0) {
56         return new EncodedBuffer();
57     }
58     sp<EncodedBuffer> buffer = gBufferPool.back();
59     gBufferPool.pop_back();
60     return buffer;
61 }
62 
return_buffer_to_pool(sp<EncodedBuffer> buffer)63 void return_buffer_to_pool(sp<EncodedBuffer> buffer) {
64     buffer->clear();
65     std::scoped_lock<std::mutex> lock(gBufferPoolLock);
66     gBufferPool.push_back(buffer);
67 }
68 
clear_buffer_pool()69 void clear_buffer_pool() {
70     std::scoped_lock<std::mutex> lock(gBufferPoolLock);
71     gBufferPool.clear();
72 }
73 
74 // ================================================================================
Fpipe()75 Fpipe::Fpipe() : mRead(), mWrite() {}
76 
~Fpipe()77 Fpipe::~Fpipe() { close(); }
78 
close()79 bool Fpipe::close() {
80     mRead.reset();
81     mWrite.reset();
82     return true;
83 }
84 
init()85 bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
86 
readFd()87 unique_fd& Fpipe::readFd() { return mRead; }
88 
writeFd()89 unique_fd& Fpipe::writeFd() { return mWrite; }
90 
fork_execute_cmd(char * const argv[],Fpipe * input,Fpipe * output,int * status)91 pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output, int* status) {
92     int in = -1;
93     if (input != nullptr) {
94         in = input->readFd().release();
95         // Auto close write end of the input pipe on exec to prevent leaking fd in child process
96         fcntl(input->writeFd().get(), F_SETFD, FD_CLOEXEC);
97     }
98     int out = output->writeFd().release();
99     // Auto close read end of the output pipe on exec
100     fcntl(output->readFd().get(), F_SETFD, FD_CLOEXEC);
101     return fork_execute_cmd(argv, in, out, status);
102 }
103 
fork_execute_cmd(char * const argv[],int in,int out,int * status)104 pid_t fork_execute_cmd(char* const argv[], int in, int out, int* status) {
105     int dummy_status = 0;
106     if (status == nullptr) {
107         status = &dummy_status;
108     }
109     *status = 0;
110     pid_t pid = vfork();
111     if (pid < 0) {
112         *status = -errno;
113         return -1;
114     }
115     if (pid == 0) {
116         // In child
117         if (in >= 0 && (TEMP_FAILURE_RETRY(dup2(in, STDIN_FILENO)) < 0 || close(in))) {
118             ALOGW("Failed to dup2 stdin.");
119             _exit(EXIT_FAILURE);
120         }
121         if (TEMP_FAILURE_RETRY(dup2(out, STDOUT_FILENO)) < 0 || close(out)) {
122             ALOGW("Failed to dup2 stdout.");
123             _exit(EXIT_FAILURE);
124         }
125         // Make sure the child dies when incidentd dies
126         prctl(PR_SET_PDEATHSIG, SIGKILL);
127         execvp(argv[0], argv);
128         _exit(errno);  // always exits with failure if any
129     }
130     // In parent
131     if ((in >= 0 && close(in) < 0) || close(out) < 0) {
132         ALOGW("Failed to close pd. Killing child process");
133         *status = -errno;
134         kill_child(pid);
135         return -1;
136     }
137     return pid;
138 }
139 
140 // ================================================================================
varargs(const char * first,va_list rest)141 const char** varargs(const char* first, va_list rest) {
142     va_list copied_rest;
143     int numOfArgs = 1;  // first is already count.
144 
145     va_copy(copied_rest, rest);
146     while (va_arg(copied_rest, const char*) != NULL) {
147         numOfArgs++;
148     }
149     va_end(copied_rest);
150 
151     // allocate extra 1 for NULL terminator
152     const char** ret = (const char**)malloc(sizeof(const char*) * (numOfArgs + 1));
153     ret[0] = first;
154     for (int i = 1; i < numOfArgs; i++) {
155         const char* arg = va_arg(rest, const char*);
156         ret[i] = arg;
157     }
158     ret[numOfArgs] = NULL;
159     return ret;
160 }
161 
162 // ================================================================================
163 const uint64_t NANOS_PER_SEC = 1000000000;
Nanotime()164 uint64_t Nanotime() {
165     timespec ts;
166     clock_gettime(CLOCK_MONOTONIC, &ts);
167     return static_cast<uint64_t>(ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec);
168 }
169 
170 // ================================================================================
statusCode(int status)171 static status_t statusCode(int status) {
172     if (WIFSIGNALED(status)) {
173         VLOG("return by signal: %s", strerror(WTERMSIG(status)));
174         return -WTERMSIG(status);
175     } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
176         VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
177         return -WEXITSTATUS(status);
178     }
179     return NO_ERROR;
180 }
181 
waitpid_with_timeout(pid_t pid,int timeout_ms,int * status)182 static bool waitpid_with_timeout(pid_t pid, int timeout_ms, int* status) {
183     sigset_t child_mask, old_mask;
184     sigemptyset(&child_mask);
185     sigaddset(&child_mask, SIGCHLD);
186 
187     // block SIGCHLD before we check if a process has exited
188     if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
189         ALOGW("*** sigprocmask failed: %s\n", strerror(errno));
190         return false;
191     }
192 
193     // if the child has exited already, handle and reset signals before leaving
194     pid_t child_pid = waitpid(pid, status, WNOHANG);
195     if (child_pid != pid) {
196         if (child_pid > 0) {
197             ALOGW("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
198             sigprocmask(SIG_SETMASK, &old_mask, nullptr);
199             return false;
200         }
201     } else {
202         sigprocmask(SIG_SETMASK, &old_mask, nullptr);
203         return true;
204     }
205 
206     // wait for a SIGCHLD
207     timespec ts;
208     ts.tv_sec = timeout_ms / 1000;
209     ts.tv_nsec = (timeout_ms % 1000) * 1000000;
210     int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
211     int saved_errno = errno;
212 
213     // Set the signals back the way they were.
214     if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
215         ALOGW("*** sigprocmask failed: %s\n", strerror(errno));
216         if (ret == 0) {
217             return false;
218         }
219     }
220     if (ret == -1) {
221         errno = saved_errno;
222         if (errno == EAGAIN) {
223             errno = ETIMEDOUT;
224         } else {
225             ALOGW("*** sigtimedwait failed: %s\n", strerror(errno));
226         }
227         return false;
228     }
229 
230     child_pid = waitpid(pid, status, WNOHANG);
231     if (child_pid != pid) {
232         if (child_pid != -1) {
233             ALOGW("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
234         } else {
235             ALOGW("*** waitpid failed: %s\n", strerror(errno));
236         }
237         return false;
238     }
239     return true;
240 }
241 
kill_child(pid_t pid)242 status_t kill_child(pid_t pid) {
243     int status;
244     kill(pid, SIGKILL);
245     if (waitpid(pid, &status, 0) == -1) return -1;
246     return statusCode(status);
247 }
248 
wait_child(pid_t pid,int timeout_ms)249 status_t wait_child(pid_t pid, int timeout_ms) {
250     int status;
251     if (waitpid_with_timeout(pid, timeout_ms, &status)) {
252         return statusCode(status);
253     }
254     return kill_child(pid);
255 }
256 
257 }  // namespace incidentd
258 }  // namespace os
259 }  // namespace android
260