blob: f3f759d6f86a0e38e163f1059425dab1df2b9e75 [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>
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070021#include <unistd.h>
22
23#include <android-base/file.h>
24#include <android-base/logging.h>
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070025#include <android-base/properties.h>
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070026#include <android-base/strings.h>
27#include <selinux/android.h>
28
29#include "action.h"
Tom Cherryd52a5b32019-07-22 16:05:36 -070030#include "builtins.h"
Tom Cherry1ab3dfc2019-04-22 17:46:37 -070031#include "proto_utils.h"
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070032#include "util.h"
33
Tom Cherryde6bd502018-02-13 16:50:08 -080034#if defined(__ANDROID__)
Tom Cherry40acb372018-08-01 13:41:12 -070035#include <android/api-level.h>
Tom Cherryde6bd502018-02-13 16:50:08 -080036#include "property_service.h"
Vic Yang92c236e2019-05-28 15:58:35 -070037#include "selabel.h"
Tom Cherryde6bd502018-02-13 16:50:08 -080038#include "selinux.h"
39#else
40#include "host_init_stubs.h"
41#endif
Tom Cherry32228482018-01-18 16:14:25 -080042
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070043using android::base::GetExecutablePath;
44using android::base::Join;
45using android::base::Socketpair;
46using android::base::Split;
47using android::base::StartsWith;
48using android::base::unique_fd;
49
50namespace android {
51namespace init {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070052namespace {
53
Tom Cherry18278d22019-11-12 16:21:20 -080054std::string shutdown_command;
55
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070056class SubcontextProcess {
57 public:
Tom Cherryd52a5b32019-07-22 16:05:36 -070058 SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070059 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
60 void MainLoop();
61
62 private:
63 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080064 SubcontextReply* reply) const;
65 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
66 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070067
Tom Cherryd52a5b32019-07-22 16:05:36 -070068 const BuiltinFunctionMap* function_map_;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070069 const std::string context_;
70 const int init_fd_;
71};
72
73void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080074 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070075 // Need to use ArraySplice instead of this code.
76 auto args = std::vector<std::string>();
77 for (const auto& string : execute_command.args()) {
78 args.emplace_back(string);
79 }
80
Tom Cherryd52a5b32019-07-22 16:05:36 -070081 auto map_result = function_map_->Find(args);
Tom Cherrybbcbc2f2019-06-10 11:08:01 -070082 Result<void> result;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070083 if (!map_result) {
84 result = Error() << "Cannot find command: " << map_result.error();
85 } else {
Tom Cherryd52a5b32019-07-22 16:05:36 -070086 result = RunBuiltinFunction(map_result->function, args, context_);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070087 }
88
89 if (result) {
Tom Cherryc49719f2018-01-10 11:04:34 -080090 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070091 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -080092 auto* failure = reply->mutable_failure();
Jiyong Park8fd64c82019-05-31 03:43:34 +090093 failure->set_error_string(result.error().message());
94 failure->set_error_errno(result.error().code());
Tom Cherryc49719f2018-01-10 11:04:34 -080095 }
96}
97
98void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
99 SubcontextReply* reply) const {
100 for (const auto& arg : expand_args_command.args()) {
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700101 auto expanded_arg = ExpandProps(arg);
102 if (!expanded_arg) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800103 auto* failure = reply->mutable_failure();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700104 failure->set_error_string(expanded_arg.error().message());
Tom Cherryc49719f2018-01-10 11:04:34 -0800105 failure->set_error_errno(0);
106 return;
107 } else {
108 auto* expand_args_reply = reply->mutable_expand_args_reply();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700109 expand_args_reply->add_expanded_args(*expanded_arg);
Tom Cherryc49719f2018-01-10 11:04:34 -0800110 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700111 }
112}
113
114void SubcontextProcess::MainLoop() {
115 pollfd ufd[1];
116 ufd[0].events = POLLIN;
117 ufd[0].fd = init_fd_;
118
119 while (true) {
120 ufd[0].revents = 0;
121 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
122 if (nr == 0) continue;
123 if (nr < 0) {
124 PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
125 }
126
127 auto init_message = ReadMessage(init_fd_);
128 if (!init_message) {
Jiyong Park8fd64c82019-05-31 03:43:34 +0900129 if (init_message.error().code() == 0) {
Luis Hector Chavez72353592018-09-21 12:27:02 -0700130 // If the init file descriptor was closed, let's exit quietly. If
131 // this was accidental, init will restart us. If init died, this
132 // avoids calling abort(3) unnecessarily.
133 return;
134 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700135 LOG(FATAL) << "Could not read message from init: " << init_message.error();
136 }
137
138 auto subcontext_command = SubcontextCommand();
139 if (!subcontext_command.ParseFromString(*init_message)) {
140 LOG(FATAL) << "Unable to parse message from init";
141 }
142
143 auto reply = SubcontextReply();
144 switch (subcontext_command.command_case()) {
145 case SubcontextCommand::kExecuteCommand: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800146 RunCommand(subcontext_command.execute_command(), &reply);
147 break;
148 }
149 case SubcontextCommand::kExpandArgsCommand: {
150 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700151 break;
152 }
153 default:
154 LOG(FATAL) << "Unknown message type from init: "
155 << subcontext_command.command_case();
156 }
157
Tom Cherry18278d22019-11-12 16:21:20 -0800158 if (!shutdown_command.empty()) {
159 reply.set_trigger_shutdown(shutdown_command);
160 shutdown_command.clear();
161 }
162
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700163 if (auto result = SendMessage(init_fd_, reply); !result) {
164 LOG(FATAL) << "Failed to send message to init: " << result.error();
165 }
166 }
167}
168
169} // namespace
170
Tom Cherryd52a5b32019-07-22 16:05:36 -0700171int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700172 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
173
174 auto context = std::string(argv[2]);
175 auto init_fd = std::atoi(argv[3]);
176
Tom Cherry0d1452e2017-10-19 14:39:35 -0700177 SelabelInitialize();
Tom Cherry32228482018-01-18 16:14:25 -0800178
Tom Cherry18278d22019-11-12 16:21:20 -0800179 trigger_shutdown = [](const std::string& command) { shutdown_command = command; };
180
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700181 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
182 subcontext_process.MainLoop();
183 return 0;
184}
185
186void Subcontext::Fork() {
187 unique_fd subcontext_socket;
188 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
189 LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
190 return;
191 }
192
193 auto result = fork();
194
195 if (result == -1) {
196 LOG(FATAL) << "Could not fork subcontext";
197 } else if (result == 0) {
198 socket_.reset();
199
200 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
201 // in the subcontext process after we exec.
Tom Cherry247ffbf2019-07-08 15:09:36 -0700202 int child_fd = dup(subcontext_socket); // NOLINT(android-cloexec-dup)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700203 if (child_fd < 0) {
204 PLOG(FATAL) << "Could not dup child_fd";
205 }
206
Tom Cherry1c005f32019-11-20 15:51:36 -0800207 // We don't switch contexts if we're running the unit tests. We don't use std::optional,
208 // since we still need a real context string to pass to the builtin functions.
209 if (context_ != kTestContext) {
210 if (setexeccon(context_.c_str()) < 0) {
211 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
212 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700213 }
214
215 auto init_path = GetExecutablePath();
216 auto child_fd_string = std::to_string(child_fd);
217 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
218 child_fd_string.c_str(), nullptr};
219 execv(init_path.data(), const_cast<char**>(args));
220
221 PLOG(FATAL) << "Could not execv subcontext init";
222 } else {
223 subcontext_socket.reset();
224 pid_ = result;
225 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
226 }
227}
228
229void Subcontext::Restart() {
230 LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
231 if (pid_) {
232 kill(pid_, SIGKILL);
233 }
234 pid_ = 0;
235 socket_.reset();
236 Fork();
237}
238
Tom Cherry14c24722019-09-18 13:47:19 -0700239bool Subcontext::PathMatchesSubcontext(const std::string& path) {
240 for (const auto& prefix : path_prefixes_) {
241 if (StartsWith(path, prefix)) {
242 return true;
243 }
244 }
245 return false;
246}
247
Tom Cherryc49719f2018-01-10 11:04:34 -0800248Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700249 if (auto result = SendMessage(socket_, subcontext_command); !result) {
250 Restart();
251 return ErrnoError() << "Failed to send message to subcontext";
252 }
253
254 auto subcontext_message = ReadMessage(socket_);
255 if (!subcontext_message) {
256 Restart();
257 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
258 }
259
Tom Cherryc49719f2018-01-10 11:04:34 -0800260 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700261 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
262 Restart();
263 return Error() << "Unable to parse message from subcontext";
264 }
Tom Cherry18278d22019-11-12 16:21:20 -0800265
266 if (subcontext_reply.has_trigger_shutdown()) {
267 trigger_shutdown(subcontext_reply.trigger_shutdown());
268 }
269
Tom Cherryc49719f2018-01-10 11:04:34 -0800270 return subcontext_reply;
271}
272
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700273Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800274 auto subcontext_command = SubcontextCommand();
275 std::copy(
276 args.begin(), args.end(),
277 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
278
279 auto subcontext_reply = TransmitMessage(subcontext_command);
280 if (!subcontext_reply) {
281 return subcontext_reply.error();
282 }
283
Tom Cherry32228482018-01-18 16:14:25 -0800284 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
285 auto& failure = subcontext_reply->failure();
286 return ResultError(failure.error_string(), failure.error_errno());
287 }
288
Tom Cherryc49719f2018-01-10 11:04:34 -0800289 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
290 return Error() << "Unexpected message type from subcontext: "
291 << subcontext_reply->reply_case();
292 }
293
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700294 return {};
Tom Cherryc49719f2018-01-10 11:04:34 -0800295}
296
297Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
298 auto subcontext_command = SubcontextCommand{};
299 std::copy(args.begin(), args.end(),
300 RepeatedPtrFieldBackInserter(
301 subcontext_command.mutable_expand_args_command()->mutable_args()));
302
303 auto subcontext_reply = TransmitMessage(subcontext_command);
304 if (!subcontext_reply) {
305 return subcontext_reply.error();
306 }
307
Tom Cherry32228482018-01-18 16:14:25 -0800308 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
309 auto& failure = subcontext_reply->failure();
310 return ResultError(failure.error_string(), failure.error_errno());
311 }
312
Tom Cherryc49719f2018-01-10 11:04:34 -0800313 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
314 return Error() << "Unexpected message type from subcontext: "
315 << subcontext_reply->reply_case();
316 }
317
318 auto& reply = subcontext_reply->expand_args_reply();
319 auto expanded_args = std::vector<std::string>{};
320 for (const auto& string : reply.expanded_args()) {
321 expanded_args.emplace_back(string);
322 }
323 return expanded_args;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700324}
325
326static std::vector<Subcontext> subcontexts;
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700327static bool shutting_down;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700328
Tom Cherry14c24722019-09-18 13:47:19 -0700329std::unique_ptr<Subcontext> InitializeSubcontext() {
Tom Cherry40acb372018-08-01 13:41:12 -0700330 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
Tom Cherry14c24722019-09-18 13:47:19 -0700331 return std::make_unique<Subcontext>(std::vector<std::string>{"/vendor", "/odm"},
332 kVendorContext);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700333 }
Tom Cherry14c24722019-09-18 13:47:19 -0700334 return nullptr;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700335}
336
337bool SubcontextChildReap(pid_t pid) {
338 for (auto& subcontext : subcontexts) {
339 if (subcontext.pid() == pid) {
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700340 if (!shutting_down) {
341 subcontext.Restart();
342 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700343 return true;
344 }
345 }
346 return false;
347}
348
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700349void SubcontextTerminate() {
350 shutting_down = true;
351 for (auto& subcontext : subcontexts) {
352 kill(subcontext.pid(), SIGTERM);
353 }
354}
355
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700356} // namespace init
357} // namespace android