subcontext.cpp revision c50144ef1d7ddebed3f765f176fa3a03d3d5f521
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 <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" 30#include "util.h" 31 32#if defined(__ANDROID__) 33#include <android-base/properties.h> 34 35#include "property_service.h" 36#include "selinux.h" 37#else 38#include "host_init_stubs.h" 39#endif 40 41using android::base::GetExecutablePath; 42using android::base::GetIntProperty; 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 52const std::string kInitContext = "u:r:init:s0"; 53const std::string kVendorContext = "u:r:vendor_init:s0"; 54 55const char* const paths_and_secontexts[2][2] = { 56 {"/vendor", kVendorContext.c_str()}, 57 {"/odm", kVendorContext.c_str()}, 58}; 59 60namespace { 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)); 67 if (result <= 0) { 68 return ErrnoError(); 69 } 70 return std::string(buffer, result); 71} 72 73template <typename T> 74Result<Success> SendMessage(int socket, const T& message) { 75 std::string message_string; 76 if (!message.SerializeToString(&message_string)) { 77 return Error() << "Unable to serialize message"; 78 } 79 80 if (message_string.size() > kBufferSize) { 81 return Error() << "Serialized message too long to send"; 82 } 83 84 if (auto result = 85 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); 86 result != static_cast<long>(message_string.size())) { 87 return ErrnoError() << "send() failed to send message contents"; 88 } 89 return Success(); 90} 91 92std::vector<std::pair<std::string, std::string>> properties_to_set; 93 94uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) { 95 properties_to_set.emplace_back(name, value); 96 return 0; 97} 98 99class SubcontextProcess { 100 public: 101 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) 102 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){}; 103 void MainLoop(); 104 105 private: 106 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 107 SubcontextReply* reply) const; 108 void ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command, 109 SubcontextReply* reply) const; 110 111 const KeywordFunctionMap* function_map_; 112 const std::string context_; 113 const int init_fd_; 114}; 115 116void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 117 SubcontextReply* reply) const { 118 // Need to use ArraySplice instead of this code. 119 auto args = std::vector<std::string>(); 120 for (const auto& string : execute_command.args()) { 121 args.emplace_back(string); 122 } 123 124 auto map_result = function_map_->FindFunction(args); 125 Result<Success> result; 126 if (!map_result) { 127 result = Error() << "Cannot find command: " << map_result.error(); 128 } else { 129 result = RunBuiltinFunction(map_result->second, args, context_); 130 } 131 132 for (const auto& [name, value] : properties_to_set) { 133 auto property = reply->add_properties_to_set(); 134 property->set_name(name); 135 property->set_value(value); 136 } 137 138 properties_to_set.clear(); 139 140 if (result) { 141 reply->set_success(true); 142 } else { 143 auto* failure = reply->mutable_failure(); 144 failure->set_error_string(result.error_string()); 145 failure->set_error_errno(result.error_errno()); 146 } 147} 148 149void SubcontextProcess::ExpandArgs(const SubcontextCommand::ExpandArgsCommand& expand_args_command, 150 SubcontextReply* reply) const { 151 for (const auto& arg : expand_args_command.args()) { 152 auto expanded_prop = std::string{}; 153 if (!expand_props(arg, &expanded_prop)) { 154 auto* failure = reply->mutable_failure(); 155 failure->set_error_string("Failed to expand '" + arg + "'"); 156 failure->set_error_errno(0); 157 return; 158 } else { 159 auto* expand_args_reply = reply->mutable_expand_args_reply(); 160 expand_args_reply->add_expanded_args(expanded_prop); 161 } 162 } 163} 164 165void SubcontextProcess::MainLoop() { 166 pollfd ufd[1]; 167 ufd[0].events = POLLIN; 168 ufd[0].fd = init_fd_; 169 170 while (true) { 171 ufd[0].revents = 0; 172 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1)); 173 if (nr == 0) continue; 174 if (nr < 0) { 175 PLOG(FATAL) << "poll() of subcontext socket failed, continuing"; 176 } 177 178 auto init_message = ReadMessage(init_fd_); 179 if (!init_message) { 180 LOG(FATAL) << "Could not read message from init: " << init_message.error(); 181 } 182 183 auto subcontext_command = SubcontextCommand(); 184 if (!subcontext_command.ParseFromString(*init_message)) { 185 LOG(FATAL) << "Unable to parse message from init"; 186 } 187 188 auto reply = SubcontextReply(); 189 switch (subcontext_command.command_case()) { 190 case SubcontextCommand::kExecuteCommand: { 191 RunCommand(subcontext_command.execute_command(), &reply); 192 break; 193 } 194 case SubcontextCommand::kExpandArgsCommand: { 195 ExpandArgs(subcontext_command.expand_args_command(), &reply); 196 break; 197 } 198 default: 199 LOG(FATAL) << "Unknown message type from init: " 200 << subcontext_command.command_case(); 201 } 202 203 if (auto result = SendMessage(init_fd_, reply); !result) { 204 LOG(FATAL) << "Failed to send message to init: " << result.error(); 205 } 206 } 207} 208 209} // namespace 210 211int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) { 212 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")"; 213 214 auto context = std::string(argv[2]); 215 auto init_fd = std::atoi(argv[3]); 216 217 SelabelInitialize(); 218 219 property_set = SubcontextPropertySet; 220 221 auto subcontext_process = SubcontextProcess(function_map, context, init_fd); 222 subcontext_process.MainLoop(); 223 return 0; 224} 225 226void Subcontext::Fork() { 227 unique_fd subcontext_socket; 228 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) { 229 LOG(FATAL) << "Could not create socket pair to communicate to subcontext"; 230 return; 231 } 232 233 auto result = fork(); 234 235 if (result == -1) { 236 LOG(FATAL) << "Could not fork subcontext"; 237 } else if (result == 0) { 238 socket_.reset(); 239 240 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number 241 // in the subcontext process after we exec. 242 int child_fd = dup(subcontext_socket); 243 if (child_fd < 0) { 244 PLOG(FATAL) << "Could not dup child_fd"; 245 } 246 247 if (setexeccon(context_.c_str()) < 0) { 248 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'"; 249 } 250 251 auto init_path = GetExecutablePath(); 252 auto child_fd_string = std::to_string(child_fd); 253 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(), 254 child_fd_string.c_str(), nullptr}; 255 execv(init_path.data(), const_cast<char**>(args)); 256 257 PLOG(FATAL) << "Could not execv subcontext init"; 258 } else { 259 subcontext_socket.reset(); 260 pid_ = result; 261 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_; 262 } 263} 264 265void Subcontext::Restart() { 266 LOG(ERROR) << "Restarting subcontext '" << context_ << "'"; 267 if (pid_) { 268 kill(pid_, SIGKILL); 269 } 270 pid_ = 0; 271 socket_.reset(); 272 Fork(); 273} 274 275Result<SubcontextReply> Subcontext::TransmitMessage(const SubcontextCommand& subcontext_command) { 276 if (auto result = SendMessage(socket_, subcontext_command); !result) { 277 Restart(); 278 return ErrnoError() << "Failed to send message to subcontext"; 279 } 280 281 auto subcontext_message = ReadMessage(socket_); 282 if (!subcontext_message) { 283 Restart(); 284 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error(); 285 } 286 287 auto subcontext_reply = SubcontextReply{}; 288 if (!subcontext_reply.ParseFromString(*subcontext_message)) { 289 Restart(); 290 return Error() << "Unable to parse message from subcontext"; 291 } 292 return subcontext_reply; 293} 294 295Result<Success> Subcontext::Execute(const std::vector<std::string>& args) { 296 auto subcontext_command = SubcontextCommand(); 297 std::copy( 298 args.begin(), args.end(), 299 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args())); 300 301 auto subcontext_reply = TransmitMessage(subcontext_command); 302 if (!subcontext_reply) { 303 return subcontext_reply.error(); 304 } 305 306 for (const auto& property : subcontext_reply->properties_to_set()) { 307 ucred cr = {.pid = pid_, .uid = 0, .gid = 0}; 308 std::string error; 309 if (HandlePropertySet(property.name(), property.value(), context_, cr, &error) != 0) { 310 LOG(ERROR) << "Subcontext init could not set '" << property.name() << "' to '" 311 << property.value() << "': " << error; 312 } 313 } 314 315 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { 316 auto& failure = subcontext_reply->failure(); 317 return ResultError(failure.error_string(), failure.error_errno()); 318 } 319 320 if (subcontext_reply->reply_case() != SubcontextReply::kSuccess) { 321 return Error() << "Unexpected message type from subcontext: " 322 << subcontext_reply->reply_case(); 323 } 324 325 return Success(); 326} 327 328Result<std::vector<std::string>> Subcontext::ExpandArgs(const std::vector<std::string>& args) { 329 auto subcontext_command = SubcontextCommand{}; 330 std::copy(args.begin(), args.end(), 331 RepeatedPtrFieldBackInserter( 332 subcontext_command.mutable_expand_args_command()->mutable_args())); 333 334 auto subcontext_reply = TransmitMessage(subcontext_command); 335 if (!subcontext_reply) { 336 return subcontext_reply.error(); 337 } 338 339 if (subcontext_reply->reply_case() == SubcontextReply::kFailure) { 340 auto& failure = subcontext_reply->failure(); 341 return ResultError(failure.error_string(), failure.error_errno()); 342 } 343 344 if (subcontext_reply->reply_case() != SubcontextReply::kExpandArgsReply) { 345 return Error() << "Unexpected message type from subcontext: " 346 << subcontext_reply->reply_case(); 347 } 348 349 auto& reply = subcontext_reply->expand_args_reply(); 350 auto expanded_args = std::vector<std::string>{}; 351 for (const auto& string : reply.expanded_args()) { 352 expanded_args.emplace_back(string); 353 } 354 return expanded_args; 355} 356 357static std::vector<Subcontext> subcontexts; 358 359std::vector<Subcontext>* InitializeSubcontexts() { 360 if (SelinuxHasVendorInit()) { 361 for (const auto& [path_prefix, secontext] : paths_and_secontexts) { 362 subcontexts.emplace_back(path_prefix, secontext); 363 } 364 } 365 return &subcontexts; 366} 367 368bool SubcontextChildReap(pid_t pid) { 369 for (auto& subcontext : subcontexts) { 370 if (subcontext.pid() == pid) { 371 subcontext.Restart(); 372 return true; 373 } 374 } 375 return false; 376} 377 378} // namespace init 379} // namespace android 380