• 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 <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