blob: be754da732d90f7ffe94534898a21ee5849d3b83 [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 Cherry0d1452e2017-10-19 14:39:35 -070030#include "selinux.h"
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070031#include "util.h"
32
33using android::base::GetExecutablePath;
34using android::base::Join;
35using android::base::Socketpair;
36using android::base::Split;
37using android::base::StartsWith;
38using android::base::unique_fd;
39
40namespace android {
41namespace init {
42
Tom Cherryac7428b2017-10-02 16:59:02 -070043const std::string kInitContext = "u:r:init:s0";
44const std::string kVendorContext = "u:r:vendor_init:s0";
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070045
46namespace {
47
48constexpr size_t kBufferSize = 4096;
49
50Result<std::string> ReadMessage(int socket) {
51 char buffer[kBufferSize] = {};
52 auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
53 if (result <= 0) {
54 return ErrnoError();
55 }
56 return std::string(buffer, result);
57}
58
59template <typename T>
60Result<Success> SendMessage(int socket, const T& message) {
61 std::string message_string;
62 if (!message.SerializeToString(&message_string)) {
63 return Error() << "Unable to serialize message";
64 }
65
66 if (message_string.size() > kBufferSize) {
67 return Error() << "Serialized message too long to send";
68 }
69
70 if (auto result =
71 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
72 result != static_cast<long>(message_string.size())) {
73 return ErrnoError() << "send() failed to send message contents";
74 }
75 return Success();
76}
77
78class SubcontextProcess {
79 public:
80 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd)
81 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
82 void MainLoop();
83
84 private:
85 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080086 SubcontextReply* reply) const;
87 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
88 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070089
90 const KeywordFunctionMap* function_map_;
91 const std::string context_;
92 const int init_fd_;
93};
94
95void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080096 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070097 // Need to use ArraySplice instead of this code.
98 auto args = std::vector<std::string>();
99 for (const auto& string : execute_command.args()) {
100 args.emplace_back(string);
101 }
102
103 auto map_result = function_map_->FindFunction(args);
104 Result<Success> result;
105 if (!map_result) {
106 result = Error() << "Cannot find command: " << map_result.error();
107 } else {
108 result = RunBuiltinFunction(map_result->second, args, context_);
109 }
110
111 if (result) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800112 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700113 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -0800114 auto* failure = reply->mutable_failure();
115 failure->set_error_string(result.error_string());
116 failure->set_error_errno(result.error_errno());
117 }
118}
119
120void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
121 SubcontextReply* reply) const {
122 for (const auto& arg : expand_args_command.args()) {
123 auto expanded_prop = std::string{};
124 if (!expand_props(arg, &expanded_prop)) {
125 auto* failure = reply->mutable_failure();
126 failure->set_error_string("Failed to expand '" + arg + "'");
127 failure->set_error_errno(0);
128 return;
129 } else {
130 auto* expand_args_reply = reply->mutable_expand_args_reply();
131 expand_args_reply->add_expanded_args(expanded_prop);
132 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700133 }
134}
135
136void SubcontextProcess::MainLoop() {
137 pollfd ufd[1];
138 ufd[0].events = POLLIN;
139 ufd[0].fd = init_fd_;
140
141 while (true) {
142 ufd[0].revents = 0;
143 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
144 if (nr == 0) continue;
145 if (nr < 0) {
146 PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
147 }
148
149 auto init_message = ReadMessage(init_fd_);
150 if (!init_message) {
151 LOG(FATAL) << "Could not read message from init: " << init_message.error();
152 }
153
154 auto subcontext_command = SubcontextCommand();
155 if (!subcontext_command.ParseFromString(*init_message)) {
156 LOG(FATAL) << "Unable to parse message from init";
157 }
158
159 auto reply = SubcontextReply();
160 switch (subcontext_command.command_case()) {
161 case SubcontextCommand::kExecuteCommand: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800162 RunCommand(subcontext_command.execute_command(), &reply);
163 break;
164 }
165 case SubcontextCommand::kExpandArgsCommand: {
166 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700167 break;
168 }
169 default:
170 LOG(FATAL) << "Unknown message type from init: "
171 << subcontext_command.command_case();
172 }
173
174 if (auto result = SendMessage(init_fd_, reply); !result) {
175 LOG(FATAL) << "Failed to send message to init: " << result.error();
176 }
177 }
178}
179
180} // namespace
181
182int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) {
183 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
184
185 auto context = std::string(argv[2]);
186 auto init_fd = std::atoi(argv[3]);
187
Tom Cherry0d1452e2017-10-19 14:39:35 -0700188 SelabelInitialize();
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700189 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
190 subcontext_process.MainLoop();
191 return 0;
192}
193
194void Subcontext::Fork() {
195 unique_fd subcontext_socket;
196 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
197 LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
198 return;
199 }
200
201 auto result = fork();
202
203 if (result == -1) {
204 LOG(FATAL) << "Could not fork subcontext";
205 } else if (result == 0) {
206 socket_.reset();
207
208 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
209 // in the subcontext process after we exec.
210 int child_fd = dup(subcontext_socket);
211 if (child_fd < 0) {
212 PLOG(FATAL) << "Could not dup child_fd";
213 }
214
215 if (setexeccon(context_.c_str()) < 0) {
216 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
217 }
218
219 auto init_path = GetExecutablePath();
220 auto child_fd_string = std::to_string(child_fd);
221 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
222 child_fd_string.c_str(), nullptr};
223 execv(init_path.data(), const_cast<char**>(args));
224
225 PLOG(FATAL) << "Could not execv subcontext init";
226 } else {
227 subcontext_socket.reset();
228 pid_ = result;
229 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
230 }
231}
232
233void Subcontext::Restart() {
234 LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
235 if (pid_) {
236 kill(pid_, SIGKILL);
237 }
238 pid_ = 0;
239 socket_.reset();
240 Fork();
241}
242
Tom Cherryc49719f2018-01-10 11:04:34 -0800243Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700244 if (auto result = SendMessage(socket_, subcontext_command); !result) {
245 Restart();
246 return ErrnoError() << "Failed to send message to subcontext";
247 }
248
249 auto subcontext_message = ReadMessage(socket_);
250 if (!subcontext_message) {
251 Restart();
252 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
253 }
254
Tom Cherryc49719f2018-01-10 11:04:34 -0800255 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700256 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
257 Restart();
258 return Error() << "Unable to parse message from subcontext";
259 }
Tom Cherryc49719f2018-01-10 11:04:34 -0800260 if (subcontext_reply.reply_case() == SubcontextReply::kFailure) {
261 auto& failure = subcontext_reply.failure();
262 return ResultError(failure.error_string(), failure.error_errno());
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700263 }
Tom Cherryc49719f2018-01-10 11:04:34 -0800264 return subcontext_reply;
265}
266
267Result<Success> Subcontext::Execute(const std::vector<std::string>& args) {
268 auto subcontext_command = SubcontextCommand();
269 std::copy(
270 args.begin(), args.end(),
271 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
272
273 auto subcontext_reply = TransmitMessage(subcontext_command);
274 if (!subcontext_reply) {
275 return subcontext_reply.error();
276 }
277
278 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
279 return Error() << "Unexpected message type from subcontext: "
280 << subcontext_reply->reply_case();
281 }
282
283 return Success();
284}
285
286Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
287 auto subcontext_command = SubcontextCommand{};
288 std::copy(args.begin(), args.end(),
289 RepeatedPtrFieldBackInserter(
290 subcontext_command.mutable_expand_args_command()->mutable_args()));
291
292 auto subcontext_reply = TransmitMessage(subcontext_command);
293 if (!subcontext_reply) {
294 return subcontext_reply.error();
295 }
296
297 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
298 return Error() << "Unexpected message type from subcontext: "
299 << subcontext_reply->reply_case();
300 }
301
302 auto& reply = subcontext_reply->expand_args_reply();
303 auto expanded_args = std::vector<std::string>{};
304 for (const auto& string : reply.expanded_args()) {
305 expanded_args.emplace_back(string);
306 }
307 return expanded_args;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700308}
309
310static std::vector<Subcontext> subcontexts;
311
312std::vector<Subcontext>* InitializeSubcontexts() {
Tom Cherry193e4342017-11-27 09:02:08 -0800313 static const char* const paths_and_secontexts[][2] = {
314 {"/vendor", kVendorContext.c_str()},
315 };
316 for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
317 subcontexts.emplace_back(path_prefix, secontext);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700318 }
319 return &subcontexts;
320}
321
322bool SubcontextChildReap(pid_t pid) {
323 for (auto& subcontext : subcontexts) {
324 if (subcontext.pid() == pid) {
325 subcontext.Restart();
326 return true;
327 }
328 }
329 return false;
330}
331
332} // namespace init
333} // namespace android