subcontext.cpp revision 0d1452ee1b2fb137e175064f4b84b1db8dde6487
1069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project/* 2069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Copyright (C) 2017 The Android Open Source Project 3069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 4069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 5069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * you may not use this file except in compliance with the License. 6069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * You may obtain a copy of the License at 7069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 8069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * 10069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 12069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * See the License for the specific language governing permissions and 14069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project * limitations under the License. 15069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project */ 16069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 17069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include "subcontext.h" 18069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 19069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <fcntl.h> 20069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <poll.h> 21069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <sys/socket.h> 22069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <unistd.h> 23069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 24069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <android-base/file.h> 25069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <android-base/logging.h> 26069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <android-base/properties.h> 27069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <android-base/strings.h> 28069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include <selinux/android.h> 29069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 30069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include "action.h" 31069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include "selinux.h" 32069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include "system/core/init/subcontext.pb.h" 33069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project#include "util.h" 34069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 35069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectusing android::base::GetBoolProperty; 36d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamathusing android::base::GetExecutablePath; 37d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamathusing android::base::Join; 38d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamathusing android::base::Socketpair; 39d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamathusing android::base::Split; 40d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamathusing android::base::StartsWith; 41069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectusing android::base::unique_fd; 42d42abb2fd917184764daf22f5f299e848b8701d7Narayan Kamath 43069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectnamespace android { 44069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectnamespace init { 45069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 46069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectconst std::string kInitContext = "u:r:init:s0"; 47069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectconst std::string kVendorContext = "u:r:vendor_init:s0"; 48069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 49069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectnamespace { 50069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 51069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Projectconstexpr size_t kBufferSize = 4096; 52069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source Project 53069490a5ca2fd1988d29daf45d892f47ad665115The Android Open Source ProjectResult<std::string> ReadMessage(int socket) { 54 char buffer[kBufferSize] = {}; 55 auto result = TEMP_FAILURE_RETRY(recv(socket, buffer, sizeof(buffer), 0)); 56 if (result <= 0) { 57 return ErrnoError(); 58 } 59 return std::string(buffer, result); 60} 61 62template <typename T> 63Result<Success> SendMessage(int socket, const T& message) { 64 std::string message_string; 65 if (!message.SerializeToString(&message_string)) { 66 return Error() << "Unable to serialize message"; 67 } 68 69 if (message_string.size() > kBufferSize) { 70 return Error() << "Serialized message too long to send"; 71 } 72 73 if (auto result = 74 TEMP_FAILURE_RETRY(send(socket, message_string.c_str(), message_string.size(), 0)); 75 result != static_cast<long>(message_string.size())) { 76 return ErrnoError() << "send() failed to send message contents"; 77 } 78 return Success(); 79} 80 81class SubcontextProcess { 82 public: 83 SubcontextProcess(const KeywordFunctionMap* function_map, std::string context, int init_fd) 84 : function_map_(function_map), context_(std::move(context)), init_fd_(init_fd){}; 85 void MainLoop(); 86 87 private: 88 void RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 89 SubcontextReply::ResultMessage* result_message) const; 90 91 const KeywordFunctionMap* function_map_; 92 const std::string context_; 93 const int init_fd_; 94}; 95 96void SubcontextProcess::RunCommand(const SubcontextCommand::ExecuteCommand& execute_command, 97 SubcontextReply::ResultMessage* result_message) const { 98 // Need to use ArraySplice instead of this code. 99 auto args = std::vector<std::string>(); 100 for (const auto& string : execute_command.args()) { 101 args.emplace_back(string); 102 } 103 104 auto map_result = function_map_->FindFunction(args); 105 Result<Success> result; 106 if (!map_result) { 107 result = Error() << "Cannot find command: " << map_result.error(); 108 } else { 109 result = RunBuiltinFunction(map_result->second, args, context_); 110 } 111 112 if (result) { 113 result_message->set_success(true); 114 } else { 115 result_message->set_success(false); 116 result_message->set_error_string(result.error_string()); 117 result_message->set_error_errno(result.error_errno()); 118 } 119} 120 121void SubcontextProcess::MainLoop() { 122 pollfd ufd[1]; 123 ufd[0].events = POLLIN; 124 ufd[0].fd = init_fd_; 125 126 while (true) { 127 ufd[0].revents = 0; 128 int nr = TEMP_FAILURE_RETRY(poll(ufd, arraysize(ufd), -1)); 129 if (nr == 0) continue; 130 if (nr < 0) { 131 PLOG(FATAL) << "poll() of subcontext socket failed, continuing"; 132 } 133 134 auto init_message = ReadMessage(init_fd_); 135 if (!init_message) { 136 LOG(FATAL) << "Could not read message from init: " << init_message.error(); 137 } 138 139 auto subcontext_command = SubcontextCommand(); 140 if (!subcontext_command.ParseFromString(*init_message)) { 141 LOG(FATAL) << "Unable to parse message from init"; 142 } 143 144 auto reply = SubcontextReply(); 145 switch (subcontext_command.command_case()) { 146 case SubcontextCommand::kExecuteCommand: { 147 RunCommand(subcontext_command.execute_command(), reply.mutable_result()); 148 break; 149 } 150 default: 151 LOG(FATAL) << "Unknown message type from init: " 152 << subcontext_command.command_case(); 153 } 154 155 if (auto result = SendMessage(init_fd_, reply); !result) { 156 LOG(FATAL) << "Failed to send message to init: " << result.error(); 157 } 158 } 159} 160 161} // namespace 162 163int SubcontextMain(int argc, char** argv, const KeywordFunctionMap* function_map) { 164 if (argc < 4) LOG(FATAL) << "Fewer than 4 args specified to subcontext (" << argc << ")"; 165 166 auto context = std::string(argv[2]); 167 auto init_fd = std::atoi(argv[3]); 168 169 SelabelInitialize(); 170 auto subcontext_process = SubcontextProcess(function_map, context, init_fd); 171 subcontext_process.MainLoop(); 172 return 0; 173} 174 175void Subcontext::Fork() { 176 unique_fd subcontext_socket; 177 if (!Socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, &socket_, &subcontext_socket)) { 178 LOG(FATAL) << "Could not create socket pair to communicate to subcontext"; 179 return; 180 } 181 182 auto result = fork(); 183 184 if (result == -1) { 185 LOG(FATAL) << "Could not fork subcontext"; 186 } else if (result == 0) { 187 socket_.reset(); 188 189 // We explicitly do not use O_CLOEXEC here, such that we can reference this FD by number 190 // in the subcontext process after we exec. 191 int child_fd = dup(subcontext_socket); 192 if (child_fd < 0) { 193 PLOG(FATAL) << "Could not dup child_fd"; 194 } 195 196 if (setexeccon(context_.c_str()) < 0) { 197 PLOG(FATAL) << "Could not set execcon for '" << context_ << "'"; 198 } 199 200 auto init_path = GetExecutablePath(); 201 auto child_fd_string = std::to_string(child_fd); 202 const char* args[] = {init_path.c_str(), "subcontext", context_.c_str(), 203 child_fd_string.c_str(), nullptr}; 204 execv(init_path.data(), const_cast<char**>(args)); 205 206 PLOG(FATAL) << "Could not execv subcontext init"; 207 } else { 208 subcontext_socket.reset(); 209 pid_ = result; 210 LOG(INFO) << "Forked subcontext for '" << context_ << "' with pid " << pid_; 211 } 212} 213 214void Subcontext::Restart() { 215 LOG(ERROR) << "Restarting subcontext '" << context_ << "'"; 216 if (pid_) { 217 kill(pid_, SIGKILL); 218 } 219 pid_ = 0; 220 socket_.reset(); 221 Fork(); 222} 223 224Result<Success> Subcontext::Execute(const std::vector<std::string>& args) { 225 auto subcontext_command = SubcontextCommand(); 226 std::copy( 227 args.begin(), args.end(), 228 RepeatedPtrFieldBackInserter(subcontext_command.mutable_execute_command()->mutable_args())); 229 230 if (auto result = SendMessage(socket_, subcontext_command); !result) { 231 Restart(); 232 return ErrnoError() << "Failed to send message to subcontext"; 233 } 234 235 auto subcontext_message = ReadMessage(socket_); 236 if (!subcontext_message) { 237 Restart(); 238 return Error() << "Failed to receive result from subcontext: " << subcontext_message.error(); 239 } 240 241 auto subcontext_reply = SubcontextReply(); 242 if (!subcontext_reply.ParseFromString(*subcontext_message)) { 243 Restart(); 244 return Error() << "Unable to parse message from subcontext"; 245 } 246 247 switch (subcontext_reply.reply_case()) { 248 case SubcontextReply::kResult: { 249 auto result = subcontext_reply.result(); 250 if (result.success()) { 251 return Success(); 252 } else { 253 return ResultError(result.error_string(), result.error_errno()); 254 } 255 } 256 default: 257 return Error() << "Unknown message type from subcontext: " 258 << subcontext_reply.reply_case(); 259 } 260} 261 262static std::vector<Subcontext> subcontexts; 263 264std::vector<Subcontext>* InitializeSubcontexts() { 265 if (GetBoolProperty("ro.init.subcontexts_enabled", false)) { 266 static const char* const paths_and_secontexts[][2] = { 267 {"/vendor", kVendorContext.c_str()}, 268 }; 269 for (const auto& [path_prefix, secontext] : paths_and_secontexts) { 270 subcontexts.emplace_back(path_prefix, secontext); 271 } 272 } 273 return &subcontexts; 274} 275 276bool SubcontextChildReap(pid_t pid) { 277 for (auto& subcontext : subcontexts) { 278 if (subcontext.pid() == pid) { 279 subcontext.Restart(); 280 return true; 281 } 282 } 283 return false; 284} 285 286} // namespace init 287} // namespace android 288