blob: 50cdf9ce36094aac34f3170557e8d71b9d8623c8 [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
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070025#define FREE_AND_NULL(ptr) \
26do { \
27 free(ptr); \
28 ptr = NULL; \
29} while(0)
30
Luis Hector Chavez945af482016-06-03 08:39:34 -070031static int container_teardown(struct container *c);
32
Luis Hector Chavez479b95f2016-06-06 08:01:05 -070033static int strdup_and_free(char **dest, const char *src)
34{
35 char *copy = strdup(src);
36 if (!copy)
37 return -ENOMEM;
38 if (*dest)
39 free(*dest);
40 *dest = copy;
41 return 0;
42}
43
Dylan Reid837c74a2016-01-22 17:25:21 -080044struct container_mount {
45 char *name;
46 char *source;
47 char *destination;
48 char *type;
49 char *data;
50 int flags;
51 int uid;
52 int gid;
53 int mode;
54 int mount_in_ns; /* True if mount should happen in new vfs ns */
55 int create; /* True if target should be created if it doesn't exist */
56};
57
58struct container_device {
59 char type; /* 'c' or 'b' for char or block */
60 char *path;
61 int fs_permissions;
62 int major;
63 int minor;
Dylan Reid355d5e42016-04-29 16:53:31 -070064 int copy_minor; /* Copy the minor from existing node, ignores |minor| */
Dylan Reid837c74a2016-01-22 17:25:21 -080065 int uid;
66 int gid;
67 int read_allowed;
68 int write_allowed;
69 int modify_allowed;
70};
71
Chinyue Chenfac909e2016-06-24 14:17:42 +080072struct container_cpu_cgroup {
73 int shares;
74 int quota;
75 int period;
76 int rt_runtime;
77 int rt_period;
78};
79
Dylan Reid837c74a2016-01-22 17:25:21 -080080/*
81 * Structure that configures how the container is run.
82 *
83 * rootfs - Path to the root of the container's filesystem.
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -070084 * rootfs_mount_flags - Flags that will be passed to mount() for the rootfs.
Keshav Santhanam0e4c3282016-07-14 10:25:16 -070085 * premounted_runfs - Path to where the container will be run.
86 * pid_file_path - Path to the file where the pid should be written.
Dylan Reid837c74a2016-01-22 17:25:21 -080087 * program_argv - The program to run and args, e.g. "/sbin/init".
88 * num_args - Number of args in program_argv.
Dylan Reid1874feb2016-06-22 17:53:50 -070089 * uid - The uid the container will run as.
Dylan Reid837c74a2016-01-22 17:25:21 -080090 * uid_map - Mapping of UIDs in the container, e.g. "0 100000 1024"
Dylan Reid1874feb2016-06-22 17:53:50 -070091 * gid - The gid the container will run as.
Dylan Reid837c74a2016-01-22 17:25:21 -080092 * gid_map - Mapping of GIDs in the container, e.g. "0 100000 1024"
93 * alt_syscall_table - Syscall table to use or NULL if none.
94 * mounts - Filesystems to mount in the new namespace.
95 * num_mounts - Number of above.
96 * devices - Device nodes to create.
97 * num_devices - Number of above.
Dylan Reid2bd9ea92016-04-07 20:57:47 -070098 * run_setfiles - Should run setfiles on mounts to enable selinux.
Chinyue Chenfac909e2016-06-24 14:17:42 +080099 * cpu_cgparams - CPU cgroup params.
Dylan Reid9e724af2016-07-21 09:58:07 -0700100 * cgroup_parent - Parent dir for cgroup creation
101 * cgroup_owner - uid to own the created cgroups
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700102 * cgroup_group - gid to own the created cgroups
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700103 * share_host_netns - Enable sharing of the host network namespace.
Dylan Reid837c74a2016-01-22 17:25:21 -0800104 */
105struct container_config {
106 char *rootfs;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700107 unsigned long rootfs_mount_flags;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700108 char *premounted_runfs;
109 char *pid_file_path;
Dylan Reid837c74a2016-01-22 17:25:21 -0800110 char **program_argv;
111 size_t num_args;
Dylan Reid1874feb2016-06-22 17:53:50 -0700112 uid_t uid;
Dylan Reid837c74a2016-01-22 17:25:21 -0800113 char *uid_map;
Dylan Reid1874feb2016-06-22 17:53:50 -0700114 gid_t gid;
Dylan Reid837c74a2016-01-22 17:25:21 -0800115 char *gid_map;
116 char *alt_syscall_table;
117 struct container_mount *mounts;
118 size_t num_mounts;
119 struct container_device *devices;
120 size_t num_devices;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700121 char *run_setfiles;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800122 struct container_cpu_cgroup cpu_cgparams;
Dylan Reid9e724af2016-07-21 09:58:07 -0700123 char *cgroup_parent;
124 uid_t cgroup_owner;
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700125 gid_t cgroup_group;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700126 int share_host_netns;
Dylan Reid837c74a2016-01-22 17:25:21 -0800127};
128
129struct container_config *container_config_create()
130{
131 return calloc(1, sizeof(struct container_config));
132}
133
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700134static void container_free_program_args(struct container_config *c)
135{
136 int i;
137
138 if (!c->program_argv)
139 return;
140 for (i = 0; i < c->num_args; ++i) {
141 FREE_AND_NULL(c->program_argv[i]);
142 }
143 FREE_AND_NULL(c->program_argv);
144}
145
146static void container_config_free_mount(struct container_mount *mount)
147{
148 FREE_AND_NULL(mount->name);
149 FREE_AND_NULL(mount->source);
150 FREE_AND_NULL(mount->destination);
151 FREE_AND_NULL(mount->type);
152 FREE_AND_NULL(mount->data);
153}
154
155static void container_config_free_device(struct container_device *device)
156{
157 FREE_AND_NULL(device->path);
158}
159
Dylan Reid837c74a2016-01-22 17:25:21 -0800160void container_config_destroy(struct container_config *c)
161{
162 size_t i;
163
164 if (c == NULL)
165 return;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700166 FREE_AND_NULL(c->rootfs);
167 container_free_program_args(c);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700168 FREE_AND_NULL(c->premounted_runfs);
169 FREE_AND_NULL(c->pid_file_path);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700170 FREE_AND_NULL(c->uid_map);
171 FREE_AND_NULL(c->gid_map);
172 FREE_AND_NULL(c->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800173 for (i = 0; i < c->num_mounts; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700174 container_config_free_mount(&c->mounts[i]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800175 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700176 FREE_AND_NULL(c->mounts);
Dylan Reid837c74a2016-01-22 17:25:21 -0800177 for (i = 0; i < c->num_devices; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700178 container_config_free_device(&c->devices[i]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800179 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700180 FREE_AND_NULL(c->devices);
181 FREE_AND_NULL(c->run_setfiles);
Dylan Reid9e724af2016-07-21 09:58:07 -0700182 FREE_AND_NULL(c->cgroup_parent);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700183 FREE_AND_NULL(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800184}
185
186int container_config_rootfs(struct container_config *c, const char *rootfs)
187{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700188 return strdup_and_free(&c->rootfs, rootfs);
Dylan Reid837c74a2016-01-22 17:25:21 -0800189}
190
Dylan Reid11456722016-05-02 11:24:50 -0700191const char *container_config_get_rootfs(const struct container_config *c)
192{
193 return c->rootfs;
194}
195
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700196void container_config_rootfs_mount_flags(struct container_config *c,
197 unsigned long rootfs_mount_flags)
198{
199 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
200 * simply check against zero later. MS_BIND is also added to avoid
201 * re-mounting the original filesystem, since the rootfs is always
202 * bind-mounted.
203 */
204 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
205}
206
207unsigned long container_config_get_rootfs_mount_flags(
208 const struct container_config *c)
209{
210 return c->rootfs_mount_flags;
211}
212
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700213int container_config_premounted_runfs(struct container_config *c, const char *runfs)
214{
215 return strdup_and_free(&c->premounted_runfs, runfs);
216}
217
218const char *container_config_get_premounted_runfs(const struct container_config *c)
219{
220 return c->premounted_runfs;
221}
222
223int container_config_pid_file(struct container_config *c, const char *path)
224{
225 return strdup_and_free(&c->pid_file_path, path);
226}
227
228const char *container_config_get_pid_file(const struct container_config *c)
229{
230 return c->pid_file_path;
231}
232
Dylan Reid837c74a2016-01-22 17:25:21 -0800233int container_config_program_argv(struct container_config *c,
234 char **argv, size_t num_args)
235{
236 size_t i;
237
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700238 container_free_program_args(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800239 c->num_args = num_args;
240 c->program_argv = calloc(num_args + 1, sizeof(char *));
241 if (!c->program_argv)
242 return -ENOMEM;
243 for (i = 0; i < num_args; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700244 if (strdup_and_free(&c->program_argv[i], argv[i]))
245 goto error_free_return;
Dylan Reid837c74a2016-01-22 17:25:21 -0800246 }
247 c->program_argv[num_args] = NULL;
248 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700249
250error_free_return:
251 container_free_program_args(c);
252 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800253}
254
Dylan Reid11456722016-05-02 11:24:50 -0700255size_t container_config_get_num_program_args(const struct container_config *c)
256{
257 return c->num_args;
258}
259
260const char *container_config_get_program_arg(const struct container_config *c,
261 size_t index)
262{
263 if (index >= c->num_args)
264 return NULL;
265 return c->program_argv[index];
266}
267
Dylan Reid1874feb2016-06-22 17:53:50 -0700268void container_config_uid(struct container_config *c, uid_t uid)
269{
270 c->uid = uid;
271}
272
273uid_t container_config_get_uid(const struct container_config *c)
274{
275 return c->uid;
276}
277
Dylan Reid837c74a2016-01-22 17:25:21 -0800278int container_config_uid_map(struct container_config *c, const char *uid_map)
279{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700280 return strdup_and_free(&c->uid_map, uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800281}
282
Dylan Reid1874feb2016-06-22 17:53:50 -0700283void container_config_gid(struct container_config *c, gid_t gid)
284{
285 c->gid = gid;
286}
287
288gid_t container_config_get_gid(const struct container_config *c)
289{
290 return c->gid;
291}
292
Dylan Reid837c74a2016-01-22 17:25:21 -0800293int container_config_gid_map(struct container_config *c, const char *gid_map)
294{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700295 return strdup_and_free(&c->gid_map, gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800296}
297
298int container_config_alt_syscall_table(struct container_config *c,
299 const char *alt_syscall_table)
300{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700301 return strdup_and_free(&c->alt_syscall_table, alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800302}
303
304int container_config_add_mount(struct container_config *c,
305 const char *name,
306 const char *source,
307 const char *destination,
308 const char *type,
309 const char *data,
310 int flags,
311 int uid,
312 int gid,
313 int mode,
314 int mount_in_ns,
315 int create)
316{
317 struct container_mount *mount_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700318 struct container_mount *current_mount;
Dylan Reid837c74a2016-01-22 17:25:21 -0800319
320 if (name == NULL || source == NULL ||
321 destination == NULL || type == NULL)
322 return -EINVAL;
323
324 mount_ptr = realloc(c->mounts,
325 sizeof(c->mounts[0]) * (c->num_mounts + 1));
326 if (!mount_ptr)
327 return -ENOMEM;
328 c->mounts = mount_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700329 current_mount = &c->mounts[c->num_mounts];
330 memset(current_mount, 0, sizeof(struct container_mount));
331
332 if (strdup_and_free(&current_mount->name, name))
333 goto error_free_return;
334 if (strdup_and_free(&current_mount->source, source))
335 goto error_free_return;
336 if (strdup_and_free(&current_mount->destination, destination))
337 goto error_free_return;
338 if (strdup_and_free(&current_mount->type, type))
339 goto error_free_return;
340 if (data && strdup_and_free(&current_mount->data, data))
341 goto error_free_return;
342 current_mount->flags = flags;
343 current_mount->uid = uid;
344 current_mount->gid = gid;
345 current_mount->mode = mode;
346 current_mount->mount_in_ns = mount_in_ns;
347 current_mount->create = create;
Dylan Reid837c74a2016-01-22 17:25:21 -0800348 ++c->num_mounts;
349 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700350
351error_free_return:
352 container_config_free_mount(current_mount);
353 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800354}
355
356int container_config_add_device(struct container_config *c,
357 char type,
358 const char *path,
359 int fs_permissions,
360 int major,
361 int minor,
Dylan Reid355d5e42016-04-29 16:53:31 -0700362 int copy_minor,
Dylan Reid837c74a2016-01-22 17:25:21 -0800363 int uid,
364 int gid,
365 int read_allowed,
366 int write_allowed,
367 int modify_allowed)
368{
369 struct container_device *dev_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700370 struct container_device *current_dev;
Dylan Reid837c74a2016-01-22 17:25:21 -0800371
372 if (path == NULL)
373 return -EINVAL;
Dylan Reid355d5e42016-04-29 16:53:31 -0700374 /* If using a dynamic minor number, ensure that minor is -1. */
375 if (copy_minor && (minor != -1))
376 return -EINVAL;
377
Dylan Reid837c74a2016-01-22 17:25:21 -0800378 dev_ptr = realloc(c->devices,
379 sizeof(c->devices[0]) * (c->num_devices + 1));
380 if (!dev_ptr)
381 return -ENOMEM;
382 c->devices = dev_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700383 current_dev = &c->devices[c->num_devices];
384 memset(current_dev, 0, sizeof(struct container_device));
385
386 current_dev->type = type;
387 if (strdup_and_free(&current_dev->path, path))
388 goto error_free_return;
389 current_dev->fs_permissions = fs_permissions;
390 current_dev->major = major;
391 current_dev->minor = minor;
392 current_dev->copy_minor = copy_minor;
393 current_dev->uid = uid;
394 current_dev->gid = gid;
395 current_dev->read_allowed = read_allowed;
396 current_dev->write_allowed = write_allowed;
397 current_dev->modify_allowed = modify_allowed;
Dylan Reid837c74a2016-01-22 17:25:21 -0800398 ++c->num_devices;
399 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700400
401error_free_return:
402 container_config_free_device(current_dev);
403 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800404}
405
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700406int container_config_run_setfiles(struct container_config *c,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700407 const char *setfiles_cmd)
408{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700409 return strdup_and_free(&c->run_setfiles, setfiles_cmd);
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700410}
Dylan Reid837c74a2016-01-22 17:25:21 -0800411
Dylan Reid11456722016-05-02 11:24:50 -0700412const char *container_config_get_run_setfiles(const struct container_config *c)
413{
414 return c->run_setfiles;
415}
416
Chinyue Chenfac909e2016-06-24 14:17:42 +0800417int container_config_set_cpu_shares(struct container_config *c, int shares)
418{
419 /* CPU shares must be 2 or higher. */
420 if (shares < 2)
421 return -EINVAL;
422
423 c->cpu_cgparams.shares = shares;
424 return 0;
425}
426
427int container_config_set_cpu_cfs_params(struct container_config *c,
428 int quota,
429 int period)
430{
431 /*
432 * quota could be set higher than period to utilize more than one CPU.
433 * quota could also be set as -1 to indicate the cgroup does not adhere
434 * to any CPU time restrictions.
435 */
436 if (quota <= 0 && quota != -1)
437 return -EINVAL;
438 if (period <= 0)
439 return -EINVAL;
440
441 c->cpu_cgparams.quota = quota;
442 c->cpu_cgparams.period = period;
443 return 0;
444}
445
446int container_config_set_cpu_rt_params(struct container_config *c,
447 int rt_runtime,
448 int rt_period)
449{
450 /*
451 * rt_runtime could be set as 0 to prevent the cgroup from using
452 * realtime CPU.
453 */
454 if (rt_runtime < 0 || rt_runtime >= rt_period)
455 return -EINVAL;
456
457 c->cpu_cgparams.rt_runtime = rt_runtime;
458 c->cpu_cgparams.rt_period = rt_period;
459 return 0;
460}
461
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800462int container_config_get_cpu_shares(struct container_config *c)
463{
464 return c->cpu_cgparams.shares;
465}
466
467int container_config_get_cpu_quota(struct container_config *c)
468{
469 return c->cpu_cgparams.quota;
470}
471
472int container_config_get_cpu_period(struct container_config *c)
473{
474 return c->cpu_cgparams.period;
475}
476
477int container_config_get_cpu_rt_runtime(struct container_config *c)
478{
479 return c->cpu_cgparams.rt_runtime;
480}
481
482int container_config_get_cpu_rt_period(struct container_config *c)
483{
484 return c->cpu_cgparams.rt_period;
485}
486
Dylan Reid9e724af2016-07-21 09:58:07 -0700487int container_config_set_cgroup_parent(struct container_config *c,
488 const char *parent,
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700489 uid_t cgroup_owner, gid_t cgroup_group)
Dylan Reid9e724af2016-07-21 09:58:07 -0700490{
491 c->cgroup_owner = cgroup_owner;
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700492 c->cgroup_group = cgroup_group;
Dylan Reid9e724af2016-07-21 09:58:07 -0700493 return strdup_and_free(&c->cgroup_parent, parent);
494}
495
496const char *container_config_get_cgroup_parent(struct container_config *c)
497{
498 return c->cgroup_parent;
499}
500
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700501void container_config_share_host_netns(struct container_config *c)
502{
503 c->share_host_netns = 1;
504}
505
506int get_container_config_share_host_netns(struct container_config *c)
507{
508 return c->share_host_netns;
509}
510
Dylan Reid837c74a2016-01-22 17:25:21 -0800511/*
512 * Container manipulation
513 */
514struct container {
Dylan Reid837c74a2016-01-22 17:25:21 -0800515 struct container_cgroup *cgroup;
516 struct minijail *jail;
517 pid_t init_pid;
518 char *runfs;
519 char *rundir;
520 char *runfsroot;
521 char *pid_file_path;
Dylan Reide040c6b2016-05-02 18:49:02 -0700522 char **ext_mounts; /* Mounts made outside of the minijail */
523 size_t num_ext_mounts;
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700524 char *name;
Dylan Reid837c74a2016-01-22 17:25:21 -0800525};
526
527struct container *container_new(const char *name,
Dylan Reide040c6b2016-05-02 18:49:02 -0700528 const char *rundir)
Dylan Reid837c74a2016-01-22 17:25:21 -0800529{
530 struct container *c;
531
Dylan Reid837c74a2016-01-22 17:25:21 -0800532 c = calloc(1, sizeof(*c));
Dylan Reidb435c682016-04-12 04:17:49 -0700533 if (!c)
534 return NULL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800535 c->rundir = strdup(rundir);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700536 c->name = strdup(name);
Dylan Reida9966422016-07-21 10:11:34 -0700537 if (!c->rundir || !c->name) {
Dylan Reid684975e2016-05-02 15:44:47 -0700538 container_destroy(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800539 return NULL;
Dylan Reidb435c682016-04-12 04:17:49 -0700540 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800541 return c;
542}
543
544void container_destroy(struct container *c)
545{
Dylan Reid684975e2016-05-02 15:44:47 -0700546 if (c->cgroup)
547 container_cgroup_destroy(c->cgroup);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700548 if (c->jail)
549 minijail_destroy(c->jail);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700550 FREE_AND_NULL(c->name);
551 FREE_AND_NULL(c->rundir);
552 FREE_AND_NULL(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800553}
554
555static int make_dir(const char *path, int uid, int gid, int mode)
556{
557 if (mkdir(path, mode))
558 return -errno;
559 if (chmod(path, mode))
560 return -errno;
561 if (chown(path, uid, gid))
562 return -errno;
563 return 0;
564}
565
566static int touch_file(const char *path, int uid, int gid, int mode)
567{
568 int rc;
569 int fd = open(path, O_RDWR | O_CREAT, mode);
570 if (fd < 0)
571 return -errno;
572 rc = fchown(fd, uid, gid);
573 close(fd);
574
575 if (rc)
576 return -errno;
577 return 0;
578}
579
580/* Make sure the mount target exists in the new rootfs. Create if needed and
581 * possible.
582 */
583static int setup_mount_destination(const struct container_mount *mnt,
Dylan Reid2149be92016-04-28 18:38:57 -0700584 const char *source,
Dylan Reid837c74a2016-01-22 17:25:21 -0800585 const char *dest)
586{
587 int rc;
588 struct stat st_buf;
589
590 rc = stat(dest, &st_buf);
591 if (rc == 0) /* destination exists */
592 return 0;
593
594 /* Try to create the destination. Either make directory or touch a file
595 * depending on the source type.
596 */
Dylan Reid2149be92016-04-28 18:38:57 -0700597 rc = stat(source, &st_buf);
Dylan Reid837c74a2016-01-22 17:25:21 -0800598 if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode))
599 return make_dir(dest, mnt->uid, mnt->gid, mnt->mode);
600
601 return touch_file(dest, mnt->uid, mnt->gid, mnt->mode);
602}
603
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700604/* Fork and exec the setfiles command to configure the selinux policy. */
Dylan Reide040c6b2016-05-02 18:49:02 -0700605static int run_setfiles_command(const struct container *c,
606 const struct container_config *config,
607 const char *dest)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700608{
609 int rc;
610 int status;
611 int pid;
612 char *context_path;
613
Dylan Reide040c6b2016-05-02 18:49:02 -0700614 if (!config->run_setfiles)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700615 return 0;
616
Dylan Reidb3621832016-03-24 10:24:57 -0700617 /* Really gross hack to avoid setfiles on /data, this should be removed
618 * when data isn't under /home/chronos/user where we can't access it as
619 * the android user.
620 * TODO(b/28705740) - Fix permission to the data directory.
621 */
622 if (strlen(dest) >= 5 && !strcmp(&dest[strlen(dest) - 5], "/data"))
623 return 0;
624
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700625 if (asprintf(&context_path, "%s/file_contexts",
626 c->runfsroot) < 0)
627 return -errno;
628
629 pid = fork();
630 if (pid == 0) {
631 const char *argv[] = {
Dylan Reide040c6b2016-05-02 18:49:02 -0700632 config->run_setfiles,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700633 "-r",
634 c->runfsroot,
635 context_path,
636 dest,
637 NULL,
638 };
639 const char *env[] = {
640 NULL,
641 };
642
643 execve(argv[0], (char *const*)argv, (char *const*)env);
644
645 /* Command failed to exec if execve returns. */
646 _exit(-errno);
647 }
648 free(context_path);
649 if (pid < 0)
650 return -errno;
651 do {
652 rc = waitpid(pid, &status, 0);
653 } while (rc == -1 && errno == EINTR);
654 if (rc < 0)
655 return -errno;
656 return status;
657}
658
Dylan Reide040c6b2016-05-02 18:49:02 -0700659/*
660 * Unmounts anything we mounted in this mount namespace in the opposite order
661 * that they were mounted.
662 */
663static int unmount_external_mounts(struct container *c)
664{
665 int ret = 0;
666
667 while (c->num_ext_mounts) {
668 c->num_ext_mounts--;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700669 if (!c->ext_mounts[c->num_ext_mounts])
670 continue;
Dylan Reide040c6b2016-05-02 18:49:02 -0700671 if (umount(c->ext_mounts[c->num_ext_mounts]))
672 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700673 FREE_AND_NULL(c->ext_mounts[c->num_ext_mounts]);
Dylan Reide040c6b2016-05-02 18:49:02 -0700674 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700675 FREE_AND_NULL(c->ext_mounts);
Dylan Reide040c6b2016-05-02 18:49:02 -0700676 return ret;
677}
678
Junichi Uekawa5d272772016-07-21 16:07:19 +0900679/*
680 * Match mount_one in minijail, mount one mountpoint with
681 * consideration for combination of MS_BIND/MS_RDONLY flag.
682 */
683static int mount_external(const char *src, const char *dest, const char *type,
684 unsigned long flags, const void *data)
685{
686 int remount_ro = 0;
687
688 /*
689 * R/O bind mounts have to be remounted since 'bind' and 'ro'
690 * can't both be specified in the original bind mount.
691 * Remount R/O after the initial mount.
692 */
693 if ((flags & MS_BIND) && (flags & MS_RDONLY)) {
694 remount_ro = 1;
695 flags &= ~MS_RDONLY;
696 }
697
698 if (mount(src, dest, type, flags, data) == -1)
699 return -1;
700
701 if (remount_ro) {
702 flags |= MS_RDONLY;
703 if (mount(src, dest, NULL, flags | MS_REMOUNT, data) == -1)
704 return -1;
705 }
706
707 return 0;
708}
709
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700710static int do_container_mount(struct container *c,
711 const struct container_mount *mnt)
712{
713 char *source = NULL;
714 char *dest = NULL;
715 int rc = 0;
716
717 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
718 return -errno;
719
720 /*
721 * If it's a bind mount relative to rootfs, append source to
722 * rootfs path, otherwise source path is absolute.
723 */
724 if ((mnt->flags & MS_BIND) && mnt->source[0] != '/') {
725 if (asprintf(&source, "%s/%s", c->runfsroot, mnt->source) < 0)
726 goto error_free_return;
727 } else {
728 if (asprintf(&source, "%s", mnt->source) < 0)
729 goto error_free_return;
730 }
731
732 if (mnt->create) {
733 rc = setup_mount_destination(mnt, source, dest);
734 if (rc)
735 goto error_free_return;
736 }
737 if (mnt->mount_in_ns) {
738 /* We can mount this with minijail. */
Dylan Reid36b9c012016-06-24 18:27:08 -0700739 rc = minijail_mount_with_data(c->jail, source, mnt->destination,
740 mnt->type, mnt->flags, mnt->data);
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700741 if (rc)
742 goto error_free_return;
743 } else {
744 /* Mount this externally and unmount it on exit. */
Junichi Uekawa5d272772016-07-21 16:07:19 +0900745 if (mount_external(source, dest, mnt->type, mnt->flags,
746 mnt->data))
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700747 goto error_free_return;
748 /* Save this to unmount when shutting down. */
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700749 rc = strdup_and_free(&c->ext_mounts[c->num_ext_mounts], dest);
750 if (rc)
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700751 goto error_free_return;
752 c->num_ext_mounts++;
753 }
754
755 goto exit;
756
757error_free_return:
758 if (!rc)
759 rc = -errno;
760exit:
761 free(source);
762 free(dest);
763 return rc;
764}
765
Dylan Reide040c6b2016-05-02 18:49:02 -0700766static int do_container_mounts(struct container *c,
767 const struct container_config *config)
Dylan Reid7daf9982016-04-28 16:55:42 -0700768{
769 unsigned int i;
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700770 int rc = 0;
Dylan Reid7daf9982016-04-28 16:55:42 -0700771
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700772 unmount_external_mounts(c);
Dylan Reide040c6b2016-05-02 18:49:02 -0700773 /*
774 * Allocate space to track anything we mount in our mount namespace.
775 * This over-allocates as it has space for all mounts.
776 */
777 c->ext_mounts = calloc(config->num_mounts, sizeof(*c->ext_mounts));
778 if (!c->ext_mounts)
779 return -errno;
780
781 for (i = 0; i < config->num_mounts; ++i) {
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700782 rc = do_container_mount(c, &config->mounts[i]);
783 if (rc)
784 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -0700785 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700786
Dylan Reid7daf9982016-04-28 16:55:42 -0700787 return 0;
Dylan Reid2149be92016-04-28 18:38:57 -0700788
789error_free_return:
Dylan Reide040c6b2016-05-02 18:49:02 -0700790 unmount_external_mounts(c);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700791 return rc;
Dylan Reid7daf9982016-04-28 16:55:42 -0700792}
793
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700794static int container_create_device(const struct container *c,
795 const struct container_device *dev,
796 int minor)
797{
798 char *path = NULL;
799 int rc = 0;
800 int mode;
801
802 switch (dev->type) {
803 case 'b':
804 mode = S_IFBLK;
805 break;
806 case 'c':
807 mode = S_IFCHR;
808 break;
809 default:
810 return -EINVAL;
811 }
812 mode |= dev->fs_permissions;
813
814 if (asprintf(&path, "%s%s", c->runfsroot, dev->path) < 0)
815 goto error_free_return;
816 if (mknod(path, mode, makedev(dev->major, minor)) && errno != EEXIST)
817 goto error_free_return;
818 if (chown(path, dev->uid, dev->gid))
819 goto error_free_return;
820 if (chmod(path, dev->fs_permissions))
821 goto error_free_return;
822
823 goto exit;
824
825error_free_return:
826 rc = -errno;
827exit:
828 free(path);
829 return rc;
830}
831
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700832static int mount_runfs(struct container *c, const struct container_config *config)
Dylan Reid837c74a2016-01-22 17:25:21 -0800833{
Dylan Reidb3621832016-03-24 10:24:57 -0700834 static const mode_t root_dir_mode = 0660;
Dylan Reide040c6b2016-05-02 18:49:02 -0700835 const char *rootfs = config->rootfs;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700836 char *runfs_template = NULL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800837
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700838 if (asprintf(&runfs_template, "%s/%s_XXXXXX", c->rundir, c->name) < 0)
839 return -ENOMEM;
840
841 c->runfs = mkdtemp(runfs_template);
842 if (!c->runfs) {
843 free(runfs_template);
844 return -errno;
845 }
846
847 /* Make sure the container uid can access the rootfs. */
848 if (chmod(c->runfs, 0700))
849 return -errno;
850 if (chown(c->runfs, config->uid, config->gid))
851 return -errno;
852
853 if (asprintf(&c->runfsroot, "%s/root", c->runfs) < 0)
854 return -errno;
855
856 if (mkdir(c->runfsroot, root_dir_mode))
857 return -errno;
858 if (chmod(c->runfsroot, root_dir_mode))
859 return -errno;
860
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700861 if (mount(rootfs, c->runfsroot, "", MS_BIND, NULL))
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700862 return -errno;
863
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700864 /* MS_BIND ignores any flags passed to it (except MS_REC). We need a
865 * second call to mount() to actually set them.
866 */
867 if (config->rootfs_mount_flags &&
868 mount(rootfs, c->runfsroot, "",
869 config->rootfs_mount_flags, NULL)) {
870 return -errno;
871 }
872
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700873 return 0;
874}
875
Keshav Santhanam36485ff2016-08-02 16:21:02 -0700876static int get_userns_id(const char *map, int id)
877{
878 char *map_copy, *mapping, *saveptr1, *saveptr2;
879 int inside, outside, length;
880 int result = 0;
881 errno = 0;
882
883 if (asprintf(&map_copy, "%s", map) < 0)
884 return -ENOMEM;
885
886 mapping = strtok_r(map_copy, ",", &saveptr1);
887 while (mapping) {
888 inside = strtol(strtok_r(mapping, " ", &saveptr2), NULL, 10);
889 outside = strtol(strtok_r(NULL, " ", &saveptr2), NULL, 10);
890 length = strtol(strtok_r(NULL, "\0", &saveptr2), NULL, 10);
891 if (errno) {
892 goto error_free_return;
893 } else if (inside < 0 || outside < 0 || length < 0) {
894 errno = EINVAL;
895 goto error_free_return;
896 }
897
898 if (id >= outside && id <= (outside + length)) {
899 result = id - (outside - inside);
900 goto exit;
901 }
902
903 mapping = strtok_r(NULL, ",", &saveptr1);
904 }
905 errno = EINVAL;
906
907error_free_return:
908 result = -errno;
909exit:
910 free(map_copy);
911 return result;
912}
913
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700914int container_start(struct container *c, const struct container_config *config)
915{
916 int rc = 0;
917 unsigned int i;
Keshav Santhanam36485ff2016-08-02 16:21:02 -0700918 int uid_userns, gid_userns;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700919
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700920 if (!c)
921 return -EINVAL;
Dylan Reide040c6b2016-05-02 18:49:02 -0700922 if (!config)
923 return -EINVAL;
924 if (!config->program_argv || !config->program_argv[0])
925 return -EINVAL;
926
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700927 if (config->premounted_runfs) {
928 c->runfs = NULL;
929 c->runfsroot = strdup(config->premounted_runfs);
930 if (!c->runfsroot) {
931 rc = -ENOMEM;
932 goto error_rmdir;
933 }
934 } else {
935 rc = mount_runfs(c, config);
936 if (rc)
937 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800938 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800939
940 c->jail = minijail_new();
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700941 if (!c->jail)
Luis Hector Chavez945af482016-06-03 08:39:34 -0700942 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800943
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700944 rc = do_container_mounts(c, config);
945 if (rc)
Dylan Reid7daf9982016-04-28 16:55:42 -0700946 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800947
Dylan Reida9966422016-07-21 10:11:34 -0700948 c->cgroup = container_cgroup_new(c->name,
949 "/sys/fs/cgroup",
950 config->cgroup_parent,
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700951 config->cgroup_owner,
952 config->cgroup_group);
Dylan Reida9966422016-07-21 10:11:34 -0700953 if (!c->cgroup)
954 goto error_rmdir;
955
Keshav Santhanam268fa032016-07-14 09:59:24 -0700956 /* Must be root to modify device cgroup or mknod */
957 if (getuid() == 0) {
958 c->cgroup->ops->deny_all_devices(c->cgroup);
Dylan Reid837c74a2016-01-22 17:25:21 -0800959
Keshav Santhanam268fa032016-07-14 09:59:24 -0700960 for (i = 0; i < config->num_devices; i++) {
961 const struct container_device *dev = &config->devices[i];
962 int minor = dev->minor;
Dylan Reid837c74a2016-01-22 17:25:21 -0800963
Keshav Santhanam268fa032016-07-14 09:59:24 -0700964 if (dev->copy_minor) {
965 struct stat st_buff;
966 if (stat(dev->path, &st_buff) < 0)
967 continue;
968 /* Use the minor macro to extract the device number. */
969 minor = minor(st_buff.st_rdev);
970 }
971 if (minor >= 0) {
972 rc = container_create_device(c, dev, minor);
973 if (rc)
974 goto error_rmdir;
975 }
976
977 rc = c->cgroup->ops->add_device(c->cgroup, dev->major,
978 minor, dev->read_allowed,
979 dev->write_allowed,
980 dev->modify_allowed, dev->type);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700981 if (rc)
Dylan Reid355d5e42016-04-29 16:53:31 -0700982 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800983 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800984 }
985
Dylan Reidd7229582016-04-27 17:08:40 -0700986 /* Potentailly run setfiles on mounts configured outside of the jail */
Dylan Reide040c6b2016-05-02 18:49:02 -0700987 for (i = 0; i < config->num_mounts; i++) {
988 const struct container_mount *mnt = &config->mounts[i];
Dylan Reidd7229582016-04-27 17:08:40 -0700989 char *dest;
990
991 if (mnt->mount_in_ns)
992 continue;
Junichi Uekawa5d272772016-07-21 16:07:19 +0900993 if (mnt->flags & MS_RDONLY)
994 continue;
Dylan Reidd7229582016-04-27 17:08:40 -0700995 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
996 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -0700997 rc = run_setfiles_command(c, config, dest);
Dylan Reidd7229582016-04-27 17:08:40 -0700998 free(dest);
999 if (rc)
1000 goto error_rmdir;
1001 }
1002
Chinyue Chenfac909e2016-06-24 14:17:42 +08001003 /* Setup CPU cgroup params. */
1004 if (config->cpu_cgparams.shares) {
1005 rc = c->cgroup->ops->set_cpu_shares(
1006 c->cgroup, config->cpu_cgparams.shares);
1007 if (rc)
1008 goto error_rmdir;
1009 }
1010 if (config->cpu_cgparams.period) {
1011 rc = c->cgroup->ops->set_cpu_quota(
1012 c->cgroup, config->cpu_cgparams.quota);
1013 if (rc)
1014 goto error_rmdir;
1015 rc = c->cgroup->ops->set_cpu_period(
1016 c->cgroup, config->cpu_cgparams.period);
1017 if (rc)
1018 goto error_rmdir;
1019 }
1020 if (config->cpu_cgparams.rt_period) {
1021 rc = c->cgroup->ops->set_cpu_rt_runtime(
1022 c->cgroup, config->cpu_cgparams.rt_runtime);
1023 if (rc)
1024 goto error_rmdir;
1025 rc = c->cgroup->ops->set_cpu_rt_period(
1026 c->cgroup, config->cpu_cgparams.rt_period);
1027 if (rc)
1028 goto error_rmdir;
1029 }
1030
Dylan Reid837c74a2016-01-22 17:25:21 -08001031 /* Setup and start the container with libminijail. */
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001032 if (config->pid_file_path) {
1033 c->pid_file_path = strdup(config->pid_file_path);
1034 if (!c->pid_file_path) {
1035 rc = -ENOMEM;
1036 goto error_rmdir;
1037 }
1038 } else if (c->runfs) {
1039 if (asprintf(&c->pid_file_path, "%s/container.pid", c->runfs) < 0) {
1040 rc = -ENOMEM;
1041 goto error_rmdir;
1042 }
1043 }
1044
1045 if (c->pid_file_path)
1046 minijail_write_pid_file(c->jail, c->pid_file_path);
Dylan Reid837c74a2016-01-22 17:25:21 -08001047 minijail_reset_signal_mask(c->jail);
1048
1049 /* Setup container namespaces. */
1050 minijail_namespace_ipc(c->jail);
1051 minijail_namespace_vfs(c->jail);
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001052 if (!config->share_host_netns)
1053 minijail_namespace_net(c->jail);
Dylan Reid837c74a2016-01-22 17:25:21 -08001054 minijail_namespace_pids(c->jail);
Dylan Reid837c74a2016-01-22 17:25:21 -08001055 minijail_namespace_user(c->jail);
Dylan Reidc6ca1042016-07-11 15:03:27 -07001056 minijail_namespace_cgroups(c->jail);
Dylan Reide040c6b2016-05-02 18:49:02 -07001057 rc = minijail_uidmap(c->jail, config->uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -08001058 if (rc)
1059 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -07001060 rc = minijail_gidmap(c->jail, config->gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -08001061 if (rc)
1062 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001063
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001064 /* Set the UID/GID inside the container if not 0. */
1065 uid_userns = get_userns_id(config->uid_map, config->uid);
1066 if (uid_userns < 0)
1067 goto error_rmdir;
1068 else if (uid_userns > 0)
1069 minijail_change_uid(c->jail, (uid_t) uid_userns);
1070 gid_userns = get_userns_id(config->gid_map, config->gid);
1071 if (gid_userns < 0)
1072 goto error_rmdir;
1073 else if (gid_userns > 0)
1074 minijail_change_gid(c->jail, (gid_t) gid_userns);
1075
Dylan Reid837c74a2016-01-22 17:25:21 -08001076 rc = minijail_enter_pivot_root(c->jail, c->runfsroot);
1077 if (rc)
1078 goto error_rmdir;
1079
1080 /* Add the cgroups configured above. */
1081 rc = minijail_add_to_cgroup(c->jail, cgroup_cpu_tasks_path(c->cgroup));
1082 if (rc)
1083 goto error_rmdir;
1084 rc = minijail_add_to_cgroup(c->jail,
1085 cgroup_cpuacct_tasks_path(c->cgroup));
1086 if (rc)
1087 goto error_rmdir;
1088 rc = minijail_add_to_cgroup(c->jail,
Dmitry Torokhov7a022712016-09-18 11:26:10 -07001089 cgroup_cpuset_tasks_path(c->cgroup));
1090 if (rc)
1091 goto error_rmdir;
1092 rc = minijail_add_to_cgroup(c->jail,
Dylan Reid837c74a2016-01-22 17:25:21 -08001093 cgroup_devices_tasks_path(c->cgroup));
1094 if (rc)
1095 goto error_rmdir;
1096 rc = minijail_add_to_cgroup(c->jail,
1097 cgroup_freezer_tasks_path(c->cgroup));
1098 if (rc)
1099 goto error_rmdir;
1100
Dylan Reide040c6b2016-05-02 18:49:02 -07001101 if (config->alt_syscall_table)
1102 minijail_use_alt_syscall(c->jail, config->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -08001103
1104 minijail_run_as_init(c->jail);
1105
Dylan Reid3da683b2016-04-05 03:35:35 -07001106 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
1107 minijail_skip_remount_private(c->jail);
1108
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001109 minijail_close_open_fds(c->jail);
1110
Dylan Reid837c74a2016-01-22 17:25:21 -08001111 rc = minijail_run_pid_pipes_no_preload(c->jail,
Dylan Reide040c6b2016-05-02 18:49:02 -07001112 config->program_argv[0],
1113 config->program_argv,
Dylan Reid837c74a2016-01-22 17:25:21 -08001114 &c->init_pid, NULL, NULL,
1115 NULL);
1116 if (rc)
1117 goto error_rmdir;
1118 return 0;
1119
1120error_rmdir:
Luis Hector Chavez945af482016-06-03 08:39:34 -07001121 if (!rc)
1122 rc = -errno;
1123 container_teardown(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001124 return rc;
1125}
1126
1127const char *container_root(struct container *c)
1128{
1129 return c->runfs;
1130}
1131
1132int container_pid(struct container *c)
1133{
1134 return c->init_pid;
1135}
1136
1137static int container_teardown(struct container *c)
1138{
Dylan Reid837c74a2016-01-22 17:25:21 -08001139 int ret = 0;
1140
Dylan Reide040c6b2016-05-02 18:49:02 -07001141 unmount_external_mounts(c);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001142 if (c->runfsroot && c->runfs) {
Luis Hector Chavez945af482016-06-03 08:39:34 -07001143 if (umount(c->runfsroot))
1144 ret = -errno;
1145 if (rmdir(c->runfsroot))
1146 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001147 FREE_AND_NULL(c->runfsroot);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001148 }
1149 if (c->pid_file_path) {
1150 if (unlink(c->pid_file_path))
1151 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001152 FREE_AND_NULL(c->pid_file_path);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001153 }
1154 if (c->runfs) {
1155 if (rmdir(c->runfs))
1156 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001157 FREE_AND_NULL(c->runfs);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001158 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001159 return ret;
1160}
1161
1162int container_wait(struct container *c)
1163{
Dylan Reidcf745c52016-04-22 10:18:03 -07001164 int rc;
1165
1166 do {
1167 rc = minijail_wait(c->jail);
Luis Hector Chavez4641e852016-06-02 15:40:19 -07001168 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001169
Luis Hector Chavez945af482016-06-03 08:39:34 -07001170 // If the process had already been reaped, still perform teardown.
1171 if (rc == -ECHILD || rc >= 0) {
Dylan Reidcf745c52016-04-22 10:18:03 -07001172 rc = container_teardown(c);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001173 }
Dylan Reidcf745c52016-04-22 10:18:03 -07001174 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001175}
1176
1177int container_kill(struct container *c)
1178{
Luis Hector Chavez945af482016-06-03 08:39:34 -07001179 if (kill(c->init_pid, SIGKILL) && errno != ESRCH)
Dylan Reid837c74a2016-01-22 17:25:21 -08001180 return -errno;
1181 return container_wait(c);
1182}