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