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 <sys/prctl.h>
22 #include <wait.h>
23
24 #include "section_list.h"
25
26 namespace android {
27 namespace os {
28 namespace incidentd {
29
30 using namespace android::base;
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 // ================================================================================
Fpipe()51 Fpipe::Fpipe() : mRead(), mWrite() {}
52
~Fpipe()53 Fpipe::~Fpipe() { close(); }
54
close()55 bool Fpipe::close() {
56 mRead.reset();
57 mWrite.reset();
58 return true;
59 }
60
init()61 bool Fpipe::init() { return Pipe(&mRead, &mWrite); }
62
readFd()63 unique_fd& Fpipe::readFd() { return mRead; }
64
writeFd()65 unique_fd& Fpipe::writeFd() { return mWrite; }
66
fork_execute_cmd(char * const argv[],Fpipe * input,Fpipe * output)67 pid_t fork_execute_cmd(char* const argv[], Fpipe* input, Fpipe* output) {
68 // fork used in multithreaded environment, avoid adding unnecessary code in child process
69 pid_t pid = fork();
70 if (pid == 0) {
71 if (input != NULL && (TEMP_FAILURE_RETRY(dup2(input->readFd().get(), STDIN_FILENO)) < 0 ||
72 !input->close())) {
73 ALOGW("Failed to dup2 stdin.");
74 _exit(EXIT_FAILURE);
75 }
76 if (TEMP_FAILURE_RETRY(dup2(output->writeFd().get(), STDOUT_FILENO)) < 0 ||
77 !output->close()) {
78 ALOGW("Failed to dup2 stdout.");
79 _exit(EXIT_FAILURE);
80 }
81 /* make sure the child dies when incidentd dies */
82 prctl(PR_SET_PDEATHSIG, SIGKILL);
83 execvp(argv[0], argv);
84 _exit(errno); // always exits with failure if any
85 }
86 // close the fds used in child process.
87 if (input != NULL) input->readFd().reset();
88 output->writeFd().reset();
89 return pid;
90 }
91
92 // ================================================================================
varargs(const char * first,va_list rest)93 const char** varargs(const char* first, va_list rest) {
94 va_list copied_rest;
95 int numOfArgs = 1; // first is already count.
96
97 va_copy(copied_rest, rest);
98 while (va_arg(copied_rest, const char*) != NULL) {
99 numOfArgs++;
100 }
101 va_end(copied_rest);
102
103 // allocate extra 1 for NULL terminator
104 const char** ret = (const char**)malloc(sizeof(const char*) * (numOfArgs + 1));
105 ret[0] = first;
106 for (int i = 1; i < numOfArgs; i++) {
107 const char* arg = va_arg(rest, const char*);
108 ret[i] = arg;
109 }
110 ret[numOfArgs] = NULL;
111 return ret;
112 }
113
114 // ================================================================================
115 const uint64_t NANOS_PER_SEC = 1000000000;
Nanotime()116 uint64_t Nanotime() {
117 timespec ts;
118 clock_gettime(CLOCK_MONOTONIC, &ts);
119 return static_cast<uint64_t>(ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec);
120 }
121
122 // ================================================================================
123 const int WAIT_MAX = 5;
124 const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000};
125
statusCode(int status)126 static status_t statusCode(int status) {
127 if (WIFSIGNALED(status)) {
128 VLOG("return by signal: %s", strerror(WTERMSIG(status)));
129 return -WTERMSIG(status);
130 } else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
131 VLOG("return by exit: %s", strerror(WEXITSTATUS(status)));
132 return -WEXITSTATUS(status);
133 }
134 return NO_ERROR;
135 }
136
kill_child(pid_t pid)137 status_t kill_child(pid_t pid) {
138 int status;
139 VLOG("try to kill child process %d", pid);
140 kill(pid, SIGKILL);
141 if (waitpid(pid, &status, 0) == -1) return -1;
142 return statusCode(status);
143 }
144
wait_child(pid_t pid)145 status_t wait_child(pid_t pid) {
146 int status;
147 bool died = false;
148 // wait for child to report status up to 1 seconds
149 for (int loop = 0; !died && loop < WAIT_MAX; loop++) {
150 if (waitpid(pid, &status, WNOHANG) == pid) died = true;
151 // sleep for 0.2 second
152 nanosleep(&WAIT_INTERVAL_NS, NULL);
153 }
154 if (!died) return kill_child(pid);
155 return statusCode(status);
156 }
157
158 } // namespace incidentd
159 } // namespace os
160 } // namespace android
161