blob: 7aa4a9d2cb1cc58a2d44c6eb29cfee28aa6de4d2 [file] [log] [blame]
Tom Cherrycb0f9bb2017-09-12 15:58:47 -07001/*
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>
Wei Wang30bbf7d2020-07-06 15:26:49 -070021#include <sys/time.h>
22#include <sys/resource.h>
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070023#include <unistd.h>
24
25#include <android-base/file.h>
26#include <android-base/logging.h>
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070027#include <android-base/properties.h>
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070028#include <android-base/strings.h>
29#include <selinux/android.h>
30
31#include "action.h"
Tom Cherryd52a5b32019-07-22 16:05:36 -070032#include "builtins.h"
Jooyung Han7bfe4772020-09-14 17:29:13 +090033#include "mount_namespace.h"
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070034#include "proto_utils.h"
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070035#include "util.h"
36
Tom Cherrya2f91362020-02-20 10:50:00 -080037#ifdef INIT_FULL_SOURCES
Tom Cherry40acb372018-08-01 13:41:12 -070038#include <android/api-level.h>
Tom Cherryde6bd502018-02-13 16:50:08 -080039#include "property_service.h"
Vic Yang92c236e2019-05-28 15:58:35 -070040#include "selabel.h"
Tom Cherryde6bd502018-02-13 16:50:08 -080041#include "selinux.h"
42#else
43#include "host_init_stubs.h"
44#endif
Tom Cherry32228482018-01-18 16:14:25 -080045
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070046using android::base::GetExecutablePath;
Jiyong Park3b3d87d2021-09-28 16:11:26 +090047using android::base::GetProperty;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070048using android::base::Join;
49using android::base::Socketpair;
50using android::base::Split;
51using android::base::StartsWith;
52using android::base::unique_fd;
53
54namespace android {
55namespace init {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070056namespace {
57
Tom Cherry18278d22019-11-12 16:21:20 -080058std::string shutdown_command;
Tom Cherrye3e77d32020-04-28 13:55:19 -070059static bool subcontext_terminated_by_shutdown;
60static std::unique_ptr<Subcontext> subcontext;
Tom Cherry18278d22019-11-12 16:21:20 -080061
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070062class SubcontextProcess {
63 public:
Tom Cherryd52a5b32019-07-22 16:05:36 -070064 SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070065 : 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,
Tom Cherryc49719f2018-01-10 11:04:34 -080070 SubcontextReply* reply) const;
71 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
72 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070073
Tom Cherryd52a5b32019-07-22 16:05:36 -070074 const BuiltinFunctionMap* function_map_;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070075 const std::string context_;
76 const int init_fd_;
77};
78
79void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080080 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070081 // 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
Tom Cherryd52a5b32019-07-22 16:05:36 -070087 auto map_result = function_map_->Find(args);
Tom Cherrybbcbc2f2019-06-10 11:08:01 -070088 Result<void> result;
Bernie Innocenticecebbb2020-02-06 03:49:33 +090089 if (!map_result.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070090 result = Error() << "Cannot find command: " << map_result.error();
91 } else {
Tom Cherryd52a5b32019-07-22 16:05:36 -070092 result = RunBuiltinFunction(map_result->function, args, context_);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070093 }
94
Bernie Innocenticecebbb2020-02-06 03:49:33 +090095 if (result.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -080096 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070097 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -080098 auto* failure = reply->mutable_failure();
Jiyong Park8fd64c82019-05-31 03:43:34 +090099 failure->set_error_string(result.error().message());
100 failure->set_error_errno(result.error().code());
Tom Cherryc49719f2018-01-10 11:04:34 -0800101 }
102}
103
104void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
105 SubcontextReply* reply) const {
106 for (const auto& arg : expand_args_command.args()) {
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700107 auto expanded_arg = ExpandProps(arg);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900108 if (!expanded_arg.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800109 auto* failure = reply->mutable_failure();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700110 failure->set_error_string(expanded_arg.error().message());
Tom Cherryc49719f2018-01-10 11:04:34 -0800111 failure->set_error_errno(0);
112 return;
113 } else {
114 auto* expand_args_reply = reply->mutable_expand_args_reply();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700115 expand_args_reply->add_expanded_args(*expanded_arg);
Tom Cherryc49719f2018-01-10 11:04:34 -0800116 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700117 }
118}
119
120void 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_);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900134 if (!init_message.ok()) {
Jiyong Park8fd64c82019-05-31 03:43:34 +0900135 if (init_message.error().code() == 0) {
Luis Hector Chavez72353592018-09-21 12:27:02 -0700136 // 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 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700141 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: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800152 RunCommand(subcontext_command.execute_command(), &reply);
153 break;
154 }
155 case SubcontextCommand::kExpandArgsCommand: {
156 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700157 break;
158 }
159 default:
160 LOG(FATAL) << "Unknown message type from init: "
161 << subcontext_command.command_case();
162 }
163
Tom Cherry18278d22019-11-12 16:21:20 -0800164 if (!shutdown_command.empty()) {
165 reply.set_trigger_shutdown(shutdown_command);
166 shutdown_command.clear();
167 }
168
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900169 if (auto result = SendMessage(init_fd_, reply); !result.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700170 LOG(FATAL) << "Failed to send message to init: " << result.error();
171 }
172 }
173}
174
175} // namespace
176
Tom Cherryd52a5b32019-07-22 16:05:36 -0700177int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700178 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
Tom Cherry0d1452e2017-10-19 14:39:35 -0700183 SelabelInitialize();
Tom Cherry32228482018-01-18 16:14:25 -0800184
Tom Cherry18278d22019-11-12 16:21:20 -0800185 trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
186
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700187 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
Wei Wang30bbf7d2020-07-06 15:26:49 -0700188 // Restore prio before main loop
189 setpriority(PRIO_PROCESS, 0, 0);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700190 subcontext_process.MainLoop();
191 return 0;
192}
193
194void 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.
Tom Cherry247ffbf2019-07-08 15:09:36 -0700210 int child_fd = dup(subcontext_socket); // NOLINT(android-cloexec-dup)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700211 if (child_fd < 0) {
212 PLOG(FATAL) << "Could not dup child_fd";
213 }
214
Tom Cherry1c005f32019-11-20 15:51:36 -0800215 // 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 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700221 }
Jooyung Han7bfe4772020-09-14 17:29:13 +0900222#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
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700229 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
243void 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
Tom Cherry14c24722019-09-18 13:47:19 -0700253bool Subcontext::PathMatchesSubcontext(const std::string& path) {
254 for (const auto& prefix : path_prefixes_) {
255 if (StartsWith(path, prefix)) {
256 return true;
257 }
258 }
259 return false;
260}
261
Tom Cherryc49719f2018-01-10 11:04:34 -0800262Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900263 if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700264 Restart();
265 return ErrnoError() << "Failed to send message to subcontext";
266 }
267
268 auto subcontext_message = ReadMessage(socket_);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900269 if (!subcontext_message.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700270 Restart();
271 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
272 }
273
Tom Cherryc49719f2018-01-10 11:04:34 -0800274 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700275 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
276 Restart();
277 return Error() << "Unable to parse message from subcontext";
278 }
Tom Cherry18278d22019-11-12 16:21:20 -0800279
280 if (subcontext_reply.has_trigger_shutdown()) {
281 trigger_shutdown(subcontext_reply.trigger_shutdown());
282 }
283
Tom Cherryc49719f2018-01-10 11:04:34 -0800284 return subcontext_reply;
285}
286
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700287Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800288 auto subcontext_command = SubcontextCommand();
289 std::copy(
290 args.begin(), args.end(),
291 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
292
293 auto subcontext_reply = TransmitMessage(subcontext_command);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900294 if (!subcontext_reply.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800295 return subcontext_reply.error();
296 }
297
Tom Cherry32228482018-01-18 16:14:25 -0800298 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
299 auto& failure = subcontext_reply->failure();
Jiyong Parkd185d4a2021-12-11 10:45:20 +0900300 return ResultError<>(failure.error_string(), failure.error_errno());
Tom Cherry32228482018-01-18 16:14:25 -0800301 }
302
Tom Cherryc49719f2018-01-10 11:04:34 -0800303 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
304 return Error() << "Unexpected message type from subcontext: "
305 << subcontext_reply->reply_case();
306 }
307
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700308 return {};
Tom Cherryc49719f2018-01-10 11:04:34 -0800309}
310
311Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
312 auto subcontext_command = SubcontextCommand{};
313 std::copy(args.begin(), args.end(),
314 RepeatedPtrFieldBackInserter(
315 subcontext_command.mutable_expand_args_command()->mutable_args()));
316
317 auto subcontext_reply = TransmitMessage(subcontext_command);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900318 if (!subcontext_reply.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800319 return subcontext_reply.error();
320 }
321
Tom Cherry32228482018-01-18 16:14:25 -0800322 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
323 auto& failure = subcontext_reply->failure();
Jiyong Parkd185d4a2021-12-11 10:45:20 +0900324 return ResultError<>(failure.error_string(), failure.error_errno());
Tom Cherry32228482018-01-18 16:14:25 -0800325 }
326
Tom Cherryc49719f2018-01-10 11:04:34 -0800327 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
328 return Error() << "Unexpected message type from subcontext: "
329 << subcontext_reply->reply_case();
330 }
331
332 auto& reply = subcontext_reply->expand_args_reply();
333 auto expanded_args = std::vector<std::string>{};
334 for (const auto& string : reply.expanded_args()) {
335 expanded_args.emplace_back(string);
336 }
337 return expanded_args;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700338}
339
Tom Cherrye3e77d32020-04-28 13:55:19 -0700340void InitializeSubcontext() {
Jiyong Park3b3d87d2021-09-28 16:11:26 +0900341 if (IsMicrodroid()) {
342 LOG(INFO) << "Not using subcontext for microdroid";
343 return;
344 }
345
Tom Cherry40acb372018-08-01 13:41:12 -0700346 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
Tom Cherrye3e77d32020-04-28 13:55:19 -0700347 subcontext.reset(
348 new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700349 }
Tom Cherrye3e77d32020-04-28 13:55:19 -0700350}
Daniel Normanf597fa52020-11-09 17:28:24 -0800351void InitializeHostSubcontext(std::vector<std::string> vendor_prefixes) {
352 subcontext.reset(new Subcontext(vendor_prefixes, kVendorContext, /*host=*/true));
353}
Tom Cherrye3e77d32020-04-28 13:55:19 -0700354
355Subcontext* GetSubcontext() {
356 return subcontext.get();
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700357}
358
359bool SubcontextChildReap(pid_t pid) {
Nikita Ioffe86b43242020-12-10 16:52:35 +0000360 if (!subcontext) {
361 return false;
362 }
Tom Cherrye3e77d32020-04-28 13:55:19 -0700363 if (subcontext->pid() == pid) {
364 if (!subcontext_terminated_by_shutdown) {
365 subcontext->Restart();
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700366 }
Tom Cherrye3e77d32020-04-28 13:55:19 -0700367 return true;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700368 }
369 return false;
370}
371
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700372void SubcontextTerminate() {
Tom Cherrye3e77d32020-04-28 13:55:19 -0700373 subcontext_terminated_by_shutdown = true;
374 kill(subcontext->pid(), SIGTERM);
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700375}
376
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700377} // namespace init
378} // namespace android