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