blob: b25124353dcee5b6d744b0d7907d9e64f00ff9fa [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) {
78 PLOG_PRESERVE(ERROR) << "Failed to fork()";
79 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()) {
93 PLOG_PRESERVE(ERROR) << "Failed to open " << ns_path.value();
94 _exit(-1);
95 }
96 if (setns(ns_fd.get(), nstype)) {
97 PLOG_PRESERVE(ERROR) << "Failed to enter PID " << container_pid << "'s "
98 << nstype_name << " namespace";
99 _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) {
110 PLOG_PRESERVE(ERROR) << "Failed to wait for callback";
111 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 Chavez835d39e2017-09-19 15:16:31 -0700122SaveErrno::SaveErrno() : saved_errno_(errno) {}
123
124SaveErrno::~SaveErrno() {
125 errno = saved_errno_;
126}
127
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700128WaitablePipe::WaitablePipe() {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700129 if (pipe2(pipe_fds, O_CLOEXEC) < 0)
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700130 PLOG(FATAL) << "Failed to create pipe";
131}
132
133WaitablePipe::~WaitablePipe() {
134 if (pipe_fds[0] != -1)
135 close(pipe_fds[0]);
136 if (pipe_fds[1] != -1)
137 close(pipe_fds[1]);
138}
139
140WaitablePipe::WaitablePipe(WaitablePipe&& other) {
141 pipe_fds[0] = pipe_fds[1] = -1;
142 std::swap(pipe_fds, other.pipe_fds);
143}
144
145void WaitablePipe::Wait() {
146 char buf;
147
148 close(pipe_fds[1]);
149 HANDLE_EINTR(read(pipe_fds[0], &buf, sizeof(buf)));
150 close(pipe_fds[0]);
151
152 pipe_fds[0] = pipe_fds[1] = -1;
153}
154
155void WaitablePipe::Signal() {
156 close(pipe_fds[0]);
157 close(pipe_fds[1]);
158
159 pipe_fds[0] = pipe_fds[1] = -1;
160}
161
162HookState::HookState() = default;
163HookState::~HookState() = default;
164
165HookState::HookState(HookState&& state) = default;
166
167bool HookState::InstallHook(struct minijail* j, minijail_hook_event_t event) {
168 if (installed_) {
169 LOG(ERROR) << "Failed to install hook: already installed";
170 return false;
171 }
172
173 // All these fds will be closed in WaitHook in the child process.
174 for (size_t i = 0; i < 2; ++i) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700175 if (minijail_preserve_fd(j, reached_pipe_.pipe_fds[i],
176 reached_pipe_.pipe_fds[i]) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700177 LOG(ERROR) << "Failed to preserve reached pipe FDs to install hook";
178 return false;
179 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700180 if (minijail_preserve_fd(j, ready_pipe_.pipe_fds[i],
181 ready_pipe_.pipe_fds[i]) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700182 LOG(ERROR) << "Failed to preserve ready pipe FDs to install hook";
183 return false;
184 }
185 }
186
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700187 if (minijail_add_hook(j, &HookState::WaitHook, this, event) != 0) {
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700188 LOG(ERROR) << "Failed to add hook";
189 return false;
190 }
191
192 installed_ = true;
193 return true;
194}
195
196bool HookState::WaitForHookAndRun(const std::vector<HookCallback>& callbacks,
197 pid_t container_pid) {
198 if (!installed_) {
199 LOG(ERROR) << "Failed to wait for hook: not installed";
200 return false;
201 }
202 reached_pipe_.Wait();
203 base::ScopedClosureRunner teardown(
204 base::Bind(&WaitablePipe::Signal, base::Unretained(&ready_pipe_)));
205
206 for (auto& callback : callbacks) {
207 bool success = callback.Run(container_pid);
208 if (!success)
209 return false;
210 }
211 return true;
212}
213
214// static
215int HookState::WaitHook(void* payload) {
216 HookState* self = reinterpret_cast<HookState*>(payload);
217
218 self->reached_pipe_.Signal();
219 self->ready_pipe_.Wait();
220
221 return 0;
222}
223
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700224bool GetUsernsOutsideId(const std::string& map, int id, int* id_out) {
225 if (map.empty()) {
226 if (id_out)
227 *id_out = id;
228 return true;
229 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700230
231 std::string map_copy = map;
232 base::StringPiece map_piece(map_copy);
233
234 for (const auto& mapping : base::SplitStringPiece(
235 map_piece, ",", base::KEEP_WHITESPACE, base::SPLIT_WANT_ALL)) {
236 std::vector<base::StringPiece> tokens = base::SplitStringPiece(
237 mapping, " ", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
238
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700239 if (tokens.size() != 3) {
240 LOG(ERROR) << "Malformed ugid mapping: '" << mapping << "'";
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700241 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700242 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700243
244 uint32_t inside, outside, length;
245 if (!base::StringToUint(tokens[0], &inside) ||
246 !base::StringToUint(tokens[1], &outside) ||
247 !base::StringToUint(tokens[2], &length)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700248 LOG(ERROR) << "Malformed ugid mapping: '" << mapping << "'";
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700249 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700250 }
251
252 if (id >= inside && id <= (inside + length)) {
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700253 if (id_out)
254 *id_out = (id - inside) + outside;
255 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700256 }
257 }
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700258 VLOG(1) << "ugid " << id << " not found in mapping";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700259
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700260 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700261}
262
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700263bool MakeDir(const base::FilePath& path, int uid, int gid, int mode) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700264 if (mkdir(path.value().c_str(), mode)) {
265 PLOG_PRESERVE(ERROR) << "Failed to mkdir " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700266 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700267 }
268 if (chmod(path.value().c_str(), mode)) {
269 PLOG_PRESERVE(ERROR) << "Failed to chmod " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700270 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700271 }
272 if (chown(path.value().c_str(), uid, gid)) {
273 PLOG_PRESERVE(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700274 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700275 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700276 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700277}
278
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700279bool TouchFile(const base::FilePath& path, int uid, int gid, int mode) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700280 base::ScopedFD fd(open(path.value().c_str(), O_RDWR | O_CREAT, mode));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700281 if (!fd.is_valid()) {
282 PLOG_PRESERVE(ERROR) << "Failed to create " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700283 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700284 }
285 if (fchown(fd.get(), uid, gid)) {
286 PLOG_PRESERVE(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700287 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700288 }
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700289 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700290}
291
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700292bool LoopdevSetup(const base::FilePath& source,
293 base::FilePath* loopdev_path_out) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700294 base::ScopedFD source_fd(open(source.value().c_str(), O_RDONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700295 if (!source_fd.is_valid()) {
296 PLOG_PRESERVE(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700297 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700298 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700299
300 base::ScopedFD control_fd(
301 open(kLoopdevCtlPath, O_RDWR | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700302 if (!control_fd.is_valid()) {
303 PLOG_PRESERVE(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700304 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700305 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700306
307 while (true) {
308 int num = ioctl(control_fd.get(), LOOP_CTL_GET_FREE);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700309 if (num < 0) {
310 PLOG_PRESERVE(ERROR) << "Failed to open " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700311 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700312 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700313
314 base::FilePath loopdev_path(base::StringPrintf("/dev/loop%i", num));
315 base::ScopedFD loop_fd(
316 open(loopdev_path.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700317 if (!loop_fd.is_valid()) {
318 PLOG_PRESERVE(ERROR) << "Failed to open " << loopdev_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700319 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700320 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700321
322 if (ioctl(loop_fd.get(), LOOP_SET_FD, source_fd.get()) == 0) {
323 *loopdev_path_out = loopdev_path;
324 break;
325 }
326
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700327 if (errno != EBUSY) {
328 PLOG_PRESERVE(ERROR) << "Failed to ioctl(LOOP_SET_FD) "
329 << loopdev_path.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700330 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700331 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700332 }
333
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700334 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700335}
336
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700337bool LoopdevDetach(const base::FilePath& loopdev) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700338 base::ScopedFD fd(
339 open(loopdev.value().c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700340 if (!fd.is_valid()) {
341 PLOG_PRESERVE(ERROR) << "Failed to open " << loopdev.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700342 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700343 }
344 if (ioctl(fd.get(), LOOP_CLR_FD) < 0) {
345 PLOG_PRESERVE(ERROR) << "Failed to ioctl(LOOP_CLR_FD) for "
346 << loopdev.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700347 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700348 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700349
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700350 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700351}
352
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700353bool DeviceMapperSetup(const base::FilePath& source,
354 const std::string& verity_cmdline,
355 base::FilePath* dm_path_out,
356 std::string* dm_name_out) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700357#if USE_device_mapper
358 // Normalize the name into something unique-esque.
359 std::string dm_name =
360 base::StringPrintf("cros-containers-%s", source.value().c_str());
361 base::ReplaceChars(dm_name, "/", "_", &dm_name);
362
363 // Get the /dev path for the higher levels to mount.
364 base::FilePath dm_path = base::FilePath(kDevMapperPath).Append(dm_name);
365
366 // Insert the source path in the verity command line.
367 std::string verity = verity_cmdline;
368 base::ReplaceSubstringsAfterOffset(&verity, 0, "@DEV@", source.value());
369
370 // Extract the first three parameters for dm-verity settings.
371 char ttype[20];
372 unsigned long long start, size;
373 int n;
374 if (sscanf(verity.c_str(), "%llu %llu %10s %n", &start, &size, ttype, &n) !=
375 3) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700376 PLOG_PRESERVE(ERROR) << "Malformed verity string " << verity;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700377 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700378 }
379
380 /* Finally create the device mapper. */
381 std::unique_ptr<struct dm_task, decltype(&dm_task_destroy)> dmt(
382 dm_task_create(DM_DEVICE_CREATE), &dm_task_destroy);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700383 if (dmt == nullptr) {
384 PLOG_PRESERVE(ERROR) << "Failed to dm_task_create() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700385 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700386 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700387
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700388 if (dm_task_set_name(dmt.get(), dm_name.c_str()) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700389 PLOG_PRESERVE(ERROR) << "Failed to dm_task_set_name() for "
390 << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700391 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700392 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700393
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700394 if (dm_task_set_ro(dmt.get()) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700395 PLOG_PRESERVE(ERROR) << "Failed to dm_task_set_ro() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700396 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700397 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700398
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700399 if (dm_task_add_target(dmt.get(), start, size, ttype, verity.c_str() + n) !=
400 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700401 PLOG_PRESERVE(ERROR) << "Failed to dm_task_add_target() for "
402 << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700403 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700404 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700405
406 uint32_t cookie = 0;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700407 if (dm_task_set_cookie(dmt.get(), &cookie, 0) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700408 PLOG_PRESERVE(ERROR) << "Failed to dm_task_set_cookie() for "
409 << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700410 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700411 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700412
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700413 if (dm_task_run(dmt.get()) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700414 PLOG_PRESERVE(ERROR) << "Failed to dm_task_run() for " << source.value();
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700415 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700416 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700417
418 /* Make sure the node exists before we continue. */
419 dm_udev_wait(cookie);
420
421 *dm_path_out = dm_path;
422 *dm_name_out = dm_name;
423#endif
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700424 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700425}
426
427// Tear down the device mapper target.
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700428bool DeviceMapperDetach(const std::string& dm_name) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700429#if USE_device_mapper
430 struct dm_task* dmt = dm_task_create(DM_DEVICE_REMOVE);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700431 if (dmt == nullptr) {
432 PLOG_PRESERVE(ERROR) << "Failed to dm_task_run() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700433 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700434 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700435
436 base::ScopedClosureRunner teardown(
437 base::Bind(base::IgnoreResult(&dm_task_destroy), base::Unretained(dmt)));
438
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700439 if (dm_task_set_name(dmt, dm_name.c_str()) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700440 PLOG_PRESERVE(ERROR) << "Failed to dm_task_set_name() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700441 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700442 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700443
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700444 if (dm_task_run(dmt) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700445 PLOG_PRESERVE(ERROR) << "Failed to dm_task_run() for " << dm_name;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700446 return false;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700447 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700448#endif
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700449 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700450}
451
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700452bool MountExternal(const std::string& src,
453 const std::string& dest,
454 const std::string& type,
455 unsigned long flags,
456 const std::string& data) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700457 bool remount_ro = false;
458
459 // R/O bind mounts have to be remounted since 'bind' and 'ro' can't both be
460 // specified in the original bind mount. Remount R/O after the initial mount.
461 if ((flags & MS_BIND) && (flags & MS_RDONLY)) {
462 remount_ro = true;
463 flags &= ~MS_RDONLY;
464 }
465
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700466 if (mount(src.c_str(), dest.c_str(), type.c_str(), flags,
467 data.empty() ? nullptr : data.c_str()) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700468 PLOG_PRESERVE(ERROR) << "Failed to mount " << src << " to " << dest;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700469 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700470 }
471
472 if (remount_ro) {
473 flags |= MS_RDONLY;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700474 if (mount(src.c_str(), dest.c_str(), nullptr, flags | MS_REMOUNT,
475 data.empty() ? nullptr : data.c_str()) != 0) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700476 PLOG_PRESERVE(ERROR) << "Failed to remount " << src << " to " << dest;
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700477 return false;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700478 }
479 }
480
Luis Hector Chavez1f7e60c2017-09-27 22:03:48 -0700481 return true;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700482}
483
Luis Hector Chavez644d2042017-09-19 18:56:44 -0700484HookCallback AdaptCallbackToRunInNamespaces(HookCallback callback,
485 std::vector<int> nstypes) {
486 return base::Bind(&RunInNamespacesHelper,
487 base::Passed(std::move(callback)),
488 base::Passed(std::move(nstypes)));
489}
490
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700491} // namespace libcontainer