blob: 0db738514dd4aea95cd10dea41ef2292bfb1fc26 [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 Chavez836d7b22017-09-14 15:11:15 -070035#include "libcontainer/container_cgroup.h"
36#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 {
212 struct container_cgroup* cgroup;
213 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
555 c->cgroup->ops->deny_all_devices(c->cgroup);
556
557 for (const auto& dev : config->cgroup_devices) {
558 rc = c->cgroup->ops->add_device(c->cgroup,
559 dev.allow,
560 dev.major,
561 dev.minor,
562 dev.read,
563 dev.write,
564 dev.modify,
565 dev.type);
566 if (rc)
567 return rc;
568 }
569
570 for (const auto& dev : config->devices) {
571 int minor = dev.minor;
572
573 if (dev.copy_minor) {
574 struct stat st_buff;
575 if (stat(dev.path.value().c_str(), &st_buff) < 0)
576 continue;
577 minor = minor(st_buff.st_rdev);
578 }
579 if (minor >= 0) {
580 rc = ContainerCreateDevice(c, config, dev, minor);
581 if (rc)
582 return rc;
583 }
584 }
585
586 for (const auto& loopdev_path : c->loopdev_paths) {
587 struct stat st;
588
589 rc = stat(loopdev_path.value().c_str(), &st);
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700590 if (rc < 0) {
591 PLOG_PRESERVE(ERROR) << "Failed to stat " << loopdev_path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700592 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700593 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700594 rc = c->cgroup->ops->add_device(
595 c->cgroup, 1, major(st.st_rdev), minor(st.st_rdev), 1, 0, 0, 'b');
596 if (rc)
597 return rc;
598 }
599
600 return 0;
601}
602
603int Setexeccon(void* payload) {
604 char* init_domain = reinterpret_cast<char*>(payload);
605 pid_t tid = syscall(SYS_gettid);
606
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700607 if (tid == -1) {
608 PLOG_PRESERVE(ERROR) << "Failed to gettid";
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700609 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700610 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700611
612 std::string exec_path =
613 base::StringPrintf("/proc/self/task/%d/attr/exec", tid);
614
615 base::ScopedFD fd(open(exec_path.c_str(), O_WRONLY | O_CLOEXEC));
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700616 if (!fd.is_valid()) {
617 PLOG_PRESERVE(ERROR) << "Failed to open " << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700618 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700619 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700620
621 if (write(fd.get(), init_domain, strlen(init_domain)) !=
622 (ssize_t)strlen(init_domain)) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700623 PLOG_PRESERVE(ERROR) << "Failed to write the SELinux label to "
624 << exec_path;
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700625 return -errno;
626 }
627
628 return 0;
629}
630
631int ContainerTeardown(struct container* c) {
632 int ret = 0;
633
634 UnmountExternalMounts(c);
635 if (!c->runfsroot.empty() && !c->runfs.empty()) {
636 /* |c->runfsroot| may have been mounted recursively. Thus use
637 * MNT_DETACH to "immediately disconnect the filesystem and all
638 * filesystems mounted below it from each other and from the
639 * mount table". Otherwise one would need to unmount every
640 * single dependent mount before unmounting |c->runfsroot|
641 * itself.
642 */
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700643 if (umount2(c->runfsroot.value().c_str(), MNT_DETACH)) {
644 PLOG_PRESERVE(ERROR) << "Failed to detach " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700645 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700646 }
647 if (rmdir(c->runfsroot.value().c_str())) {
648 PLOG_PRESERVE(ERROR) << "Failed to rmdir " << c->runfsroot.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700649 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700650 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700651 }
652 if (!c->pid_file_path.empty()) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700653 if (unlink(c->pid_file_path.value().c_str())) {
654 PLOG_PRESERVE(ERROR) << "Failed to unlink " << c->pid_file_path.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700655 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700656 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700657 }
658 if (!c->runfs.empty()) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700659 if (rmdir(c->runfs.value().c_str())) {
660 PLOG_PRESERVE(ERROR) << "Failed to rmdir " << c->runfs.value();
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700661 ret = -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -0700662 }
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700663 }
664 return ret;
665}
666
667
668} // namespace
669
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700670struct container_config* container_config_create() {
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700671 return new (std::nothrow) struct container_config();
Dylan Reid837c74a2016-01-22 17:25:21 -0800672}
673
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700674void container_config_destroy(struct container_config* c) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700675 if (c == nullptr)
676 return;
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700677 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -0800678}
679
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700680int container_config_config_root(struct container_config* c,
681 const char* config_root) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700682 c->config_root = base::FilePath(config_root);
683 return 0;
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500684}
685
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700686const char* container_config_get_config_root(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700687 return c->config_root.value().c_str();
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500688}
689
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700690int container_config_rootfs(struct container_config* c, const char* rootfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700691 c->rootfs = base::FilePath(rootfs);
692 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800693}
694
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700695const char* container_config_get_rootfs(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700696 return c->rootfs.value().c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700697}
698
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700699void container_config_rootfs_mount_flags(struct container_config* c,
700 unsigned long rootfs_mount_flags) {
701 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
702 * simply check against zero later. MS_BIND is also added to avoid
703 * re-mounting the original filesystem, since the rootfs is always
704 * bind-mounted.
705 */
706 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700707}
708
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700709unsigned long container_config_get_rootfs_mount_flags(
710 const struct container_config* c) {
711 return c->rootfs_mount_flags;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700712}
713
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700714int container_config_premounted_runfs(struct container_config* c,
715 const char* runfs) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700716 c->premounted_runfs = base::FilePath(runfs);
717 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700718}
719
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700720const char* container_config_get_premounted_runfs(
721 const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700722 return c->premounted_runfs.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700723}
724
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700725int container_config_pid_file(struct container_config* c, const char* path) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700726 c->pid_file_path = base::FilePath(path);
727 return 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700728}
729
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700730const char* container_config_get_pid_file(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700731 return c->pid_file_path.value().c_str();
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700732}
733
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700734int container_config_program_argv(struct container_config* c,
735 const char** argv,
736 size_t num_args) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700737 if (num_args < 1)
738 return -EINVAL;
739 c->program_argv.clear();
740 c->program_argv.reserve(num_args);
741 for (size_t i = 0; i < num_args; ++i)
742 c->program_argv.emplace_back(argv[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700743 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800744}
745
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700746size_t container_config_get_num_program_args(const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700747 return c->program_argv.size();
Dylan Reid11456722016-05-02 11:24:50 -0700748}
749
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700750const char* container_config_get_program_arg(const struct container_config* c,
751 size_t index) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700752 if (index >= c->program_argv.size())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700753 return nullptr;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700754 return c->program_argv[index].c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700755}
756
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700757void container_config_uid(struct container_config* c, uid_t uid) {
758 c->uid = uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700759}
760
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700761uid_t container_config_get_uid(const struct container_config* c) {
762 return c->uid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700763}
764
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700765int container_config_uid_map(struct container_config* c, const char* uid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700766 c->uid_map = uid_map;
767 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800768}
769
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700770void container_config_gid(struct container_config* c, gid_t gid) {
771 c->gid = gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700772}
773
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700774gid_t container_config_get_gid(const struct container_config* c) {
775 return c->gid;
Dylan Reid1874feb2016-06-22 17:53:50 -0700776}
777
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700778int container_config_gid_map(struct container_config* c, const char* gid_map) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700779 c->gid_map = gid_map;
780 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800781}
782
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700783int container_config_alt_syscall_table(struct container_config* c,
784 const char* alt_syscall_table) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700785 c->alt_syscall_table = alt_syscall_table;
786 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800787}
788
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700789int container_config_add_rlimit(struct container_config* c,
790 int type,
791 uint32_t cur,
792 uint32_t max) {
Luis Hector Chavez81efb332017-09-18 14:01:29 -0700793 if (c->num_rlimits >= kMaxRlimits)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700794 return -ENOMEM;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700795 c->rlimits[c->num_rlimits].type = type;
796 c->rlimits[c->num_rlimits].cur = cur;
797 c->rlimits[c->num_rlimits].max = max;
798 c->num_rlimits++;
799 return 0;
Dylan Reid93fa4602017-06-06 13:39:31 -0700800}
801
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700802int container_config_add_mount(struct container_config* c,
803 const char* name,
804 const char* source,
805 const char* destination,
806 const char* type,
807 const char* data,
808 const char* verity,
809 int flags,
810 int uid,
811 int gid,
812 int mode,
813 int mount_in_ns,
814 int create,
815 int loopback) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700816 if (name == nullptr || source == nullptr || destination == nullptr ||
817 type == nullptr)
818 return -EINVAL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800819
Luis Hector Chavez5381d002017-09-16 12:54:24 -0700820 c->mounts.emplace_back(Mount{name,
821 base::FilePath(source),
822 base::FilePath(destination),
823 type,
824 data ? data : "",
825 verity ? verity : "",
826 flags,
827 uid,
828 gid,
829 mode,
830 mount_in_ns != 0,
831 create != 0,
832 loopback != 0});
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700833
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700834 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800835}
836
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700837int container_config_add_cgroup_device(struct container_config* c,
838 int allow,
839 char type,
840 int major,
841 int minor,
842 int read,
843 int write,
844 int modify) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700845 c->cgroup_devices.emplace_back(CgroupDevice{
846 allow != 0, type, major, minor, read != 0, write != 0, modify != 0});
Dylan Reid4843d6b2017-03-31 18:14:30 -0700847
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700848 return 0;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700849}
850
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700851int container_config_add_device(struct container_config* c,
852 char type,
853 const char* path,
854 int fs_permissions,
855 int major,
856 int minor,
857 int copy_minor,
858 int uid,
859 int gid,
860 int read_allowed,
861 int write_allowed,
862 int modify_allowed) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700863 if (path == nullptr)
864 return -EINVAL;
865 /* If using a dynamic minor number, ensure that minor is -1. */
866 if (copy_minor && (minor != -1))
867 return -EINVAL;
Dylan Reid355d5e42016-04-29 16:53:31 -0700868
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700869 if (read_allowed || write_allowed || modify_allowed) {
870 if (container_config_add_cgroup_device(c,
871 1,
872 type,
873 major,
874 minor,
875 read_allowed,
876 write_allowed,
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700877 modify_allowed)) {
878 return -ENOMEM;
879 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700880 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700881
Luis Hector Chaveze1062e82017-09-18 09:57:37 -0700882 c->devices.emplace_back(Device{
883 type,
884 base::FilePath(path),
885 fs_permissions,
886 major,
887 minor,
888 copy_minor != 0,
889 uid,
890 gid,
891 });
892
893 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -0800894}
895
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700896int container_config_run_setfiles(struct container_config* c,
897 const char* setfiles_cmd) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700898 c->run_setfiles = setfiles_cmd;
899 return 0;
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700900}
Dylan Reid837c74a2016-01-22 17:25:21 -0800901
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700902const char* container_config_get_run_setfiles(
903 const struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700904 return c->run_setfiles.c_str();
Dylan Reid11456722016-05-02 11:24:50 -0700905}
906
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700907int container_config_set_cpu_shares(struct container_config* c, int shares) {
908 /* CPU shares must be 2 or higher. */
909 if (shares < 2)
910 return -EINVAL;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800911
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700912 c->cpu_cgparams.shares = shares;
913 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800914}
915
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700916int container_config_set_cpu_cfs_params(struct container_config* c,
917 int quota,
918 int period) {
919 /*
920 * quota could be set higher than period to utilize more than one CPU.
921 * quota could also be set as -1 to indicate the cgroup does not adhere
922 * to any CPU time restrictions.
923 */
924 if (quota <= 0 && quota != -1)
925 return -EINVAL;
926 if (period <= 0)
927 return -EINVAL;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800928
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700929 c->cpu_cgparams.quota = quota;
930 c->cpu_cgparams.period = period;
931 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800932}
933
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700934int container_config_set_cpu_rt_params(struct container_config* c,
935 int rt_runtime,
936 int rt_period) {
937 /*
938 * rt_runtime could be set as 0 to prevent the cgroup from using
939 * realtime CPU.
940 */
941 if (rt_runtime < 0 || rt_runtime >= rt_period)
942 return -EINVAL;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800943
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700944 c->cpu_cgparams.rt_runtime = rt_runtime;
945 c->cpu_cgparams.rt_period = rt_period;
946 return 0;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800947}
948
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700949int container_config_get_cpu_shares(struct container_config* c) {
950 return c->cpu_cgparams.shares;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800951}
952
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700953int container_config_get_cpu_quota(struct container_config* c) {
954 return c->cpu_cgparams.quota;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800955}
956
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700957int container_config_get_cpu_period(struct container_config* c) {
958 return c->cpu_cgparams.period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800959}
960
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700961int container_config_get_cpu_rt_runtime(struct container_config* c) {
962 return c->cpu_cgparams.rt_runtime;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800963}
964
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700965int container_config_get_cpu_rt_period(struct container_config* c) {
966 return c->cpu_cgparams.rt_period;
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800967}
968
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700969int container_config_set_cgroup_parent(struct container_config* c,
970 const char* parent,
971 uid_t cgroup_owner,
972 gid_t cgroup_group) {
973 c->cgroup_owner = cgroup_owner;
974 c->cgroup_group = cgroup_group;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700975 c->cgroup_parent = base::FilePath(parent);
976 return 0;
Dylan Reid9e724af2016-07-21 09:58:07 -0700977}
978
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700979const char* container_config_get_cgroup_parent(struct container_config* c) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -0700980 return c->cgroup_parent.value().c_str();
Dylan Reid9e724af2016-07-21 09:58:07 -0700981}
982
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700983void container_config_share_host_netns(struct container_config* c) {
984 c->share_host_netns = 1;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700985}
986
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700987int get_container_config_share_host_netns(struct container_config* c) {
988 return c->share_host_netns;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700989}
990
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700991void container_config_keep_fds_open(struct container_config* c) {
992 c->keep_fds_open = 1;
Dylan Reidc4335842016-11-11 10:24:52 -0800993}
994
Luis Hector Chavez31735bc2017-09-15 08:17:10 -0700995void container_config_set_capmask(struct container_config* c,
996 uint64_t capmask,
997 int ambient) {
998 c->use_capmask = 1;
999 c->capmask = capmask;
1000 c->use_capmask_ambient = ambient;
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001001}
1002
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001003void container_config_set_securebits_skip_mask(struct container_config* c,
1004 uint64_t securebits_skip_mask) {
1005 c->securebits_skip_mask = securebits_skip_mask;
Luis Hector Chavezcd44ba72017-06-30 13:01:38 -07001006}
1007
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001008void container_config_set_run_as_init(struct container_config* c,
1009 int run_as_init) {
1010 c->do_init = !run_as_init;
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001011}
1012
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001013int container_config_set_selinux_context(struct container_config* c,
1014 const char* context) {
1015 if (!context)
1016 return -EINVAL;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001017 c->selinux_context = context;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001018 return 0;
Luis Hector Chavez15e8e672017-07-20 15:13:27 -07001019}
1020
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001021void container_config_set_pre_execve_hook(struct container_config* c,
1022 int (*hook)(void*),
1023 void* payload) {
1024 c->pre_start_hook = hook;
1025 c->pre_start_hook_payload = payload;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001026}
1027
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001028int container_config_inherit_fds(struct container_config* c,
1029 int* inherited_fds,
1030 size_t inherited_fd_count) {
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001031 if (!c->inherited_fds.empty())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001032 return -EINVAL;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001033 for (size_t i = 0; i < inherited_fd_count; ++i)
1034 c->inherited_fds.emplace_back(inherited_fds[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001035 return 0;
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001036}
1037
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001038struct container* container_new(const char* name, const char* rundir) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001039 struct container* c = new (std::nothrow) container();
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001040 if (!c)
1041 return nullptr;
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001042 c->rundir = base::FilePath(rundir);
1043 c->name = name;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001044 return c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001045}
1046
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001047void container_destroy(struct container* c) {
1048 if (c->cgroup)
1049 container_cgroup_destroy(c->cgroup);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001050 delete c;
Dylan Reid837c74a2016-01-22 17:25:21 -08001051}
1052
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001053int container_start(struct container* c,
1054 const struct container_config* config) {
1055 int rc = 0;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001056
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001057 if (!c)
1058 return -EINVAL;
1059 if (!config)
1060 return -EINVAL;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001061 if (config->program_argv.empty())
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001062 return -EINVAL;
Dylan Reide040c6b2016-05-02 18:49:02 -07001063
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001064 // This will run in all the error cases.
1065 base::ScopedClosureRunner teardown(
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001066 base::Bind(base::IgnoreResult(&ContainerTeardown), base::Unretained(c)));
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001067
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001068 if (!config->config_root.empty())
1069 c->config_root = config->config_root;
1070 if (!config->premounted_runfs.empty()) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001071 c->runfs.clear();
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001072 c->runfsroot = config->premounted_runfs;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001073 } else {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001074 rc = MountRunfs(c, config);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001075 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001076 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001077 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001078
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001079 c->jail.reset(minijail_new());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001080 if (!c->jail)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001081 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -08001082
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001083 rc = DoContainerMounts(c, config);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001084 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001085 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001086
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001087 int cgroup_uid = GetUsernsOutsideId(config->uid_map, config->cgroup_owner);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001088 if (cgroup_uid < 0)
1089 return cgroup_uid;
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001090 int cgroup_gid = GetUsernsOutsideId(config->gid_map, config->cgroup_group);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001091 if (cgroup_gid < 0)
1092 return cgroup_gid;
Stephen Barber1a398c72017-01-23 12:39:44 -08001093
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001094 c->cgroup = container_cgroup_new(c->name.c_str(),
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001095 "/sys/fs/cgroup",
1096 config->cgroup_parent.value().c_str(),
1097 cgroup_uid,
1098 cgroup_gid);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001099 if (!c->cgroup)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001100 return -errno;
Dylan Reida9966422016-07-21 10:11:34 -07001101
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001102 /* Must be root to modify device cgroup or mknod */
1103 if (getuid() == 0) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001104 rc = DeviceSetup(c, config);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001105 if (rc)
1106 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001107 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001108
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001109 /* Potentially run setfiles on mounts configured outside of the jail */
1110 const base::FilePath kDataPath("/data");
1111 const base::FilePath kCachePath("/cache");
1112 std::vector<base::FilePath> destinations;
1113 for (const auto& mnt : config->mounts) {
1114 if (mnt.mount_in_ns)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001115 continue;
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001116 if (mnt.flags & MS_RDONLY)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001117 continue;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001118
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001119 /* A hack to avoid setfiles on /data and /cache. */
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001120 if (mnt.destination == kDataPath || mnt.destination == kCachePath)
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001121 continue;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001122
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001123 destinations.emplace_back(
1124 GetPathInOuterNamespace(c->runfsroot, mnt.destination));
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001125 }
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001126 if (!destinations.empty()) {
1127 rc = RunSetfilesCommand(c, config, destinations);
1128 if (rc)
1129 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001130 }
Dylan Reidd7229582016-04-27 17:08:40 -07001131
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001132 /* Setup CPU cgroup params. */
1133 if (config->cpu_cgparams.shares) {
1134 rc = c->cgroup->ops->set_cpu_shares(c->cgroup, config->cpu_cgparams.shares);
1135 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001136 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001137 }
1138 if (config->cpu_cgparams.period) {
1139 rc = c->cgroup->ops->set_cpu_quota(c->cgroup, config->cpu_cgparams.quota);
1140 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001141 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001142 rc = c->cgroup->ops->set_cpu_period(c->cgroup, config->cpu_cgparams.period);
1143 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001144 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001145 }
1146 if (config->cpu_cgparams.rt_period) {
1147 rc = c->cgroup->ops->set_cpu_rt_runtime(c->cgroup,
1148 config->cpu_cgparams.rt_runtime);
1149 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001150 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001151 rc = c->cgroup->ops->set_cpu_rt_period(c->cgroup,
1152 config->cpu_cgparams.rt_period);
1153 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001154 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001155 }
Chinyue Chenfac909e2016-06-24 14:17:42 +08001156
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001157 /* Setup and start the container with libminijail. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001158 if (!config->pid_file_path.empty())
1159 c->pid_file_path = config->pid_file_path;
1160 else if (!c->runfs.empty())
1161 c->pid_file_path = c->runfs.Append("container.pid");
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001162
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001163 if (!c->pid_file_path.empty())
1164 minijail_write_pid_file(c->jail.get(), c->pid_file_path.value().c_str());
1165 minijail_reset_signal_mask(c->jail.get());
Dylan Reid837c74a2016-01-22 17:25:21 -08001166
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001167 /* Setup container namespaces. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001168 minijail_namespace_ipc(c->jail.get());
1169 minijail_namespace_vfs(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001170 if (!config->share_host_netns)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001171 minijail_namespace_net(c->jail.get());
1172 minijail_namespace_pids(c->jail.get());
1173 minijail_namespace_user(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001174 if (getuid() != 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001175 minijail_namespace_user_disable_setgroups(c->jail.get());
1176 minijail_namespace_cgroups(c->jail.get());
1177 rc = minijail_uidmap(c->jail.get(), config->uid_map.c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001178 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001179 return rc;
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001180 rc = minijail_gidmap(c->jail.get(), config->gid_map.c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001181 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001182 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001183
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001184 /* Set the UID/GID inside the container if not 0. */
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001185 rc = GetUsernsOutsideId(config->uid_map, config->uid);
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->uid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001189 minijail_change_uid(c->jail.get(), config->uid);
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001190 rc = GetUsernsOutsideId(config->gid_map, config->gid);
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001191 if (rc < 0)
1192 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001193 else if (config->gid > 0)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001194 minijail_change_gid(c->jail.get(), config->gid);
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001195
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001196 rc = minijail_enter_pivot_root(c->jail.get(), c->runfsroot.value().c_str());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001197 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001198 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001199
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001200 /* Add the cgroups configured above. */
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001201 for (int i = 0; i < NUM_CGROUP_TYPES; i++) {
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001202 if (c->cgroup->cgroup_tasks_paths[i]) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001203 rc = minijail_add_to_cgroup(c->jail.get(),
1204 c->cgroup->cgroup_tasks_paths[i]);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001205 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001206 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001207 }
1208 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001209
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001210 if (!config->alt_syscall_table.empty())
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001211 minijail_use_alt_syscall(c->jail.get(), config->alt_syscall_table.c_str());
Dylan Reid837c74a2016-01-22 17:25:21 -08001212
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001213 for (int i = 0; i < config->num_rlimits; i++) {
Luis Hector Chaveze1062e82017-09-18 09:57:37 -07001214 const Rlimit& lim = config->rlimits[i];
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001215 rc = minijail_rlimit(c->jail.get(), lim.type, lim.cur, lim.max);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001216 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001217 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001218 }
Dylan Reid93fa4602017-06-06 13:39:31 -07001219
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001220 if (!config->selinux_context.empty()) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001221 rc = minijail_add_hook(c->jail.get(),
1222 &Setexeccon,
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001223 const_cast<char*>(config->selinux_context.c_str()),
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001224 MINIJAIL_HOOK_EVENT_PRE_EXECVE);
1225 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001226 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001227 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001228
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001229 if (config->pre_start_hook) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001230 rc = minijail_add_hook(c->jail.get(),
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001231 config->pre_start_hook,
1232 config->pre_start_hook_payload,
1233 MINIJAIL_HOOK_EVENT_PRE_EXECVE);
1234 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001235 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001236 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001237
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001238 for (int fd : config->inherited_fds) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001239 rc = minijail_preserve_fd(c->jail.get(), fd, fd);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001240 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001241 return rc;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001242 }
Luis Hector Chavezf8e8f4c2017-08-01 01:09:39 -07001243
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001244 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001245 minijail_skip_remount_private(c->jail.get());
Dylan Reid3da683b2016-04-05 03:35:35 -07001246
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001247 if (!config->keep_fds_open)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001248 minijail_close_open_fds(c->jail.get());
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001249
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001250 if (config->use_capmask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001251 minijail_use_caps(c->jail.get(), config->capmask);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001252 if (config->use_capmask_ambient) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001253 minijail_set_ambient_caps(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001254 }
1255 if (config->securebits_skip_mask) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001256 minijail_skip_setting_securebits(c->jail.get(),
1257 config->securebits_skip_mask);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001258 }
1259 }
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001260
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001261 if (!config->do_init)
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001262 minijail_run_as_init(c->jail.get());
Luis Hector Chavezdac65c32017-07-21 10:30:23 -07001263
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001264 std::vector<char*> argv_cstr;
1265 argv_cstr.reserve(config->program_argv.size() + 1);
1266 for (const auto& arg : config->program_argv)
1267 argv_cstr.emplace_back(const_cast<char*>(arg.c_str()));
1268 argv_cstr.emplace_back(nullptr);
1269
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001270 rc = minijail_run_pid_pipes_no_preload(c->jail.get(),
Luis Hector Chavez9cde12a2017-09-18 10:53:38 -07001271 argv_cstr[0],
1272 argv_cstr.data(),
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001273 &c->init_pid,
1274 nullptr,
1275 nullptr,
1276 nullptr);
1277 if (rc)
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001278 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001279
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001280 // The container has started successfully, no need to tear it down anymore.
1281 ignore_result(teardown.Release());
1282 return 0;
Dylan Reid837c74a2016-01-22 17:25:21 -08001283}
1284
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001285const char* container_root(struct container* c) {
Luis Hector Chavez5381d002017-09-16 12:54:24 -07001286 return c->runfs.value().c_str();
Dylan Reid837c74a2016-01-22 17:25:21 -08001287}
1288
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001289int container_pid(struct container* c) {
1290 return c->init_pid;
Dylan Reid837c74a2016-01-22 17:25:21 -08001291}
1292
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001293int container_wait(struct container* c) {
1294 int rc;
Dylan Reidcf745c52016-04-22 10:18:03 -07001295
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001296 do {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001297 rc = minijail_wait(c->jail.get());
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001298 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001299
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001300 // If the process had already been reaped, still perform teardown.
1301 if (rc == -ECHILD || rc >= 0) {
Luis Hector Chavez626f5c82017-09-18 11:19:32 -07001302 rc = ContainerTeardown(c);
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001303 }
1304 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001305}
1306
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001307int container_kill(struct container* c) {
Luis Hector Chavez835d39e2017-09-19 15:16:31 -07001308 if (kill(c->init_pid, SIGKILL) && errno != ESRCH) {
1309 PLOG_PRESERVE(ERROR) << "Failed to kill " << c->init_pid;
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001310 return -errno;
Luis Hector Chavez835d39e2017-09-19 15:16:31 -07001311 }
Luis Hector Chavez31735bc2017-09-15 08:17:10 -07001312 return container_wait(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001313}