subcontext.cpp revision 193e43494f8afffaa1098690f1d249a3e61f2d43
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 "selinux.h" 31#include "system/core/init/subcontext.pb.h" 32#include "util.h" 33 34using android::base::GetExecutablePath; 35using android::base::Join; 36using android::base::Socketpair; 37using android::base::Split; 38using android::base::StartsWith; 39using android::base::unique_fd; 40 41namespace android { 42namespace init { 43 44const std::string kInitContext = "u:r:init:s0"; 45const std::string kVendorContext = "u:r:vendor_init:s0"; 46 47namespace { 48 49constexpr size_t kBufferSize = 4096; 50 51Result<std::string> ReadMessage(int socket) { 52 char buffer[kBufferSize] = {}; 53 auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0)); 54 if (result <= 0) { 55 return ErrnoError(); 56 } 57 return std::string(buffer, result); 58} 59 60template <typename T> 61Result<Success> SendMessage(int socket, const T& message) { 62 std::string message_string; 63 if (!message.SerializeToString(&message_string)) { 64 return Error() << "Unable to serialize message"; 65 } 66 67 if (message_string.size() > kBufferSize) { 68 return Error() << "Serialized message too long to send"; 69 } 70 71 if (auto result = 72 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); 73 result != static_cast<long>(message_string.size())) { 74 return ErrnoError() << "send() failed to send message contents"; 75 } 76 return Success(); 77} 78 79class SubcontextProcess { 80 public: 81 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) 82 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){}; 83 void MainLoop(); 84 85 private: 86 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 87 SubcontextReply::ResultMessage* result_message) const; 88 89 const KeywordFunctionMap* function_map_; 90 const std::string context_; 91 const int init_fd_; 92}; 93 94void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 95 SubcontextReply::ResultMessage* result_message) const { 96 // Need to use ArraySplice instead of this code. 97 auto args = std::vector<std::string>(); 98 for (const auto& string : execute_command.args()) { 99 args.emplace_back(string); 100 } 101 102 auto map_result = function_map_->FindFunction(args); 103 Result<Success> result; 104 if (!map_result) { 105 result = Error() << "Cannot find command: " << map_result.error(); 106 } else { 107 result = RunBuiltinFunction(map_result->second, args, context_); 108 } 109 110 if (result) { 111 result_message->set_success(true); 112 } else { 113 result_message->set_success(false); 114 result_message->set_error_string(result.error_string()); 115 result_message->set_error_errno(result.error_errno()); 116 } 117} 118 119void SubcontextProcess::MainLoop() { 120 pollfd ufd[1]; 121 ufd[0].events = POLLIN; 122 ufd[0].fd = init_fd_; 123 124 while (true) { 125 ufd[0].revents = 0; 126 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1)); 127 if (nr == 0) continue; 128 if (nr < 0) { 129 PLOG(FATAL) << "poll() of subcontext socket failed, continuing"; 130 } 131 132 auto init_message = ReadMessage(init_fd_); 133 if (!init_message) { 134 LOG(FATAL) << "Could not read message from init: " << init_message.error(); 135 } 136 137 auto subcontext_command = SubcontextCommand(); 138 if (!subcontext_command.ParseFromString(*init_message)) { 139 LOG(FATAL) << "Unable to parse message from init"; 140 } 141 142 auto reply = SubcontextReply(); 143 switch (subcontext_command.command_case()) { 144 case SubcontextCommand::kExecuteCommand: { 145 RunCommand(subcontext_command.execute_command(), reply.mutable_result()); 146 break; 147 } 148 default: 149 LOG(FATAL) << "Unknown message type from init: " 150 << subcontext_command.command_case(); 151 } 152 153 if (auto result = SendMessage(init_fd_, reply); !result) { 154 LOG(FATAL) << "Failed to send message to init: " << result.error(); 155 } 156 } 157} 158 159} // namespace 160 161int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) { 162 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")"; 163 164 auto context = std::string(argv[2]); 165 auto init_fd = std::atoi(argv[3]); 166 167 SelabelInitialize(); 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 static const char* const paths_and_secontexts[][2] = { 264 {"/vendor", kVendorContext.c_str()}, 265 }; 266 for (const auto& [path_prefix, secontext] : paths_and_secontexts) { 267 subcontexts.emplace_back(path_prefix, secontext); 268 } 269 return &subcontexts; 270} 271 272bool SubcontextChildReap(pid_t pid) { 273 for (auto& subcontext : subcontexts) { 274 if (subcontext.pid() == pid) { 275 subcontext.Restart(); 276 return true; 277 } 278 } 279 return false; 280} 281 282} // namespace init 283} // namespace android 284