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