subcontext.cpp revision 79193a42e7aa5760a6f98c0718e3d70c560d0e8e
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/properties.h> 27#include <android-base/strings.h> 28#include <selinux/android.h> 29 30#include "action.h" 31#include "system/core/init/subcontext.pb.h" 32#include "util.h" 33 34using android::base::GetBoolProperty; 35using android::base::GetExecutablePath; 36using android::base::Join; 37using android::base::Socketpair; 38using android::base::Split; 39using android::base::StartsWith; 40using android::base::unique_fd; 41 42namespace android { 43namespace init { 44 45const std::string kInitContext = "u:r:init:s0"; 46const std::string kVendorContext = "u:r:vendor_init:s0"; 47 48namespace { 49 50constexpr size_t kBufferSize = 4096; 51 52Result<std::string> ReadMessage(int socket) { 53 char buffer[kBufferSize] = {}; 54 auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0)); 55 if (result <= 0) { 56 return ErrnoError(); 57 } 58 return std::string(buffer, result); 59} 60 61template <typename T> 62Result<Success> SendMessage(int socket, const T& message) { 63 std::string message_string; 64 if (!message.SerializeToString(&message_string)) { 65 return Error() << "Unable to serialize message"; 66 } 67 68 if (message_string.size() > kBufferSize) { 69 return Error() << "Serialized message too long to send"; 70 } 71 72 if (auto result = 73 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); 74 result != static_cast<long>(message_string.size())) { 75 return ErrnoError() << "send() failed to send message contents"; 76 } 77 return Success(); 78} 79 80class SubcontextProcess { 81 public: 82 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) 83 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){}; 84 void MainLoop(); 85 86 private: 87 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 88 SubcontextReply::ResultMessage* result_message) const; 89 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, 96 SubcontextReply::ResultMessage* result_message) const { 97 // 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) { 112 result_message->set_success(true); 113 } else { 114 result_message->set_success(false); 115 result_message->set_error_string(result.error_string()); 116 result_message->set_error_errno(result.error_errno()); 117 } 118} 119 120void SubcontextProcess::MainLoop() { 121 pollfd ufd[1]; 122 ufd[0].events = POLLIN; 123 ufd[0].fd = init_fd_; 124 125 while (true) { 126 ufd[0].revents = 0; 127 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1)); 128 if (nr == 0) continue; 129 if (nr < 0) { 130 PLOG(FATAL) << "poll() of subcontext socket failed, continuing"; 131 } 132 133 auto init_message = ReadMessage(init_fd_); 134 if (!init_message) { 135 LOG(FATAL) << "Could not read message from init: " << init_message.error(); 136 } 137 138 auto subcontext_command = SubcontextCommand(); 139 if (!subcontext_command.ParseFromString(*init_message)) { 140 LOG(FATAL) << "Unable to parse message from init"; 141 } 142 143 auto reply = SubcontextReply(); 144 switch (subcontext_command.command_case()) { 145 case SubcontextCommand::kExecuteCommand: { 146 RunCommand(subcontext_command.execute_command(), reply.mutable_result()); 147 break; 148 } 149 default: 150 LOG(FATAL) << "Unknown message type from init: " 151 << subcontext_command.command_case(); 152 } 153 154 if (auto result = SendMessage(init_fd_, reply); !result) { 155 LOG(FATAL) << "Failed to send message to init: " << result.error(); 156 } 157 } 158} 159 160} // namespace 161 162int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) { 163 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")"; 164 165 auto context = std::string(argv[2]); 166 auto init_fd = std::atoi(argv[3]); 167 168 auto subcontext_process = SubcontextProcess(function_map, context, init_fd); 169 subcontext_process.MainLoop(); 170 return 0; 171} 172 173void Subcontext::Fork() { 174 unique_fd subcontext_socket; 175 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) { 176 LOG(FATAL) << "Could not create socket pair to communicate to subcontext"; 177 return; 178 } 179 180 auto result = fork(); 181 182 if (result == -1) { 183 LOG(FATAL) << "Could not fork subcontext"; 184 } else if (result == 0) { 185 socket_.reset(); 186 187 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number 188 // in the subcontext process after we exec. 189 int child_fd = dup(subcontext_socket); 190 if (child_fd < 0) { 191 PLOG(FATAL) << "Could not dup child_fd"; 192 } 193 194 if (setexeccon(context_.c_str()) < 0) { 195 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'"; 196 } 197 198 auto init_path = GetExecutablePath(); 199 auto child_fd_string = std::to_string(child_fd); 200 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(), 201 child_fd_string.c_str(), nullptr}; 202 execv(init_path.data(), const_cast<char**>(args)); 203 204 PLOG(FATAL) << "Could not execv subcontext init"; 205 } else { 206 subcontext_socket.reset(); 207 pid_ = result; 208 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_; 209 } 210} 211 212void Subcontext::Restart() { 213 LOG(ERROR) << "Restarting subcontext '" << context_ << "'"; 214 if (pid_) { 215 kill(pid_, SIGKILL); 216 } 217 pid_ = 0; 218 socket_.reset(); 219 Fork(); 220} 221 222Result<Success> Subcontext::Execute(const std::vector<std::string>& args) { 223 auto subcontext_command = SubcontextCommand(); 224 std::copy( 225 args.begin(), args.end(), 226 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args())); 227 228 if (auto result = SendMessage(socket_, subcontext_command); !result) { 229 Restart(); 230 return ErrnoError() << "Failed to send message to subcontext"; 231 } 232 233 auto subcontext_message = ReadMessage(socket_); 234 if (!subcontext_message) { 235 Restart(); 236 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error(); 237 } 238 239 auto subcontext_reply = SubcontextReply(); 240 if (!subcontext_reply.ParseFromString(*subcontext_message)) { 241 Restart(); 242 return Error() << "Unable to parse message from subcontext"; 243 } 244 245 switch (subcontext_reply.reply_case()) { 246 case SubcontextReply::kResult: { 247 auto result = subcontext_reply.result(); 248 if (result.success()) { 249 return Success(); 250 } else { 251 return ResultError(result.error_string(), result.error_errno()); 252 } 253 } 254 default: 255 return Error() << "Unknown message type from subcontext: " 256 << subcontext_reply.reply_case(); 257 } 258} 259 260static std::vector<Subcontext> subcontexts; 261 262std::vector<Subcontext>* InitializeSubcontexts() { 263 if (GetBoolProperty("ro.init.subcontexts_enabled", false)) { 264 static const char* const paths_and_secontexts[][2] = { 265 {"/vendor", kVendorContext.c_str()}, 266 }; 267 for (const auto& [path_prefix, secontext] : paths_and_secontexts) { 268 subcontexts.emplace_back(path_prefix, secontext); 269 } 270 } 271 return &subcontexts; 272} 273 274bool SubcontextChildReap(pid_t pid) { 275 for (auto& subcontext : subcontexts) { 276 if (subcontext.pid() == pid) { 277 subcontext.Restart(); 278 return true; 279 } 280 } 281 return false; 282} 283 284} // namespace init 285} // namespace android 286