blob: d25954cd6c4896f73f66f98c0db3d1c6a5004bf9 [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 Chavez81efb332017-09-18 14:01:29 -0700120} // namespace
121
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700122WaitablePipe::WaitablePipe() {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700123 if (pipe2(pipe_fds, O_CLOEXEC) < 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700124 PLOG(FATAL) << "Failed to create pipe";
125}
126
127WaitablePipe::~WaitablePipe() {
128 if (pipe_fds[0] != -1)
129 close(pipe_fds[0]);
130 if (pipe_fds[1] != -1)
131 close(pipe_fds[1]);
132}
133
134WaitablePipe::WaitablePipe(WaitablePipe&& other) {
135 pipe_fds[0] = pipe_fds[1] = -1;
136 std::swap(pipe_fds, other.pipe_fds);
137}
138
139void WaitablePipe::Wait() {
140 char buf;
141
142 close(pipe_fds[1]);
143 HANDLE_EINTR(read(pipe_fds[0], &buf, sizeof(buf)));
144 close(pipe_fds[0]);
145
146 pipe_fds[0] = pipe_fds[1] = -1;
147}
148
149void WaitablePipe::Signal() {
150 close(pipe_fds[0]);
151 close(pipe_fds[1]);
152
153 pipe_fds[0] = pipe_fds[1] = -1;
154}
155
156HookState::HookState() = default;
157HookState::~HookState() = default;
158
159HookState::HookState(HookState&& state) = default;
160
161bool HookState::InstallHook(struct minijail* j, minijail_hook_event_t event) {
162 if (installed_) {
163 LOG(ERROR) << "Failed to install hook: already installed";
164 return false;
165 }
166
167 // All these fds will be closed in WaitHook in the child process.
168 for (size_t i = 0; i < 2; ++i) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700169 if (minijail_preserve_fd(j, reached_pipe_.pipe_fds[i],
170 reached_pipe_.pipe_fds[i]) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700171 LOG(ERROR) << "Failed to preserve reached pipe FDs to install hook";
172 return false;
173 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700174 if (minijail_preserve_fd(j, ready_pipe_.pipe_fds[i],
175 ready_pipe_.pipe_fds[i]) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700176 LOG(ERROR) << "Failed to preserve ready pipe FDs to install hook";
177 return false;
178 }
179 }
180
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700181 if (minijail_add_hook(j, &HookState::WaitHook, this, event) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700182 LOG(ERROR) << "Failed to add hook";
183 return false;
184 }
185
186 installed_ = true;
187 return true;
188}
189
190bool HookState::WaitForHookAndRun(const std::vector<HookCallback>& callbacks,
191 pid_t container_pid) {
192 if (!installed_) {
193 LOG(ERROR) << "Failed to wait for hook: not installed";
194 return false;
195 }
196 reached_pipe_.Wait();
197 base::ScopedClosureRunner teardown(
198 base::Bind(&WaitablePipe::Signal, base::Unretained(&ready_pipe_)));
199
200 for (auto& callback : callbacks) {
201 bool success = callback.Run(container_pid);
202 if (!success)
203 return false;
204 }
205 return true;
206}
207
208// static
209int HookState::WaitHook(void* payload) {
210 HookState* self = reinterpret_cast<HookState*>(payload);
211
212 self->reached_pipe_.Signal();
213 self->ready_pipe_.Wait();
214
215 return 0;
216}
217
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700218bool GetUsernsOutsideId(const std::string& map, int id, int* id_out) {
219 if (map.empty()) {
220 if (id_out)
221 *id_out = id;
222 return true;
223 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700224
225 std::string map_copy = map;
226 base::StringPiece map_piece(map_copy);
227
228 for (const auto& mapping : base::SplitStringPiece(
229 map_piece, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
230 std::vector<base::StringPiece> tokens = base::SplitStringPiece(
231 mapping, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
232
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700233 if (tokens.size() != 3) {
234 LOG(ERROR) << "Malformed ugid mapping: '" << mapping << "'";
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700235 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700236 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700237
238 uint32_t inside, outside, length;
239 if (!base::StringToUint(tokens[0], &inside) ||
240 !base::StringToUint(tokens[1], &outside) ||
241 !base::StringToUint(tokens[2], &length)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700242 LOG(ERROR) << "Malformed ugid mapping: '" << mapping << "'";
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700243 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700244 }
245
246 if (id >= inside && id <= (inside + length)) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700247 if (id_out)
248 *id_out = (id - inside) + outside;
249 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700250 }
251 }
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700252 VLOG(1) << "ugid " << id << " not found in mapping";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700253
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700254 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700255}
256
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700257bool MakeDir(const base::FilePath& path, int uid, int gid, int mode) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700258 if (mkdir(path.value().c_str(), mode)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700259 PLOG(ERROR) << "Failed to mkdir " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700260 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700261 }
262 if (chmod(path.value().c_str(), mode)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700263 PLOG(ERROR) << "Failed to chmod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700264 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700265 }
266 if (chown(path.value().c_str(), uid, gid)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700267 PLOG(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700268 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700269 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700270 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700271}
272
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700273bool TouchFile(const base::FilePath& path, int uid, int gid, int mode) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700274 base::ScopedFD fd(open(path.value().c_str(), O_RDWR | O_CREAT, mode));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700275 if (!fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700276 PLOG(ERROR) << "Failed to create " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700277 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700278 }
279 if (fchown(fd.get(), uid, gid)) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700280 PLOG(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700281 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700282 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700283 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700284}
285
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700286bool LoopdevSetup(const base::FilePath& source,
287 base::FilePath* loopdev_path_out) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700288 base::ScopedFD source_fd(open(source.value().c_str(), O_RDONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700289 if (!source_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700290 PLOG(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700291 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700292 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700293
294 base::ScopedFD control_fd(
295 open(kLoopdevCtlPath, O_RDWR | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700296 if (!control_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700297 PLOG(ERROR) << "Failed to open " << source.value();
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 while (true) {
302 int num = ioctl(control_fd.get(), LOOP_CTL_GET_FREE);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700303 if (num < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700304 PLOG(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700305 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700306 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700307
308 base::FilePath loopdev_path(base::StringPrintf("/dev/loop%i", num));
309 base::ScopedFD loop_fd(
310 open(loopdev_path.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700311 if (!loop_fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700312 PLOG(ERROR) << "Failed to open " << loopdev_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700313 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700314 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700315
316 if (ioctl(loop_fd.get(), LOOP_SET_FD, source_fd.get()) == 0) {
317 *loopdev_path_out = loopdev_path;
318 break;
319 }
320
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700321 if (errno != EBUSY) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700322 PLOG(ERROR) << "Failed to ioctl(LOOP_SET_FD) " << loopdev_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700323 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700324 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700325 }
326
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700327 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700328}
329
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700330bool LoopdevDetach(const base::FilePath& loopdev) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700331 base::ScopedFD fd(
332 open(loopdev.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700333 if (!fd.is_valid()) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700334 PLOG(ERROR) << "Failed to open " << loopdev.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700335 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700336 }
337 if (ioctl(fd.get(), LOOP_CLR_FD) < 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700338 PLOG(ERROR) << "Failed to ioctl(LOOP_CLR_FD) for " << loopdev.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700339 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700340 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700341
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700342 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700343}
344
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700345bool DeviceMapperSetup(const base::FilePath& source,
346 const std::string& verity_cmdline,
347 base::FilePath* dm_path_out,
348 std::string* dm_name_out) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700349#if USE_device_mapper
350 // Normalize the name into something unique-esque.
351 std::string dm_name =
352 base::StringPrintf("cros-containers-%s", source.value().c_str());
353 base::ReplaceChars(dm_name, "/", "_", &dm_name);
354
355 // Get the /dev path for the higher levels to mount.
356 base::FilePath dm_path = base::FilePath(kDevMapperPath).Append(dm_name);
357
358 // Insert the source path in the verity command line.
359 std::string verity = verity_cmdline;
360 base::ReplaceSubstringsAfterOffset(&verity, 0, "@DEV@", source.value());
361
362 // Extract the first three parameters for dm-verity settings.
363 char ttype[20];
364 unsigned long long start, size;
365 int n;
366 if (sscanf(verity.c_str(), "%llu %llu %10s %n", &start, &size, ttype, &n) !=
367 3) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700368 PLOG(ERROR) << "Malformed verity string " << verity;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700369 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700370 }
371
372 /* Finally create the device mapper. */
373 std::unique_ptr<struct dm_task, decltype(&dm_task_destroy)> dmt(
374 dm_task_create(DM_DEVICE_CREATE), &dm_task_destroy);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700375 if (dmt == nullptr) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700376 PLOG(ERROR) << "Failed to dm_task_create() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700377 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700378 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700379
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700380 if (dm_task_set_name(dmt.get(), dm_name.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700381 PLOG(ERROR) << "Failed to dm_task_set_name() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700382 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700383 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700384
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700385 if (dm_task_set_ro(dmt.get()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700386 PLOG(ERROR) << "Failed to dm_task_set_ro() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700387 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700388 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700389
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700390 if (dm_task_add_target(dmt.get(), start, size, ttype, verity.c_str() + n) !=
391 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700392 PLOG(ERROR) << "Failed to dm_task_add_target() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700393 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700394 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700395
396 uint32_t cookie = 0;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700397 if (dm_task_set_cookie(dmt.get(), &cookie, 0) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700398 PLOG(ERROR) << "Failed to dm_task_set_cookie() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700399 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700400 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700401
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700402 if (dm_task_run(dmt.get()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700403 PLOG(ERROR) << "Failed to dm_task_run() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700404 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700405 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700406
407 /* Make sure the node exists before we continue. */
408 dm_udev_wait(cookie);
409
410 *dm_path_out = dm_path;
411 *dm_name_out = dm_name;
412#endif
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700413 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700414}
415
416// Tear down the device mapper target.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700417bool DeviceMapperDetach(const std::string& dm_name) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700418#if USE_device_mapper
419 struct dm_task* dmt = dm_task_create(DM_DEVICE_REMOVE);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700420 if (dmt == nullptr) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700421 PLOG(ERROR) << "Failed to dm_task_run() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700422 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700423 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700424
425 base::ScopedClosureRunner teardown(
426 base::Bind(base::IgnoreResult(&dm_task_destroy), base::Unretained(dmt)));
427
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700428 if (dm_task_set_name(dmt, dm_name.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700429 PLOG(ERROR) << "Failed to dm_task_set_name() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700430 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700431 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700432
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700433 if (dm_task_run(dmt) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700434 PLOG(ERROR) << "Failed to dm_task_run() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700435 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700436 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700437#endif
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700438 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700439}
440
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700441bool MountExternal(const std::string& src,
442 const std::string& dest,
443 const std::string& type,
444 unsigned long flags,
445 const std::string& data) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700446 bool remount_ro = false;
447
448 // R/O bind mounts have to be remounted since 'bind' and 'ro' can't both be
449 // specified in the original bind mount. Remount R/O after the initial mount.
450 if ((flags & MS_BIND) && (flags & MS_RDONLY)) {
451 remount_ro = true;
452 flags &= ~MS_RDONLY;
453 }
454
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700455 if (mount(src.c_str(), dest.c_str(), type.c_str(), flags,
456 data.empty() ? nullptr : data.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700457 PLOG(ERROR) << "Failed to mount " << src << " to " << dest;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700458 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700459 }
460
461 if (remount_ro) {
462 flags |= MS_RDONLY;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700463 if (mount(src.c_str(), dest.c_str(), nullptr, flags | MS_REMOUNT,
464 data.empty() ? nullptr : data.c_str()) != 0) {
Luis Hector Chavezdc61f8d2017-10-02 11:12:46 -0700465 PLOG(ERROR) << "Failed to remount " << src << " to " << dest;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700466 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700467 }
468 }
469
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700470 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700471}
472
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700473HookCallback AdaptCallbackToRunInNamespaces(HookCallback callback,
474 std::vector<int> nstypes) {
475 return base::Bind(&RunInNamespacesHelper,
476 base::Passed(std::move(callback)),
477 base::Passed(std::move(nstypes)));
478}
479
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700480} // namespace libcontainer