blob: 9d4ea8cd3c316937aa459ef649eeef5d59fe6396 [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"
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070033#include "proto_utils.h"
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070034#include "util.h"
35
Tom Cherrya2f91362020-02-20 10:50:00 -080036#ifdef INIT_FULL_SOURCES
Tom Cherry40acb372018-08-01 13:41:12 -070037#include <android/api-level.h>
Tom Cherryde6bd502018-02-13 16:50:08 -080038#include "property_service.h"
Vic Yang92c236e2019-05-28 15:58:35 -070039#include "selabel.h"
Tom Cherryde6bd502018-02-13 16:50:08 -080040#include "selinux.h"
41#else
42#include "host_init_stubs.h"
43#endif
Tom Cherry32228482018-01-18 16:14:25 -080044
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070045using android::base::GetExecutablePath;
46using android::base::Join;
47using android::base::Socketpair;
48using android::base::Split;
49using android::base::StartsWith;
50using android::base::unique_fd;
51
52namespace android {
53namespace init {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070054namespace {
55
Tom Cherry18278d22019-11-12 16:21:20 -080056std::string shutdown_command;
Tom Cherrye3e77d32020-04-28 13:55:19 -070057static bool subcontext_terminated_by_shutdown;
58static std::unique_ptr<Subcontext> subcontext;
Tom Cherry18278d22019-11-12 16:21:20 -080059
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070060class SubcontextProcess {
61 public:
Tom Cherryd52a5b32019-07-22 16:05:36 -070062 SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070063 : 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,
Tom Cherryc49719f2018-01-10 11:04:34 -080068 SubcontextReply* reply) const;
69 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
70 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070071
Tom Cherryd52a5b32019-07-22 16:05:36 -070072 const BuiltinFunctionMap* function_map_;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070073 const std::string context_;
74 const int init_fd_;
75};
76
77void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080078 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070079 // 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
Tom Cherryd52a5b32019-07-22 16:05:36 -070085 auto map_result = function_map_->Find(args);
Tom Cherrybbcbc2f2019-06-10 11:08:01 -070086 Result<void> result;
Bernie Innocenticecebbb2020-02-06 03:49:33 +090087 if (!map_result.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070088 result = Error() << "Cannot find command: " << map_result.error();
89 } else {
Tom Cherryd52a5b32019-07-22 16:05:36 -070090 result = RunBuiltinFunction(map_result->function, args, context_);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070091 }
92
Bernie Innocenticecebbb2020-02-06 03:49:33 +090093 if (result.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -080094 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070095 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -080096 auto* failure = reply->mutable_failure();
Jiyong Park8fd64c82019-05-31 03:43:34 +090097 failure->set_error_string(result.error().message());
98 failure->set_error_errno(result.error().code());
Tom Cherryc49719f2018-01-10 11:04:34 -080099 }
100}
101
102void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
103 SubcontextReply* reply) const {
104 for (const auto& arg : expand_args_command.args()) {
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700105 auto expanded_arg = ExpandProps(arg);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900106 if (!expanded_arg.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800107 auto* failure = reply->mutable_failure();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700108 failure->set_error_string(expanded_arg.error().message());
Tom Cherryc49719f2018-01-10 11:04:34 -0800109 failure->set_error_errno(0);
110 return;
111 } else {
112 auto* expand_args_reply = reply->mutable_expand_args_reply();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700113 expand_args_reply->add_expanded_args(*expanded_arg);
Tom Cherryc49719f2018-01-10 11:04:34 -0800114 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700115 }
116}
117
118void 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_);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900132 if (!init_message.ok()) {
Jiyong Park8fd64c82019-05-31 03:43:34 +0900133 if (init_message.error().code() == 0) {
Luis Hector Chavez72353592018-09-21 12:27:02 -0700134 // 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 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700139 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: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800150 RunCommand(subcontext_command.execute_command(), &reply);
151 break;
152 }
153 case SubcontextCommand::kExpandArgsCommand: {
154 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700155 break;
156 }
157 default:
158 LOG(FATAL) << "Unknown message type from init: "
159 << subcontext_command.command_case();
160 }
161
Tom Cherry18278d22019-11-12 16:21:20 -0800162 if (!shutdown_command.empty()) {
163 reply.set_trigger_shutdown(shutdown_command);
164 shutdown_command.clear();
165 }
166
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900167 if (auto result = SendMessage(init_fd_, reply); !result.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700168 LOG(FATAL) << "Failed to send message to init: " << result.error();
169 }
170 }
171}
172
173} // namespace
174
Tom Cherryd52a5b32019-07-22 16:05:36 -0700175int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700176 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
Tom Cherry0d1452e2017-10-19 14:39:35 -0700181 SelabelInitialize();
Tom Cherry32228482018-01-18 16:14:25 -0800182
Tom Cherry18278d22019-11-12 16:21:20 -0800183 trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
184
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700185 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
Wei Wang30bbf7d2020-07-06 15:26:49 -0700186 // Restore prio before main loop
187 setpriority(PRIO_PROCESS, 0, 0);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700188 subcontext_process.MainLoop();
189 return 0;
190}
191
192void 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.
Tom Cherry247ffbf2019-07-08 15:09:36 -0700208 int child_fd = dup(subcontext_socket); // NOLINT(android-cloexec-dup)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700209 if (child_fd < 0) {
210 PLOG(FATAL) << "Could not dup child_fd";
211 }
212
Tom Cherry1c005f32019-11-20 15:51:36 -0800213 // 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 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700219 }
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
235void 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
Tom Cherry14c24722019-09-18 13:47:19 -0700245bool 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
Tom Cherryc49719f2018-01-10 11:04:34 -0800254Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900255 if (auto result = SendMessage(socket_, subcontext_command); !result.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700256 Restart();
257 return ErrnoError() << "Failed to send message to subcontext";
258 }
259
260 auto subcontext_message = ReadMessage(socket_);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900261 if (!subcontext_message.ok()) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700262 Restart();
263 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
264 }
265
Tom Cherryc49719f2018-01-10 11:04:34 -0800266 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700267 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
268 Restart();
269 return Error() << "Unable to parse message from subcontext";
270 }
Tom Cherry18278d22019-11-12 16:21:20 -0800271
272 if (subcontext_reply.has_trigger_shutdown()) {
273 trigger_shutdown(subcontext_reply.trigger_shutdown());
274 }
275
Tom Cherryc49719f2018-01-10 11:04:34 -0800276 return subcontext_reply;
277}
278
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700279Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800280 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);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900286 if (!subcontext_reply.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800287 return subcontext_reply.error();
288 }
289
Tom Cherry32228482018-01-18 16:14:25 -0800290 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
291 auto& failure = subcontext_reply->failure();
292 return ResultError(failure.error_string(), failure.error_errno());
293 }
294
Tom Cherryc49719f2018-01-10 11:04:34 -0800295 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
296 return Error() << "Unexpected message type from subcontext: "
297 << subcontext_reply->reply_case();
298 }
299
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700300 return {};
Tom Cherryc49719f2018-01-10 11:04:34 -0800301}
302
303Result<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);
Bernie Innocenticecebbb2020-02-06 03:49:33 +0900310 if (!subcontext_reply.ok()) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800311 return subcontext_reply.error();
312 }
313
Tom Cherry32228482018-01-18 16:14:25 -0800314 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
315 auto& failure = subcontext_reply->failure();
316 return ResultError(failure.error_string(), failure.error_errno());
317 }
318
Tom Cherryc49719f2018-01-10 11:04:34 -0800319 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;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700330}
331
Tom Cherrye3e77d32020-04-28 13:55:19 -0700332void InitializeSubcontext() {
Tom Cherry40acb372018-08-01 13:41:12 -0700333 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
Tom Cherrye3e77d32020-04-28 13:55:19 -0700334 subcontext.reset(
335 new Subcontext(std::vector<std::string>{"/vendor", "/odm"}, kVendorContext));
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700336 }
Tom Cherrye3e77d32020-04-28 13:55:19 -0700337}
338
339Subcontext* GetSubcontext() {
340 return subcontext.get();
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700341}
342
343bool SubcontextChildReap(pid_t pid) {
Tom Cherrye3e77d32020-04-28 13:55:19 -0700344 if (subcontext->pid() == pid) {
345 if (!subcontext_terminated_by_shutdown) {
346 subcontext->Restart();
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700347 }
Tom Cherrye3e77d32020-04-28 13:55:19 -0700348 return true;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700349 }
350 return false;
351}
352
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700353void SubcontextTerminate() {
Tom Cherrye3e77d32020-04-28 13:55:19 -0700354 subcontext_terminated_by_shutdown = true;
355 kill(subcontext->pid(), SIGTERM);
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700356}
357
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700358} // namespace init
359} // namespace android