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
17 #include "subcontext.h"
18
19 #include <fcntl.h>
20 #include <poll.h>
21 #include <sys/time.h>
22 #include <sys/resource.h>
23 #include <unistd.h>
24
25 #include <android-base/file.h>
26 #include <android-base/logging.h>
27 #include <android-base/properties.h>
28 #include <android-base/strings.h>
29 #include <selinux/android.h>
30
31 #include "action.h"
32 #include "builtins.h"
33 #include "proto_utils.h"
34 #include "util.h"
35
36 #ifdef INIT_FULL_SOURCES
37 #include <android/api-level.h>
38 #include "property_service.h"
39 #include "selabel.h"
40 #include "selinux.h"
41 #else
42 #include "host_init_stubs.h"
43 #endif
44
45 using android::base::GetExecutablePath;
46 using android::base::Join;
47 using android::base::Socketpair;
48 using android::base::Split;
49 using android::base::StartsWith;
50 using android::base::unique_fd;
51
52 namespace android {
53 namespace init {
54 namespace {
55
56 std::string shutdown_command;
57 static bool subcontext_terminated_by_shutdown;
58 static std::unique_ptr<Subcontext> subcontext;
59
60 class SubcontextProcess {
61 public:
SubcontextProcess(const BuiltinFunctionMap * function_map,std::string context,int init_fd)62 SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
63 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
64 void MainLoop();
65
66 private:
67 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
68 SubcontextReply* reply) const;
69 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
70 SubcontextReply* reply) const;
71
72 const BuiltinFunctionMap* function_map_;
73 const std::string context_;
74 const int init_fd_;
75 };
76
RunCommand(const SubcontextCommand::ExecuteCommand & execute_command,SubcontextReply * reply) const77 void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
78 SubcontextReply* reply) const {
79 // Need to use ArraySplice instead of this code.
80 auto args = std::vector<std::string>();
81 for (const auto& string : execute_command.args()) {
82 args.emplace_back(string);
83 }
84
85 auto map_result = function_map_->Find(args);
86 Result<void> result;
87 if (!map_result.ok()) {
88 result = Error() << "Cannot find command: " << map_result.error();
89 } else {
90 result = RunBuiltinFunction(map_result->function, args, context_);
91 }
92
93 if (result.ok()) {
94 reply->set_success(true);
95 } else {
96 auto* failure = reply->mutable_failure();
97 failure->set_error_string(result.error().message());
98 failure->set_error_errno(result.error().code());
99 }
100 }
101
ExpandArgs(const SubcontextCommand::ExpandArgsCommand & expand_args_command,SubcontextReply * reply) const102 void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
103 SubcontextReply* reply) const {
104 for (const auto& arg : expand_args_command.args()) {
105 auto expanded_arg = ExpandProps(arg);
106 if (!expanded_arg.ok()) {
107 auto* failure = reply->mutable_failure();
108 failure->set_error_string(expanded_arg.error().message());
109 failure->set_error_errno(0);
110 return;
111 } else {
112 auto* expand_args_reply = reply->mutable_expand_args_reply();
113 expand_args_reply->add_expanded_args(*expanded_arg);
114 }
115 }
116 }
117
MainLoop()118 void SubcontextProcess::MainLoop() {
119 pollfd ufd[1];
120 ufd[0].events = POLLIN;
121 ufd[0].fd = init_fd_;
122
123 while (true) {
124 ufd[0].revents = 0;
125 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
126 if (nr == 0) continue;
127 if (nr < 0) {
128 PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
129 }
130
131 auto init_message = ReadMessage(init_fd_);
132 if (!init_message.ok()) {
133 if (init_message.error().code() == 0) {
134 // If the init file descriptor was closed, let's exit quietly. If
135 // this was accidental, init will restart us. If init died, this
136 // avoids calling abort(3) unnecessarily.
137 return;
138 }
139 LOG(FATAL) << "Could not read message from init: " << init_message.error();
140 }
141
142 auto subcontext_command = SubcontextCommand();
143 if (!subcontext_command.ParseFromString(*init_message)) {
144 LOG(FATAL) << "Unable to parse message from init";
145 }
146
147 auto reply = SubcontextReply();
148 switch (subcontext_command.command_case()) {
149 case SubcontextCommand::kExecuteCommand: {
150 RunCommand(subcontext_command.execute_command(), &reply);
151 break;
152 }
153 case SubcontextCommand::kExpandArgsCommand: {
154 ExpandArgs(subcontext_command.expand_args_command(), &reply);
155 break;
156 }
157 default:
158 LOG(FATAL) << "Unknown message type from init: "
159 << subcontext_command.command_case();
160 }
161
162 if (!shutdown_command.empty()) {
163 reply.set_trigger_shutdown(shutdown_command);
164 shutdown_command.clear();
165 }
166
167 if (auto result = SendMessage(init_fd_, reply); !result.ok()) {
168 LOG(FATAL) << "Failed to send message to init: " << result.error();
169 }
170 }
171 }
172
173 } // namespace
174
SubcontextMain(int argc,char ** argv,const BuiltinFunctionMap * function_map)175 int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
176 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
177
178 auto context = std::string(argv[2]);
179 auto init_fd = std::atoi(argv[3]);
180
181 SelabelInitialize();
182
183 trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
184
185 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
186 // Restore prio before main loop
187 setpriority(PRIO_PROCESS, 0, 0);
188 subcontext_process.MainLoop();
189 return 0;
190 }
191
Fork()192 void Subcontext::Fork() {
193 unique_fd subcontext_socket;
194 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
195 LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
196 return;
197 }
198
199 auto result = fork();
200
201 if (result == -1) {
202 LOG(FATAL) << "Could not fork subcontext";
203 } else if (result == 0) {
204 socket_.reset();
205
206 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
207 // in the subcontext process after we exec.
208 int child_fd = dup(subcontext_socket); // NOLINT(android-cloexec-dup)
209 if (child_fd < 0) {
210 PLOG(FATAL) << "Could not dup child_fd";
211 }
212
213 // We don't switch contexts if we're running the unit tests. We don't use std::optional,
214 // since we still need a real context string to pass to the builtin functions.
215 if (context_ != kTestContext) {
216 if (setexeccon(context_.c_str()) < 0) {
217 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
218 }
219 }
220
221 auto init_path = GetExecutablePath();
222 auto child_fd_string = std::to_string(child_fd);
223 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
224 child_fd_string.c_str(), nullptr};
225 execv(init_path.data(), const_cast<char**>(args));
226
227 PLOG(FATAL) << "Could not execv subcontext init";
228 } else {
229 subcontext_socket.reset();
230 pid_ = result;
231 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
232 }
233 }
234
Restart()235 void Subcontext::Restart() {
236 LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
237 if (pid_) {
238 kill(pid_, SIGKILL);
239 }
240 pid_ = 0;
241 socket_.reset();
242 Fork();
243 }
244
PathMatchesSubcontext(const std::string & path)245 bool Subcontext::PathMatchesSubcontext(const std::string& path) {
246 for (const auto& prefix : path_prefixes_) {
247 if (StartsWith(path, prefix)) {
248 return true;
249 }
250 }
251 return false;
252 }
253
TransmitMessage(const SubcontextCommand & subcontext_command)254 Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
255 if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
256 Restart();
257 return ErrnoError() << "Failed to send message to subcontext";
258 }
259
260 auto subcontext_message = ReadMessage(socket_);
261 if (!subcontext_message.ok()) {
262 Restart();
263 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
264 }
265
266 auto subcontext_reply = SubcontextReply{};
267 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
268 Restart();
269 return Error() << "Unable to parse message from subcontext";
270 }
271
272 if (subcontext_reply.has_trigger_shutdown()) {
273 trigger_shutdown(subcontext_reply.trigger_shutdown());
274 }
275
276 return subcontext_reply;
277 }
278
Execute(const std::vector<std::string> & args)279 Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
280 auto subcontext_command = SubcontextCommand();
281 std::copy(
282 args.begin(), args.end(),
283 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
284
285 auto subcontext_reply = TransmitMessage(subcontext_command);
286 if (!subcontext_reply.ok()) {
287 return subcontext_reply.error();
288 }
289
290 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
291 auto& failure = subcontext_reply->failure();
292 return ResultError(failure.error_string(), failure.error_errno());
293 }
294
295 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
296 return Error() << "Unexpected message type from subcontext: "
297 << subcontext_reply->reply_case();
298 }
299
300 return {};
301 }
302
ExpandArgs(const std::vector<std::string> & args)303 Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
304 auto subcontext_command = SubcontextCommand{};
305 std::copy(args.begin(), args.end(),
306 RepeatedPtrFieldBackInserter(
307 subcontext_command.mutable_expand_args_command()->mutable_args()));
308
309 auto subcontext_reply = TransmitMessage(subcontext_command);
310 if (!subcontext_reply.ok()) {
311 return subcontext_reply.error();
312 }
313
314 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
315 auto& failure = subcontext_reply->failure();
316 return ResultError(failure.error_string(), failure.error_errno());
317 }
318
319 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
320 return Error() << "Unexpected message type from subcontext: "
321 << subcontext_reply->reply_case();
322 }
323
324 auto& reply = subcontext_reply->expand_args_reply();
325 auto expanded_args = std::vector<std::string>{};
326 for (const auto& string : reply.expanded_args()) {
327 expanded_args.emplace_back(string);
328 }
329 return expanded_args;
330 }
331
InitializeSubcontext()332 void InitializeSubcontext() {
333 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
334 subcontext.reset(
335 new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
336 }
337 }
338
GetSubcontext()339 Subcontext* GetSubcontext() {
340 return subcontext.get();
341 }
342
SubcontextChildReap(pid_t pid)343 bool SubcontextChildReap(pid_t pid) {
344 if (subcontext->pid() == pid) {
345 if (!subcontext_terminated_by_shutdown) {
346 subcontext->Restart();
347 }
348 return true;
349 }
350 return false;
351 }
352
SubcontextTerminate()353 void SubcontextTerminate() {
354 subcontext_terminated_by_shutdown = true;
355 kill(subcontext->pid(), SIGTERM);
356 }
357
358 } // namespace init
359 } // namespace android
360