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