blob: 6a4792d6182f0d35e7a2a29694348e50c7c4e584 [file] [log] [blame]
Luis Hector Chavez81efb332017-09-18 14:01:29 -07001// Copyright 2016 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.
Dylan Reid837c74a2016-01-22 17:25:21 -08004
Dylan Reid837c74a2016-01-22 17:25:21 -08005#include <errno.h>
6#include <fcntl.h>
Dylan Reid837c74a2016-01-22 17:25:21 -08007#include <signal.h>
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07008#include <stdint.h>
Dylan Reid837c74a2016-01-22 17:25:21 -08009#include <stdlib.h>
10#include <string.h>
11#include <sys/mount.h>
12#include <sys/stat.h>
13#include <sys/types.h>
Dylan Reid2bd9ea92016-04-07 20:57:47 -070014#include <sys/wait.h>
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070015#include <syscall.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080016#include <unistd.h>
17
Luis Hector Chavez5381d002017-09-16 12:54:24 -070018#include <memory>
19#include <string>
20#include <vector>
21
22#include <base/bind.h>
23#include <base/bind_helpers.h>
24#include <base/callback_helpers.h>
25#include <base/files/file_path.h>
26#include <base/files/file_util.h>
27#include <base/files/scoped_file.h>
Luis Hector Chavez835d39e2017-09-19 15:16:31 -070028#include <base/logging.h>
Luis Hector Chavez5381d002017-09-16 12:54:24 -070029#include <base/macros.h>
30#include <base/strings/string_util.h>
31#include <base/strings/stringprintf.h>
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070032#include <libminijail.h>
Luis Hector Chavez626f5c82017-09-18 11:19:32 -070033#include <scoped_minijail.h>
Mike Frysinger412dbd22017-01-06 01:50:34 -050034
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -070035#include "libcontainer/cgroup.h"
Luis Hector Chavez836d7b22017-09-14 15:11:15 -070036#include "libcontainer/libcontainer.h"
Luis Hector Chavez81efb332017-09-18 14:01:29 -070037#include "libcontainer/libcontainer_util.h"
Yusuke Sato91f11f02016-12-02 16:15:13 -080038
Luis Hector Chavez5381d002017-09-16 12:54:24 -070039namespace {
40
Luis Hector Chavez81efb332017-09-18 14:01:29 -070041using libcontainer::DeviceMapperDetach;
42using libcontainer::DeviceMapperSetup;
43using libcontainer::GetUsernsOutsideId;
44using libcontainer::LoopdevDetach;
45using libcontainer::LoopdevSetup;
46using libcontainer::MakeDir;
47using libcontainer::MountExternal;
48using libcontainer::TouchFile;
Mike Frysinger412dbd22017-01-06 01:50:34 -050049
Luis Hector Chavez81efb332017-09-18 14:01:29 -070050constexpr size_t kMaxNumSetfilesArgs = 128;
51constexpr size_t kMaxRlimits = 32; // Linux defines 15 at the time of writing.
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070052
Luis Hector Chavez5381d002017-09-16 12:54:24 -070053struct Mount {
54 std::string name;
55 base::FilePath source;
56 base::FilePath destination;
57 std::string type;
58 std::string data;
59 std::string verity;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070060 int flags;
61 int uid;
62 int gid;
63 int mode;
Luis Hector Chavez5381d002017-09-16 12:54:24 -070064
65 // True if mount should happen in new vfs ns.
66 bool mount_in_ns;
67
68 // True if target should be created if it doesn't exist.
69 bool create;
70
71 // True if target should be mounted via loopback.
72 bool loopback;
Dylan Reid837c74a2016-01-22 17:25:21 -080073};
74
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070075struct Device {
76 // 'c' or 'b' for char or block
77 char type;
78 base::FilePath path;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070079 int fs_permissions;
80 int major;
81 int minor;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070082
83 // Copy the minor from existing node, ignores |minor|.
84 bool copy_minor;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070085 int uid;
86 int gid;
Dylan Reid4843d6b2017-03-31 18:14:30 -070087};
88
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070089struct CgroupDevice {
90 bool allow;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -070091 char type;
Luis Hector Chaveze1062e82017-09-18 09:57:37 -070092
93 // -1 for either major or minor means all.
94 int major;
95 int minor;
96
97 bool read;
98 bool write;
99 bool modify;
Dylan Reid837c74a2016-01-22 17:25:21 -0800100};
101
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700102struct CpuCgroup {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700103 int shares;
104 int quota;
105 int period;
106 int rt_runtime;
107 int rt_period;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800108};
109
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700110struct Rlimit {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700111 int type;
112 uint32_t cur;
113 uint32_t max;
Dylan Reid93fa4602017-06-06 13:39:31 -0700114};
115
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700116} // namespace
117
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700118// Structure that configures how the container is run.
Dylan Reid837c74a2016-01-22 17:25:21 -0800119struct container_config {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700120 // Path to the root of the container itself.
121 base::FilePath config_root;
122
123 // Path to the root of the container's filesystem.
124 base::FilePath rootfs;
125
126 // Flags that will be passed to mount() for the rootfs.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700127 unsigned long rootfs_mount_flags;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700128
129 // Path to where the container will be run.
130 base::FilePath premounted_runfs;
131
132 // Path to the file where the pid should be written.
133 base::FilePath pid_file_path;
134
135 // The program to run and args, e.g. "/sbin/init".
136 std::vector<std::string> program_argv;
137
138 // The uid the container will run as.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700139 uid_t uid;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700140
141 // Mapping of UIDs in the container, e.g. "0 100000 1024"
142 std::string uid_map;
143
144 // The gid the container will run as.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700145 gid_t gid;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700146
147 // Mapping of GIDs in the container, e.g. "0 100000 1024"
148 std::string gid_map;
149
150 // Syscall table to use or nullptr if none.
151 std::string alt_syscall_table;
152
153 // Filesystems to mount in the new namespace.
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700154 std::vector<Mount> mounts;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700155
156 // Device nodes to create.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700157 std::vector<Device> devices;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700158
159 // Device node cgroup permissions.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700160 std::vector<CgroupDevice> cgroup_devices;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700161
162 // Should run setfiles on mounts to enable selinux.
163 std::string run_setfiles;
164
165 // CPU cgroup params.
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700166 CpuCgroup cpu_cgparams;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700167
168 // Parent dir for cgroup creation
169 base::FilePath cgroup_parent;
170
171 // uid to own the created cgroups
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700172 uid_t cgroup_owner;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700173
174 // gid to own the created cgroups
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700175 gid_t cgroup_group;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700176
177 // Enable sharing of the host network namespace.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700178 int share_host_netns;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700179
180 // Allow the child process to keep open FDs (for stdin/out/err).
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700181 int keep_fds_open;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700182
183 // Array of rlimits for the contained process.
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700184 Rlimit rlimits[kMaxRlimits];
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700185
186 // The number of elements in `rlimits`.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700187 int num_rlimits;
188 int use_capmask;
189 int use_capmask_ambient;
190 uint64_t capmask;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700191
192 // The mask of securebits to skip when restricting caps.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700193 uint64_t securebits_skip_mask;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700194
195 // Whether the container needs an extra process to be run as init.
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700196 int do_init;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700197
198 // The SELinux context name the container will run under.
199 std::string selinux_context;
200
201 // A function pointer to be called prior to calling execve(2).
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700202 minijail_hook_t pre_start_hook;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700203
204 // Parameter that will be passed to pre_start_hook().
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700205 void* pre_start_hook_payload;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700206
207 std::vector<int> inherited_fds;
Dylan Reid837c74a2016-01-22 17:25:21 -0800208};
209
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700210// Container manipulation
211struct container {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700212 std::unique_ptr<libcontainer::Cgroup> cgroup;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700213 ScopedMinijail jail;
214 pid_t init_pid;
215 base::FilePath config_root;
216 base::FilePath runfs;
217 base::FilePath rundir;
218 base::FilePath runfsroot;
219 base::FilePath pid_file_path;
220
221 // Mounts made outside of the minijail.
222 std::vector<base::FilePath> ext_mounts;
223 std::vector<base::FilePath> loopdev_paths;
224 std::vector<std::string> device_mappers;
225 std::string name;
226};
227
228namespace {
229
230// Returns the path for |path_in_container| in the outer namespace.
231base::FilePath GetPathInOuterNamespace(
232 const base::FilePath& root, const base::FilePath& path_in_container) {
233 if (path_in_container.IsAbsolute())
234 return base::FilePath(root.value() + path_in_container.value());
235 return root.Append(path_in_container);
236}
237
238// Make sure the mount target exists in the new rootfs. Create if needed and
239// possible.
240int SetupMountDestination(const struct container_config* config,
241 const Mount& mount,
242 const base::FilePath& source,
243 const base::FilePath& dest) {
244 int rc;
245
246 struct stat st_buf;
247 rc = stat(dest.value().c_str(), &st_buf);
248 if (rc == 0) {
249 // destination exists.
250 return 0;
251 }
252
253 // Try to create the destination. Either make directory or touch a file
254 // depending on the source type.
255 int uid_userns = GetUsernsOutsideId(config->uid_map, mount.uid);
256 if (uid_userns < 0)
257 return uid_userns;
258 int gid_userns = GetUsernsOutsideId(config->gid_map, mount.gid);
259 if (gid_userns < 0)
260 return gid_userns;
261
262 rc = stat(source.value().c_str(), &st_buf);
263 if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode))
264 return MakeDir(dest, uid_userns, gid_userns, mount.mode);
265
266 return TouchFile(dest, uid_userns, gid_userns, mount.mode);
267}
268
269// Fork and exec the setfiles command to configure the selinux policy.
270int RunSetfilesCommand(const struct container* c,
271 const struct container_config* config,
272 const std::vector<base::FilePath>& destinations) {
273 if (config->run_setfiles.empty())
274 return 0;
275
276 int pid = fork();
277 if (pid == 0) {
278 size_t arg_index = 0;
279 const char* argv[kMaxNumSetfilesArgs];
280 const char* env[] = {
281 nullptr,
282 };
283
284 base::FilePath context_path = c->runfsroot.Append("file_contexts");
285
286 argv[arg_index++] = config->run_setfiles.c_str();
287 argv[arg_index++] = "-r";
288 argv[arg_index++] = c->runfsroot.value().c_str();
289 argv[arg_index++] = context_path.value().c_str();
290 if (arg_index + destinations.size() >= kMaxNumSetfilesArgs)
291 _exit(-E2BIG);
292 for (const auto& destination : destinations)
293 argv[arg_index++] = destination.value().c_str();
294 argv[arg_index] = nullptr;
295
296 execve(
297 argv[0], const_cast<char* const*>(argv), const_cast<char* const*>(env));
298
299 /* Command failed to exec if execve returns. */
300 _exit(-errno);
301 }
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700302 if (pid < 0) {
303 PLOG_PRESERVE(ERROR) << "Failed to fork to run setfiles";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700304 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700305 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700306
307 int rc;
308 int status;
309 do {
310 rc = waitpid(pid, &status, 0);
311 } while (rc == -1 && errno == EINTR);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700312 if (rc < 0) {
313 PLOG_PRESERVE(ERROR) << "Failed to wait for setfiles";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700314 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700315 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700316 return status;
317}
318
319// Unmounts anything we mounted in this mount namespace in the opposite order
320// that they were mounted.
321int UnmountExternalMounts(struct container* c) {
322 int ret = 0;
323
324 for (auto it = c->ext_mounts.rbegin(); it != c->ext_mounts.rend(); ++it) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700325 if (umount(it->value().c_str())) {
326 PLOG_PRESERVE(ERROR) << "Failed to unmount " << it->value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700327 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700328 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700329 }
330 c->ext_mounts.clear();
331
332 for (auto it = c->loopdev_paths.rbegin(); it != c->loopdev_paths.rend();
333 ++it) {
334 int rc = LoopdevDetach(*it);
335 if (rc)
336 ret = rc;
337 }
338 c->loopdev_paths.clear();
339
340 for (auto it = c->device_mappers.rbegin(); it != c->device_mappers.rend();
341 ++it) {
342 if (DeviceMapperDetach(*it))
343 ret = -errno;
344 }
345 c->device_mappers.clear();
346
347 return ret;
348}
349
350int DoContainerMount(struct container* c,
351 const struct container_config* config,
352 const Mount& mount) {
353 int rc = 0;
354
355 base::FilePath dest =
356 GetPathInOuterNamespace(c->runfsroot, mount.destination);
357
358 // If it's a bind mount relative to rootfs, append source to
359 // rootfs path, otherwise source path is absolute.
360 base::FilePath source;
361 if ((mount.flags & MS_BIND) && !mount.source.IsAbsolute()) {
362 source = GetPathInOuterNamespace(c->runfsroot, mount.source);
363 } else if (mount.loopback && !mount.source.IsAbsolute() &&
364 !c->config_root.empty()) {
365 source = GetPathInOuterNamespace(c->config_root, mount.source);
366 } else {
367 source = mount.source;
368 }
369
370 // Only create the destinations for external mounts, minijail will take
371 // care of those mounted in the new namespace.
372 if (mount.create && !mount.mount_in_ns) {
373 rc = SetupMountDestination(config, mount, source, dest);
374 if (rc)
375 return rc;
376 }
377 if (mount.loopback) {
378 // Record this loopback file for cleanup later.
379 base::FilePath loop_source = source;
380 rc = LoopdevSetup(loop_source, &source);
381 if (rc)
382 return rc;
383
384 // Save this to cleanup when shutting down.
385 c->loopdev_paths.push_back(source);
386 }
387 if (!mount.verity.empty()) {
388 // Set this device up via dm-verity.
389 std::string dm_name;
390 base::FilePath dm_source = source;
391 rc = DeviceMapperSetup(dm_source, mount.verity, &source, &dm_name);
392 if (rc)
393 return rc;
394
395 // Save this to cleanup when shutting down.
396 c->device_mappers.push_back(dm_name);
397 }
398 if (mount.mount_in_ns) {
399 // We can mount this with minijail.
400 rc = minijail_mount_with_data(
401 c->jail.get(),
402 source.value().c_str(),
403 mount.destination.value().c_str(),
404 mount.type.c_str(),
405 mount.flags,
406 mount.data.empty() ? nullptr : mount.data.c_str());
407 if (rc)
408 return rc;
409 } else {
410 // Mount this externally and unmount it on exit.
411 rc = MountExternal(source.value(),
412 dest.value(),
413 mount.type,
414 mount.flags,
415 mount.data);
416 if (rc)
417 return rc;
418 // Save this to unmount when shutting down.
419 c->ext_mounts.push_back(dest);
420 }
421
422 return 0;
423}
424
425int DoContainerMounts(struct container* c,
426 const struct container_config* config) {
427 UnmountExternalMounts(c);
428
429 // This will run in all the error cases.
430 base::ScopedClosureRunner teardown(base::Bind(
431 base::IgnoreResult(&UnmountExternalMounts), base::Unretained(c)));
432
433 for (const auto& mount : config->mounts) {
434 int rc = DoContainerMount(c, config, mount);
435 if (rc)
436 return rc;
437 }
438
439 // The mounts have been done successfully, no need to tear them down anymore.
440 ignore_result(teardown.Release());
441
442 return 0;
443}
444
445int ContainerCreateDevice(const struct container* c,
446 const struct container_config* config,
447 const Device& dev,
448 int minor) {
449 mode_t mode = dev.fs_permissions;
450 switch (dev.type) {
451 case 'b':
452 mode |= S_IFBLK;
453 break;
454 case 'c':
455 mode |= S_IFCHR;
456 break;
457 default:
458 return -EINVAL;
459 }
460
461 int uid_userns = GetUsernsOutsideId(config->uid_map, dev.uid);
462 if (uid_userns < 0)
463 return uid_userns;
464 int gid_userns = GetUsernsOutsideId(config->gid_map, dev.gid);
465 if (gid_userns < 0)
466 return gid_userns;
467
468 base::FilePath path = GetPathInOuterNamespace(c->runfsroot, dev.path);
469 if (mknod(path.value().c_str(), mode, makedev(dev.major, minor)) &&
470 errno != EEXIST) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700471 PLOG_PRESERVE(ERROR) << "Failed to mknod " << path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700472 return -errno;
473 }
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700474 if (chown(path.value().c_str(), uid_userns, gid_userns)) {
475 PLOG_PRESERVE(ERROR) << "Failed to chown " << path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700476 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700477 }
478 if (chmod(path.value().c_str(), dev.fs_permissions)) {
479 PLOG_PRESERVE(ERROR) << "Failed to chmod " << path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700480 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700481 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700482
483 return 0;
484}
485
486int MountRunfs(struct container* c, const struct container_config* config) {
487 {
488 std::string runfs_template = base::StringPrintf(
489 "%s/%s_XXXXXX", c->rundir.value().c_str(), c->name.c_str());
490 // TODO(lhchavez): Replace this with base::CreateTemporaryDirInDir().
491 char* runfs_path = mkdtemp(const_cast<char*>(runfs_template.c_str()));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700492 if (!runfs_path) {
493 PLOG_PRESERVE(ERROR) << "Failed to mkdtemp in " << c->rundir.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700494 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700495 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700496 c->runfs = base::FilePath(runfs_path);
497 }
498
499 int uid_userns = GetUsernsOutsideId(config->uid_map, config->uid);
500 if (uid_userns < 0)
501 return uid_userns;
502 int gid_userns = GetUsernsOutsideId(config->gid_map, config->gid);
503 if (gid_userns < 0)
504 return gid_userns;
505
506 // Make sure the container uid can access the rootfs.
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700507 if (chmod(c->runfs.value().c_str(), 0700)) {
508 PLOG_PRESERVE(ERROR) << "Failed to chmod " << c->runfs.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700509 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700510 }
511 if (chown(c->runfs.value().c_str(), uid_userns, gid_userns)) {
512 PLOG_PRESERVE(ERROR) << "Failed to chown " << c->runfs.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700513 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700514 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700515
516 c->runfsroot = c->runfs.Append("root");
517
518 constexpr mode_t kRootDirMode = 0660;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700519 if (mkdir(c->runfsroot.value().c_str(), kRootDirMode)) {
520 PLOG_PRESERVE(ERROR) << "Failed to mkdir " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700521 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700522 }
523 if (chmod(c->runfsroot.value().c_str(), kRootDirMode)) {
524 PLOG_PRESERVE(ERROR) << "Failed to chmod " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700525 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700526 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700527
528 if (mount(config->rootfs.value().c_str(),
529 c->runfsroot.value().c_str(),
530 "",
531 MS_BIND | (config->rootfs_mount_flags & MS_REC),
532 nullptr)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700533 PLOG_PRESERVE(ERROR) << "Failed to bind-mount " << config->rootfs.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700534 return -errno;
535 }
536
537 // MS_BIND ignores any flags passed to it (except MS_REC). We need a
538 // second call to mount() to actually set them.
539 if (config->rootfs_mount_flags &&
540 mount(config->rootfs.value().c_str(),
541 c->runfsroot.value().c_str(),
542 "",
543 (config->rootfs_mount_flags & ~MS_REC),
544 nullptr)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700545 PLOG_PRESERVE(ERROR) << "Failed to remount " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700546 return -errno;
547 }
548
549 return 0;
550}
551
552int DeviceSetup(struct container* c, const struct container_config* config) {
553 int rc;
554
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700555 c->cgroup->DenyAllDevices();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700556
557 for (const auto& dev : config->cgroup_devices) {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700558 rc = c->cgroup->AddDevice(dev.allow,
559 dev.major,
560 dev.minor,
561 dev.read,
562 dev.write,
563 dev.modify,
564 dev.type);
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700565 if (rc)
566 return rc;
567 }
568
569 for (const auto& dev : config->devices) {
570 int minor = dev.minor;
571
572 if (dev.copy_minor) {
573 struct stat st_buff;
574 if (stat(dev.path.value().c_str(), &st_buff) < 0)
575 continue;
576 minor = minor(st_buff.st_rdev);
577 }
578 if (minor >= 0) {
579 rc = ContainerCreateDevice(c, config, dev, minor);
580 if (rc)
581 return rc;
582 }
583 }
584
585 for (const auto& loopdev_path : c->loopdev_paths) {
586 struct stat st;
587
588 rc = stat(loopdev_path.value().c_str(), &st);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700589 if (rc < 0) {
590 PLOG_PRESERVE(ERROR) << "Failed to stat " << loopdev_path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700591 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700592 }
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -0700593 rc = c->cgroup->AddDevice(
594 1, major(st.st_rdev), minor(st.st_rdev), 1, 0, 0, 'b');
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700595 if (rc)
596 return rc;
597 }
598
599 return 0;
600}
601
602int Setexeccon(void* payload) {
603 char* init_domain = reinterpret_cast<char*>(payload);
604 pid_t tid = syscall(SYS_gettid);
605
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700606 if (tid == -1) {
607 PLOG_PRESERVE(ERROR) << "Failed to gettid";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700608 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700609 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700610
611 std::string exec_path =
612 base::StringPrintf("/proc/self/task/%d/attr/exec", tid);
613
614 base::ScopedFD fd(open(exec_path.c_str(), O_WRONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700615 if (!fd.is_valid()) {
616 PLOG_PRESERVE(ERROR) << "Failed to open " << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700617 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700618 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700619
620 if (write(fd.get(), init_domain, strlen(init_domain)) !=
621 (ssize_t)strlen(init_domain)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700622 PLOG_PRESERVE(ERROR) << "Failed to write the SELinux label to "
623 << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700624 return -errno;
625 }
626
627 return 0;
628}
629
630int ContainerTeardown(struct container* c) {
631 int ret = 0;
632
633 UnmountExternalMounts(c);
634 if (!c->runfsroot.empty() && !c->runfs.empty()) {
635 /* |c->runfsroot| may have been mounted recursively. Thus use
636 * MNT_DETACH to "immediately disconnect the filesystem and all
637 * filesystems mounted below it from each other and from the
638 * mount table". Otherwise one would need to unmount every
639 * single dependent mount before unmounting |c->runfsroot|
640 * itself.
641 */
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700642 if (umount2(c->runfsroot.value().c_str(), MNT_DETACH)) {
643 PLOG_PRESERVE(ERROR) << "Failed to detach " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700644 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700645 }
646 if (rmdir(c->runfsroot.value().c_str())) {
647 PLOG_PRESERVE(ERROR) << "Failed to rmdir " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700648 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700649 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700650 }
651 if (!c->pid_file_path.empty()) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700652 if (unlink(c->pid_file_path.value().c_str())) {
653 PLOG_PRESERVE(ERROR) << "Failed to unlink " << c->pid_file_path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700654 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700655 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700656 }
657 if (!c->runfs.empty()) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700658 if (rmdir(c->runfs.value().c_str())) {
659 PLOG_PRESERVE(ERROR) << "Failed to rmdir " << c->runfs.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700660 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700661 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700662 }
663 return ret;
664}
665
666
667} // namespace
668
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700669struct container_config* container_config_create() {
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700670 return new (std::nothrow) struct container_config();
Dylan Reid837c74a2016-01-22 17:25:21 -0800671}
672
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700673void container_config_destroy(struct container_config* c) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700674 if (c == nullptr)
675 return;
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700676 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -0800677}
678
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700679int container_config_config_root(struct container_config* c,
680 const char* config_root) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700681 c->config_root = base::FilePath(config_root);
682 return 0;
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500683}
684
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700685const char* container_config_get_config_root(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700686 return c->config_root.value().c_str();
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500687}
688
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700689int container_config_rootfs(struct container_config* c, const char* rootfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700690 c->rootfs = base::FilePath(rootfs);
691 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800692}
693
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700694const char* container_config_get_rootfs(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700695 return c->rootfs.value().c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700696}
697
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700698void container_config_rootfs_mount_flags(struct container_config* c,
699 unsigned long rootfs_mount_flags) {
700 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
701 * simply check against zero later. MS_BIND is also added to avoid
702 * re-mounting the original filesystem, since the rootfs is always
703 * bind-mounted.
704 */
705 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700706}
707
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700708unsigned long container_config_get_rootfs_mount_flags(
709 const struct container_config* c) {
710 return c->rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700711}
712
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700713int container_config_premounted_runfs(struct container_config* c,
714 const char* runfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700715 c->premounted_runfs = base::FilePath(runfs);
716 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700717}
718
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700719const char* container_config_get_premounted_runfs(
720 const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700721 return c->premounted_runfs.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700722}
723
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700724int container_config_pid_file(struct container_config* c, const char* path) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700725 c->pid_file_path = base::FilePath(path);
726 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700727}
728
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700729const char* container_config_get_pid_file(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700730 return c->pid_file_path.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700731}
732
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700733int container_config_program_argv(struct container_config* c,
734 const char** argv,
735 size_t num_args) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700736 if (num_args < 1)
737 return -EINVAL;
738 c->program_argv.clear();
739 c->program_argv.reserve(num_args);
740 for (size_t i = 0; i < num_args; ++i)
741 c->program_argv.emplace_back(argv[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700742 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800743}
744
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700745size_t container_config_get_num_program_args(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700746 return c->program_argv.size();
Dylan Reid11456722016-05-02 11:24:50 -0700747}
748
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700749const char* container_config_get_program_arg(const struct container_config* c,
750 size_t index) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700751 if (index >= c->program_argv.size())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700752 return nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700753 return c->program_argv[index].c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700754}
755
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700756void container_config_uid(struct container_config* c, uid_t uid) {
757 c->uid = uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700758}
759
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700760uid_t container_config_get_uid(const struct container_config* c) {
761 return c->uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700762}
763
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700764int container_config_uid_map(struct container_config* c, const char* uid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700765 c->uid_map = uid_map;
766 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800767}
768
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700769void container_config_gid(struct container_config* c, gid_t gid) {
770 c->gid = gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700771}
772
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700773gid_t container_config_get_gid(const struct container_config* c) {
774 return c->gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700775}
776
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700777int container_config_gid_map(struct container_config* c, const char* gid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700778 c->gid_map = gid_map;
779 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800780}
781
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700782int container_config_alt_syscall_table(struct container_config* c,
783 const char* alt_syscall_table) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700784 c->alt_syscall_table = alt_syscall_table;
785 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800786}
787
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700788int container_config_add_rlimit(struct container_config* c,
789 int type,
790 uint32_t cur,
791 uint32_t max) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700792 if (c->num_rlimits >= kMaxRlimits)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700793 return -ENOMEM;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700794 c->rlimits[c->num_rlimits].type = type;
795 c->rlimits[c->num_rlimits].cur = cur;
796 c->rlimits[c->num_rlimits].max = max;
797 c->num_rlimits++;
798 return 0;
Dylan Reid93fa4602017-06-06 13:39:31 -0700799}
800
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700801int container_config_add_mount(struct container_config* c,
802 const char* name,
803 const char* source,
804 const char* destination,
805 const char* type,
806 const char* data,
807 const char* verity,
808 int flags,
809 int uid,
810 int gid,
811 int mode,
812 int mount_in_ns,
813 int create,
814 int loopback) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700815 if (name == nullptr || source == nullptr || destination == nullptr ||
816 type == nullptr)
817 return -EINVAL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800818
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700819 c->mounts.emplace_back(Mount{name,
820 base::FilePath(source),
821 base::FilePath(destination),
822 type,
823 data ? data : "",
824 verity ? verity : "",
825 flags,
826 uid,
827 gid,
828 mode,
829 mount_in_ns != 0,
830 create != 0,
831 loopback != 0});
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700832
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700833 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800834}
835
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700836int container_config_add_cgroup_device(struct container_config* c,
837 int allow,
838 char type,
839 int major,
840 int minor,
841 int read,
842 int write,
843 int modify) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700844 c->cgroup_devices.emplace_back(CgroupDevice{
845 allow != 0, type, major, minor, read != 0, write != 0, modify != 0});
Dylan Reid4843d6b2017-03-31 18:14:30 -0700846
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700847 return 0;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700848}
849
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700850int container_config_add_device(struct container_config* c,
851 char type,
852 const char* path,
853 int fs_permissions,
854 int major,
855 int minor,
856 int copy_minor,
857 int uid,
858 int gid,
859 int read_allowed,
860 int write_allowed,
861 int modify_allowed) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700862 if (path == nullptr)
863 return -EINVAL;
864 /* If using a dynamic minor number, ensure that minor is -1. */
865 if (copy_minor && (minor != -1))
866 return -EINVAL;
Dylan Reid355d5e42016-04-29 16:53:31 -0700867
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700868 if (read_allowed || write_allowed || modify_allowed) {
869 if (container_config_add_cgroup_device(c,
870 1,
871 type,
872 major,
873 minor,
874 read_allowed,
875 write_allowed,
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700876 modify_allowed)) {
877 return -ENOMEM;
878 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700879 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700880
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700881 c->devices.emplace_back(Device{
882 type,
883 base::FilePath(path),
884 fs_permissions,
885 major,
886 minor,
887 copy_minor != 0,
888 uid,
889 gid,
890 });
891
892 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800893}
894
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700895int container_config_run_setfiles(struct container_config* c,
896 const char* setfiles_cmd) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700897 c->run_setfiles = setfiles_cmd;
898 return 0;
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700899}
Dylan Reid837c74a2016-01-22 17:25:21 -0800900
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700901const char* container_config_get_run_setfiles(
902 const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700903 return c->run_setfiles.c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700904}
905
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700906int container_config_set_cpu_shares(struct container_config* c, int shares) {
907 /* CPU shares must be 2 or higher. */
908 if (shares < 2)
909 return -EINVAL;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800910
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700911 c->cpu_cgparams.shares = shares;
912 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800913}
914
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700915int container_config_set_cpu_cfs_params(struct container_config* c,
916 int quota,
917 int period) {
918 /*
919 * quota could be set higher than period to utilize more than one CPU.
920 * quota could also be set as -1 to indicate the cgroup does not adhere
921 * to any CPU time restrictions.
922 */
923 if (quota <= 0 && quota != -1)
924 return -EINVAL;
925 if (period <= 0)
926 return -EINVAL;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800927
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700928 c->cpu_cgparams.quota = quota;
929 c->cpu_cgparams.period = period;
930 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800931}
932
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700933int container_config_set_cpu_rt_params(struct container_config* c,
934 int rt_runtime,
935 int rt_period) {
936 /*
937 * rt_runtime could be set as 0 to prevent the cgroup from using
938 * realtime CPU.
939 */
940 if (rt_runtime < 0 || rt_runtime >= rt_period)
941 return -EINVAL;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800942
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700943 c->cpu_cgparams.rt_runtime = rt_runtime;
944 c->cpu_cgparams.rt_period = rt_period;
945 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800946}
947
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700948int container_config_get_cpu_shares(struct container_config* c) {
949 return c->cpu_cgparams.shares;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800950}
951
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700952int container_config_get_cpu_quota(struct container_config* c) {
953 return c->cpu_cgparams.quota;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800954}
955
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700956int container_config_get_cpu_period(struct container_config* c) {
957 return c->cpu_cgparams.period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800958}
959
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700960int container_config_get_cpu_rt_runtime(struct container_config* c) {
961 return c->cpu_cgparams.rt_runtime;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800962}
963
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700964int container_config_get_cpu_rt_period(struct container_config* c) {
965 return c->cpu_cgparams.rt_period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800966}
967
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700968int container_config_set_cgroup_parent(struct container_config* c,
969 const char* parent,
970 uid_t cgroup_owner,
971 gid_t cgroup_group) {
972 c->cgroup_owner = cgroup_owner;
973 c->cgroup_group = cgroup_group;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700974 c->cgroup_parent = base::FilePath(parent);
975 return 0;
Dylan Reid9e724af2016-07-21 09:58:07 -0700976}
977
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700978const char* container_config_get_cgroup_parent(struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700979 return c->cgroup_parent.value().c_str();
Dylan Reid9e724af2016-07-21 09:58:07 -0700980}
981
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700982void container_config_share_host_netns(struct container_config* c) {
983 c->share_host_netns = 1;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700984}
985
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700986int get_container_config_share_host_netns(struct container_config* c) {
987 return c->share_host_netns;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700988}
989
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700990void container_config_keep_fds_open(struct container_config* c) {
991 c->keep_fds_open = 1;
Dylan Reidc4335842016-11-11 10:24:52 -0800992}
993
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700994void container_config_set_capmask(struct container_config* c,
995 uint64_t capmask,
996 int ambient) {
997 c->use_capmask = 1;
998 c->capmask = capmask;
999 c->use_capmask_ambient = ambient;
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001000}
1001
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001002void container_config_set_securebits_skip_mask(struct container_config* c,
1003 uint64_t securebits_skip_mask) {
1004 c->securebits_skip_mask = securebits_skip_mask;
Luis Hector Chavezcd44ba72017-06-30 13:01:38 -07001005}
1006
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001007void container_config_set_run_as_init(struct container_config* c,
1008 int run_as_init) {
1009 c->do_init = !run_as_init;
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001010}
1011
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001012int container_config_set_selinux_context(struct container_config* c,
1013 const char* context) {
1014 if (!context)
1015 return -EINVAL;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001016 c->selinux_context = context;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001017 return 0;
Luis Hector Chavez15e8e672017-07-20 15:13:27 -07001018}
1019
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001020void container_config_set_pre_execve_hook(struct container_config* c,
1021 int (*hook)(void*),
1022 void* payload) {
1023 c->pre_start_hook = hook;
1024 c->pre_start_hook_payload = payload;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001025}
1026
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001027int container_config_inherit_fds(struct container_config* c,
1028 int* inherited_fds,
1029 size_t inherited_fd_count) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001030 if (!c->inherited_fds.empty())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001031 return -EINVAL;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001032 for (size_t i = 0; i < inherited_fd_count; ++i)
1033 c->inherited_fds.emplace_back(inherited_fds[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001034 return 0;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001035}
1036
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001037struct container* container_new(const char* name, const char* rundir) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001038 struct container* c = new (std::nothrow) container();
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001039 if (!c)
1040 return nullptr;
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001041 c->rundir = base::FilePath(rundir);
1042 c->name = name;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001043 return c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001044}
1045
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001046void container_destroy(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001047 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001048}
1049
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001050int container_start(struct container* c,
1051 const struct container_config* config) {
1052 int rc = 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001053
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001054 if (!c)
1055 return -EINVAL;
1056 if (!config)
1057 return -EINVAL;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001058 if (config->program_argv.empty())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001059 return -EINVAL;
Dylan Reide040c6b2016-05-02 18:49:02 -07001060
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001061 // This will run in all the error cases.
1062 base::ScopedClosureRunner teardown(
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001063 base::Bind(base::IgnoreResult(&ContainerTeardown), base::Unretained(c)));
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001064
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001065 if (!config->config_root.empty())
1066 c->config_root = config->config_root;
1067 if (!config->premounted_runfs.empty()) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001068 c->runfs.clear();
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001069 c->runfsroot = config->premounted_runfs;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001070 } else {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001071 rc = MountRunfs(c, config);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001072 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001073 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001074 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001075
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001076 c->jail.reset(minijail_new());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001077 if (!c->jail)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001078 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -08001079
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001080 rc = DoContainerMounts(c, config);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001081 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001082 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001083
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001084 int cgroup_uid = GetUsernsOutsideId(config->uid_map, config->cgroup_owner);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001085 if (cgroup_uid < 0)
1086 return cgroup_uid;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001087 int cgroup_gid = GetUsernsOutsideId(config->gid_map, config->cgroup_group);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001088 if (cgroup_gid < 0)
1089 return cgroup_gid;
Stephen Barber1a398c72017-01-23 12:39:44 -08001090
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001091 c->cgroup = libcontainer::Cgroup::Create(c->name,
1092 base::FilePath("/sys/fs/cgroup"),
1093 config->cgroup_parent,
1094 cgroup_uid,
1095 cgroup_gid);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001096 if (!c->cgroup)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001097 return -errno;
Dylan Reida9966422016-07-21 10:11:34 -07001098
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001099 /* Must be root to modify device cgroup or mknod */
1100 if (getuid() == 0) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001101 rc = DeviceSetup(c, config);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001102 if (rc)
1103 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001104 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001105
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001106 /* Potentially run setfiles on mounts configured outside of the jail */
1107 const base::FilePath kDataPath("/data");
1108 const base::FilePath kCachePath("/cache");
1109 std::vector<base::FilePath> destinations;
1110 for (const auto& mnt : config->mounts) {
1111 if (mnt.mount_in_ns)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001112 continue;
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001113 if (mnt.flags & MS_RDONLY)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001114 continue;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001115
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001116 /* A hack to avoid setfiles on /data and /cache. */
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001117 if (mnt.destination == kDataPath || mnt.destination == kCachePath)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001118 continue;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001119
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001120 destinations.emplace_back(
1121 GetPathInOuterNamespace(c->runfsroot, mnt.destination));
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001122 }
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001123 if (!destinations.empty()) {
1124 rc = RunSetfilesCommand(c, config, destinations);
1125 if (rc)
1126 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001127 }
Dylan Reidd7229582016-04-27 17:08:40 -07001128
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001129 /* Setup CPU cgroup params. */
1130 if (config->cpu_cgparams.shares) {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001131 rc = c->cgroup->SetCpuShares(config->cpu_cgparams.shares);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001132 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001133 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001134 }
1135 if (config->cpu_cgparams.period) {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001136 rc = c->cgroup->SetCpuQuota(config->cpu_cgparams.quota);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001137 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001138 return rc;
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001139 rc = c->cgroup->SetCpuPeriod(config->cpu_cgparams.period);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001140 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001141 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001142 }
1143 if (config->cpu_cgparams.rt_period) {
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001144 rc = c->cgroup->SetCpuRtRuntime(config->cpu_cgparams.rt_runtime);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001145 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001146 return rc;
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001147 rc = c->cgroup->SetCpuRtPeriod(config->cpu_cgparams.rt_period);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001148 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001149 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001150 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001151
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001152 /* Setup and start the container with libminijail. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001153 if (!config->pid_file_path.empty())
1154 c->pid_file_path = config->pid_file_path;
1155 else if (!c->runfs.empty())
1156 c->pid_file_path = c->runfs.Append("container.pid");
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001157
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001158 if (!c->pid_file_path.empty())
1159 minijail_write_pid_file(c->jail.get(), c->pid_file_path.value().c_str());
1160 minijail_reset_signal_mask(c->jail.get());
Dylan Reid837c74a2016-01-22 17:25:21 -08001161
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001162 /* Setup container namespaces. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001163 minijail_namespace_ipc(c->jail.get());
1164 minijail_namespace_vfs(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001165 if (!config->share_host_netns)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001166 minijail_namespace_net(c->jail.get());
1167 minijail_namespace_pids(c->jail.get());
1168 minijail_namespace_user(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001169 if (getuid() != 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001170 minijail_namespace_user_disable_setgroups(c->jail.get());
1171 minijail_namespace_cgroups(c->jail.get());
1172 rc = minijail_uidmap(c->jail.get(), config->uid_map.c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001173 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001174 return rc;
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001175 rc = minijail_gidmap(c->jail.get(), config->gid_map.c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001176 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001177 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001178
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001179 /* Set the UID/GID inside the container if not 0. */
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001180 rc = GetUsernsOutsideId(config->uid_map, config->uid);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001181 if (rc < 0)
1182 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001183 else if (config->uid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001184 minijail_change_uid(c->jail.get(), config->uid);
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001185 rc = GetUsernsOutsideId(config->gid_map, config->gid);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001186 if (rc < 0)
1187 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001188 else if (config->gid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001189 minijail_change_gid(c->jail.get(), config->gid);
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001190
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001191 rc = minijail_enter_pivot_root(c->jail.get(), c->runfsroot.value().c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001192 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001193 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001194
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001195 // Add the cgroups configured above.
1196 for (int32_t i = 0; i < libcontainer::Cgroup::Type::NUM_TYPES; i++) {
1197 if (c->cgroup->has_tasks_path(i)) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001198 rc = minijail_add_to_cgroup(c->jail.get(),
Luis Hector Chavez76ae9ac2017-09-20 21:13:08 -07001199 c->cgroup->tasks_path(i).value().c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001200 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001201 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001202 }
1203 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001204
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001205 if (!config->alt_syscall_table.empty())
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001206 minijail_use_alt_syscall(c->jail.get(), config->alt_syscall_table.c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -08001207
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001208 for (int i = 0; i < config->num_rlimits; i++) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001209 const Rlimit& lim = config->rlimits[i];
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001210 rc = minijail_rlimit(c->jail.get(), lim.type, lim.cur, lim.max);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001211 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001212 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001213 }
Dylan Reid93fa4602017-06-06 13:39:31 -07001214
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001215 if (!config->selinux_context.empty()) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001216 rc = minijail_add_hook(c->jail.get(),
1217 &Setexeccon,
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001218 const_cast<char*>(config->selinux_context.c_str()),
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001219 MINIJAIL_HOOK_EVENT_PRE_EXECVE);
1220 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001221 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001222 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001223
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001224 if (config->pre_start_hook) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001225 rc = minijail_add_hook(c->jail.get(),
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001226 config->pre_start_hook,
1227 config->pre_start_hook_payload,
1228 MINIJAIL_HOOK_EVENT_PRE_EXECVE);
1229 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001230 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001231 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001232
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001233 for (int fd : config->inherited_fds) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001234 rc = minijail_preserve_fd(c->jail.get(), fd, fd);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001235 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001236 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001237 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001238
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001239 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001240 minijail_skip_remount_private(c->jail.get());
Dylan Reid3da683b2016-04-05 03:35:35 -07001241
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001242 if (!config->keep_fds_open)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001243 minijail_close_open_fds(c->jail.get());
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001244
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001245 if (config->use_capmask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001246 minijail_use_caps(c->jail.get(), config->capmask);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001247 if (config->use_capmask_ambient) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001248 minijail_set_ambient_caps(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001249 }
1250 if (config->securebits_skip_mask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001251 minijail_skip_setting_securebits(c->jail.get(),
1252 config->securebits_skip_mask);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001253 }
1254 }
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001255
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001256 if (!config->do_init)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001257 minijail_run_as_init(c->jail.get());
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001258
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001259 std::vector<char*> argv_cstr;
1260 argv_cstr.reserve(config->program_argv.size() + 1);
1261 for (const auto& arg : config->program_argv)
1262 argv_cstr.emplace_back(const_cast<char*>(arg.c_str()));
1263 argv_cstr.emplace_back(nullptr);
1264
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001265 rc = minijail_run_pid_pipes_no_preload(c->jail.get(),
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001266 argv_cstr[0],
1267 argv_cstr.data(),
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001268 &c->init_pid,
1269 nullptr,
1270 nullptr,
1271 nullptr);
1272 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001273 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001274
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001275 // The container has started successfully, no need to tear it down anymore.
1276 ignore_result(teardown.Release());
1277 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001278}
1279
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001280const char* container_root(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001281 return c->runfs.value().c_str();
Dylan Reid837c74a2016-01-22 17:25:21 -08001282}
1283
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001284int container_pid(struct container* c) {
1285 return c->init_pid;
Dylan Reid837c74a2016-01-22 17:25:21 -08001286}
1287
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001288int container_wait(struct container* c) {
1289 int rc;
Dylan Reidcf745c52016-04-22 10:18:03 -07001290
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001291 do {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001292 rc = minijail_wait(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001293 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001294
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001295 // If the process had already been reaped, still perform teardown.
1296 if (rc == -ECHILD || rc >= 0) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001297 rc = ContainerTeardown(c);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001298 }
1299 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001300}
1301
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001302int container_kill(struct container* c) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -07001303 if (kill(c->init_pid, SIGKILL) && errno != ESRCH) {
1304 PLOG_PRESERVE(ERROR) << "Failed to kill " << c->init_pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001305 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -07001306 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001307 return container_wait(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001308}