blob: 8b36dc7b182a7270466be36e7628441d97d162ac [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 Reidb435c682016-04-12 04:17:49 -0700318 if (!c->rundir) {
319 free(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 Reid837c74a2016-01-22 17:25:21 -0800327 container_cgroup_destroy(c->cgroup);
328 free(c->rundir);
329 free(c);
330}
331
332static int make_dir(const char *path, int uid, int gid, int mode)
333{
334 if (mkdir(path, mode))
335 return -errno;
336 if (chmod(path, mode))
337 return -errno;
338 if (chown(path, uid, gid))
339 return -errno;
340 return 0;
341}
342
343static int touch_file(const char *path, int uid, int gid, int mode)
344{
345 int rc;
346 int fd = open(path, O_RDWR | O_CREAT, mode);
347 if (fd < 0)
348 return -errno;
349 rc = fchown(fd, uid, gid);
350 close(fd);
351
352 if (rc)
353 return -errno;
354 return 0;
355}
356
357/* Make sure the mount target exists in the new rootfs. Create if needed and
358 * possible.
359 */
360static int setup_mount_destination(const struct container_mount *mnt,
Dylan Reid2149be92016-04-28 18:38:57 -0700361 const char *source,
Dylan Reid837c74a2016-01-22 17:25:21 -0800362 const char *dest)
363{
364 int rc;
365 struct stat st_buf;
366
367 rc = stat(dest, &st_buf);
368 if (rc == 0) /* destination exists */
369 return 0;
370
371 /* Try to create the destination. Either make directory or touch a file
372 * depending on the source type.
373 */
Dylan Reid2149be92016-04-28 18:38:57 -0700374 rc = stat(source, &st_buf);
Dylan Reid837c74a2016-01-22 17:25:21 -0800375 if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode))
376 return make_dir(dest, mnt->uid, mnt->gid, mnt->mode);
377
378 return touch_file(dest, mnt->uid, mnt->gid, mnt->mode);
379}
380
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700381/* Fork and exec the setfiles command to configure the selinux policy. */
Dylan Reide040c6b2016-05-02 18:49:02 -0700382static int run_setfiles_command(const struct container *c,
383 const struct container_config *config,
384 const char *dest)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700385{
386 int rc;
387 int status;
388 int pid;
389 char *context_path;
390
Dylan Reide040c6b2016-05-02 18:49:02 -0700391 if (!config->run_setfiles)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700392 return 0;
393
394 if (asprintf(&context_path, "%s/file_contexts",
395 c->runfsroot) < 0)
396 return -errno;
397
398 pid = fork();
399 if (pid == 0) {
400 const char *argv[] = {
Dylan Reide040c6b2016-05-02 18:49:02 -0700401 config->run_setfiles,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700402 "-r",
403 c->runfsroot,
404 context_path,
405 dest,
406 NULL,
407 };
408 const char *env[] = {
409 NULL,
410 };
411
412 execve(argv[0], (char *const*)argv, (char *const*)env);
413
414 /* Command failed to exec if execve returns. */
415 _exit(-errno);
416 }
417 free(context_path);
418 if (pid < 0)
419 return -errno;
420 do {
421 rc = waitpid(pid, &status, 0);
422 } while (rc == -1 && errno == EINTR);
423 if (rc < 0)
424 return -errno;
425 return status;
426}
427
Dylan Reide040c6b2016-05-02 18:49:02 -0700428/*
429 * Unmounts anything we mounted in this mount namespace in the opposite order
430 * that they were mounted.
431 */
432static int unmount_external_mounts(struct container *c)
433{
434 int ret = 0;
435
436 while (c->num_ext_mounts) {
437 c->num_ext_mounts--;
438 if (umount(c->ext_mounts[c->num_ext_mounts]))
439 ret = -errno;
440 free(c->ext_mounts[c->num_ext_mounts]);
441 }
442 free(c->ext_mounts);
443 return ret;
444}
445
446static int do_container_mounts(struct container *c,
447 const struct container_config *config)
Dylan Reid7daf9982016-04-28 16:55:42 -0700448{
449 unsigned int i;
Dylan Reid2149be92016-04-28 18:38:57 -0700450 char *source;
451 char *dest;
Dylan Reid7daf9982016-04-28 16:55:42 -0700452
Dylan Reide040c6b2016-05-02 18:49:02 -0700453 /*
454 * Allocate space to track anything we mount in our mount namespace.
455 * This over-allocates as it has space for all mounts.
456 */
457 c->ext_mounts = calloc(config->num_mounts, sizeof(*c->ext_mounts));
458 if (!c->ext_mounts)
459 return -errno;
460
461 for (i = 0; i < config->num_mounts; ++i) {
462 const struct container_mount *mnt = &config->mounts[i];
Dylan Reid7daf9982016-04-28 16:55:42 -0700463
Dylan Reid2149be92016-04-28 18:38:57 -0700464 source = NULL;
465 dest = NULL;
Dylan Reid7daf9982016-04-28 16:55:42 -0700466 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
467 return -errno;
468
Dylan Reid2149be92016-04-28 18:38:57 -0700469 /*
470 * If it's a bind mount relative to rootfs, append source to
471 * rootfs path, otherwise source path is absolute.
472 */
473 if ((mnt->flags & MS_BIND) && mnt->source[0] != '/') {
474 if (asprintf(&source, "%s/%s", c->runfsroot,
475 mnt->source) < 0)
476 goto error_free_return;
477 } else {
478 if (asprintf(&source, "%s", mnt->source) < 0)
479 goto error_free_return;
480 }
481
Dylan Reid7daf9982016-04-28 16:55:42 -0700482 if (mnt->create) {
Dylan Reid2149be92016-04-28 18:38:57 -0700483 if (setup_mount_destination(mnt, source, dest))
484 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -0700485 }
486 if (mnt->mount_in_ns) {
Dylan Reid2149be92016-04-28 18:38:57 -0700487 /* We can mount this with minijail. */
488 if (minijail_mount(c->jail, source, mnt->destination,
489 mnt->type, mnt->flags))
490 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -0700491 } else {
492 /*
493 * Mount this externally and unmount it on exit. Don't
494 * allow execution from external mounts.
495 */
Dylan Reid2149be92016-04-28 18:38:57 -0700496 if (mount(source, dest, mnt->type,
497 mnt->flags | MS_NOEXEC, mnt->data))
498 goto error_free_return;
Dylan Reide040c6b2016-05-02 18:49:02 -0700499 /* Save this to unmount when shutting down. */
500 c->ext_mounts[c->num_ext_mounts] = strdup(dest);
501 c->num_ext_mounts++;
Dylan Reid7daf9982016-04-28 16:55:42 -0700502 }
Dylan Reid2149be92016-04-28 18:38:57 -0700503 free(source);
Dylan Reid7daf9982016-04-28 16:55:42 -0700504 free(dest);
505 }
506 return 0;
Dylan Reid2149be92016-04-28 18:38:57 -0700507
508error_free_return:
509 free(dest);
510 free(source);
Dylan Reide040c6b2016-05-02 18:49:02 -0700511 unmount_external_mounts(c);
Dylan Reid2149be92016-04-28 18:38:57 -0700512 return -errno;
Dylan Reid7daf9982016-04-28 16:55:42 -0700513}
514
Dylan Reide040c6b2016-05-02 18:49:02 -0700515int container_start(struct container *c, const struct container_config *config)
Dylan Reid837c74a2016-01-22 17:25:21 -0800516{
517 int rc;
518 unsigned int i;
Dylan Reide040c6b2016-05-02 18:49:02 -0700519 const char *rootfs = config->rootfs;
Dylan Reid837c74a2016-01-22 17:25:21 -0800520 char *runfs_template;
521
Dylan Reide040c6b2016-05-02 18:49:02 -0700522 if (!config)
523 return -EINVAL;
524 if (!config->program_argv || !config->program_argv[0])
525 return -EINVAL;
526
Dylan Reid837c74a2016-01-22 17:25:21 -0800527 if (asprintf(&runfs_template, "%s/%s_XXXXXX", c->rundir, c->name) < 0)
528 return -errno;
529
530 c->runfs = mkdtemp(runfs_template);
531 if (!c->runfs) {
532 free(runfs_template);
533 return -errno;
534 }
535 if (asprintf(&c->runfsroot, "%s/root", c->runfs) < 0) {
536 free(runfs_template);
537 return -errno;
538 }
539
540 rc = mkdir(c->runfsroot, 0660);
541 if (rc)
542 goto error_rmdir;
543
544 rc = mount(rootfs, c->runfsroot, "", MS_BIND | MS_RDONLY | MS_NOEXEC,
545 NULL);
546 if (rc)
547 goto error_rmdir;
548
549 c->jail = minijail_new();
550
Dylan Reide040c6b2016-05-02 18:49:02 -0700551 if (do_container_mounts(c, config))
Dylan Reid7daf9982016-04-28 16:55:42 -0700552 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800553
554 c->cgroup->ops->deny_all_devices(c->cgroup);
555
Dylan Reide040c6b2016-05-02 18:49:02 -0700556 for (i = 0; i < config->num_devices; i++) {
557 const struct container_device *dev = &config->devices[i];
Dylan Reid837c74a2016-01-22 17:25:21 -0800558 int mode;
Dylan Reid355d5e42016-04-29 16:53:31 -0700559 int minor = dev->minor;
Dylan Reid837c74a2016-01-22 17:25:21 -0800560
561 switch (dev->type) {
562 case 'b':
563 mode = S_IFBLK;
564 break;
565 case 'c':
566 mode = S_IFCHR;
567 break;
568 default:
569 goto error_rmdir;
570 }
571 mode |= dev->fs_permissions;
572
Dylan Reid355d5e42016-04-29 16:53:31 -0700573 if (dev->copy_minor) {
574 struct stat st_buff;
575 if (stat(dev->path, &st_buff) < 0)
576 goto error_rmdir;
577 /* Use the minor macro to extract the device number. */
578 minor = minor(st_buff.st_rdev);
579 }
580 if (minor >= 0) {
581 char *path;
582
583 if (asprintf(&path, "%s%s", c->runfsroot, dev->path) < 0)
584 goto error_rmdir;
585 rc = mknod(path, mode, makedev(dev->major, minor));
Dylan Reid837c74a2016-01-22 17:25:21 -0800586 if (rc && errno != EEXIST) {
587 free(path);
588 goto error_rmdir;
589 }
590 rc = chown(path, dev->uid, dev->gid);
591 if (rc) {
592 free(path);
593 goto error_rmdir;
594 }
595 rc = chmod(path, dev->fs_permissions);
596 free(path);
597 if (rc)
598 goto error_rmdir;
599 }
600
601 rc = c->cgroup->ops->add_device(c->cgroup, dev->major,
Dylan Reid355d5e42016-04-29 16:53:31 -0700602 minor, dev->read_allowed,
Dylan Reid837c74a2016-01-22 17:25:21 -0800603 dev->write_allowed,
604 dev->modify_allowed, dev->type);
605 if (rc)
606 goto error_rmdir;
607 }
608
Dylan Reidd7229582016-04-27 17:08:40 -0700609 /* Potentailly run setfiles on mounts configured outside of the jail */
Dylan Reide040c6b2016-05-02 18:49:02 -0700610 for (i = 0; i < config->num_mounts; i++) {
611 const struct container_mount *mnt = &config->mounts[i];
Dylan Reidd7229582016-04-27 17:08:40 -0700612 char *dest;
613
614 if (mnt->mount_in_ns)
615 continue;
616 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
617 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -0700618 rc = run_setfiles_command(c, config, dest);
Dylan Reidd7229582016-04-27 17:08:40 -0700619 free(dest);
620 if (rc)
621 goto error_rmdir;
622 }
623
Dylan Reid837c74a2016-01-22 17:25:21 -0800624 /* Setup and start the container with libminijail. */
625 if (asprintf(&c->pid_file_path, "%s/container.pid", c->runfs) < 0)
626 goto error_rmdir;
627 minijail_write_pid_file(c->jail, c->pid_file_path);
628 minijail_reset_signal_mask(c->jail);
629
630 /* Setup container namespaces. */
631 minijail_namespace_ipc(c->jail);
632 minijail_namespace_vfs(c->jail);
633 minijail_namespace_net(c->jail);
634 minijail_namespace_pids(c->jail);
635/* TODO(dgreid) - Enable user namespaces
636 minijail_namespace_user(c->jail);
Dylan Reide040c6b2016-05-02 18:49:02 -0700637 rc = minijail_uidmap(c->jail, config->uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800638 if (rc)
639 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -0700640 rc = minijail_gidmap(c->jail, config->gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800641 if (rc)
642 goto error_rmdir;
643*/
644
645 rc = minijail_enter_pivot_root(c->jail, c->runfsroot);
646 if (rc)
647 goto error_rmdir;
648
649 /* Add the cgroups configured above. */
650 rc = minijail_add_to_cgroup(c->jail, cgroup_cpu_tasks_path(c->cgroup));
651 if (rc)
652 goto error_rmdir;
653 rc = minijail_add_to_cgroup(c->jail,
654 cgroup_cpuacct_tasks_path(c->cgroup));
655 if (rc)
656 goto error_rmdir;
657 rc = minijail_add_to_cgroup(c->jail,
658 cgroup_devices_tasks_path(c->cgroup));
659 if (rc)
660 goto error_rmdir;
661 rc = minijail_add_to_cgroup(c->jail,
662 cgroup_freezer_tasks_path(c->cgroup));
663 if (rc)
664 goto error_rmdir;
665
Dylan Reide040c6b2016-05-02 18:49:02 -0700666 if (config->alt_syscall_table)
667 minijail_use_alt_syscall(c->jail, config->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800668
669 minijail_run_as_init(c->jail);
670
Dylan Reid3da683b2016-04-05 03:35:35 -0700671 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
672 minijail_skip_remount_private(c->jail);
673
Dylan Reid837c74a2016-01-22 17:25:21 -0800674 /* Last mount is to make '/' executable in the container. */
675 rc = minijail_mount(c->jail, rootfs, "/", "",
676 MS_REMOUNT | MS_RDONLY);
677 if (rc)
678 goto error_rmdir;
679
680 rc = minijail_run_pid_pipes_no_preload(c->jail,
Dylan Reide040c6b2016-05-02 18:49:02 -0700681 config->program_argv[0],
682 config->program_argv,
Dylan Reid837c74a2016-01-22 17:25:21 -0800683 &c->init_pid, NULL, NULL,
684 NULL);
685 if (rc)
686 goto error_rmdir;
687 return 0;
688
689error_rmdir:
690 umount(c->runfsroot);
691 rmdir(c->runfsroot);
692 unlink(c->pid_file_path);
693 free(c->pid_file_path);
694 rmdir(c->runfs);
695 free(c->runfsroot);
696 free(c->runfs);
697 return rc;
698}
699
700const char *container_root(struct container *c)
701{
702 return c->runfs;
703}
704
705int container_pid(struct container *c)
706{
707 return c->init_pid;
708}
709
710static int container_teardown(struct container *c)
711{
Dylan Reid837c74a2016-01-22 17:25:21 -0800712 int ret = 0;
713
Dylan Reide040c6b2016-05-02 18:49:02 -0700714 unmount_external_mounts(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800715 if (umount(c->runfsroot))
716 ret = -errno;
717 if (rmdir(c->runfsroot))
718 ret = -errno;
719 if (unlink(c->pid_file_path))
720 ret = -errno;
721 if (rmdir(c->runfs))
722 ret = -errno;
723 free(c->pid_file_path);
724 free(c->runfsroot);
725 free(c->runfs);
726 return ret;
727}
728
729int container_wait(struct container *c)
730{
Dylan Reidcf745c52016-04-22 10:18:03 -0700731 int rc;
732
733 do {
734 rc = minijail_wait(c->jail);
735 } while (rc == -1 && errno == EINTR);
736
737 if (rc == 0)
738 rc = container_teardown(c);
739 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -0800740}
741
742int container_kill(struct container *c)
743{
744 int rc;
745
746 rc = kill(c->init_pid, SIGKILL);
747 if (rc)
748 return -errno;
749 return container_wait(c);
750}