blob: a13f0c7667ff0c55d7add481fa623d391a4e6dfb [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>
21#include <sys/socket.h>
22#include <unistd.h>
23
24#include <android-base/file.h>
25#include <android-base/logging.h>
26#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 Cherrycb0f9bb2017-09-12 15:58:47 -070031#include "util.h"
32
Tom Cherryde6bd502018-02-13 16:50:08 -080033#if defined(__ANDROID__)
Tom Cherry40acb372018-08-01 13:41:12 -070034#include <android/api-level.h>
Tom Cherryde6bd502018-02-13 16:50:08 -080035#include "property_service.h"
Vic Yang92c236e2019-05-28 15:58:35 -070036#include "selabel.h"
Tom Cherryde6bd502018-02-13 16:50:08 -080037#include "selinux.h"
38#else
39#include "host_init_stubs.h"
40#endif
Tom Cherry32228482018-01-18 16:14:25 -080041
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070042using android::base::GetExecutablePath;
43using android::base::Join;
44using android::base::Socketpair;
45using android::base::Split;
46using android::base::StartsWith;
47using android::base::unique_fd;
48
49namespace android {
50namespace init {
51
Tom Cherryac7428b2017-10-02 16:59:02 -070052const std::string kInitContext = "u:r:init:s0";
53const std::string kVendorContext = "u:r:vendor_init:s0";
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070054
Tom Cherrydc375862018-02-28 10:39:01 -080055const char* const paths_and_secontexts[2][2] = {
56 {"/vendor", kVendorContext.c_str()},
57 {"/odm", kVendorContext.c_str()},
58};
59
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070060namespace {
61
62constexpr size_t kBufferSize = 4096;
63
64Result<std::string> ReadMessage(int socket) {
65 char buffer[kBufferSize] = {};
66 auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
Luis Hector Chavez72353592018-09-21 12:27:02 -070067 if (result == 0) {
68 return Error();
69 } else if (result < 0) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070070 return ErrnoError();
71 }
72 return std::string(buffer, result);
73}
74
75template <typename T>
Tom Cherrybbcbc2f2019-06-10 11:08:01 -070076Result<void> SendMessage(int socket, const T& message) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070077 std::string message_string;
78 if (!message.SerializeToString(&message_string)) {
79 return Error() << "Unable to serialize message";
80 }
81
82 if (message_string.size() > kBufferSize) {
83 return Error() << "Serialized message too long to send";
84 }
85
86 if (auto result =
87 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
88 result != static_cast<long>(message_string.size())) {
89 return ErrnoError() << "send() failed to send message contents";
90 }
Tom Cherrybbcbc2f2019-06-10 11:08:01 -070091 return {};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070092}
93
Tom Cherry32228482018-01-18 16:14:25 -080094std::vector<std::pair<std::string, std::string>> properties_to_set;
95
96uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
97 properties_to_set.emplace_back(name, value);
Tom Cherryde6bd502018-02-13 16:50:08 -080098 return 0;
Tom Cherry32228482018-01-18 16:14:25 -080099}
100
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700101class SubcontextProcess {
102 public:
Tom Cherryd52a5b32019-07-22 16:05:36 -0700103 SubcontextProcess(const BuiltinFunctionMap* function_map, std::string context, int init_fd)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700104 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
105 void MainLoop();
106
107 private:
108 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -0800109 SubcontextReply* reply) const;
110 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
111 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700112
Tom Cherryd52a5b32019-07-22 16:05:36 -0700113 const BuiltinFunctionMap* function_map_;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700114 const std::string context_;
115 const int init_fd_;
116};
117
118void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -0800119 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700120 // Need to use ArraySplice instead of this code.
121 auto args = std::vector<std::string>();
122 for (const auto& string : execute_command.args()) {
123 args.emplace_back(string);
124 }
125
Tom Cherryd52a5b32019-07-22 16:05:36 -0700126 auto map_result = function_map_->Find(args);
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700127 Result<void> result;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700128 if (!map_result) {
129 result = Error() << "Cannot find command: " << map_result.error();
130 } else {
Tom Cherryd52a5b32019-07-22 16:05:36 -0700131 result = RunBuiltinFunction(map_result->function, args, context_);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700132 }
133
Tom Cherry32228482018-01-18 16:14:25 -0800134 for (const auto& [name, value] : properties_to_set) {
135 auto property = reply->add_properties_to_set();
136 property->set_name(name);
137 property->set_value(value);
138 }
139
140 properties_to_set.clear();
141
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700142 if (result) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800143 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700144 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -0800145 auto* failure = reply->mutable_failure();
Jiyong Park8fd64c82019-05-31 03:43:34 +0900146 failure->set_error_string(result.error().message());
147 failure->set_error_errno(result.error().code());
Tom Cherryc49719f2018-01-10 11:04:34 -0800148 }
149}
150
151void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
152 SubcontextReply* reply) const {
153 for (const auto& arg : expand_args_command.args()) {
154 auto expanded_prop = std::string{};
155 if (!expand_props(arg, &expanded_prop)) {
156 auto* failure = reply->mutable_failure();
157 failure->set_error_string("Failed to expand '" + arg + "'");
158 failure->set_error_errno(0);
159 return;
160 } else {
161 auto* expand_args_reply = reply->mutable_expand_args_reply();
162 expand_args_reply->add_expanded_args(expanded_prop);
163 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700164 }
165}
166
167void SubcontextProcess::MainLoop() {
168 pollfd ufd[1];
169 ufd[0].events = POLLIN;
170 ufd[0].fd = init_fd_;
171
172 while (true) {
173 ufd[0].revents = 0;
174 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
175 if (nr == 0) continue;
176 if (nr < 0) {
177 PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
178 }
179
180 auto init_message = ReadMessage(init_fd_);
181 if (!init_message) {
Jiyong Park8fd64c82019-05-31 03:43:34 +0900182 if (init_message.error().code() == 0) {
Luis Hector Chavez72353592018-09-21 12:27:02 -0700183 // If the init file descriptor was closed, let's exit quietly. If
184 // this was accidental, init will restart us. If init died, this
185 // avoids calling abort(3) unnecessarily.
186 return;
187 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700188 LOG(FATAL) << "Could not read message from init: " << init_message.error();
189 }
190
191 auto subcontext_command = SubcontextCommand();
192 if (!subcontext_command.ParseFromString(*init_message)) {
193 LOG(FATAL) << "Unable to parse message from init";
194 }
195
196 auto reply = SubcontextReply();
197 switch (subcontext_command.command_case()) {
198 case SubcontextCommand::kExecuteCommand: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800199 RunCommand(subcontext_command.execute_command(), &reply);
200 break;
201 }
202 case SubcontextCommand::kExpandArgsCommand: {
203 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700204 break;
205 }
206 default:
207 LOG(FATAL) << "Unknown message type from init: "
208 << subcontext_command.command_case();
209 }
210
211 if (auto result = SendMessage(init_fd_, reply); !result) {
212 LOG(FATAL) << "Failed to send message to init: " << result.error();
213 }
214 }
215}
216
217} // namespace
218
Tom Cherryd52a5b32019-07-22 16:05:36 -0700219int SubcontextMain(int argc, char** argv, const BuiltinFunctionMap* function_map) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700220 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
221
222 auto context = std::string(argv[2]);
223 auto init_fd = std::atoi(argv[3]);
224
Tom Cherry0d1452e2017-10-19 14:39:35 -0700225 SelabelInitialize();
Tom Cherry32228482018-01-18 16:14:25 -0800226
227 property_set = SubcontextPropertySet;
228
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700229 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
230 subcontext_process.MainLoop();
231 return 0;
232}
233
234void Subcontext::Fork() {
235 unique_fd subcontext_socket;
236 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
237 LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
238 return;
239 }
240
241 auto result = fork();
242
243 if (result == -1) {
244 LOG(FATAL) << "Could not fork subcontext";
245 } else if (result == 0) {
246 socket_.reset();
247
248 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
249 // in the subcontext process after we exec.
Tom Cherry247ffbf2019-07-08 15:09:36 -0700250 int child_fd = dup(subcontext_socket); // NOLINT(android-cloexec-dup)
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700251 if (child_fd < 0) {
252 PLOG(FATAL) << "Could not dup child_fd";
253 }
254
255 if (setexeccon(context_.c_str()) < 0) {
256 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
257 }
258
259 auto init_path = GetExecutablePath();
260 auto child_fd_string = std::to_string(child_fd);
261 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
262 child_fd_string.c_str(), nullptr};
263 execv(init_path.data(), const_cast<char**>(args));
264
265 PLOG(FATAL) << "Could not execv subcontext init";
266 } else {
267 subcontext_socket.reset();
268 pid_ = result;
269 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
270 }
271}
272
273void Subcontext::Restart() {
274 LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
275 if (pid_) {
276 kill(pid_, SIGKILL);
277 }
278 pid_ = 0;
279 socket_.reset();
280 Fork();
281}
282
Tom Cherryc49719f2018-01-10 11:04:34 -0800283Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700284 if (auto result = SendMessage(socket_, subcontext_command); !result) {
285 Restart();
286 return ErrnoError() << "Failed to send message to subcontext";
287 }
288
289 auto subcontext_message = ReadMessage(socket_);
290 if (!subcontext_message) {
291 Restart();
292 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
293 }
294
Tom Cherryc49719f2018-01-10 11:04:34 -0800295 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700296 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
297 Restart();
298 return Error() << "Unable to parse message from subcontext";
299 }
Tom Cherryc49719f2018-01-10 11:04:34 -0800300 return subcontext_reply;
301}
302
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700303Result<void> Subcontext::Execute(const std::vector<std::string>& args) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800304 auto subcontext_command = SubcontextCommand();
305 std::copy(
306 args.begin(), args.end(),
307 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
308
309 auto subcontext_reply = TransmitMessage(subcontext_command);
310 if (!subcontext_reply) {
311 return subcontext_reply.error();
312 }
313
Tom Cherry32228482018-01-18 16:14:25 -0800314 for (const auto& property : subcontext_reply->properties_to_set()) {
315 ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
Tom Cherry69d47aa2018-03-01 11:00:57 -0800316 std::string error;
317 if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) {
318 LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '"
319 << property.value() << "': " << error;
320 }
Tom Cherry32228482018-01-18 16:14:25 -0800321 }
322
323 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
324 auto& failure = subcontext_reply->failure();
325 return ResultError(failure.error_string(), failure.error_errno());
326 }
327
Tom Cherryc49719f2018-01-10 11:04:34 -0800328 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
329 return Error() << "Unexpected message type from subcontext: "
330 << subcontext_reply->reply_case();
331 }
332
Tom Cherrybbcbc2f2019-06-10 11:08:01 -0700333 return {};
Tom Cherryc49719f2018-01-10 11:04:34 -0800334}
335
336Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
337 auto subcontext_command = SubcontextCommand{};
338 std::copy(args.begin(), args.end(),
339 RepeatedPtrFieldBackInserter(
340 subcontext_command.mutable_expand_args_command()->mutable_args()));
341
342 auto subcontext_reply = TransmitMessage(subcontext_command);
343 if (!subcontext_reply) {
344 return subcontext_reply.error();
345 }
346
Tom Cherry32228482018-01-18 16:14:25 -0800347 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
348 auto& failure = subcontext_reply->failure();
349 return ResultError(failure.error_string(), failure.error_errno());
350 }
351
Tom Cherryc49719f2018-01-10 11:04:34 -0800352 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
353 return Error() << "Unexpected message type from subcontext: "
354 << subcontext_reply->reply_case();
355 }
356
357 auto& reply = subcontext_reply->expand_args_reply();
358 auto expanded_args = std::vector<std::string>{};
359 for (const auto& string : reply.expanded_args()) {
360 expanded_args.emplace_back(string);
361 }
362 return expanded_args;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700363}
364
365static std::vector<Subcontext> subcontexts;
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700366static bool shutting_down;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700367
368std::vector<Subcontext>* InitializeSubcontexts() {
Tom Cherry40acb372018-08-01 13:41:12 -0700369 if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) {
Tom Cherrya1dbeb82018-04-11 15:50:00 -0700370 for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
371 subcontexts.emplace_back(path_prefix, secontext);
372 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700373 }
374 return &subcontexts;
375}
376
377bool SubcontextChildReap(pid_t pid) {
378 for (auto& subcontext : subcontexts) {
379 if (subcontext.pid() == pid) {
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700380 if (!shutting_down) {
381 subcontext.Restart();
382 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700383 return true;
384 }
385 }
386 return false;
387}
388
Luis Hector Chavez92c49bc2018-07-27 11:19:25 -0700389void SubcontextTerminate() {
390 shutting_down = true;
391 for (auto& subcontext : subcontexts) {
392 kill(subcontext.pid(), SIGTERM);
393 }
394}
395
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700396} // namespace init
397} // namespace android