blob: f3b643ad7e27823872c19babb440491e5fc7f4a0 [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 Cherry32228482018-01-18 16:14:25 -080030#include "property_service.h"
Tom Cherry0d1452e2017-10-19 14:39:35 -070031#include "selinux.h"
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070032#include "util.h"
33
Tom Cherry32228482018-01-18 16:14:25 -080034#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
35#include <sys/_system_properties.h>
36
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070037using android::base::GetExecutablePath;
38using android::base::Join;
39using android::base::Socketpair;
40using android::base::Split;
41using android::base::StartsWith;
42using android::base::unique_fd;
43
44namespace android {
45namespace init {
46
Tom Cherryac7428b2017-10-02 16:59:02 -070047const std::string kInitContext = "u:r:init:s0";
48const std::string kVendorContext = "u:r:vendor_init:s0";
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070049
50namespace {
51
52constexpr size_t kBufferSize = 4096;
53
54Result<std::string> ReadMessage(int socket) {
55 char buffer[kBufferSize] = {};
56 auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0));
57 if (result <= 0) {
58 return ErrnoError();
59 }
60 return std::string(buffer, result);
61}
62
63template <typename T>
64Result<Success> SendMessage(int socket, const T& message) {
65 std::string message_string;
66 if (!message.SerializeToString(&message_string)) {
67 return Error() << "Unable to serialize message";
68 }
69
70 if (message_string.size() > kBufferSize) {
71 return Error() << "Serialized message too long to send";
72 }
73
74 if (auto result =
75 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0));
76 result != static_cast<long>(message_string.size())) {
77 return ErrnoError() << "send() failed to send message contents";
78 }
79 return Success();
80}
81
Tom Cherry32228482018-01-18 16:14:25 -080082std::vector<std::pair<std::string, std::string>> properties_to_set;
83
84uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
85 properties_to_set.emplace_back(name, value);
86 return PROP_SUCCESS;
87}
88
Tom Cherrycb0f9bb2017-09-12 15:58:47 -070089class SubcontextProcess {
90 public:
91 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd)
92 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){};
93 void MainLoop();
94
95 private:
96 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -080097 SubcontextReply* reply) const;
98 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
99 SubcontextReply* reply) const;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700100
101 const KeywordFunctionMap* function_map_;
102 const std::string context_;
103 const int init_fd_;
104};
105
106void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command,
Tom Cherryc49719f2018-01-10 11:04:34 -0800107 SubcontextReply* reply) const {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700108 // Need to use ArraySplice instead of this code.
109 auto args = std::vector<std::string>();
110 for (const auto& string : execute_command.args()) {
111 args.emplace_back(string);
112 }
113
114 auto map_result = function_map_->FindFunction(args);
115 Result<Success> result;
116 if (!map_result) {
117 result = Error() << "Cannot find command: " << map_result.error();
118 } else {
119 result = RunBuiltinFunction(map_result->second, args, context_);
120 }
121
Tom Cherry32228482018-01-18 16:14:25 -0800122 for (const auto& [name, value] : properties_to_set) {
123 auto property = reply->add_properties_to_set();
124 property->set_name(name);
125 property->set_value(value);
126 }
127
128 properties_to_set.clear();
129
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700130 if (result) {
Tom Cherryc49719f2018-01-10 11:04:34 -0800131 reply->set_success(true);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700132 } else {
Tom Cherryc49719f2018-01-10 11:04:34 -0800133 auto* failure = reply->mutable_failure();
134 failure->set_error_string(result.error_string());
135 failure->set_error_errno(result.error_errno());
136 }
137}
138
139void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command,
140 SubcontextReply* reply) const {
141 for (const auto& arg : expand_args_command.args()) {
142 auto expanded_prop = std::string{};
143 if (!expand_props(arg, &expanded_prop)) {
144 auto* failure = reply->mutable_failure();
145 failure->set_error_string("Failed to expand '" + arg + "'");
146 failure->set_error_errno(0);
147 return;
148 } else {
149 auto* expand_args_reply = reply->mutable_expand_args_reply();
150 expand_args_reply->add_expanded_args(expanded_prop);
151 }
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700152 }
153}
154
155void SubcontextProcess::MainLoop() {
156 pollfd ufd[1];
157 ufd[0].events = POLLIN;
158 ufd[0].fd = init_fd_;
159
160 while (true) {
161 ufd[0].revents = 0;
162 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1));
163 if (nr == 0) continue;
164 if (nr < 0) {
165 PLOG(FATAL) << "poll() of subcontext socket failed, continuing";
166 }
167
168 auto init_message = ReadMessage(init_fd_);
169 if (!init_message) {
170 LOG(FATAL) << "Could not read message from init: " << init_message.error();
171 }
172
173 auto subcontext_command = SubcontextCommand();
174 if (!subcontext_command.ParseFromString(*init_message)) {
175 LOG(FATAL) << "Unable to parse message from init";
176 }
177
178 auto reply = SubcontextReply();
179 switch (subcontext_command.command_case()) {
180 case SubcontextCommand::kExecuteCommand: {
Tom Cherryc49719f2018-01-10 11:04:34 -0800181 RunCommand(subcontext_command.execute_command(), &reply);
182 break;
183 }
184 case SubcontextCommand::kExpandArgsCommand: {
185 ExpandArgs(subcontext_command.expand_args_command(), &reply);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700186 break;
187 }
188 default:
189 LOG(FATAL) << "Unknown message type from init: "
190 << subcontext_command.command_case();
191 }
192
193 if (auto result = SendMessage(init_fd_, reply); !result) {
194 LOG(FATAL) << "Failed to send message to init: " << result.error();
195 }
196 }
197}
198
199} // namespace
200
201int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) {
202 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")";
203
204 auto context = std::string(argv[2]);
205 auto init_fd = std::atoi(argv[3]);
206
Tom Cherry0d1452e2017-10-19 14:39:35 -0700207 SelabelInitialize();
Tom Cherry32228482018-01-18 16:14:25 -0800208
209 property_set = SubcontextPropertySet;
210
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700211 auto subcontext_process = SubcontextProcess(function_map, context, init_fd);
212 subcontext_process.MainLoop();
213 return 0;
214}
215
216void Subcontext::Fork() {
217 unique_fd subcontext_socket;
218 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) {
219 LOG(FATAL) << "Could not create socket pair to communicate to subcontext";
220 return;
221 }
222
223 auto result = fork();
224
225 if (result == -1) {
226 LOG(FATAL) << "Could not fork subcontext";
227 } else if (result == 0) {
228 socket_.reset();
229
230 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number
231 // in the subcontext process after we exec.
232 int child_fd = dup(subcontext_socket);
233 if (child_fd < 0) {
234 PLOG(FATAL) << "Could not dup child_fd";
235 }
236
237 if (setexeccon(context_.c_str()) < 0) {
238 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'";
239 }
240
241 auto init_path = GetExecutablePath();
242 auto child_fd_string = std::to_string(child_fd);
243 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(),
244 child_fd_string.c_str(), nullptr};
245 execv(init_path.data(), const_cast<char**>(args));
246
247 PLOG(FATAL) << "Could not execv subcontext init";
248 } else {
249 subcontext_socket.reset();
250 pid_ = result;
251 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_;
252 }
253}
254
255void Subcontext::Restart() {
256 LOG(ERROR) << "Restarting subcontext '" << context_ << "'";
257 if (pid_) {
258 kill(pid_, SIGKILL);
259 }
260 pid_ = 0;
261 socket_.reset();
262 Fork();
263}
264
Tom Cherryc49719f2018-01-10 11:04:34 -0800265Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) {
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700266 if (auto result = SendMessage(socket_, subcontext_command); !result) {
267 Restart();
268 return ErrnoError() << "Failed to send message to subcontext";
269 }
270
271 auto subcontext_message = ReadMessage(socket_);
272 if (!subcontext_message) {
273 Restart();
274 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error();
275 }
276
Tom Cherryc49719f2018-01-10 11:04:34 -0800277 auto subcontext_reply = SubcontextReply{};
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700278 if (!subcontext_reply.ParseFromString(*subcontext_message)) {
279 Restart();
280 return Error() << "Unable to parse message from subcontext";
281 }
Tom Cherryc49719f2018-01-10 11:04:34 -0800282 return subcontext_reply;
283}
284
285Result<Success> Subcontext::Execute(const std::vector<std::string>& args) {
286 auto subcontext_command = SubcontextCommand();
287 std::copy(
288 args.begin(), args.end(),
289 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args()));
290
291 auto subcontext_reply = TransmitMessage(subcontext_command);
292 if (!subcontext_reply) {
293 return subcontext_reply.error();
294 }
295
Tom Cherry32228482018-01-18 16:14:25 -0800296 for (const auto& property : subcontext_reply->properties_to_set()) {
297 ucred cr = {.pid = pid_, .uid = 0, .gid = 0};
298 HandlePropertySet(property.name(), property.value(), context_, cr);
299 }
300
301 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
302 auto& failure = subcontext_reply->failure();
303 return ResultError(failure.error_string(), failure.error_errno());
304 }
305
Tom Cherryc49719f2018-01-10 11:04:34 -0800306 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) {
307 return Error() << "Unexpected message type from subcontext: "
308 << subcontext_reply->reply_case();
309 }
310
311 return Success();
312}
313
314Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) {
315 auto subcontext_command = SubcontextCommand{};
316 std::copy(args.begin(), args.end(),
317 RepeatedPtrFieldBackInserter(
318 subcontext_command.mutable_expand_args_command()->mutable_args()));
319
320 auto subcontext_reply = TransmitMessage(subcontext_command);
321 if (!subcontext_reply) {
322 return subcontext_reply.error();
323 }
324
Tom Cherry32228482018-01-18 16:14:25 -0800325 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) {
326 auto& failure = subcontext_reply->failure();
327 return ResultError(failure.error_string(), failure.error_errno());
328 }
329
Tom Cherryc49719f2018-01-10 11:04:34 -0800330 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) {
331 return Error() << "Unexpected message type from subcontext: "
332 << subcontext_reply->reply_case();
333 }
334
335 auto& reply = subcontext_reply->expand_args_reply();
336 auto expanded_args = std::vector<std::string>{};
337 for (const auto& string : reply.expanded_args()) {
338 expanded_args.emplace_back(string);
339 }
340 return expanded_args;
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700341}
342
343static std::vector<Subcontext> subcontexts;
344
345std::vector<Subcontext>* InitializeSubcontexts() {
Tom Cherry193e4342017-11-27 09:02:08 -0800346 static const char* const paths_and_secontexts[][2] = {
347 {"/vendor", kVendorContext.c_str()},
348 };
349 for (const auto& [path_prefix, secontext] : paths_and_secontexts) {
350 subcontexts.emplace_back(path_prefix, secontext);
Tom Cherrycb0f9bb2017-09-12 15:58:47 -0700351 }
352 return &subcontexts;
353}
354
355bool SubcontextChildReap(pid_t pid) {
356 for (auto& subcontext : subcontexts) {
357 if (subcontext.pid() == pid) {
358 subcontext.Restart();
359 return true;
360 }
361 }
362 return false;
363}
364
365} // namespace init
366} // namespace android