blob: 9dd73f0c584a84d7d8744501515e1480b4713b4b [file] [log] [blame]
Luis Hector Chavez81efb332017-09-18 14:01:29 -07001// Copyright 2017 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "libcontainer/libcontainer_util.h"
6
7#include <errno.h>
8#include <fcntl.h>
9#if USE_device_mapper
10#include <libdevmapper.h>
11#endif
12#include <linux/loop.h>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070013#include <sched.h>
Luis Hector Chavez81efb332017-09-18 14:01:29 -070014#include <sys/mount.h>
15#include <sys/stat.h>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070016#include <sys/wait.h>
Luis Hector Chavez81efb332017-09-18 14:01:29 -070017
18#include <memory>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070019#include <utility>
Luis Hector Chavez81efb332017-09-18 14:01:29 -070020#include <vector>
21
22#include <base/bind.h>
23#include <base/bind_helpers.h>
24#include <base/callback_helpers.h>
25#include <base/files/scoped_file.h>
Luis Hector Chavez835d39e2017-09-19 15:16:31 -070026#include <base/logging.h>
Luis Hector Chavez644d2042017-09-19 18:56:44 -070027#include <base/macros.h>
28#include <base/posix/eintr_wrapper.h>
Luis Hector Chavez81efb332017-09-18 14:01:29 -070029#include <base/strings/string_number_conversions.h>
30#include <base/strings/string_split.h>
31#include <base/strings/string_util.h>
32#include <base/strings/stringprintf.h>
33
Luis Hector Chavez644d2042017-09-19 18:56:44 -070034// New cgroup namespace might not be in linux-headers yet.
35#ifndef CLONE_NEWCGROUP
36#define CLONE_NEWCGROUP 0x02000000
37#endif
38
Luis Hector Chavez81efb332017-09-18 14:01:29 -070039namespace libcontainer {
40
41namespace {
42
43constexpr base::FilePath::CharType kLoopdevCtlPath[] =
44 FILE_PATH_LITERAL("/dev/loop-control");
45#if USE_device_mapper
46constexpr base::FilePath::CharType kDevMapperPath[] =
47 FILE_PATH_LITERAL("/dev/mapper/");
48#endif
49
Luis Hector Chavez644d2042017-09-19 18:56:44 -070050// Gets the namespace name for |nstype|.
51std::string GetNamespaceNameForType(int nstype) {
52 switch (nstype) {
53 case CLONE_NEWCGROUP:
54 return "cgroup";
55 case CLONE_NEWIPC:
56 return "ipc";
57 case CLONE_NEWNET:
58 return "net";
59 case CLONE_NEWNS:
60 return "mnt";
61 case CLONE_NEWPID:
62 return "pid";
63 case CLONE_NEWUSER:
64 return "user";
65 case CLONE_NEWUTS:
66 return "uts";
67 }
68 return std::string();
69}
70
71// Helper function that runs |callback| in all the namespaces identified by
72// |nstypes|.
73bool RunInNamespacesHelper(HookCallback callback,
74 std::vector<int> nstypes,
75 pid_t container_pid) {
76 pid_t child = fork();
77 if (child < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -070078 PLOG(ERROR) << "Failed to fork()";
Luis Hector Chavez644d2042017-09-19 18:56:44 -070079 return false;
80 }
81
82 if (child == 0) {
83 for (const int nstype : nstypes) {
84 std::string nstype_name = GetNamespaceNameForType(nstype);
85 if (nstype_name.empty()) {
86 LOG(ERROR) << "Invalid namespace type " << nstype;
87 _exit(-1);
88 }
89 base::FilePath ns_path = base::FilePath(base::StringPrintf(
90 "/proc/%d/ns/%s", container_pid, nstype_name.c_str()));
91 base::ScopedFD ns_fd(open(ns_path.value().c_str(), O_RDONLY));
92 if (!ns_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -070093 PLOG(ERROR) << "Failed to open " << ns_path.value();
Luis Hector Chavez644d2042017-09-19 18:56:44 -070094 _exit(-1);
95 }
96 if (setns(ns_fd.get(), nstype)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -070097 PLOG(ERROR) << "Failed to enter PID " << container_pid << "'s "
98 << nstype_name << " namespace";
Luis Hector Chavez644d2042017-09-19 18:56:44 -070099 _exit(-1);
100 }
101 }
102
103 // Preserve normal POSIX semantics of calling exit(2) with 0 for success and
104 // non-zero for failure.
105 _exit(callback.Run(container_pid) ? 0 : 1);
106 }
107
108 int status;
109 if (HANDLE_EINTR(waitpid(child, &status, 0)) < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700110 PLOG(ERROR) << "Failed to wait for callback";
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700111 return false;
112 }
113 if (!WIFEXITED(status)) {
114 LOG(ERROR) << "Callback terminated abnormally: " << std::hex << status;
115 return false;
116 }
117 return static_cast<int8_t>(WEXITSTATUS(status)) == 0;
118}
119
Luis Hector Chaveze03926a2017-09-28 17:28:49 -0700120// Helper function that runs a program execve(2)-style.
121bool ExecveCallbackHelper(base::FilePath filename,
122 std::vector<std::string> args,
123 base::ScopedFD stdin_fd,
124 base::ScopedFD stdout_fd,
125 base::ScopedFD stderr_fd,
126 pid_t container_pid) {
127 pid_t child = fork();
128 if (child < 0) {
129 PLOG(ERROR) << "Failed to fork()";
130 return false;
131 }
132
133 if (child == 0) {
134 if (stdin_fd.is_valid()) {
135 if (dup2(stdin_fd.get(), STDIN_FILENO) == -1) {
136 PLOG(ERROR) << "Failed to dup2() stdin fd";
137 _exit(-1);
138 }
139 }
140 if (stdout_fd.is_valid()) {
141 if (dup2(stdout_fd.get(), STDOUT_FILENO) == -1) {
142 PLOG(ERROR) << "Failed to dup2() stdout fd";
143 _exit(-1);
144 }
145 }
146 if (stderr_fd.is_valid()) {
147 if (dup2(stderr_fd.get(), STDERR_FILENO) == -1) {
148 PLOG(ERROR) << "Failed to dup2() stderr fd";
149 _exit(-1);
150 }
151 }
152
153 std::string pid_str = base::IntToString(container_pid);
154 std::vector<const char*> argv;
155 argv.reserve(args.size() + 1);
156 for (const auto& arg : args) {
157 if (arg == "$PID") {
158 argv.emplace_back(pid_str.c_str());
159 continue;
160 }
161 argv.emplace_back(arg.c_str());
162 }
163 argv.emplace_back(nullptr);
164
165 execve(filename.value().c_str(), const_cast<char**>(argv.data()), environ);
166
167 // Only happens when execve(2) fails.
168 _exit(-1);
169 }
170
171 int status;
172 if (HANDLE_EINTR(waitpid(child, &status, 0)) < 0) {
173 PLOG(ERROR) << "Failed to wait for hook";
174 return false;
175 }
176 if (!WIFEXITED(status)) {
177 LOG(ERROR) << "Hook terminated abnormally: " << std::hex << status;
178 return false;
179 }
180 return static_cast<int8_t>(WEXITSTATUS(status)) == 0;
181}
182
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700183} // namespace
184
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700185WaitablePipe::WaitablePipe() {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700186 if (pipe2(pipe_fds, O_CLOEXEC) < 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700187 PLOG(FATAL) << "Failed to create pipe";
188}
189
190WaitablePipe::~WaitablePipe() {
191 if (pipe_fds[0] != -1)
192 close(pipe_fds[0]);
193 if (pipe_fds[1] != -1)
194 close(pipe_fds[1]);
195}
196
197WaitablePipe::WaitablePipe(WaitablePipe&& other) {
198 pipe_fds[0] = pipe_fds[1] = -1;
199 std::swap(pipe_fds, other.pipe_fds);
200}
201
202void WaitablePipe::Wait() {
203 char buf;
204
205 close(pipe_fds[1]);
206 HANDLE_EINTR(read(pipe_fds[0], &buf, sizeof(buf)));
207 close(pipe_fds[0]);
208
209 pipe_fds[0] = pipe_fds[1] = -1;
210}
211
212void WaitablePipe::Signal() {
213 close(pipe_fds[0]);
214 close(pipe_fds[1]);
215
216 pipe_fds[0] = pipe_fds[1] = -1;
217}
218
219HookState::HookState() = default;
220HookState::~HookState() = default;
221
222HookState::HookState(HookState&& state) = default;
223
224bool HookState::InstallHook(struct minijail* j, minijail_hook_event_t event) {
225 if (installed_) {
226 LOG(ERROR) << "Failed to install hook: already installed";
227 return false;
228 }
229
230 // All these fds will be closed in WaitHook in the child process.
231 for (size_t i = 0; i < 2; ++i) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700232 if (minijail_preserve_fd(j, reached_pipe_.pipe_fds[i],
233 reached_pipe_.pipe_fds[i]) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700234 LOG(ERROR) << "Failed to preserve reached pipe FDs to install hook";
235 return false;
236 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700237 if (minijail_preserve_fd(j, ready_pipe_.pipe_fds[i],
238 ready_pipe_.pipe_fds[i]) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700239 LOG(ERROR) << "Failed to preserve ready pipe FDs to install hook";
240 return false;
241 }
242 }
243
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700244 if (minijail_add_hook(j, &HookState::WaitHook, this, event) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700245 LOG(ERROR) << "Failed to add hook";
246 return false;
247 }
248
249 installed_ = true;
250 return true;
251}
252
253bool HookState::WaitForHookAndRun(const std::vector<HookCallback>& callbacks,
254 pid_t container_pid) {
255 if (!installed_) {
256 LOG(ERROR) << "Failed to wait for hook: not installed";
257 return false;
258 }
259 reached_pipe_.Wait();
260 base::ScopedClosureRunner teardown(
261 base::Bind(&WaitablePipe::Signal, base::Unretained(&ready_pipe_)));
262
263 for (auto& callback : callbacks) {
264 bool success = callback.Run(container_pid);
265 if (!success)
266 return false;
267 }
268 return true;
269}
270
271// static
272int HookState::WaitHook(void* payload) {
273 HookState* self = reinterpret_cast<HookState*>(payload);
274
275 self->reached_pipe_.Signal();
276 self->ready_pipe_.Wait();
277
278 return 0;
279}
280
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700281bool GetUsernsOutsideId(const std::string& map, int id, int* id_out) {
282 if (map.empty()) {
283 if (id_out)
284 *id_out = id;
285 return true;
286 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700287
288 std::string map_copy = map;
289 base::StringPiece map_piece(map_copy);
290
291 for (const auto& mapping : base::SplitStringPiece(
292 map_piece, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
293 std::vector<base::StringPiece> tokens = base::SplitStringPiece(
294 mapping, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
295
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700296 if (tokens.size() != 3) {
297 LOG(ERROR) << "Malformed ugid mapping: '" << mapping << "'";
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700298 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700299 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700300
301 uint32_t inside, outside, length;
302 if (!base::StringToUint(tokens[0], &inside) ||
303 !base::StringToUint(tokens[1], &outside) ||
304 !base::StringToUint(tokens[2], &length)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700305 LOG(ERROR) << "Malformed ugid mapping: '" << mapping << "'";
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700306 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700307 }
308
309 if (id >= inside && id <= (inside + length)) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700310 if (id_out)
311 *id_out = (id - inside) + outside;
312 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700313 }
314 }
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700315 VLOG(1) << "ugid " << id << " not found in mapping";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700316
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700317 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700318}
319
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700320bool MakeDir(const base::FilePath& path, int uid, int gid, int mode) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700321 if (mkdir(path.value().c_str(), mode)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700322 PLOG(ERROR) << "Failed to mkdir " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700323 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700324 }
325 if (chmod(path.value().c_str(), mode)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700326 PLOG(ERROR) << "Failed to chmod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700327 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700328 }
329 if (chown(path.value().c_str(), uid, gid)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700330 PLOG(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700331 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700332 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700333 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700334}
335
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700336bool TouchFile(const base::FilePath& path, int uid, int gid, int mode) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700337 base::ScopedFD fd(open(path.value().c_str(), O_RDWR | O_CREAT, mode));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700338 if (!fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700339 PLOG(ERROR) << "Failed to create " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700340 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700341 }
342 if (fchown(fd.get(), uid, gid)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700343 PLOG(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700344 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700345 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700346 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700347}
348
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700349bool LoopdevSetup(const base::FilePath& source,
350 base::FilePath* loopdev_path_out) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700351 base::ScopedFD source_fd(open(source.value().c_str(), O_RDONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700352 if (!source_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700353 PLOG(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700354 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700355 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700356
357 base::ScopedFD control_fd(
358 open(kLoopdevCtlPath, O_RDWR | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700359 if (!control_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700360 PLOG(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700361 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700362 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700363
364 while (true) {
365 int num = ioctl(control_fd.get(), LOOP_CTL_GET_FREE);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700366 if (num < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700367 PLOG(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700368 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700369 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700370
371 base::FilePath loopdev_path(base::StringPrintf("/dev/loop%i", num));
372 base::ScopedFD loop_fd(
373 open(loopdev_path.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700374 if (!loop_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700375 PLOG(ERROR) << "Failed to open " << loopdev_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700376 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700377 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700378
379 if (ioctl(loop_fd.get(), LOOP_SET_FD, source_fd.get()) == 0) {
380 *loopdev_path_out = loopdev_path;
381 break;
382 }
383
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700384 if (errno != EBUSY) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700385 PLOG(ERROR) << "Failed to ioctl(LOOP_SET_FD) " << loopdev_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700386 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700387 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700388 }
389
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700390 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700391}
392
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700393bool LoopdevDetach(const base::FilePath& loopdev) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700394 base::ScopedFD fd(
395 open(loopdev.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700396 if (!fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700397 PLOG(ERROR) << "Failed to open " << loopdev.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700398 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700399 }
400 if (ioctl(fd.get(), LOOP_CLR_FD) < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700401 PLOG(ERROR) << "Failed to ioctl(LOOP_CLR_FD) for " << loopdev.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700402 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700403 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700404
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700405 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700406}
407
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700408bool DeviceMapperSetup(const base::FilePath& source,
409 const std::string& verity_cmdline,
410 base::FilePath* dm_path_out,
411 std::string* dm_name_out) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700412#if USE_device_mapper
413 // Normalize the name into something unique-esque.
414 std::string dm_name =
415 base::StringPrintf("cros-containers-%s", source.value().c_str());
416 base::ReplaceChars(dm_name, "/", "_", &dm_name);
417
418 // Get the /dev path for the higher levels to mount.
419 base::FilePath dm_path = base::FilePath(kDevMapperPath).Append(dm_name);
420
421 // Insert the source path in the verity command line.
422 std::string verity = verity_cmdline;
423 base::ReplaceSubstringsAfterOffset(&verity, 0, "@DEV@", source.value());
424
425 // Extract the first three parameters for dm-verity settings.
426 char ttype[20];
427 unsigned long long start, size;
428 int n;
429 if (sscanf(verity.c_str(), "%llu %llu %10s %n", &start, &size, ttype, &n) !=
430 3) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700431 PLOG(ERROR) << "Malformed verity string " << verity;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700432 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700433 }
434
435 /* Finally create the device mapper. */
436 std::unique_ptr<struct dm_task, decltype(&dm_task_destroy)> dmt(
437 dm_task_create(DM_DEVICE_CREATE), &dm_task_destroy);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700438 if (dmt == nullptr) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700439 PLOG(ERROR) << "Failed to dm_task_create() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700440 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700441 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700442
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700443 if (dm_task_set_name(dmt.get(), dm_name.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700444 PLOG(ERROR) << "Failed to dm_task_set_name() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700445 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700446 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700447
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700448 if (dm_task_set_ro(dmt.get()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700449 PLOG(ERROR) << "Failed to dm_task_set_ro() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700450 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700451 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700452
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700453 if (dm_task_add_target(dmt.get(), start, size, ttype, verity.c_str() + n) !=
454 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700455 PLOG(ERROR) << "Failed to dm_task_add_target() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700456 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700457 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700458
459 uint32_t cookie = 0;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700460 if (dm_task_set_cookie(dmt.get(), &cookie, 0) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700461 PLOG(ERROR) << "Failed to dm_task_set_cookie() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700462 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700463 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700464
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700465 if (dm_task_run(dmt.get()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700466 PLOG(ERROR) << "Failed to dm_task_run() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700467 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700468 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700469
470 /* Make sure the node exists before we continue. */
471 dm_udev_wait(cookie);
472
473 *dm_path_out = dm_path;
474 *dm_name_out = dm_name;
475#endif
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700476 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700477}
478
479// Tear down the device mapper target.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700480bool DeviceMapperDetach(const std::string& dm_name) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700481#if USE_device_mapper
482 struct dm_task* dmt = dm_task_create(DM_DEVICE_REMOVE);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700483 if (dmt == nullptr) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700484 PLOG(ERROR) << "Failed to dm_task_run() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700485 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700486 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700487
488 base::ScopedClosureRunner teardown(
489 base::Bind(base::IgnoreResult(&dm_task_destroy), base::Unretained(dmt)));
490
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700491 if (dm_task_set_name(dmt, dm_name.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700492 PLOG(ERROR) << "Failed to dm_task_set_name() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700493 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700494 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700495
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700496 if (dm_task_run(dmt) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700497 PLOG(ERROR) << "Failed to dm_task_run() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700498 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700499 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700500#endif
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700501 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700502}
503
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700504bool MountExternal(const std::string& src,
505 const std::string& dest,
506 const std::string& type,
507 unsigned long flags,
508 const std::string& data) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700509 bool remount_ro = false;
510
511 // R/O bind mounts have to be remounted since 'bind' and 'ro' can't both be
512 // specified in the original bind mount. Remount R/O after the initial mount.
513 if ((flags & MS_BIND) && (flags & MS_RDONLY)) {
514 remount_ro = true;
515 flags &= ~MS_RDONLY;
516 }
517
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700518 if (mount(src.c_str(), dest.c_str(), type.c_str(), flags,
519 data.empty() ? nullptr : data.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700520 PLOG(ERROR) << "Failed to mount " << src << " to " << dest;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700521 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700522 }
523
524 if (remount_ro) {
525 flags |= MS_RDONLY;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700526 if (mount(src.c_str(), dest.c_str(), nullptr, flags | MS_REMOUNT,
527 data.empty() ? nullptr : data.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700528 PLOG(ERROR) << "Failed to remount " << src << " to " << dest;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700529 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700530 }
531 }
532
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700533 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700534}
535
Luis Hector Chaveze03926a2017-09-28 17:28:49 -0700536bool Pipe2(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe, int flags) {
537 int fds[2];
538 if (pipe2(fds, flags) != 0)
539 return false;
540 read_pipe->reset(fds[0]);
541 write_pipe->reset(fds[1]);
542 return true;
543}
544
545HookCallback CreateExecveCallback(base::FilePath filename,
546 std::vector<std::string> args,
547 base::ScopedFD stdin_fd,
548 base::ScopedFD stdout_fd,
549 base::ScopedFD stderr_fd) {
550 return base::Bind(
551 &ExecveCallbackHelper, filename, args, base::Passed(std::move(stdin_fd)),
552 base::Passed(std::move(stdout_fd)), base::Passed(std::move(stderr_fd)));
553}
554
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700555HookCallback AdaptCallbackToRunInNamespaces(HookCallback callback,
556 std::vector<int> nstypes) {
557 return base::Bind(&RunInNamespacesHelper,
558 base::Passed(std::move(callback)),
559 base::Passed(std::move(nstypes)));
560}
561
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700562} // namespace libcontainer