blob: ec93b5837efe73dc406ddd97364d271b9716f3b2 [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 {
52
Tom Cherryac7428b2017-10-02 16:59:02 -070053const std::string kInitContext = "u:r:init:s0";
54const std::string kVendorContext = "u:r:vendor_init:s0";
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070055
Tom Cherrydc375862018-02-28 10:39:01 -080056const char* const paths_and_secontexts[2][2] = {
57 {"/vendor", kVendorContext.c_str()},
58 {"/odm", kVendorContext.c_str()},
59};
60
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070061namespace {
62
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070063class SubcontextProcess {
64 public:
Tom Cherryd52a5b32019-07-22 16:05:36 -070065 SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070066 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
67 void MainLoop();
68
69 private:
70 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080071 SubcontextReply* reply) const;
72 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
73 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070074
Tom Cherryd52a5b32019-07-22 16:05:36 -070075 const BuiltinFunctionMap* function_map_;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070076 const std::string context_;
77 const int init_fd_;
78};
79
80void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080081 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070082 // Need to use ArraySplice instead of this code.
83 auto args = std::vector<std::string>();
84 for (const auto& string : execute_command.args()) {
85 args.emplace_back(string);
86 }
87
Tom Cherryd52a5b32019-07-22 16:05:36 -070088 auto map_result = function_map_->Find(args);
Tom Cherrybbcbc2f2019-06-10 11:08:01 -070089 Result<void> result;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070090 if (!map_result) {
91 result = Error() << "Cannot find command: " << map_result.error();
92 } else {
Tom Cherryd52a5b32019-07-22 16:05:36 -070093 result = RunBuiltinFunction(map_result->function, args, context_);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070094 }
95
96 if (result) {
Tom Cherryc49719f2018-01-10 11:04:34 -080097 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070098 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -080099 auto* failure = reply->mutable_failure();
Jiyong Park8fd64c82019-05-31 03:43:34 +0900100 failure->set_error_string(result.error().message());
101 failure->set_error_errno(result.error().code());
Tom Cherryc49719f2018-01-10 11:04:34 -0800102 }
103}
104
105void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
106 SubcontextReply* reply) const {
107 for (const auto& arg : expand_args_command.args()) {
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700108 auto expanded_arg = ExpandProps(arg);
109 if (!expanded_arg) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800110 auto* failure = reply->mutable_failure();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700111 failure->set_error_string(expanded_arg.error().message());
Tom Cherryc49719f2018-01-10 11:04:34 -0800112 failure->set_error_errno(0);
113 return;
114 } else {
115 auto* expand_args_reply = reply->mutable_expand_args_reply();
Tom Cherryc5cf85d2019-07-31 13:59:15 -0700116 expand_args_reply->add_expanded_args(*expanded_arg);
Tom Cherryc49719f2018-01-10 11:04:34 -0800117 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700118 }
119}
120
121void SubcontextProcess::MainLoop() {
122 pollfd ufd[1];
123 ufd[0].events = POLLIN;
124 ufd[0].fd = init_fd_;
125
126 while (true) {
127 ufd[0].revents = 0;
128 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
129 if (nr == 0) continue;
130 if (nr < 0) {
131 PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
132 }
133
134 auto init_message = ReadMessage(init_fd_);
135 if (!init_message) {
Jiyong Park8fd64c82019-05-31 03:43:34 +0900136 if (init_message.error().code() == 0) {
Luis Hector Chavez72353592018-09-21 12:27:02 -0700137 // If the init file descriptor was closed, let's exit quietly. If
138 // this was accidental, init will restart us. If init died, this
139 // avoids calling abort(3) unnecessarily.
140 return;
141 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700142 LOG(FATAL) << "Could not read message from init: " << init_message.error();
143 }
144
145 auto subcontext_command = SubcontextCommand();
146 if (!subcontext_command.ParseFromString(*init_message)) {
147 LOG(FATAL) << "Unable to parse message from init";
148 }
149
150 auto reply = SubcontextReply();
151 switch (subcontext_command.command_case()) {
152 case SubcontextCommand::kExecuteCommand: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800153 RunCommand(subcontext_command.execute_command(), &reply);
154 break;
155 }
156 case SubcontextCommand::kExpandArgsCommand: {
157 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700158 break;
159 }
160 default:
161 LOG(FATAL) << "Unknown message type from init: "
162 << subcontext_command.command_case();
163 }
164
165 if (auto result = SendMessage(init_fd_, reply); !result) {
166 LOG(FATAL) << "Failed to send message to init: " << result.error();
167 }
168 }
169}
170
171} // namespace
172
Tom Cherryd52a5b32019-07-22 16:05:36 -0700173int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700174 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
Tom Cherry0d1452e2017-10-19 14:39:35 -0700179 SelabelInitialize();
Tom Cherry32228482018-01-18 16:14:25 -0800180
Tom Cherry1ab3dfc2019-04-22 17:46:37 -0700181 property_set = [](const std::string& key, const std::string& value) -> uint32_t {
182 android::base::SetProperty(key, value);
183 return 0;
184 };
Tom Cherry32228482018-01-18 16:14:25 -0800185
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700186 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
187 subcontext_process.MainLoop();
188 return 0;
189}
190
191void Subcontext::Fork() {
192 unique_fd subcontext_socket;
193 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
194 LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
195 return;
196 }
197
198 auto result = fork();
199
200 if (result == -1) {
201 LOG(FATAL) << "Could not fork subcontext";
202 } else if (result == 0) {
203 socket_.reset();
204
205 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
206 // in the subcontext process after we exec.
Tom Cherry247ffbf2019-07-08 15:09:36 -0700207 int child_fd = dup(subcontext_socket); // NOLINT(android-cloexec-dup)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700208 if (child_fd < 0) {
209 PLOG(FATAL) << "Could not dup child_fd";
210 }
211
212 if (setexeccon(context_.c_str()) < 0) {
213 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
214 }
215
216 auto init_path = GetExecutablePath();
217 auto child_fd_string = std::to_string(child_fd);
218 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
219 child_fd_string.c_str(), nullptr};
220 execv(init_path.data(), const_cast<char**>(args));
221
222 PLOG(FATAL) << "Could not execv subcontext init";
223 } else {
224 subcontext_socket.reset();
225 pid_ = result;
226 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
227 }
228}
229
230void Subcontext::Restart() {
231 LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
232 if (pid_) {
233 kill(pid_, SIGKILL);
234 }
235 pid_ = 0;
236 socket_.reset();
237 Fork();
238}
239
Tom Cherryc49719f2018-01-10 11:04:34 -0800240Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700241 if (auto result = SendMessage(socket_, subcontext_command); !result) {
242 Restart();
243 return ErrnoError() << "Failed to send message to subcontext";
244 }
245
246 auto subcontext_message = ReadMessage(socket_);
247 if (!subcontext_message) {
248 Restart();
249 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
250 }
251
Tom Cherryc49719f2018-01-10 11:04:34 -0800252 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700253 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
254 Restart();
255 return Error() << "Unable to parse message from subcontext";
256 }
Tom Cherryc49719f2018-01-10 11:04:34 -0800257 return subcontext_reply;
258}
259
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700260Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800261 auto subcontext_command = SubcontextCommand();
262 std::copy(
263 args.begin(), args.end(),
264 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
265
266 auto subcontext_reply = TransmitMessage(subcontext_command);
267 if (!subcontext_reply) {
268 return subcontext_reply.error();
269 }
270
Tom Cherry32228482018-01-18 16:14:25 -0800271 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
272 auto& failure = subcontext_reply->failure();
273 return ResultError(failure.error_string(), failure.error_errno());
274 }
275
Tom Cherryc49719f2018-01-10 11:04:34 -0800276 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
277 return Error() << "Unexpected message type from subcontext: "
278 << subcontext_reply->reply_case();
279 }
280
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700281 return {};
Tom Cherryc49719f2018-01-10 11:04:34 -0800282}
283
284Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
285 auto subcontext_command = SubcontextCommand{};
286 std::copy(args.begin(), args.end(),
287 RepeatedPtrFieldBackInserter(
288 subcontext_command.mutable_expand_args_command()->mutable_args()));
289
290 auto subcontext_reply = TransmitMessage(subcontext_command);
291 if (!subcontext_reply) {
292 return subcontext_reply.error();
293 }
294
Tom Cherry32228482018-01-18 16:14:25 -0800295 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
296 auto& failure = subcontext_reply->failure();
297 return ResultError(failure.error_string(), failure.error_errno());
298 }
299
Tom Cherryc49719f2018-01-10 11:04:34 -0800300 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
301 return Error() << "Unexpected message type from subcontext: "
302 << subcontext_reply->reply_case();
303 }
304
305 auto& reply = subcontext_reply->expand_args_reply();
306 auto expanded_args = std::vector<std::string>{};
307 for (const auto& string : reply.expanded_args()) {
308 expanded_args.emplace_back(string);
309 }
310 return expanded_args;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700311}
312
313static std::vector<Subcontext> subcontexts;
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700314static bool shutting_down;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700315
316std::vector<Subcontext>* InitializeSubcontexts() {
Tom Cherry40acb372018-08-01 13:41:12 -0700317 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
Tom Cherrya1dbeb82018-04-11 15:50:00 -0700318 for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
319 subcontexts.emplace_back(path_prefix, secontext);
320 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700321 }
322 return &subcontexts;
323}
324
325bool SubcontextChildReap(pid_t pid) {
326 for (auto& subcontext : subcontexts) {
327 if (subcontext.pid() == pid) {
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700328 if (!shutting_down) {
329 subcontext.Restart();
330 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700331 return true;
332 }
333 }
334 return false;
335}
336
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700337void SubcontextTerminate() {
338 shutting_down = true;
339 for (auto& subcontext : subcontexts) {
340 kill(subcontext.pid(), SIGTERM);
341 }
342}
343
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700344} // namespace init
345} // namespace android