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