blob: c8dae01d17b05ebc5b86a23ba61ef0414380934f [file] [log] [blame]
Dylan Reid837c74a2016-01-22 17:25:21 -08001/* 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.
4 */
5
6#define _GNU_SOURCE /* For asprintf */
7
8#include <errno.h>
9#include <fcntl.h>
Mike Frysinger05e594e2017-01-10 02:11:08 -050010#if USE_device_mapper
11#include <libdevmapper.h>
12#endif
Dylan Reid837c74a2016-01-22 17:25:21 -080013#include <malloc.h>
14#include <signal.h>
Luis Hector Chavezff5978f2017-06-27 12:52:58 -070015#include <stdint.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080016#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <sys/mount.h>
20#include <sys/stat.h>
21#include <sys/types.h>
Dylan Reid2bd9ea92016-04-07 20:57:47 -070022#include <sys/wait.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080023#include <unistd.h>
24
Mike Frysinger412dbd22017-01-06 01:50:34 -050025#include <linux/loop.h>
26
Dylan Reid837c74a2016-01-22 17:25:21 -080027#include "container_cgroup.h"
28#include "libcontainer.h"
29#include "libminijail.h"
30
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070031#define FREE_AND_NULL(ptr) \
32do { \
33 free(ptr); \
34 ptr = NULL; \
35} while(0)
36
Yusuke Sato91f11f02016-12-02 16:15:13 -080037#define MAX_NUM_SETFILES_ARGS 128
38
Mike Frysinger412dbd22017-01-06 01:50:34 -050039static const char loopdev_ctl[] = "/dev/loop-control";
Mike Frysinger05e594e2017-01-10 02:11:08 -050040#if USE_device_mapper
41static const char dm_dev_prefix[] = "/dev/mapper/";
42#endif
Mike Frysinger412dbd22017-01-06 01:50:34 -050043
Luis Hector Chavez945af482016-06-03 08:39:34 -070044static int container_teardown(struct container *c);
45
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070046static int strdup_and_free(char **dest, const char *src)
47{
48 char *copy = strdup(src);
49 if (!copy)
50 return -ENOMEM;
51 if (*dest)
52 free(*dest);
53 *dest = copy;
54 return 0;
55}
56
Dylan Reid837c74a2016-01-22 17:25:21 -080057struct container_mount {
58 char *name;
59 char *source;
60 char *destination;
61 char *type;
62 char *data;
Mike Frysinger05e594e2017-01-10 02:11:08 -050063 char *verity;
Dylan Reid837c74a2016-01-22 17:25:21 -080064 int flags;
65 int uid;
66 int gid;
67 int mode;
68 int mount_in_ns; /* True if mount should happen in new vfs ns */
69 int create; /* True if target should be created if it doesn't exist */
Mike Frysinger412dbd22017-01-06 01:50:34 -050070 int loopback; /* True if target should be mounted via loopback */
Dylan Reid837c74a2016-01-22 17:25:21 -080071};
72
73struct container_device {
74 char type; /* 'c' or 'b' for char or block */
75 char *path;
76 int fs_permissions;
77 int major;
78 int minor;
Dylan Reid355d5e42016-04-29 16:53:31 -070079 int copy_minor; /* Copy the minor from existing node, ignores |minor| */
Dylan Reid837c74a2016-01-22 17:25:21 -080080 int uid;
81 int gid;
Dylan Reid4843d6b2017-03-31 18:14:30 -070082};
83
84struct container_cgroup_device {
85 int allow;
86 char type;
87 int major; /* -1 means all */
88 int minor; /* -1 means all */
89 int read;
90 int write;
91 int modify;
Dylan Reid837c74a2016-01-22 17:25:21 -080092};
93
Chinyue Chenfac909e2016-06-24 14:17:42 +080094struct container_cpu_cgroup {
95 int shares;
96 int quota;
97 int period;
98 int rt_runtime;
99 int rt_period;
100};
101
Dylan Reid837c74a2016-01-22 17:25:21 -0800102/*
103 * Structure that configures how the container is run.
104 *
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500105 * config_root - Path to the root of the container itself.
Dylan Reid837c74a2016-01-22 17:25:21 -0800106 * rootfs - Path to the root of the container's filesystem.
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700107 * rootfs_mount_flags - Flags that will be passed to mount() for the rootfs.
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700108 * premounted_runfs - Path to where the container will be run.
109 * pid_file_path - Path to the file where the pid should be written.
Dylan Reid837c74a2016-01-22 17:25:21 -0800110 * program_argv - The program to run and args, e.g. "/sbin/init".
111 * num_args - Number of args in program_argv.
Dylan Reid1874feb2016-06-22 17:53:50 -0700112 * uid - The uid the container will run as.
Dylan Reid837c74a2016-01-22 17:25:21 -0800113 * uid_map - Mapping of UIDs in the container, e.g. "0 100000 1024"
Dylan Reid1874feb2016-06-22 17:53:50 -0700114 * gid - The gid the container will run as.
Dylan Reid837c74a2016-01-22 17:25:21 -0800115 * gid_map - Mapping of GIDs in the container, e.g. "0 100000 1024"
116 * alt_syscall_table - Syscall table to use or NULL if none.
117 * mounts - Filesystems to mount in the new namespace.
118 * num_mounts - Number of above.
119 * devices - Device nodes to create.
120 * num_devices - Number of above.
Dylan Reid4843d6b2017-03-31 18:14:30 -0700121 * cgroup_devices - Device node cgroup permissions.
122 * num_cgroup_devices - Number of above.
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700123 * run_setfiles - Should run setfiles on mounts to enable selinux.
Chinyue Chenfac909e2016-06-24 14:17:42 +0800124 * cpu_cgparams - CPU cgroup params.
Dylan Reid9e724af2016-07-21 09:58:07 -0700125 * cgroup_parent - Parent dir for cgroup creation
126 * cgroup_owner - uid to own the created cgroups
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700127 * cgroup_group - gid to own the created cgroups
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700128 * share_host_netns - Enable sharing of the host network namespace.
Dylan Reidc4335842016-11-11 10:24:52 -0800129 * keep_fds_open - Allow the child process to keep open FDs (for stdin/out/err).
Dylan Reid837c74a2016-01-22 17:25:21 -0800130 */
131struct container_config {
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500132 char *config_root;
Dylan Reid837c74a2016-01-22 17:25:21 -0800133 char *rootfs;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700134 unsigned long rootfs_mount_flags;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700135 char *premounted_runfs;
136 char *pid_file_path;
Dylan Reid837c74a2016-01-22 17:25:21 -0800137 char **program_argv;
138 size_t num_args;
Dylan Reid1874feb2016-06-22 17:53:50 -0700139 uid_t uid;
Dylan Reid837c74a2016-01-22 17:25:21 -0800140 char *uid_map;
Dylan Reid1874feb2016-06-22 17:53:50 -0700141 gid_t gid;
Dylan Reid837c74a2016-01-22 17:25:21 -0800142 char *gid_map;
143 char *alt_syscall_table;
144 struct container_mount *mounts;
145 size_t num_mounts;
146 struct container_device *devices;
147 size_t num_devices;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700148 struct container_cgroup_device *cgroup_devices;
149 size_t num_cgroup_devices;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700150 char *run_setfiles;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800151 struct container_cpu_cgroup cpu_cgparams;
Dylan Reid9e724af2016-07-21 09:58:07 -0700152 char *cgroup_parent;
153 uid_t cgroup_owner;
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700154 gid_t cgroup_group;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700155 int share_host_netns;
Dylan Reidc4335842016-11-11 10:24:52 -0800156 int keep_fds_open;
Luis Hector Chavezff5978f2017-06-27 12:52:58 -0700157 int use_capmask;
158 int use_capmask_ambient;
159 uint64_t capmask;
Dylan Reid837c74a2016-01-22 17:25:21 -0800160};
161
162struct container_config *container_config_create()
163{
164 return calloc(1, sizeof(struct container_config));
165}
166
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700167static void container_free_program_args(struct container_config *c)
168{
169 int i;
170
171 if (!c->program_argv)
172 return;
173 for (i = 0; i < c->num_args; ++i) {
174 FREE_AND_NULL(c->program_argv[i]);
175 }
176 FREE_AND_NULL(c->program_argv);
177}
178
179static void container_config_free_mount(struct container_mount *mount)
180{
181 FREE_AND_NULL(mount->name);
182 FREE_AND_NULL(mount->source);
183 FREE_AND_NULL(mount->destination);
184 FREE_AND_NULL(mount->type);
185 FREE_AND_NULL(mount->data);
186}
187
188static void container_config_free_device(struct container_device *device)
189{
190 FREE_AND_NULL(device->path);
191}
192
Dylan Reid837c74a2016-01-22 17:25:21 -0800193void container_config_destroy(struct container_config *c)
194{
195 size_t i;
196
197 if (c == NULL)
198 return;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700199 FREE_AND_NULL(c->rootfs);
200 container_free_program_args(c);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700201 FREE_AND_NULL(c->premounted_runfs);
202 FREE_AND_NULL(c->pid_file_path);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700203 FREE_AND_NULL(c->uid_map);
204 FREE_AND_NULL(c->gid_map);
205 FREE_AND_NULL(c->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800206 for (i = 0; i < c->num_mounts; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700207 container_config_free_mount(&c->mounts[i]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800208 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700209 FREE_AND_NULL(c->mounts);
Dylan Reid837c74a2016-01-22 17:25:21 -0800210 for (i = 0; i < c->num_devices; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700211 container_config_free_device(&c->devices[i]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800212 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700213 FREE_AND_NULL(c->devices);
Dylan Reida34f8162017-05-10 11:33:11 -0700214 FREE_AND_NULL(c->cgroup_devices);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700215 FREE_AND_NULL(c->run_setfiles);
Dylan Reid9e724af2016-07-21 09:58:07 -0700216 FREE_AND_NULL(c->cgroup_parent);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700217 FREE_AND_NULL(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800218}
219
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500220int container_config_config_root(struct container_config *c,
221 const char *config_root)
222{
223 return strdup_and_free(&c->config_root, config_root);
224}
225
226const char *container_config_get_config_root(const struct container_config *c)
227{
228 return c->config_root;
229}
230
Dylan Reid837c74a2016-01-22 17:25:21 -0800231int container_config_rootfs(struct container_config *c, const char *rootfs)
232{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700233 return strdup_and_free(&c->rootfs, rootfs);
Dylan Reid837c74a2016-01-22 17:25:21 -0800234}
235
Dylan Reid11456722016-05-02 11:24:50 -0700236const char *container_config_get_rootfs(const struct container_config *c)
237{
238 return c->rootfs;
239}
240
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700241void container_config_rootfs_mount_flags(struct container_config *c,
242 unsigned long rootfs_mount_flags)
243{
244 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
245 * simply check against zero later. MS_BIND is also added to avoid
246 * re-mounting the original filesystem, since the rootfs is always
247 * bind-mounted.
248 */
249 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
250}
251
252unsigned long container_config_get_rootfs_mount_flags(
253 const struct container_config *c)
254{
255 return c->rootfs_mount_flags;
256}
257
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700258int container_config_premounted_runfs(struct container_config *c, const char *runfs)
259{
260 return strdup_and_free(&c->premounted_runfs, runfs);
261}
262
263const char *container_config_get_premounted_runfs(const struct container_config *c)
264{
265 return c->premounted_runfs;
266}
267
268int container_config_pid_file(struct container_config *c, const char *path)
269{
270 return strdup_and_free(&c->pid_file_path, path);
271}
272
273const char *container_config_get_pid_file(const struct container_config *c)
274{
275 return c->pid_file_path;
276}
277
Dylan Reid837c74a2016-01-22 17:25:21 -0800278int container_config_program_argv(struct container_config *c,
Dylan Reid17fd53f2016-11-18 19:14:41 -0800279 const char **argv, size_t num_args)
Dylan Reid837c74a2016-01-22 17:25:21 -0800280{
281 size_t i;
282
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700283 container_free_program_args(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800284 c->num_args = num_args;
285 c->program_argv = calloc(num_args + 1, sizeof(char *));
286 if (!c->program_argv)
287 return -ENOMEM;
288 for (i = 0; i < num_args; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700289 if (strdup_and_free(&c->program_argv[i], argv[i]))
290 goto error_free_return;
Dylan Reid837c74a2016-01-22 17:25:21 -0800291 }
292 c->program_argv[num_args] = NULL;
293 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700294
295error_free_return:
296 container_free_program_args(c);
297 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800298}
299
Dylan Reid11456722016-05-02 11:24:50 -0700300size_t container_config_get_num_program_args(const struct container_config *c)
301{
302 return c->num_args;
303}
304
305const char *container_config_get_program_arg(const struct container_config *c,
306 size_t index)
307{
308 if (index >= c->num_args)
309 return NULL;
310 return c->program_argv[index];
311}
312
Dylan Reid1874feb2016-06-22 17:53:50 -0700313void container_config_uid(struct container_config *c, uid_t uid)
314{
315 c->uid = uid;
316}
317
318uid_t container_config_get_uid(const struct container_config *c)
319{
320 return c->uid;
321}
322
Dylan Reid837c74a2016-01-22 17:25:21 -0800323int container_config_uid_map(struct container_config *c, const char *uid_map)
324{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700325 return strdup_and_free(&c->uid_map, uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800326}
327
Dylan Reid1874feb2016-06-22 17:53:50 -0700328void container_config_gid(struct container_config *c, gid_t gid)
329{
330 c->gid = gid;
331}
332
333gid_t container_config_get_gid(const struct container_config *c)
334{
335 return c->gid;
336}
337
Dylan Reid837c74a2016-01-22 17:25:21 -0800338int container_config_gid_map(struct container_config *c, const char *gid_map)
339{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700340 return strdup_and_free(&c->gid_map, gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800341}
342
343int container_config_alt_syscall_table(struct container_config *c,
344 const char *alt_syscall_table)
345{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700346 return strdup_and_free(&c->alt_syscall_table, alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800347}
348
349int container_config_add_mount(struct container_config *c,
350 const char *name,
351 const char *source,
352 const char *destination,
353 const char *type,
354 const char *data,
Mike Frysinger05e594e2017-01-10 02:11:08 -0500355 const char *verity,
Dylan Reid837c74a2016-01-22 17:25:21 -0800356 int flags,
357 int uid,
358 int gid,
359 int mode,
360 int mount_in_ns,
Mike Frysinger412dbd22017-01-06 01:50:34 -0500361 int create,
362 int loopback)
Dylan Reid837c74a2016-01-22 17:25:21 -0800363{
364 struct container_mount *mount_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700365 struct container_mount *current_mount;
Dylan Reid837c74a2016-01-22 17:25:21 -0800366
367 if (name == NULL || source == NULL ||
368 destination == NULL || type == NULL)
369 return -EINVAL;
370
371 mount_ptr = realloc(c->mounts,
372 sizeof(c->mounts[0]) * (c->num_mounts + 1));
373 if (!mount_ptr)
374 return -ENOMEM;
375 c->mounts = mount_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700376 current_mount = &c->mounts[c->num_mounts];
377 memset(current_mount, 0, sizeof(struct container_mount));
378
379 if (strdup_and_free(&current_mount->name, name))
380 goto error_free_return;
381 if (strdup_and_free(&current_mount->source, source))
382 goto error_free_return;
383 if (strdup_and_free(&current_mount->destination, destination))
384 goto error_free_return;
385 if (strdup_and_free(&current_mount->type, type))
386 goto error_free_return;
387 if (data && strdup_and_free(&current_mount->data, data))
388 goto error_free_return;
Mike Frysinger05e594e2017-01-10 02:11:08 -0500389 if (verity && strdup_and_free(&current_mount->verity, verity))
390 goto error_free_return;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700391 current_mount->flags = flags;
392 current_mount->uid = uid;
393 current_mount->gid = gid;
394 current_mount->mode = mode;
395 current_mount->mount_in_ns = mount_in_ns;
396 current_mount->create = create;
Mike Frysinger412dbd22017-01-06 01:50:34 -0500397 current_mount->loopback = loopback;
Dylan Reid837c74a2016-01-22 17:25:21 -0800398 ++c->num_mounts;
399 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700400
401error_free_return:
402 container_config_free_mount(current_mount);
403 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800404}
405
Dylan Reid4843d6b2017-03-31 18:14:30 -0700406int container_config_add_cgroup_device(struct container_config *c,
407 int allow,
408 char type,
409 int major,
410 int minor,
411 int read,
412 int write,
413 int modify)
414{
415 struct container_cgroup_device *dev_ptr;
416 struct container_cgroup_device *current_dev;
417
418 dev_ptr = realloc(c->cgroup_devices,
419 sizeof(c->cgroup_devices[0]) *
420 (c->num_cgroup_devices + 1));
421 if (!dev_ptr)
422 return -ENOMEM;
423 c->cgroup_devices = dev_ptr;
424
425 current_dev = &c->cgroup_devices[c->num_cgroup_devices];
426 memset(current_dev, 0, sizeof(struct container_cgroup_device));
427 current_dev->allow = allow;
428 current_dev->type = type;
429 current_dev->major = major;
430 current_dev->minor = minor;
431 current_dev->read = read;
432 current_dev->write = write;
433 current_dev->modify = modify;
434 ++c->num_cgroup_devices;
435
436 return 0;
437}
438
Dylan Reid837c74a2016-01-22 17:25:21 -0800439int container_config_add_device(struct container_config *c,
440 char type,
441 const char *path,
442 int fs_permissions,
443 int major,
444 int minor,
Dylan Reid355d5e42016-04-29 16:53:31 -0700445 int copy_minor,
Dylan Reid837c74a2016-01-22 17:25:21 -0800446 int uid,
447 int gid,
448 int read_allowed,
449 int write_allowed,
450 int modify_allowed)
451{
452 struct container_device *dev_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700453 struct container_device *current_dev;
Dylan Reid837c74a2016-01-22 17:25:21 -0800454
455 if (path == NULL)
456 return -EINVAL;
Dylan Reid355d5e42016-04-29 16:53:31 -0700457 /* If using a dynamic minor number, ensure that minor is -1. */
458 if (copy_minor && (minor != -1))
459 return -EINVAL;
460
Dylan Reid837c74a2016-01-22 17:25:21 -0800461 dev_ptr = realloc(c->devices,
462 sizeof(c->devices[0]) * (c->num_devices + 1));
463 if (!dev_ptr)
464 return -ENOMEM;
465 c->devices = dev_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700466 current_dev = &c->devices[c->num_devices];
467 memset(current_dev, 0, sizeof(struct container_device));
468
469 current_dev->type = type;
470 if (strdup_and_free(&current_dev->path, path))
471 goto error_free_return;
472 current_dev->fs_permissions = fs_permissions;
473 current_dev->major = major;
474 current_dev->minor = minor;
475 current_dev->copy_minor = copy_minor;
476 current_dev->uid = uid;
477 current_dev->gid = gid;
Dylan Reid4843d6b2017-03-31 18:14:30 -0700478 if (read_allowed || write_allowed || modify_allowed) {
479 if (container_config_add_cgroup_device(c,
480 1,
481 type,
482 major,
483 minor,
484 read_allowed,
485 write_allowed,
486 modify_allowed))
487 goto error_free_return;
488 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800489 ++c->num_devices;
490 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700491
492error_free_return:
493 container_config_free_device(current_dev);
494 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800495}
496
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700497int container_config_run_setfiles(struct container_config *c,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700498 const char *setfiles_cmd)
499{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700500 return strdup_and_free(&c->run_setfiles, setfiles_cmd);
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700501}
Dylan Reid837c74a2016-01-22 17:25:21 -0800502
Dylan Reid11456722016-05-02 11:24:50 -0700503const char *container_config_get_run_setfiles(const struct container_config *c)
504{
505 return c->run_setfiles;
506}
507
Chinyue Chenfac909e2016-06-24 14:17:42 +0800508int container_config_set_cpu_shares(struct container_config *c, int shares)
509{
510 /* CPU shares must be 2 or higher. */
511 if (shares < 2)
512 return -EINVAL;
513
514 c->cpu_cgparams.shares = shares;
515 return 0;
516}
517
518int container_config_set_cpu_cfs_params(struct container_config *c,
519 int quota,
520 int period)
521{
522 /*
523 * quota could be set higher than period to utilize more than one CPU.
524 * quota could also be set as -1 to indicate the cgroup does not adhere
525 * to any CPU time restrictions.
526 */
527 if (quota <= 0 && quota != -1)
528 return -EINVAL;
529 if (period <= 0)
530 return -EINVAL;
531
532 c->cpu_cgparams.quota = quota;
533 c->cpu_cgparams.period = period;
534 return 0;
535}
536
537int container_config_set_cpu_rt_params(struct container_config *c,
538 int rt_runtime,
539 int rt_period)
540{
541 /*
542 * rt_runtime could be set as 0 to prevent the cgroup from using
543 * realtime CPU.
544 */
545 if (rt_runtime < 0 || rt_runtime >= rt_period)
546 return -EINVAL;
547
548 c->cpu_cgparams.rt_runtime = rt_runtime;
549 c->cpu_cgparams.rt_period = rt_period;
550 return 0;
551}
552
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800553int container_config_get_cpu_shares(struct container_config *c)
554{
555 return c->cpu_cgparams.shares;
556}
557
558int container_config_get_cpu_quota(struct container_config *c)
559{
560 return c->cpu_cgparams.quota;
561}
562
563int container_config_get_cpu_period(struct container_config *c)
564{
565 return c->cpu_cgparams.period;
566}
567
568int container_config_get_cpu_rt_runtime(struct container_config *c)
569{
570 return c->cpu_cgparams.rt_runtime;
571}
572
573int container_config_get_cpu_rt_period(struct container_config *c)
574{
575 return c->cpu_cgparams.rt_period;
576}
577
Dylan Reid9e724af2016-07-21 09:58:07 -0700578int container_config_set_cgroup_parent(struct container_config *c,
579 const char *parent,
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700580 uid_t cgroup_owner, gid_t cgroup_group)
Dylan Reid9e724af2016-07-21 09:58:07 -0700581{
582 c->cgroup_owner = cgroup_owner;
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700583 c->cgroup_group = cgroup_group;
Dylan Reid9e724af2016-07-21 09:58:07 -0700584 return strdup_and_free(&c->cgroup_parent, parent);
585}
586
587const char *container_config_get_cgroup_parent(struct container_config *c)
588{
589 return c->cgroup_parent;
590}
591
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700592void container_config_share_host_netns(struct container_config *c)
593{
594 c->share_host_netns = 1;
595}
596
597int get_container_config_share_host_netns(struct container_config *c)
598{
599 return c->share_host_netns;
600}
601
Dylan Reidc4335842016-11-11 10:24:52 -0800602void container_config_keep_fds_open(struct container_config *c)
603{
604 c->keep_fds_open = 1;
605}
606
Luis Hector Chavezff5978f2017-06-27 12:52:58 -0700607void container_config_set_capmask(struct container_config *c,
608 uint64_t capmask,
609 int ambient)
610{
611 c->use_capmask = 1;
612 c->capmask = capmask;
613 c->use_capmask_ambient = ambient;
614}
615
Dylan Reid837c74a2016-01-22 17:25:21 -0800616/*
617 * Container manipulation
618 */
619struct container {
Dylan Reid837c74a2016-01-22 17:25:21 -0800620 struct container_cgroup *cgroup;
621 struct minijail *jail;
622 pid_t init_pid;
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500623 char *config_root;
Dylan Reid837c74a2016-01-22 17:25:21 -0800624 char *runfs;
625 char *rundir;
626 char *runfsroot;
627 char *pid_file_path;
Dylan Reide040c6b2016-05-02 18:49:02 -0700628 char **ext_mounts; /* Mounts made outside of the minijail */
629 size_t num_ext_mounts;
Mike Frysinger412dbd22017-01-06 01:50:34 -0500630 char **loopdevs;
631 size_t num_loopdevs;
Mike Frysinger05e594e2017-01-10 02:11:08 -0500632 char **device_mappers;
633 size_t num_device_mappers;
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700634 char *name;
Dylan Reid837c74a2016-01-22 17:25:21 -0800635};
636
637struct container *container_new(const char *name,
Dylan Reide040c6b2016-05-02 18:49:02 -0700638 const char *rundir)
Dylan Reid837c74a2016-01-22 17:25:21 -0800639{
640 struct container *c;
641
Dylan Reid837c74a2016-01-22 17:25:21 -0800642 c = calloc(1, sizeof(*c));
Dylan Reidb435c682016-04-12 04:17:49 -0700643 if (!c)
644 return NULL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800645 c->rundir = strdup(rundir);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700646 c->name = strdup(name);
Dylan Reida9966422016-07-21 10:11:34 -0700647 if (!c->rundir || !c->name) {
Dylan Reid684975e2016-05-02 15:44:47 -0700648 container_destroy(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800649 return NULL;
Dylan Reidb435c682016-04-12 04:17:49 -0700650 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800651 return c;
652}
653
654void container_destroy(struct container *c)
655{
Dylan Reid684975e2016-05-02 15:44:47 -0700656 if (c->cgroup)
657 container_cgroup_destroy(c->cgroup);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700658 if (c->jail)
659 minijail_destroy(c->jail);
Mike Frysingerb22acdf2017-01-08 02:02:35 -0500660 FREE_AND_NULL(c->config_root);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700661 FREE_AND_NULL(c->name);
662 FREE_AND_NULL(c->rundir);
663 FREE_AND_NULL(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800664}
665
Stephen Barber1a398c72017-01-23 12:39:44 -0800666/*
667 * Given a uid/gid map of "inside1 outside1 length1, ...", and an id
668 * inside of the user namespace, return the equivalent outside id, or
669 * return < 0 on error.
670 */
671static int get_userns_outside_id(const char *map, int id)
672{
673 char *map_copy, *mapping, *saveptr1, *saveptr2;
674 int inside, outside, length;
675 int result = 0;
676 errno = 0;
677
678 if (asprintf(&map_copy, "%s", map) < 0)
679 return -ENOMEM;
680
681 mapping = strtok_r(map_copy, ",", &saveptr1);
682 while (mapping) {
683 inside = strtol(strtok_r(mapping, " ", &saveptr2), NULL, 10);
684 outside = strtol(strtok_r(NULL, " ", &saveptr2), NULL, 10);
685 length = strtol(strtok_r(NULL, "\0", &saveptr2), NULL, 10);
686 if (errno) {
687 goto error_free_return;
688 } else if (inside < 0 || outside < 0 || length < 0) {
689 errno = EINVAL;
690 goto error_free_return;
691 }
692
693 if (id >= inside && id <= (inside + length)) {
694 result = (id - inside) + outside;
695 goto exit;
696 }
697
698 mapping = strtok_r(NULL, ",", &saveptr1);
699 }
700 errno = EINVAL;
701
702error_free_return:
703 result = -errno;
704exit:
705 free(map_copy);
706 return result;
707}
708
Dylan Reid837c74a2016-01-22 17:25:21 -0800709static int make_dir(const char *path, int uid, int gid, int mode)
710{
711 if (mkdir(path, mode))
712 return -errno;
713 if (chmod(path, mode))
714 return -errno;
715 if (chown(path, uid, gid))
716 return -errno;
717 return 0;
718}
719
720static int touch_file(const char *path, int uid, int gid, int mode)
721{
722 int rc;
723 int fd = open(path, O_RDWR | O_CREAT, mode);
724 if (fd < 0)
725 return -errno;
726 rc = fchown(fd, uid, gid);
727 close(fd);
728
729 if (rc)
730 return -errno;
731 return 0;
732}
733
734/* Make sure the mount target exists in the new rootfs. Create if needed and
735 * possible.
736 */
Stephen Barber1a398c72017-01-23 12:39:44 -0800737static int setup_mount_destination(const struct container_config *config,
738 const struct container_mount *mnt,
Dylan Reid2149be92016-04-28 18:38:57 -0700739 const char *source,
Dylan Reid837c74a2016-01-22 17:25:21 -0800740 const char *dest)
741{
Stephen Barber1a398c72017-01-23 12:39:44 -0800742 int uid_userns, gid_userns;
Dylan Reid837c74a2016-01-22 17:25:21 -0800743 int rc;
744 struct stat st_buf;
745
746 rc = stat(dest, &st_buf);
747 if (rc == 0) /* destination exists */
748 return 0;
749
750 /* Try to create the destination. Either make directory or touch a file
751 * depending on the source type.
752 */
Stephen Barber1a398c72017-01-23 12:39:44 -0800753 uid_userns = get_userns_outside_id(config->uid_map, mnt->uid);
754 if (uid_userns < 0)
755 return uid_userns;
756 gid_userns = get_userns_outside_id(config->gid_map, mnt->gid);
757 if (gid_userns < 0)
758 return gid_userns;
759
Dylan Reid2149be92016-04-28 18:38:57 -0700760 rc = stat(source, &st_buf);
Dylan Reid837c74a2016-01-22 17:25:21 -0800761 if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode))
Stephen Barber1a398c72017-01-23 12:39:44 -0800762 return make_dir(dest, uid_userns, gid_userns, mnt->mode);
Dylan Reid837c74a2016-01-22 17:25:21 -0800763
Stephen Barber1a398c72017-01-23 12:39:44 -0800764 return touch_file(dest, uid_userns, gid_userns, mnt->mode);
Dylan Reid837c74a2016-01-22 17:25:21 -0800765}
766
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700767/* Fork and exec the setfiles command to configure the selinux policy. */
Dylan Reide040c6b2016-05-02 18:49:02 -0700768static int run_setfiles_command(const struct container *c,
769 const struct container_config *config,
Yusuke Sato91f11f02016-12-02 16:15:13 -0800770 char *const *destinations, size_t num_destinations)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700771{
772 int rc;
773 int status;
774 int pid;
775 char *context_path;
776
Dylan Reide040c6b2016-05-02 18:49:02 -0700777 if (!config->run_setfiles)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700778 return 0;
779
780 if (asprintf(&context_path, "%s/file_contexts",
781 c->runfsroot) < 0)
782 return -errno;
783
784 pid = fork();
785 if (pid == 0) {
Yusuke Sato91f11f02016-12-02 16:15:13 -0800786 size_t i;
787 size_t arg_index = 0;
788 const char *argv[MAX_NUM_SETFILES_ARGS];
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700789 const char *env[] = {
790 NULL,
791 };
792
Yusuke Sato91f11f02016-12-02 16:15:13 -0800793 argv[arg_index++] = config->run_setfiles;
794 argv[arg_index++] = "-r";
795 argv[arg_index++] = c->runfsroot;
796 argv[arg_index++] = context_path;
797 if (arg_index + num_destinations >= MAX_NUM_SETFILES_ARGS)
798 _exit(-E2BIG);
799 for (i = 0; i < num_destinations; ++i) {
800 argv[arg_index++] = destinations[i];
801 }
802 argv[arg_index] = NULL;
803
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700804 execve(argv[0], (char *const*)argv, (char *const*)env);
805
806 /* Command failed to exec if execve returns. */
807 _exit(-errno);
808 }
809 free(context_path);
810 if (pid < 0)
811 return -errno;
812 do {
813 rc = waitpid(pid, &status, 0);
814 } while (rc == -1 && errno == EINTR);
815 if (rc < 0)
816 return -errno;
817 return status;
818}
819
Mike Frysinger412dbd22017-01-06 01:50:34 -0500820/* Find a free loop device and attach it. */
821static int loopdev_setup(char **loopdev_ret, const char *source)
822{
823 int ret = 0;
824 int source_fd = -1;
825 int control_fd = -1;
826 int loop_fd = -1;
827 char *loopdev = NULL;
828
829 source_fd = open(source, O_RDONLY|O_CLOEXEC);
830 if (source_fd < 0)
831 goto error;
832
833 control_fd = open(loopdev_ctl, O_RDWR|O_NOFOLLOW|O_CLOEXEC);
834 if (control_fd < 0)
835 goto error;
836
837 while (1) {
838 int num = ioctl(control_fd, LOOP_CTL_GET_FREE);
839 if (num < 0)
840 goto error;
841
842 if (asprintf(&loopdev, "/dev/loop%i", num) < 0)
843 goto error;
844
845 loop_fd = open(loopdev, O_RDONLY|O_NOFOLLOW|O_CLOEXEC);
846 if (loop_fd < 0)
847 goto error;
848
849 if (ioctl(loop_fd, LOOP_SET_FD, source_fd) == 0)
850 break;
851
852 if (errno != EBUSY)
853 goto error;
854
855 /* Clean up resources for the next pass. */
856 free(loopdev);
857 close(loop_fd);
858 }
859
860 *loopdev_ret = loopdev;
861 goto exit;
862
863error:
864 ret = -errno;
865 free(loopdev);
866exit:
867 if (source_fd != -1)
868 close(source_fd);
869 if (control_fd != -1)
870 close(control_fd);
871 if (loop_fd != -1)
872 close(loop_fd);
873 return ret;
874}
875
876/* Detach the specified loop device. */
877static int loopdev_detach(const char *loopdev)
878{
879 int ret = 0;
880 int fd;
881
882 fd = open(loopdev, O_RDONLY|O_NOFOLLOW|O_CLOEXEC);
883 if (fd < 0)
884 goto error;
885 if (ioctl(fd, LOOP_CLR_FD) < 0)
886 goto error;
887
888 goto exit;
889
890error:
891 ret = -errno;
892exit:
893 if (fd != -1)
894 close(fd);
895 return ret;
896}
897
Mike Frysinger05e594e2017-01-10 02:11:08 -0500898/* Create a new device mapper target for the source. */
899static int dm_setup(char **dm_path_ret, char **dm_name_ret, const char *source,
900 const char *verity_cmdline)
901{
902 int ret = 0;
903#if USE_device_mapper
904 char *p;
905 char *dm_path = NULL;
906 char *dm_name = NULL;
907 char *verity = NULL;
908 struct dm_task *dmt = NULL;
909 uint32_t cookie = 0;
910
911 /* Normalize the name into something unique-esque. */
912 if (asprintf(&dm_name, "cros-containers-%s", source) < 0)
913 goto error;
914 p = dm_name;
915 while ((p = strchr(p, '/')) != NULL)
916 *p++ = '_';
917
918 /* Get the /dev path for the higher levels to mount. */
919 if (asprintf(&dm_path, "%s%s", dm_dev_prefix, dm_name) < 0)
920 goto error;
921
922 /* Insert the source path in the verity command line. */
923 size_t source_len = strlen(source);
924 verity = malloc(strlen(verity_cmdline) + source_len * 2 + 1);
925 strcpy(verity, verity_cmdline);
926 while ((p = strstr(verity, "@DEV@")) != NULL) {
927 memmove(p + source_len, p + 5, strlen(p + 5) + 1);
928 memcpy(p, source, source_len);
929 }
930
931 /* Extract the first three parameters for dm-verity settings. */
932 char ttype[20];
933 unsigned long long start, size;
934 int n;
935 if (sscanf(verity, "%llu %llu %10s %n", &start, &size, ttype, &n) != 3)
936 goto error;
937
938 /* Finally create the device mapper. */
939 dmt = dm_task_create(DM_DEVICE_CREATE);
940 if (dmt == NULL)
941 goto error;
942
943 if (!dm_task_set_name(dmt, dm_name))
944 goto error;
945
946 if (!dm_task_set_ro(dmt))
947 goto error;
948
949 if (!dm_task_add_target(dmt, start, size, ttype, verity + n))
950 goto error;
951
952 if (!dm_task_set_cookie(dmt, &cookie, 0))
953 goto error;
954
955 if (!dm_task_run(dmt))
956 goto error;
957
958 /* Make sure the node exists before we continue. */
959 dm_udev_wait(cookie);
960
961 *dm_path_ret = dm_path;
962 *dm_name_ret = dm_name;
963 goto exit;
964
965error:
966 ret = -errno;
967 free(dm_name);
968 free(dm_path);
969exit:
970 free(verity);
971 if (dmt)
972 dm_task_destroy(dmt);
973#endif
974 return ret;
975}
976
977/* Tear down the device mapper target. */
978static int dm_detach(const char *dm_name)
979{
980 int ret = 0;
981#if USE_device_mapper
982 struct dm_task *dmt;
983
984 dmt = dm_task_create(DM_DEVICE_REMOVE);
985 if (dmt == NULL)
986 goto error;
987
988 if (!dm_task_set_name(dmt, dm_name))
989 goto error;
990
991 if (!dm_task_run(dmt))
992 goto error;
993
994 goto exit;
995
996error:
997 ret = -errno;
998exit:
999 dm_task_destroy(dmt);
1000#endif
1001 return ret;
1002}
1003
Dylan Reide040c6b2016-05-02 18:49:02 -07001004/*
1005 * Unmounts anything we mounted in this mount namespace in the opposite order
1006 * that they were mounted.
1007 */
1008static int unmount_external_mounts(struct container *c)
1009{
1010 int ret = 0;
1011
1012 while (c->num_ext_mounts) {
1013 c->num_ext_mounts--;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001014 if (!c->ext_mounts[c->num_ext_mounts])
1015 continue;
Dylan Reide040c6b2016-05-02 18:49:02 -07001016 if (umount(c->ext_mounts[c->num_ext_mounts]))
1017 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001018 FREE_AND_NULL(c->ext_mounts[c->num_ext_mounts]);
Dylan Reide040c6b2016-05-02 18:49:02 -07001019 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001020 FREE_AND_NULL(c->ext_mounts);
Mike Frysinger412dbd22017-01-06 01:50:34 -05001021
1022 while (c->num_loopdevs) {
1023 c->num_loopdevs--;
1024 if (loopdev_detach(c->loopdevs[c->num_loopdevs]))
1025 ret = -errno;
1026 FREE_AND_NULL(c->loopdevs[c->num_loopdevs]);
1027 }
1028 FREE_AND_NULL(c->loopdevs);
1029
Mike Frysinger05e594e2017-01-10 02:11:08 -05001030 while (c->num_device_mappers) {
1031 c->num_device_mappers--;
1032 if (dm_detach(c->device_mappers[c->num_device_mappers]))
1033 ret = -errno;
1034 FREE_AND_NULL(c->device_mappers[c->num_device_mappers]);
1035 }
1036 FREE_AND_NULL(c->device_mappers);
1037
Dylan Reide040c6b2016-05-02 18:49:02 -07001038 return ret;
1039}
1040
Junichi Uekawa5d272772016-07-21 16:07:19 +09001041/*
1042 * Match mount_one in minijail, mount one mountpoint with
1043 * consideration for combination of MS_BIND/MS_RDONLY flag.
1044 */
1045static int mount_external(const char *src, const char *dest, const char *type,
1046 unsigned long flags, const void *data)
1047{
1048 int remount_ro = 0;
1049
1050 /*
1051 * R/O bind mounts have to be remounted since 'bind' and 'ro'
1052 * can't both be specified in the original bind mount.
1053 * Remount R/O after the initial mount.
1054 */
1055 if ((flags & MS_BIND) && (flags & MS_RDONLY)) {
1056 remount_ro = 1;
1057 flags &= ~MS_RDONLY;
1058 }
1059
1060 if (mount(src, dest, type, flags, data) == -1)
1061 return -1;
1062
1063 if (remount_ro) {
1064 flags |= MS_RDONLY;
1065 if (mount(src, dest, NULL, flags | MS_REMOUNT, data) == -1)
1066 return -1;
1067 }
1068
1069 return 0;
1070}
1071
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001072static int do_container_mount(struct container *c,
Stephen Barber1a398c72017-01-23 12:39:44 -08001073 const struct container_config *config,
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001074 const struct container_mount *mnt)
1075{
Mike Frysinger05e594e2017-01-10 02:11:08 -05001076 char *dm_source = NULL;
Mike Frysinger412dbd22017-01-06 01:50:34 -05001077 char *loop_source = NULL;
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001078 char *source = NULL;
1079 char *dest = NULL;
1080 int rc = 0;
1081
1082 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
1083 return -errno;
1084
1085 /*
1086 * If it's a bind mount relative to rootfs, append source to
1087 * rootfs path, otherwise source path is absolute.
1088 */
1089 if ((mnt->flags & MS_BIND) && mnt->source[0] != '/') {
1090 if (asprintf(&source, "%s/%s", c->runfsroot, mnt->source) < 0)
1091 goto error_free_return;
Mike Frysingerb22acdf2017-01-08 02:02:35 -05001092 } else if (mnt->loopback && mnt->source[0] != '/' && c->config_root) {
1093 if (asprintf(&source, "%s/%s", c->config_root, mnt->source) < 0)
1094 goto error_free_return;
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001095 } else {
1096 if (asprintf(&source, "%s", mnt->source) < 0)
1097 goto error_free_return;
1098 }
1099
Dylan Reidbd5234c2017-06-06 21:20:07 -07001100 // Only create the destinations for external mounts, minijail will take
1101 // care of those mounted in the new namespace.
1102 if (mnt->create && !mnt->mount_in_ns) {
Stephen Barber1a398c72017-01-23 12:39:44 -08001103 rc = setup_mount_destination(config, mnt, source, dest);
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001104 if (rc)
1105 goto error_free_return;
1106 }
Mike Frysinger412dbd22017-01-06 01:50:34 -05001107 if (mnt->loopback) {
1108 /* Record this loopback file for cleanup later. */
1109 loop_source = source;
1110 source = NULL;
1111 rc = loopdev_setup(&source, loop_source);
1112 if (rc)
1113 goto error_free_return;
1114
Mike Frysinger05e594e2017-01-10 02:11:08 -05001115 /* Save this to cleanup when shutting down. */
Mike Frysinger412dbd22017-01-06 01:50:34 -05001116 rc = strdup_and_free(&c->loopdevs[c->num_loopdevs], source);
1117 if (rc)
1118 goto error_free_return;
1119 c->num_loopdevs++;
1120 }
Mike Frysinger05e594e2017-01-10 02:11:08 -05001121 if (mnt->verity) {
1122 /* Set this device up via dm-verity. */
1123 char *dm_name;
1124 dm_source = source;
1125 source = NULL;
1126 rc = dm_setup(&source, &dm_name, dm_source, mnt->verity);
1127 if (rc)
1128 goto error_free_return;
1129
1130 /* Save this to cleanup when shutting down. */
1131 rc = strdup_and_free(&c->device_mappers[c->num_device_mappers],
1132 dm_name);
1133 free(dm_name);
1134 if (rc)
1135 goto error_free_return;
1136 c->num_device_mappers++;
1137 }
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001138 if (mnt->mount_in_ns) {
1139 /* We can mount this with minijail. */
Dylan Reid36b9c012016-06-24 18:27:08 -07001140 rc = minijail_mount_with_data(c->jail, source, mnt->destination,
1141 mnt->type, mnt->flags, mnt->data);
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001142 if (rc)
1143 goto error_free_return;
1144 } else {
1145 /* Mount this externally and unmount it on exit. */
Junichi Uekawa5d272772016-07-21 16:07:19 +09001146 if (mount_external(source, dest, mnt->type, mnt->flags,
1147 mnt->data))
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001148 goto error_free_return;
1149 /* Save this to unmount when shutting down. */
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001150 rc = strdup_and_free(&c->ext_mounts[c->num_ext_mounts], dest);
1151 if (rc)
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001152 goto error_free_return;
1153 c->num_ext_mounts++;
1154 }
1155
1156 goto exit;
1157
1158error_free_return:
1159 if (!rc)
1160 rc = -errno;
1161exit:
Mike Frysinger05e594e2017-01-10 02:11:08 -05001162 free(dm_source);
Mike Frysinger412dbd22017-01-06 01:50:34 -05001163 free(loop_source);
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001164 free(source);
1165 free(dest);
1166 return rc;
1167}
1168
Dylan Reide040c6b2016-05-02 18:49:02 -07001169static int do_container_mounts(struct container *c,
1170 const struct container_config *config)
Dylan Reid7daf9982016-04-28 16:55:42 -07001171{
1172 unsigned int i;
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -07001173 int rc = 0;
Dylan Reid7daf9982016-04-28 16:55:42 -07001174
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001175 unmount_external_mounts(c);
Dylan Reide040c6b2016-05-02 18:49:02 -07001176 /*
1177 * Allocate space to track anything we mount in our mount namespace.
1178 * This over-allocates as it has space for all mounts.
1179 */
1180 c->ext_mounts = calloc(config->num_mounts, sizeof(*c->ext_mounts));
1181 if (!c->ext_mounts)
1182 return -errno;
Mike Frysinger412dbd22017-01-06 01:50:34 -05001183 c->loopdevs = calloc(config->num_mounts, sizeof(*c->loopdevs));
1184 if (!c->loopdevs)
1185 return -errno;
Mike Frysinger05e594e2017-01-10 02:11:08 -05001186 c->device_mappers = calloc(config->num_mounts, sizeof(*c->device_mappers));
1187 if (!c->device_mappers)
1188 return -errno;
Dylan Reide040c6b2016-05-02 18:49:02 -07001189
1190 for (i = 0; i < config->num_mounts; ++i) {
Stephen Barber1a398c72017-01-23 12:39:44 -08001191 rc = do_container_mount(c, config, &config->mounts[i]);
Luis Hector Chavez3341ed62016-06-06 08:04:04 -07001192 if (rc)
1193 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -07001194 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001195
Dylan Reid7daf9982016-04-28 16:55:42 -07001196 return 0;
Dylan Reid2149be92016-04-28 18:38:57 -07001197
1198error_free_return:
Dylan Reide040c6b2016-05-02 18:49:02 -07001199 unmount_external_mounts(c);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -07001200 return rc;
Dylan Reid7daf9982016-04-28 16:55:42 -07001201}
1202
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001203static int container_create_device(const struct container *c,
Stephen Barber1a398c72017-01-23 12:39:44 -08001204 const struct container_config *config,
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001205 const struct container_device *dev,
1206 int minor)
1207{
1208 char *path = NULL;
1209 int rc = 0;
1210 int mode;
Stephen Barber1a398c72017-01-23 12:39:44 -08001211 int uid_userns, gid_userns;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001212
1213 switch (dev->type) {
1214 case 'b':
1215 mode = S_IFBLK;
1216 break;
1217 case 'c':
1218 mode = S_IFCHR;
1219 break;
1220 default:
1221 return -EINVAL;
1222 }
1223 mode |= dev->fs_permissions;
1224
Stephen Barber1a398c72017-01-23 12:39:44 -08001225 uid_userns = get_userns_outside_id(config->uid_map, dev->uid);
1226 if (uid_userns < 0)
1227 return uid_userns;
1228 gid_userns = get_userns_outside_id(config->gid_map, dev->gid);
1229 if (gid_userns < 0)
1230 return gid_userns;
1231
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001232 if (asprintf(&path, "%s%s", c->runfsroot, dev->path) < 0)
1233 goto error_free_return;
1234 if (mknod(path, mode, makedev(dev->major, minor)) && errno != EEXIST)
1235 goto error_free_return;
Stephen Barber1a398c72017-01-23 12:39:44 -08001236 if (chown(path, uid_userns, gid_userns))
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001237 goto error_free_return;
1238 if (chmod(path, dev->fs_permissions))
1239 goto error_free_return;
1240
1241 goto exit;
1242
1243error_free_return:
1244 rc = -errno;
1245exit:
1246 free(path);
1247 return rc;
1248}
1249
Stephen Barber1a398c72017-01-23 12:39:44 -08001250
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001251static int mount_runfs(struct container *c, const struct container_config *config)
Dylan Reid837c74a2016-01-22 17:25:21 -08001252{
Dylan Reidb3621832016-03-24 10:24:57 -07001253 static const mode_t root_dir_mode = 0660;
Dylan Reide040c6b2016-05-02 18:49:02 -07001254 const char *rootfs = config->rootfs;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001255 char *runfs_template = NULL;
Stephen Barber1a398c72017-01-23 12:39:44 -08001256 int uid_userns, gid_userns;
Dylan Reid837c74a2016-01-22 17:25:21 -08001257
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001258 if (asprintf(&runfs_template, "%s/%s_XXXXXX", c->rundir, c->name) < 0)
1259 return -ENOMEM;
1260
1261 c->runfs = mkdtemp(runfs_template);
1262 if (!c->runfs) {
1263 free(runfs_template);
1264 return -errno;
1265 }
1266
Stephen Barber1a398c72017-01-23 12:39:44 -08001267 uid_userns = get_userns_outside_id(config->uid_map, config->uid);
1268 if (uid_userns < 0)
1269 return uid_userns;
1270 gid_userns = get_userns_outside_id(config->gid_map, config->gid);
1271 if (gid_userns < 0)
1272 return gid_userns;
1273
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001274 /* Make sure the container uid can access the rootfs. */
1275 if (chmod(c->runfs, 0700))
1276 return -errno;
Stephen Barber1a398c72017-01-23 12:39:44 -08001277 if (chown(c->runfs, uid_userns, gid_userns))
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001278 return -errno;
1279
1280 if (asprintf(&c->runfsroot, "%s/root", c->runfs) < 0)
1281 return -errno;
1282
1283 if (mkdir(c->runfsroot, root_dir_mode))
1284 return -errno;
1285 if (chmod(c->runfsroot, root_dir_mode))
1286 return -errno;
1287
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -07001288 if (mount(rootfs, c->runfsroot, "", MS_BIND, NULL))
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001289 return -errno;
1290
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -07001291 /* MS_BIND ignores any flags passed to it (except MS_REC). We need a
1292 * second call to mount() to actually set them.
1293 */
1294 if (config->rootfs_mount_flags &&
1295 mount(rootfs, c->runfsroot, "",
1296 config->rootfs_mount_flags, NULL)) {
1297 return -errno;
1298 }
1299
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001300 return 0;
1301}
1302
Dylan Reidacedff92017-03-31 17:41:40 -07001303static int device_setup(struct container *c,
1304 const struct container_config *config)
1305{
Dylan Reid43d4e5c2017-04-05 09:40:11 -07001306 int rc;
1307 size_t i;
Dylan Reidacedff92017-03-31 17:41:40 -07001308
1309 c->cgroup->ops->deny_all_devices(c->cgroup);
1310
Dylan Reid4843d6b2017-03-31 18:14:30 -07001311 for (i = 0; i < config->num_cgroup_devices; i++) {
1312 const struct container_cgroup_device *dev =
1313 &config->cgroup_devices[i];
1314 rc = c->cgroup->ops->add_device(c->cgroup,
1315 dev->allow,
1316 dev->major,
1317 dev->minor,
1318 dev->read,
1319 dev->write,
1320 dev->modify,
1321 dev->type);
1322 if (rc)
1323 return rc;
1324 }
1325
Dylan Reidacedff92017-03-31 17:41:40 -07001326 for (i = 0; i < config->num_devices; i++) {
1327 const struct container_device *dev = &config->devices[i];
1328 int minor = dev->minor;
1329
1330 if (dev->copy_minor) {
1331 struct stat st_buff;
1332 if (stat(dev->path, &st_buff) < 0)
1333 continue;
1334 minor = minor(st_buff.st_rdev);
1335 }
1336 if (minor >= 0) {
1337 rc = container_create_device(c, config, dev, minor);
1338 if (rc)
1339 return rc;
1340 }
Dylan Reidacedff92017-03-31 17:41:40 -07001341 }
1342
1343 for (i = 0; i < c->num_loopdevs; ++i) {
1344 struct stat st;
1345
Dylan Reid43d4e5c2017-04-05 09:40:11 -07001346 rc = stat(c->loopdevs[i], &st);
1347 if (rc < 0)
1348 return -errno;
Dylan Reid4843d6b2017-03-31 18:14:30 -07001349 rc = c->cgroup->ops->add_device(c->cgroup, 1, major(st.st_rdev),
Dylan Reidacedff92017-03-31 17:41:40 -07001350 minor(st.st_rdev),
1351 1, 0, 0, 'b');
1352 if (rc)
1353 return rc;
1354 }
1355
1356 return 0;
1357}
1358
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001359int container_start(struct container *c, const struct container_config *config)
1360{
1361 int rc = 0;
1362 unsigned int i;
Stephen Barber1a398c72017-01-23 12:39:44 -08001363 int cgroup_uid, cgroup_gid;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001364 char **destinations;
1365 size_t num_destinations;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001366
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001367 if (!c)
1368 return -EINVAL;
Dylan Reide040c6b2016-05-02 18:49:02 -07001369 if (!config)
1370 return -EINVAL;
1371 if (!config->program_argv || !config->program_argv[0])
1372 return -EINVAL;
1373
Mike Frysingerb22acdf2017-01-08 02:02:35 -05001374 if (config->config_root) {
1375 c->config_root = strdup(config->config_root);
1376 if (!c->config_root) {
1377 rc = -ENOMEM;
1378 goto error_rmdir;
1379 }
1380 }
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001381 if (config->premounted_runfs) {
1382 c->runfs = NULL;
1383 c->runfsroot = strdup(config->premounted_runfs);
1384 if (!c->runfsroot) {
1385 rc = -ENOMEM;
1386 goto error_rmdir;
1387 }
1388 } else {
1389 rc = mount_runfs(c, config);
1390 if (rc)
1391 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001392 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001393
1394 c->jail = minijail_new();
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001395 if (!c->jail)
Luis Hector Chavez945af482016-06-03 08:39:34 -07001396 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001397
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -07001398 rc = do_container_mounts(c, config);
1399 if (rc)
Dylan Reid7daf9982016-04-28 16:55:42 -07001400 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001401
Stephen Barber1a398c72017-01-23 12:39:44 -08001402 cgroup_uid = get_userns_outside_id(config->uid_map,
1403 config->cgroup_owner);
1404 if (cgroup_uid < 0) {
1405 rc = cgroup_uid;
1406 goto error_rmdir;
1407 }
1408 cgroup_gid = get_userns_outside_id(config->gid_map,
1409 config->cgroup_group);
1410 if (cgroup_gid < 0) {
1411 rc = cgroup_gid;
1412 goto error_rmdir;
1413 }
1414
Dylan Reida9966422016-07-21 10:11:34 -07001415 c->cgroup = container_cgroup_new(c->name,
1416 "/sys/fs/cgroup",
1417 config->cgroup_parent,
Stephen Barber1a398c72017-01-23 12:39:44 -08001418 cgroup_uid,
1419 cgroup_gid);
Dylan Reida9966422016-07-21 10:11:34 -07001420 if (!c->cgroup)
1421 goto error_rmdir;
1422
Keshav Santhanam268fa032016-07-14 09:59:24 -07001423 /* Must be root to modify device cgroup or mknod */
1424 if (getuid() == 0) {
Dylan Reidacedff92017-03-31 17:41:40 -07001425 if (device_setup(c, config))
1426 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001427 }
1428
Dylan Reidd7229582016-04-27 17:08:40 -07001429 /* Potentailly run setfiles on mounts configured outside of the jail */
Yusuke Sato91f11f02016-12-02 16:15:13 -08001430 destinations = calloc(config->num_mounts, sizeof(char *));
1431 num_destinations = 0;
Dylan Reide040c6b2016-05-02 18:49:02 -07001432 for (i = 0; i < config->num_mounts; i++) {
1433 const struct container_mount *mnt = &config->mounts[i];
Yusuke Sato91f11f02016-12-02 16:15:13 -08001434 char* dest = mnt->destination;
Dylan Reidd7229582016-04-27 17:08:40 -07001435
1436 if (mnt->mount_in_ns)
1437 continue;
Junichi Uekawa5d272772016-07-21 16:07:19 +09001438 if (mnt->flags & MS_RDONLY)
1439 continue;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001440
Yusuke Satod33db432016-12-05 16:24:37 -08001441 /* A hack to avoid setfiles on /data and /cache. */
1442 if (!strcmp(dest, "/data") || !strcmp(dest, "/cache"))
Yusuke Sato91f11f02016-12-02 16:15:13 -08001443 continue;
1444
1445 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0) {
1446 size_t j;
1447 for (j = 0; j < num_destinations; ++j) {
1448 free(destinations[j]);
1449 }
1450 free(destinations);
Dylan Reidd7229582016-04-27 17:08:40 -07001451 goto error_rmdir;
Yusuke Sato91f11f02016-12-02 16:15:13 -08001452 }
1453
1454 destinations[num_destinations++] = dest;
Dylan Reidd7229582016-04-27 17:08:40 -07001455 }
Yusuke Sato91f11f02016-12-02 16:15:13 -08001456 if (num_destinations) {
1457 size_t i;
1458 rc = run_setfiles_command(c, config, destinations, num_destinations);
1459 for (i = 0; i < num_destinations; ++i) {
1460 free(destinations[i]);
1461 }
1462 }
1463 free(destinations);
1464 if (rc)
1465 goto error_rmdir;
Dylan Reidd7229582016-04-27 17:08:40 -07001466
Chinyue Chenfac909e2016-06-24 14:17:42 +08001467 /* Setup CPU cgroup params. */
1468 if (config->cpu_cgparams.shares) {
1469 rc = c->cgroup->ops->set_cpu_shares(
1470 c->cgroup, config->cpu_cgparams.shares);
1471 if (rc)
1472 goto error_rmdir;
1473 }
1474 if (config->cpu_cgparams.period) {
1475 rc = c->cgroup->ops->set_cpu_quota(
1476 c->cgroup, config->cpu_cgparams.quota);
1477 if (rc)
1478 goto error_rmdir;
1479 rc = c->cgroup->ops->set_cpu_period(
1480 c->cgroup, config->cpu_cgparams.period);
1481 if (rc)
1482 goto error_rmdir;
1483 }
1484 if (config->cpu_cgparams.rt_period) {
1485 rc = c->cgroup->ops->set_cpu_rt_runtime(
1486 c->cgroup, config->cpu_cgparams.rt_runtime);
1487 if (rc)
1488 goto error_rmdir;
1489 rc = c->cgroup->ops->set_cpu_rt_period(
1490 c->cgroup, config->cpu_cgparams.rt_period);
1491 if (rc)
1492 goto error_rmdir;
1493 }
1494
Dylan Reid837c74a2016-01-22 17:25:21 -08001495 /* Setup and start the container with libminijail. */
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001496 if (config->pid_file_path) {
1497 c->pid_file_path = strdup(config->pid_file_path);
1498 if (!c->pid_file_path) {
1499 rc = -ENOMEM;
1500 goto error_rmdir;
1501 }
1502 } else if (c->runfs) {
1503 if (asprintf(&c->pid_file_path, "%s/container.pid", c->runfs) < 0) {
1504 rc = -ENOMEM;
1505 goto error_rmdir;
1506 }
1507 }
1508
1509 if (c->pid_file_path)
1510 minijail_write_pid_file(c->jail, c->pid_file_path);
Dylan Reid837c74a2016-01-22 17:25:21 -08001511 minijail_reset_signal_mask(c->jail);
1512
1513 /* Setup container namespaces. */
1514 minijail_namespace_ipc(c->jail);
1515 minijail_namespace_vfs(c->jail);
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001516 if (!config->share_host_netns)
1517 minijail_namespace_net(c->jail);
Dylan Reid837c74a2016-01-22 17:25:21 -08001518 minijail_namespace_pids(c->jail);
Dylan Reid837c74a2016-01-22 17:25:21 -08001519 minijail_namespace_user(c->jail);
Mike Frysingerfbd60552017-01-03 17:28:48 -05001520 if (getuid() != 0)
1521 minijail_namespace_user_disable_setgroups(c->jail);
Dylan Reidc6ca1042016-07-11 15:03:27 -07001522 minijail_namespace_cgroups(c->jail);
Dylan Reide040c6b2016-05-02 18:49:02 -07001523 rc = minijail_uidmap(c->jail, config->uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -08001524 if (rc)
1525 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -07001526 rc = minijail_gidmap(c->jail, config->gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -08001527 if (rc)
1528 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001529
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001530 /* Set the UID/GID inside the container if not 0. */
Stephen Barber1a398c72017-01-23 12:39:44 -08001531 if (get_userns_outside_id(config->uid_map, config->uid) < 0)
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001532 goto error_rmdir;
Stephen Barber1a398c72017-01-23 12:39:44 -08001533 else if (config->uid > 0)
1534 minijail_change_uid(c->jail, config->uid);
1535 if (get_userns_outside_id(config->gid_map, config->gid) < 0)
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001536 goto error_rmdir;
Stephen Barber1a398c72017-01-23 12:39:44 -08001537 else if (config->gid > 0)
1538 minijail_change_gid(c->jail, config->gid);
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001539
Dylan Reid837c74a2016-01-22 17:25:21 -08001540 rc = minijail_enter_pivot_root(c->jail, c->runfsroot);
1541 if (rc)
1542 goto error_rmdir;
1543
1544 /* Add the cgroups configured above. */
Dmitry Torokhov0d253a62017-01-05 09:41:33 -08001545 for (i = 0; i < NUM_CGROUP_TYPES; i++) {
1546 if (c->cgroup->cgroup_tasks_paths[i]) {
1547 rc = minijail_add_to_cgroup(c->jail,
1548 c->cgroup->cgroup_tasks_paths[i]);
1549 if (rc)
1550 goto error_rmdir;
1551 }
1552 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001553
Dylan Reide040c6b2016-05-02 18:49:02 -07001554 if (config->alt_syscall_table)
1555 minijail_use_alt_syscall(c->jail, config->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -08001556
1557 minijail_run_as_init(c->jail);
1558
Dylan Reid3da683b2016-04-05 03:35:35 -07001559 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
1560 minijail_skip_remount_private(c->jail);
1561
Dylan Reidc4335842016-11-11 10:24:52 -08001562 if (!config->keep_fds_open)
1563 minijail_close_open_fds(c->jail);
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001564
Luis Hector Chavezff5978f2017-06-27 12:52:58 -07001565 if (config->use_capmask) {
1566 minijail_use_caps(c->jail, config->capmask);
1567 if (config->use_capmask_ambient) {
1568 minijail_set_ambient_caps(c->jail);
1569 }
1570 }
1571
Dylan Reid837c74a2016-01-22 17:25:21 -08001572 rc = minijail_run_pid_pipes_no_preload(c->jail,
Dylan Reide040c6b2016-05-02 18:49:02 -07001573 config->program_argv[0],
1574 config->program_argv,
Dylan Reid837c74a2016-01-22 17:25:21 -08001575 &c->init_pid, NULL, NULL,
1576 NULL);
1577 if (rc)
1578 goto error_rmdir;
1579 return 0;
1580
1581error_rmdir:
Luis Hector Chavez945af482016-06-03 08:39:34 -07001582 if (!rc)
1583 rc = -errno;
1584 container_teardown(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001585 return rc;
1586}
1587
1588const char *container_root(struct container *c)
1589{
1590 return c->runfs;
1591}
1592
1593int container_pid(struct container *c)
1594{
1595 return c->init_pid;
1596}
1597
1598static int container_teardown(struct container *c)
1599{
Dylan Reid837c74a2016-01-22 17:25:21 -08001600 int ret = 0;
1601
Dylan Reide040c6b2016-05-02 18:49:02 -07001602 unmount_external_mounts(c);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001603 if (c->runfsroot && c->runfs) {
Luis Hector Chavez945af482016-06-03 08:39:34 -07001604 if (umount(c->runfsroot))
1605 ret = -errno;
1606 if (rmdir(c->runfsroot))
1607 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001608 FREE_AND_NULL(c->runfsroot);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001609 }
1610 if (c->pid_file_path) {
1611 if (unlink(c->pid_file_path))
1612 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001613 FREE_AND_NULL(c->pid_file_path);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001614 }
1615 if (c->runfs) {
1616 if (rmdir(c->runfs))
1617 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001618 FREE_AND_NULL(c->runfs);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001619 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001620 return ret;
1621}
1622
1623int container_wait(struct container *c)
1624{
Dylan Reidcf745c52016-04-22 10:18:03 -07001625 int rc;
1626
1627 do {
1628 rc = minijail_wait(c->jail);
Luis Hector Chavez4641e852016-06-02 15:40:19 -07001629 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001630
Luis Hector Chavez945af482016-06-03 08:39:34 -07001631 // If the process had already been reaped, still perform teardown.
1632 if (rc == -ECHILD || rc >= 0) {
Dylan Reidcf745c52016-04-22 10:18:03 -07001633 rc = container_teardown(c);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001634 }
Dylan Reidcf745c52016-04-22 10:18:03 -07001635 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001636}
1637
1638int container_kill(struct container *c)
1639{
Luis Hector Chavez945af482016-06-03 08:39:34 -07001640 if (kill(c->init_pid, SIGKILL) && errno != ESRCH)
Dylan Reid837c74a2016-01-22 17:25:21 -08001641 return -errno;
1642 return container_wait(c);
1643}