blob: d16c9555d0617887f467afe4aca482bad9f46298 [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>
10#include <malloc.h>
11#include <signal.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <sys/mount.h>
16#include <sys/stat.h>
17#include <sys/types.h>
Dylan Reid2bd9ea92016-04-07 20:57:47 -070018#include <sys/wait.h>
Dylan Reid837c74a2016-01-22 17:25:21 -080019#include <unistd.h>
20
21#include "container_cgroup.h"
22#include "libcontainer.h"
23#include "libminijail.h"
24
25struct container_mount {
26 char *name;
27 char *source;
28 char *destination;
29 char *type;
30 char *data;
31 int flags;
32 int uid;
33 int gid;
34 int mode;
35 int mount_in_ns; /* True if mount should happen in new vfs ns */
36 int create; /* True if target should be created if it doesn't exist */
37};
38
39struct container_device {
40 char type; /* 'c' or 'b' for char or block */
41 char *path;
42 int fs_permissions;
43 int major;
44 int minor;
Dylan Reid355d5e42016-04-29 16:53:31 -070045 int copy_minor; /* Copy the minor from existing node, ignores |minor| */
Dylan Reid837c74a2016-01-22 17:25:21 -080046 int uid;
47 int gid;
48 int read_allowed;
49 int write_allowed;
50 int modify_allowed;
51};
52
53/*
54 * Structure that configures how the container is run.
55 *
56 * rootfs - Path to the root of the container's filesystem.
57 * program_argv - The program to run and args, e.g. "/sbin/init".
58 * num_args - Number of args in program_argv.
59 * uid_map - Mapping of UIDs in the container, e.g. "0 100000 1024"
60 * gid_map - Mapping of GIDs in the container, e.g. "0 100000 1024"
61 * alt_syscall_table - Syscall table to use or NULL if none.
62 * mounts - Filesystems to mount in the new namespace.
63 * num_mounts - Number of above.
64 * devices - Device nodes to create.
65 * num_devices - Number of above.
Dylan Reid2bd9ea92016-04-07 20:57:47 -070066 * run_setfiles - Should run setfiles on mounts to enable selinux.
Dylan Reid837c74a2016-01-22 17:25:21 -080067 */
68struct container_config {
69 char *rootfs;
70 char **program_argv;
71 size_t num_args;
72 char *uid_map;
73 char *gid_map;
74 char *alt_syscall_table;
75 struct container_mount *mounts;
76 size_t num_mounts;
77 struct container_device *devices;
78 size_t num_devices;
Dylan Reid2bd9ea92016-04-07 20:57:47 -070079 const char *run_setfiles;
Dylan Reid837c74a2016-01-22 17:25:21 -080080};
81
82struct container_config *container_config_create()
83{
84 return calloc(1, sizeof(struct container_config));
85}
86
87void container_config_destroy(struct container_config *c)
88{
89 size_t i;
90
91 if (c == NULL)
92 return;
93 free(c->rootfs);
94 for (i = 0; i < c->num_args; ++i)
95 free(c->program_argv[i]);
96 free(c->program_argv);
97 free(c->uid_map);
98 free(c->gid_map);
99 free(c->alt_syscall_table);
100 for (i = 0; i < c->num_mounts; ++i) {
101 free(c->mounts[i].name);
102 free(c->mounts[i].source);
103 free(c->mounts[i].destination);
104 free(c->mounts[i].type);
105 free(c->mounts[i].data);
106 }
107 free(c->mounts);
108 for (i = 0; i < c->num_devices; ++i) {
109 free(c->devices[i].path);
110 }
111 free(c->devices);
112 free(c);
113}
114
115int container_config_rootfs(struct container_config *c, const char *rootfs)
116{
117 c->rootfs = strdup(rootfs);
118 if (!c->rootfs)
119 return -ENOMEM;
120 return 0;
121}
122
Dylan Reid11456722016-05-02 11:24:50 -0700123const char *container_config_get_rootfs(const struct container_config *c)
124{
125 return c->rootfs;
126}
127
Dylan Reid837c74a2016-01-22 17:25:21 -0800128int container_config_program_argv(struct container_config *c,
129 char **argv, size_t num_args)
130{
131 size_t i;
132
133 c->num_args = num_args;
134 c->program_argv = calloc(num_args + 1, sizeof(char *));
135 if (!c->program_argv)
136 return -ENOMEM;
137 for (i = 0; i < num_args; ++i) {
138 c->program_argv[i] = strdup(argv[i]);
139 if (!c->program_argv[i])
140 return -ENOMEM;
141 }
142 c->program_argv[num_args] = NULL;
143 return 0;
144}
145
Dylan Reid11456722016-05-02 11:24:50 -0700146size_t container_config_get_num_program_args(const struct container_config *c)
147{
148 return c->num_args;
149}
150
151const char *container_config_get_program_arg(const struct container_config *c,
152 size_t index)
153{
154 if (index >= c->num_args)
155 return NULL;
156 return c->program_argv[index];
157}
158
Dylan Reid837c74a2016-01-22 17:25:21 -0800159int container_config_uid_map(struct container_config *c, const char *uid_map)
160{
161 c->uid_map = strdup(uid_map);
162 if (!c->uid_map)
163 return -ENOMEM;
164 return 0;
165}
166
167int container_config_gid_map(struct container_config *c, const char *gid_map)
168{
169 c->gid_map = strdup(gid_map);
170 if (!c->gid_map)
171 return -ENOMEM;
172 return 0;
173}
174
175int container_config_alt_syscall_table(struct container_config *c,
176 const char *alt_syscall_table)
177{
178 c->alt_syscall_table = strdup(alt_syscall_table);
179 if (!c->alt_syscall_table)
180 return -ENOMEM;
181 return 0;
182}
183
184int container_config_add_mount(struct container_config *c,
185 const char *name,
186 const char *source,
187 const char *destination,
188 const char *type,
189 const char *data,
190 int flags,
191 int uid,
192 int gid,
193 int mode,
194 int mount_in_ns,
195 int create)
196{
197 struct container_mount *mount_ptr;
198
199 if (name == NULL || source == NULL ||
200 destination == NULL || type == NULL)
201 return -EINVAL;
202
203 mount_ptr = realloc(c->mounts,
204 sizeof(c->mounts[0]) * (c->num_mounts + 1));
205 if (!mount_ptr)
206 return -ENOMEM;
207 c->mounts = mount_ptr;
208 c->mounts[c->num_mounts].name = strdup(name);
209 if (!c->mounts[c->num_mounts].name)
210 return -ENOMEM;
211 c->mounts[c->num_mounts].source = strdup(source);
212 if (!c->mounts[c->num_mounts].source)
213 return -ENOMEM;
214 c->mounts[c->num_mounts].destination = strdup(destination);
215 if (!c->mounts[c->num_mounts].destination)
216 return -ENOMEM;
217 c->mounts[c->num_mounts].type = strdup(type);
218 if (!c->mounts[c->num_mounts].type)
219 return -ENOMEM;
220 if (data) {
221 c->mounts[c->num_mounts].data = strdup(data);
222 if (!c->mounts[c->num_mounts].data)
223 return -ENOMEM;
224 } else {
225 c->mounts[c->num_mounts].data = NULL;
226 }
227 c->mounts[c->num_mounts].flags = flags;
228 c->mounts[c->num_mounts].uid = uid;
229 c->mounts[c->num_mounts].gid = gid;
230 c->mounts[c->num_mounts].mode = mode;
231 c->mounts[c->num_mounts].mount_in_ns = mount_in_ns;
232 c->mounts[c->num_mounts].create = create;
233 ++c->num_mounts;
234 return 0;
235}
236
237int container_config_add_device(struct container_config *c,
238 char type,
239 const char *path,
240 int fs_permissions,
241 int major,
242 int minor,
Dylan Reid355d5e42016-04-29 16:53:31 -0700243 int copy_minor,
Dylan Reid837c74a2016-01-22 17:25:21 -0800244 int uid,
245 int gid,
246 int read_allowed,
247 int write_allowed,
248 int modify_allowed)
249{
250 struct container_device *dev_ptr;
251
252 if (path == NULL)
253 return -EINVAL;
Dylan Reid355d5e42016-04-29 16:53:31 -0700254 /* If using a dynamic minor number, ensure that minor is -1. */
255 if (copy_minor && (minor != -1))
256 return -EINVAL;
257
Dylan Reid837c74a2016-01-22 17:25:21 -0800258 dev_ptr = realloc(c->devices,
259 sizeof(c->devices[0]) * (c->num_devices + 1));
260 if (!dev_ptr)
261 return -ENOMEM;
262 c->devices = dev_ptr;
263 c->devices[c->num_devices].type = type;
264 c->devices[c->num_devices].path = strdup(path);
265 if (!c->devices[c->num_devices].path)
266 return -ENOMEM;
267 c->devices[c->num_devices].fs_permissions = fs_permissions;
268 c->devices[c->num_devices].major = major;
269 c->devices[c->num_devices].minor = minor;
Dylan Reid355d5e42016-04-29 16:53:31 -0700270 c->devices[c->num_devices].copy_minor = copy_minor;
Dylan Reid837c74a2016-01-22 17:25:21 -0800271 c->devices[c->num_devices].uid = uid;
272 c->devices[c->num_devices].gid = gid;
273 c->devices[c->num_devices].read_allowed = read_allowed;
274 c->devices[c->num_devices].write_allowed = write_allowed;
275 c->devices[c->num_devices].modify_allowed = modify_allowed;
276 ++c->num_devices;
277 return 0;
278}
279
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700280void container_config_run_setfiles(struct container_config *c,
281 const char *setfiles_cmd)
282{
283 c->run_setfiles = setfiles_cmd;
284}
Dylan Reid837c74a2016-01-22 17:25:21 -0800285
Dylan Reid11456722016-05-02 11:24:50 -0700286const char *container_config_get_run_setfiles(const struct container_config *c)
287{
288 return c->run_setfiles;
289}
290
Dylan Reid837c74a2016-01-22 17:25:21 -0800291/*
292 * Container manipulation
293 */
294struct container {
Dylan Reid837c74a2016-01-22 17:25:21 -0800295 struct container_cgroup *cgroup;
296 struct minijail *jail;
297 pid_t init_pid;
298 char *runfs;
299 char *rundir;
300 char *runfsroot;
301 char *pid_file_path;
Dylan Reide040c6b2016-05-02 18:49:02 -0700302 char **ext_mounts; /* Mounts made outside of the minijail */
303 size_t num_ext_mounts;
Dylan Reid837c74a2016-01-22 17:25:21 -0800304 const char *name;
305};
306
307struct container *container_new(const char *name,
Dylan Reide040c6b2016-05-02 18:49:02 -0700308 const char *rundir)
Dylan Reid837c74a2016-01-22 17:25:21 -0800309{
310 struct container *c;
311
Dylan Reid837c74a2016-01-22 17:25:21 -0800312 c = calloc(1, sizeof(*c));
Dylan Reidb435c682016-04-12 04:17:49 -0700313 if (!c)
314 return NULL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800315 c->name = name;
Dylan Reid837c74a2016-01-22 17:25:21 -0800316 c->cgroup = container_cgroup_new(name, "/sys/fs/cgroup");
317 c->rundir = strdup(rundir);
Dylan Reid684975e2016-05-02 15:44:47 -0700318 if (!c->cgroup || !c->rundir) {
319 container_destroy(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800320 return NULL;
Dylan Reidb435c682016-04-12 04:17:49 -0700321 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800322 return c;
323}
324
325void container_destroy(struct container *c)
326{
Dylan Reid684975e2016-05-02 15:44:47 -0700327 if (c->cgroup)
328 container_cgroup_destroy(c->cgroup);
Dylan Reid837c74a2016-01-22 17:25:21 -0800329 free(c->rundir);
330 free(c);
331}
332
333static int make_dir(const char *path, int uid, int gid, int mode)
334{
335 if (mkdir(path, mode))
336 return -errno;
337 if (chmod(path, mode))
338 return -errno;
339 if (chown(path, uid, gid))
340 return -errno;
341 return 0;
342}
343
344static int touch_file(const char *path, int uid, int gid, int mode)
345{
346 int rc;
347 int fd = open(path, O_RDWR | O_CREAT, mode);
348 if (fd < 0)
349 return -errno;
350 rc = fchown(fd, uid, gid);
351 close(fd);
352
353 if (rc)
354 return -errno;
355 return 0;
356}
357
358/* Make sure the mount target exists in the new rootfs. Create if needed and
359 * possible.
360 */
361static int setup_mount_destination(const struct container_mount *mnt,
Dylan Reid2149be92016-04-28 18:38:57 -0700362 const char *source,
Dylan Reid837c74a2016-01-22 17:25:21 -0800363 const char *dest)
364{
365 int rc;
366 struct stat st_buf;
367
368 rc = stat(dest, &st_buf);
369 if (rc == 0) /* destination exists */
370 return 0;
371
372 /* Try to create the destination. Either make directory or touch a file
373 * depending on the source type.
374 */
Dylan Reid2149be92016-04-28 18:38:57 -0700375 rc = stat(source, &st_buf);
Dylan Reid837c74a2016-01-22 17:25:21 -0800376 if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode))
377 return make_dir(dest, mnt->uid, mnt->gid, mnt->mode);
378
379 return touch_file(dest, mnt->uid, mnt->gid, mnt->mode);
380}
381
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700382/* Fork and exec the setfiles command to configure the selinux policy. */
Dylan Reide040c6b2016-05-02 18:49:02 -0700383static int run_setfiles_command(const struct container *c,
384 const struct container_config *config,
385 const char *dest)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700386{
387 int rc;
388 int status;
389 int pid;
390 char *context_path;
391
Dylan Reide040c6b2016-05-02 18:49:02 -0700392 if (!config->run_setfiles)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700393 return 0;
394
395 if (asprintf(&context_path, "%s/file_contexts",
396 c->runfsroot) < 0)
397 return -errno;
398
399 pid = fork();
400 if (pid == 0) {
401 const char *argv[] = {
Dylan Reide040c6b2016-05-02 18:49:02 -0700402 config->run_setfiles,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700403 "-r",
404 c->runfsroot,
405 context_path,
406 dest,
407 NULL,
408 };
409 const char *env[] = {
410 NULL,
411 };
412
413 execve(argv[0], (char *const*)argv, (char *const*)env);
414
415 /* Command failed to exec if execve returns. */
416 _exit(-errno);
417 }
418 free(context_path);
419 if (pid < 0)
420 return -errno;
421 do {
422 rc = waitpid(pid, &status, 0);
423 } while (rc == -1 && errno == EINTR);
424 if (rc < 0)
425 return -errno;
426 return status;
427}
428
Dylan Reide040c6b2016-05-02 18:49:02 -0700429/*
430 * Unmounts anything we mounted in this mount namespace in the opposite order
431 * that they were mounted.
432 */
433static int unmount_external_mounts(struct container *c)
434{
435 int ret = 0;
436
437 while (c->num_ext_mounts) {
438 c->num_ext_mounts--;
439 if (umount(c->ext_mounts[c->num_ext_mounts]))
440 ret = -errno;
441 free(c->ext_mounts[c->num_ext_mounts]);
442 }
443 free(c->ext_mounts);
444 return ret;
445}
446
447static int do_container_mounts(struct container *c,
448 const struct container_config *config)
Dylan Reid7daf9982016-04-28 16:55:42 -0700449{
450 unsigned int i;
Dylan Reid2149be92016-04-28 18:38:57 -0700451 char *source;
452 char *dest;
Dylan Reid7daf9982016-04-28 16:55:42 -0700453
Dylan Reide040c6b2016-05-02 18:49:02 -0700454 /*
455 * Allocate space to track anything we mount in our mount namespace.
456 * This over-allocates as it has space for all mounts.
457 */
458 c->ext_mounts = calloc(config->num_mounts, sizeof(*c->ext_mounts));
459 if (!c->ext_mounts)
460 return -errno;
461
462 for (i = 0; i < config->num_mounts; ++i) {
463 const struct container_mount *mnt = &config->mounts[i];
Dylan Reid7daf9982016-04-28 16:55:42 -0700464
Dylan Reid2149be92016-04-28 18:38:57 -0700465 source = NULL;
466 dest = NULL;
Dylan Reid7daf9982016-04-28 16:55:42 -0700467 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
468 return -errno;
469
Dylan Reid2149be92016-04-28 18:38:57 -0700470 /*
471 * If it's a bind mount relative to rootfs, append source to
472 * rootfs path, otherwise source path is absolute.
473 */
474 if ((mnt->flags & MS_BIND) && mnt->source[0] != '/') {
475 if (asprintf(&source, "%s/%s", c->runfsroot,
476 mnt->source) < 0)
477 goto error_free_return;
478 } else {
479 if (asprintf(&source, "%s", mnt->source) < 0)
480 goto error_free_return;
481 }
482
Dylan Reid7daf9982016-04-28 16:55:42 -0700483 if (mnt->create) {
Dylan Reid2149be92016-04-28 18:38:57 -0700484 if (setup_mount_destination(mnt, source, dest))
485 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -0700486 }
487 if (mnt->mount_in_ns) {
Dylan Reid2149be92016-04-28 18:38:57 -0700488 /* We can mount this with minijail. */
489 if (minijail_mount(c->jail, source, mnt->destination,
490 mnt->type, mnt->flags))
491 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -0700492 } else {
493 /*
494 * Mount this externally and unmount it on exit. Don't
495 * allow execution from external mounts.
496 */
Dylan Reid2149be92016-04-28 18:38:57 -0700497 if (mount(source, dest, mnt->type,
498 mnt->flags | MS_NOEXEC, mnt->data))
499 goto error_free_return;
Dylan Reide040c6b2016-05-02 18:49:02 -0700500 /* Save this to unmount when shutting down. */
501 c->ext_mounts[c->num_ext_mounts] = strdup(dest);
502 c->num_ext_mounts++;
Dylan Reid7daf9982016-04-28 16:55:42 -0700503 }
Dylan Reid2149be92016-04-28 18:38:57 -0700504 free(source);
Dylan Reid7daf9982016-04-28 16:55:42 -0700505 free(dest);
506 }
507 return 0;
Dylan Reid2149be92016-04-28 18:38:57 -0700508
509error_free_return:
510 free(dest);
511 free(source);
Dylan Reide040c6b2016-05-02 18:49:02 -0700512 unmount_external_mounts(c);
Dylan Reid2149be92016-04-28 18:38:57 -0700513 return -errno;
Dylan Reid7daf9982016-04-28 16:55:42 -0700514}
515
Dylan Reide040c6b2016-05-02 18:49:02 -0700516int container_start(struct container *c, const struct container_config *config)
Dylan Reid837c74a2016-01-22 17:25:21 -0800517{
518 int rc;
519 unsigned int i;
Dylan Reide040c6b2016-05-02 18:49:02 -0700520 const char *rootfs = config->rootfs;
Dylan Reid837c74a2016-01-22 17:25:21 -0800521 char *runfs_template;
522
Dylan Reide040c6b2016-05-02 18:49:02 -0700523 if (!config)
524 return -EINVAL;
525 if (!config->program_argv || !config->program_argv[0])
526 return -EINVAL;
527
Dylan Reid837c74a2016-01-22 17:25:21 -0800528 if (asprintf(&runfs_template, "%s/%s_XXXXXX", c->rundir, c->name) < 0)
529 return -errno;
530
531 c->runfs = mkdtemp(runfs_template);
532 if (!c->runfs) {
533 free(runfs_template);
534 return -errno;
535 }
536 if (asprintf(&c->runfsroot, "%s/root", c->runfs) < 0) {
537 free(runfs_template);
538 return -errno;
539 }
540
541 rc = mkdir(c->runfsroot, 0660);
542 if (rc)
543 goto error_rmdir;
544
545 rc = mount(rootfs, c->runfsroot, "", MS_BIND | MS_RDONLY | MS_NOEXEC,
546 NULL);
547 if (rc)
548 goto error_rmdir;
549
550 c->jail = minijail_new();
551
Dylan Reide040c6b2016-05-02 18:49:02 -0700552 if (do_container_mounts(c, config))
Dylan Reid7daf9982016-04-28 16:55:42 -0700553 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800554
555 c->cgroup->ops->deny_all_devices(c->cgroup);
556
Dylan Reide040c6b2016-05-02 18:49:02 -0700557 for (i = 0; i < config->num_devices; i++) {
558 const struct container_device *dev = &config->devices[i];
Dylan Reid837c74a2016-01-22 17:25:21 -0800559 int mode;
Dylan Reid355d5e42016-04-29 16:53:31 -0700560 int minor = dev->minor;
Dylan Reid837c74a2016-01-22 17:25:21 -0800561
562 switch (dev->type) {
563 case 'b':
564 mode = S_IFBLK;
565 break;
566 case 'c':
567 mode = S_IFCHR;
568 break;
569 default:
570 goto error_rmdir;
571 }
572 mode |= dev->fs_permissions;
573
Dylan Reid355d5e42016-04-29 16:53:31 -0700574 if (dev->copy_minor) {
575 struct stat st_buff;
576 if (stat(dev->path, &st_buff) < 0)
577 goto error_rmdir;
578 /* Use the minor macro to extract the device number. */
579 minor = minor(st_buff.st_rdev);
580 }
581 if (minor >= 0) {
582 char *path;
583
584 if (asprintf(&path, "%s%s", c->runfsroot, dev->path) < 0)
585 goto error_rmdir;
586 rc = mknod(path, mode, makedev(dev->major, minor));
Dylan Reid837c74a2016-01-22 17:25:21 -0800587 if (rc && errno != EEXIST) {
588 free(path);
589 goto error_rmdir;
590 }
591 rc = chown(path, dev->uid, dev->gid);
592 if (rc) {
593 free(path);
594 goto error_rmdir;
595 }
596 rc = chmod(path, dev->fs_permissions);
597 free(path);
598 if (rc)
599 goto error_rmdir;
600 }
601
602 rc = c->cgroup->ops->add_device(c->cgroup, dev->major,
Dylan Reid355d5e42016-04-29 16:53:31 -0700603 minor, dev->read_allowed,
Dylan Reid837c74a2016-01-22 17:25:21 -0800604 dev->write_allowed,
605 dev->modify_allowed, dev->type);
606 if (rc)
607 goto error_rmdir;
608 }
609
Dylan Reidd7229582016-04-27 17:08:40 -0700610 /* Potentailly run setfiles on mounts configured outside of the jail */
Dylan Reide040c6b2016-05-02 18:49:02 -0700611 for (i = 0; i < config->num_mounts; i++) {
612 const struct container_mount *mnt = &config->mounts[i];
Dylan Reidd7229582016-04-27 17:08:40 -0700613 char *dest;
614
615 if (mnt->mount_in_ns)
616 continue;
617 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
618 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -0700619 rc = run_setfiles_command(c, config, dest);
Dylan Reidd7229582016-04-27 17:08:40 -0700620 free(dest);
621 if (rc)
622 goto error_rmdir;
623 }
624
Dylan Reid837c74a2016-01-22 17:25:21 -0800625 /* Setup and start the container with libminijail. */
626 if (asprintf(&c->pid_file_path, "%s/container.pid", c->runfs) < 0)
627 goto error_rmdir;
628 minijail_write_pid_file(c->jail, c->pid_file_path);
629 minijail_reset_signal_mask(c->jail);
630
631 /* Setup container namespaces. */
632 minijail_namespace_ipc(c->jail);
633 minijail_namespace_vfs(c->jail);
634 minijail_namespace_net(c->jail);
635 minijail_namespace_pids(c->jail);
636/* TODO(dgreid) - Enable user namespaces
637 minijail_namespace_user(c->jail);
Dylan Reide040c6b2016-05-02 18:49:02 -0700638 rc = minijail_uidmap(c->jail, config->uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800639 if (rc)
640 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -0700641 rc = minijail_gidmap(c->jail, config->gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800642 if (rc)
643 goto error_rmdir;
644*/
645
646 rc = minijail_enter_pivot_root(c->jail, c->runfsroot);
647 if (rc)
648 goto error_rmdir;
649
650 /* Add the cgroups configured above. */
651 rc = minijail_add_to_cgroup(c->jail, cgroup_cpu_tasks_path(c->cgroup));
652 if (rc)
653 goto error_rmdir;
654 rc = minijail_add_to_cgroup(c->jail,
655 cgroup_cpuacct_tasks_path(c->cgroup));
656 if (rc)
657 goto error_rmdir;
658 rc = minijail_add_to_cgroup(c->jail,
659 cgroup_devices_tasks_path(c->cgroup));
660 if (rc)
661 goto error_rmdir;
662 rc = minijail_add_to_cgroup(c->jail,
663 cgroup_freezer_tasks_path(c->cgroup));
664 if (rc)
665 goto error_rmdir;
666
Dylan Reide040c6b2016-05-02 18:49:02 -0700667 if (config->alt_syscall_table)
668 minijail_use_alt_syscall(c->jail, config->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800669
670 minijail_run_as_init(c->jail);
671
Dylan Reid3da683b2016-04-05 03:35:35 -0700672 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
673 minijail_skip_remount_private(c->jail);
674
Dylan Reid837c74a2016-01-22 17:25:21 -0800675 /* Last mount is to make '/' executable in the container. */
676 rc = minijail_mount(c->jail, rootfs, "/", "",
677 MS_REMOUNT | MS_RDONLY);
678 if (rc)
679 goto error_rmdir;
680
681 rc = minijail_run_pid_pipes_no_preload(c->jail,
Dylan Reide040c6b2016-05-02 18:49:02 -0700682 config->program_argv[0],
683 config->program_argv,
Dylan Reid837c74a2016-01-22 17:25:21 -0800684 &c->init_pid, NULL, NULL,
685 NULL);
686 if (rc)
687 goto error_rmdir;
688 return 0;
689
690error_rmdir:
691 umount(c->runfsroot);
692 rmdir(c->runfsroot);
Dylan Reid5fa22082016-05-05 09:20:43 -0700693 if (c->pid_file_path)
694 unlink(c->pid_file_path);
Dylan Reid837c74a2016-01-22 17:25:21 -0800695 free(c->pid_file_path);
696 rmdir(c->runfs);
697 free(c->runfsroot);
698 free(c->runfs);
699 return rc;
700}
701
702const char *container_root(struct container *c)
703{
704 return c->runfs;
705}
706
707int container_pid(struct container *c)
708{
709 return c->init_pid;
710}
711
712static int container_teardown(struct container *c)
713{
Dylan Reid837c74a2016-01-22 17:25:21 -0800714 int ret = 0;
715
Dylan Reide040c6b2016-05-02 18:49:02 -0700716 unmount_external_mounts(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800717 if (umount(c->runfsroot))
718 ret = -errno;
719 if (rmdir(c->runfsroot))
720 ret = -errno;
Dylan Reid5fa22082016-05-05 09:20:43 -0700721 if (c->pid_file_path && unlink(c->pid_file_path))
Dylan Reid837c74a2016-01-22 17:25:21 -0800722 ret = -errno;
723 if (rmdir(c->runfs))
724 ret = -errno;
725 free(c->pid_file_path);
726 free(c->runfsroot);
727 free(c->runfs);
728 return ret;
729}
730
731int container_wait(struct container *c)
732{
Dylan Reidcf745c52016-04-22 10:18:03 -0700733 int rc;
734
735 do {
736 rc = minijail_wait(c->jail);
737 } while (rc == -1 && errno == EINTR);
738
Dylan Reid0025ab02016-06-01 10:54:44 -0700739 if (rc >= 0)
Dylan Reidcf745c52016-04-22 10:18:03 -0700740 rc = container_teardown(c);
741 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -0800742}
743
744int container_kill(struct container *c)
745{
746 int rc;
747
748 rc = kill(c->init_pid, SIGKILL);
749 if (rc)
750 return -errno;
751 return container_wait(c);
752}