Home | History | Annotate | Download | only in init
      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 
     41 using android::base::GetExecutablePath;
     42 using android::base::GetIntProperty;
     43 using android::base::Join;
     44 using android::base::Socketpair;
     45 using android::base::Split;
     46 using android::base::StartsWith;
     47 using android::base::unique_fd;
     48 
     49 namespace android {
     50 namespace init {
     51 
     52 const std::string kInitContext = "u:r:init:s0";
     53 const std::string kVendorContext = "u:r:vendor_init:s0";
     54 
     55 const char* const paths_and_secontexts[2][2] = {
     56     {"/vendor", kVendorContext.c_str()},
     57     {"/odm", kVendorContext.c_str()},
     58 };
     59 
     60 namespace {
     61 
     62 constexpr size_t kBufferSize = 4096;
     63 
     64 Result<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 
     73 template <typename T>
     74 Result<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 
     92 std::vector<std::pair<std::string, std::string>> properties_to_set;
     93 
     94 uint32_t SubcontextPropertySet(const std::string& name, const std::string& value) {
     95     properties_to_set.emplace_back(name, value);
     96     return 0;
     97 }
     98 
     99 class 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 
    116 void 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 
    149 void 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 
    165 void 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 
    211 int 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 
    226 void 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 
    265 void 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 
    275 Result<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 
    295 Result<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 
    328 Result<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 
    357 static std::vector<Subcontext> subcontexts;
    358 
    359 std::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 
    368 bool 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