blob: ffceea7e1c336e4bbc6e0a42cde45fc91f4e6569 [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 Reidc4335842016-11-11 10:24:52 -0800104 * keep_fds_open - Allow the child process to keep open FDs (for stdin/out/err).
Dylan Reid837c74a2016-01-22 17:25:21 -0800105 */
106struct container_config {
107 char *rootfs;
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700108 unsigned long rootfs_mount_flags;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700109 char *premounted_runfs;
110 char *pid_file_path;
Dylan Reid837c74a2016-01-22 17:25:21 -0800111 char **program_argv;
112 size_t num_args;
Dylan Reid1874feb2016-06-22 17:53:50 -0700113 uid_t uid;
Dylan Reid837c74a2016-01-22 17:25:21 -0800114 char *uid_map;
Dylan Reid1874feb2016-06-22 17:53:50 -0700115 gid_t gid;
Dylan Reid837c74a2016-01-22 17:25:21 -0800116 char *gid_map;
117 char *alt_syscall_table;
118 struct container_mount *mounts;
119 size_t num_mounts;
120 struct container_device *devices;
121 size_t num_devices;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700122 char *run_setfiles;
Chinyue Chenfac909e2016-06-24 14:17:42 +0800123 struct container_cpu_cgroup cpu_cgparams;
Dylan Reid9e724af2016-07-21 09:58:07 -0700124 char *cgroup_parent;
125 uid_t cgroup_owner;
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700126 gid_t cgroup_group;
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700127 int share_host_netns;
Dylan Reidc4335842016-11-11 10:24:52 -0800128 int keep_fds_open;
Dylan Reid837c74a2016-01-22 17:25:21 -0800129};
130
131struct container_config *container_config_create()
132{
133 return calloc(1, sizeof(struct container_config));
134}
135
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700136static void container_free_program_args(struct container_config *c)
137{
138 int i;
139
140 if (!c->program_argv)
141 return;
142 for (i = 0; i < c->num_args; ++i) {
143 FREE_AND_NULL(c->program_argv[i]);
144 }
145 FREE_AND_NULL(c->program_argv);
146}
147
148static void container_config_free_mount(struct container_mount *mount)
149{
150 FREE_AND_NULL(mount->name);
151 FREE_AND_NULL(mount->source);
152 FREE_AND_NULL(mount->destination);
153 FREE_AND_NULL(mount->type);
154 FREE_AND_NULL(mount->data);
155}
156
157static void container_config_free_device(struct container_device *device)
158{
159 FREE_AND_NULL(device->path);
160}
161
Dylan Reid837c74a2016-01-22 17:25:21 -0800162void container_config_destroy(struct container_config *c)
163{
164 size_t i;
165
166 if (c == NULL)
167 return;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700168 FREE_AND_NULL(c->rootfs);
169 container_free_program_args(c);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700170 FREE_AND_NULL(c->premounted_runfs);
171 FREE_AND_NULL(c->pid_file_path);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700172 FREE_AND_NULL(c->uid_map);
173 FREE_AND_NULL(c->gid_map);
174 FREE_AND_NULL(c->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800175 for (i = 0; i < c->num_mounts; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700176 container_config_free_mount(&c->mounts[i]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800177 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700178 FREE_AND_NULL(c->mounts);
Dylan Reid837c74a2016-01-22 17:25:21 -0800179 for (i = 0; i < c->num_devices; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700180 container_config_free_device(&c->devices[i]);
Dylan Reid837c74a2016-01-22 17:25:21 -0800181 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700182 FREE_AND_NULL(c->devices);
183 FREE_AND_NULL(c->run_setfiles);
Dylan Reid9e724af2016-07-21 09:58:07 -0700184 FREE_AND_NULL(c->cgroup_parent);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700185 FREE_AND_NULL(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800186}
187
188int container_config_rootfs(struct container_config *c, const char *rootfs)
189{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700190 return strdup_and_free(&c->rootfs, rootfs);
Dylan Reid837c74a2016-01-22 17:25:21 -0800191}
192
Dylan Reid11456722016-05-02 11:24:50 -0700193const char *container_config_get_rootfs(const struct container_config *c)
194{
195 return c->rootfs;
196}
197
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700198void container_config_rootfs_mount_flags(struct container_config *c,
199 unsigned long rootfs_mount_flags)
200{
201 /* Since we are going to add MS_REMOUNT anyways, add it here so we can
202 * simply check against zero later. MS_BIND is also added to avoid
203 * re-mounting the original filesystem, since the rootfs is always
204 * bind-mounted.
205 */
206 c->rootfs_mount_flags = MS_REMOUNT | MS_BIND | rootfs_mount_flags;
207}
208
209unsigned long container_config_get_rootfs_mount_flags(
210 const struct container_config *c)
211{
212 return c->rootfs_mount_flags;
213}
214
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700215int container_config_premounted_runfs(struct container_config *c, const char *runfs)
216{
217 return strdup_and_free(&c->premounted_runfs, runfs);
218}
219
220const char *container_config_get_premounted_runfs(const struct container_config *c)
221{
222 return c->premounted_runfs;
223}
224
225int container_config_pid_file(struct container_config *c, const char *path)
226{
227 return strdup_and_free(&c->pid_file_path, path);
228}
229
230const char *container_config_get_pid_file(const struct container_config *c)
231{
232 return c->pid_file_path;
233}
234
Dylan Reid837c74a2016-01-22 17:25:21 -0800235int container_config_program_argv(struct container_config *c,
236 char **argv, size_t num_args)
237{
238 size_t i;
239
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700240 container_free_program_args(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800241 c->num_args = num_args;
242 c->program_argv = calloc(num_args + 1, sizeof(char *));
243 if (!c->program_argv)
244 return -ENOMEM;
245 for (i = 0; i < num_args; ++i) {
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700246 if (strdup_and_free(&c->program_argv[i], argv[i]))
247 goto error_free_return;
Dylan Reid837c74a2016-01-22 17:25:21 -0800248 }
249 c->program_argv[num_args] = NULL;
250 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700251
252error_free_return:
253 container_free_program_args(c);
254 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800255}
256
Dylan Reid11456722016-05-02 11:24:50 -0700257size_t container_config_get_num_program_args(const struct container_config *c)
258{
259 return c->num_args;
260}
261
262const char *container_config_get_program_arg(const struct container_config *c,
263 size_t index)
264{
265 if (index >= c->num_args)
266 return NULL;
267 return c->program_argv[index];
268}
269
Dylan Reid1874feb2016-06-22 17:53:50 -0700270void container_config_uid(struct container_config *c, uid_t uid)
271{
272 c->uid = uid;
273}
274
275uid_t container_config_get_uid(const struct container_config *c)
276{
277 return c->uid;
278}
279
Dylan Reid837c74a2016-01-22 17:25:21 -0800280int container_config_uid_map(struct container_config *c, const char *uid_map)
281{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700282 return strdup_and_free(&c->uid_map, uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800283}
284
Dylan Reid1874feb2016-06-22 17:53:50 -0700285void container_config_gid(struct container_config *c, gid_t gid)
286{
287 c->gid = gid;
288}
289
290gid_t container_config_get_gid(const struct container_config *c)
291{
292 return c->gid;
293}
294
Dylan Reid837c74a2016-01-22 17:25:21 -0800295int container_config_gid_map(struct container_config *c, const char *gid_map)
296{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700297 return strdup_and_free(&c->gid_map, gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -0800298}
299
300int container_config_alt_syscall_table(struct container_config *c,
301 const char *alt_syscall_table)
302{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700303 return strdup_and_free(&c->alt_syscall_table, alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -0800304}
305
306int container_config_add_mount(struct container_config *c,
307 const char *name,
308 const char *source,
309 const char *destination,
310 const char *type,
311 const char *data,
312 int flags,
313 int uid,
314 int gid,
315 int mode,
316 int mount_in_ns,
317 int create)
318{
319 struct container_mount *mount_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700320 struct container_mount *current_mount;
Dylan Reid837c74a2016-01-22 17:25:21 -0800321
322 if (name == NULL || source == NULL ||
323 destination == NULL || type == NULL)
324 return -EINVAL;
325
326 mount_ptr = realloc(c->mounts,
327 sizeof(c->mounts[0]) * (c->num_mounts + 1));
328 if (!mount_ptr)
329 return -ENOMEM;
330 c->mounts = mount_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700331 current_mount = &c->mounts[c->num_mounts];
332 memset(current_mount, 0, sizeof(struct container_mount));
333
334 if (strdup_and_free(&current_mount->name, name))
335 goto error_free_return;
336 if (strdup_and_free(&current_mount->source, source))
337 goto error_free_return;
338 if (strdup_and_free(&current_mount->destination, destination))
339 goto error_free_return;
340 if (strdup_and_free(&current_mount->type, type))
341 goto error_free_return;
342 if (data && strdup_and_free(&current_mount->data, data))
343 goto error_free_return;
344 current_mount->flags = flags;
345 current_mount->uid = uid;
346 current_mount->gid = gid;
347 current_mount->mode = mode;
348 current_mount->mount_in_ns = mount_in_ns;
349 current_mount->create = create;
Dylan Reid837c74a2016-01-22 17:25:21 -0800350 ++c->num_mounts;
351 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700352
353error_free_return:
354 container_config_free_mount(current_mount);
355 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800356}
357
358int container_config_add_device(struct container_config *c,
359 char type,
360 const char *path,
361 int fs_permissions,
362 int major,
363 int minor,
Dylan Reid355d5e42016-04-29 16:53:31 -0700364 int copy_minor,
Dylan Reid837c74a2016-01-22 17:25:21 -0800365 int uid,
366 int gid,
367 int read_allowed,
368 int write_allowed,
369 int modify_allowed)
370{
371 struct container_device *dev_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700372 struct container_device *current_dev;
Dylan Reid837c74a2016-01-22 17:25:21 -0800373
374 if (path == NULL)
375 return -EINVAL;
Dylan Reid355d5e42016-04-29 16:53:31 -0700376 /* If using a dynamic minor number, ensure that minor is -1. */
377 if (copy_minor && (minor != -1))
378 return -EINVAL;
379
Dylan Reid837c74a2016-01-22 17:25:21 -0800380 dev_ptr = realloc(c->devices,
381 sizeof(c->devices[0]) * (c->num_devices + 1));
382 if (!dev_ptr)
383 return -ENOMEM;
384 c->devices = dev_ptr;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700385 current_dev = &c->devices[c->num_devices];
386 memset(current_dev, 0, sizeof(struct container_device));
387
388 current_dev->type = type;
389 if (strdup_and_free(&current_dev->path, path))
390 goto error_free_return;
391 current_dev->fs_permissions = fs_permissions;
392 current_dev->major = major;
393 current_dev->minor = minor;
394 current_dev->copy_minor = copy_minor;
395 current_dev->uid = uid;
396 current_dev->gid = gid;
397 current_dev->read_allowed = read_allowed;
398 current_dev->write_allowed = write_allowed;
399 current_dev->modify_allowed = modify_allowed;
Dylan Reid837c74a2016-01-22 17:25:21 -0800400 ++c->num_devices;
401 return 0;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700402
403error_free_return:
404 container_config_free_device(current_dev);
405 return -ENOMEM;
Dylan Reid837c74a2016-01-22 17:25:21 -0800406}
407
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700408int container_config_run_setfiles(struct container_config *c,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700409 const char *setfiles_cmd)
410{
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700411 return strdup_and_free(&c->run_setfiles, setfiles_cmd);
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700412}
Dylan Reid837c74a2016-01-22 17:25:21 -0800413
Dylan Reid11456722016-05-02 11:24:50 -0700414const char *container_config_get_run_setfiles(const struct container_config *c)
415{
416 return c->run_setfiles;
417}
418
Chinyue Chenfac909e2016-06-24 14:17:42 +0800419int container_config_set_cpu_shares(struct container_config *c, int shares)
420{
421 /* CPU shares must be 2 or higher. */
422 if (shares < 2)
423 return -EINVAL;
424
425 c->cpu_cgparams.shares = shares;
426 return 0;
427}
428
429int container_config_set_cpu_cfs_params(struct container_config *c,
430 int quota,
431 int period)
432{
433 /*
434 * quota could be set higher than period to utilize more than one CPU.
435 * quota could also be set as -1 to indicate the cgroup does not adhere
436 * to any CPU time restrictions.
437 */
438 if (quota <= 0 && quota != -1)
439 return -EINVAL;
440 if (period <= 0)
441 return -EINVAL;
442
443 c->cpu_cgparams.quota = quota;
444 c->cpu_cgparams.period = period;
445 return 0;
446}
447
448int container_config_set_cpu_rt_params(struct container_config *c,
449 int rt_runtime,
450 int rt_period)
451{
452 /*
453 * rt_runtime could be set as 0 to prevent the cgroup from using
454 * realtime CPU.
455 */
456 if (rt_runtime < 0 || rt_runtime >= rt_period)
457 return -EINVAL;
458
459 c->cpu_cgparams.rt_runtime = rt_runtime;
460 c->cpu_cgparams.rt_period = rt_period;
461 return 0;
462}
463
Chinyue Chen4f3fd682016-07-01 14:11:42 +0800464int container_config_get_cpu_shares(struct container_config *c)
465{
466 return c->cpu_cgparams.shares;
467}
468
469int container_config_get_cpu_quota(struct container_config *c)
470{
471 return c->cpu_cgparams.quota;
472}
473
474int container_config_get_cpu_period(struct container_config *c)
475{
476 return c->cpu_cgparams.period;
477}
478
479int container_config_get_cpu_rt_runtime(struct container_config *c)
480{
481 return c->cpu_cgparams.rt_runtime;
482}
483
484int container_config_get_cpu_rt_period(struct container_config *c)
485{
486 return c->cpu_cgparams.rt_period;
487}
488
Dylan Reid9e724af2016-07-21 09:58:07 -0700489int container_config_set_cgroup_parent(struct container_config *c,
490 const char *parent,
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700491 uid_t cgroup_owner, gid_t cgroup_group)
Dylan Reid9e724af2016-07-21 09:58:07 -0700492{
493 c->cgroup_owner = cgroup_owner;
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700494 c->cgroup_group = cgroup_group;
Dylan Reid9e724af2016-07-21 09:58:07 -0700495 return strdup_and_free(&c->cgroup_parent, parent);
496}
497
498const char *container_config_get_cgroup_parent(struct container_config *c)
499{
500 return c->cgroup_parent;
501}
502
Keshav Santhanam1b6bf672016-08-10 18:35:12 -0700503void container_config_share_host_netns(struct container_config *c)
504{
505 c->share_host_netns = 1;
506}
507
508int get_container_config_share_host_netns(struct container_config *c)
509{
510 return c->share_host_netns;
511}
512
Dylan Reidc4335842016-11-11 10:24:52 -0800513void container_config_keep_fds_open(struct container_config *c)
514{
515 c->keep_fds_open = 1;
516}
517
Dylan Reid837c74a2016-01-22 17:25:21 -0800518/*
519 * Container manipulation
520 */
521struct container {
Dylan Reid837c74a2016-01-22 17:25:21 -0800522 struct container_cgroup *cgroup;
523 struct minijail *jail;
524 pid_t init_pid;
525 char *runfs;
526 char *rundir;
527 char *runfsroot;
528 char *pid_file_path;
Dylan Reide040c6b2016-05-02 18:49:02 -0700529 char **ext_mounts; /* Mounts made outside of the minijail */
530 size_t num_ext_mounts;
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700531 char *name;
Dylan Reid837c74a2016-01-22 17:25:21 -0800532};
533
534struct container *container_new(const char *name,
Dylan Reide040c6b2016-05-02 18:49:02 -0700535 const char *rundir)
Dylan Reid837c74a2016-01-22 17:25:21 -0800536{
537 struct container *c;
538
Dylan Reid837c74a2016-01-22 17:25:21 -0800539 c = calloc(1, sizeof(*c));
Dylan Reidb435c682016-04-12 04:17:49 -0700540 if (!c)
541 return NULL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800542 c->rundir = strdup(rundir);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700543 c->name = strdup(name);
Dylan Reida9966422016-07-21 10:11:34 -0700544 if (!c->rundir || !c->name) {
Dylan Reid684975e2016-05-02 15:44:47 -0700545 container_destroy(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800546 return NULL;
Dylan Reidb435c682016-04-12 04:17:49 -0700547 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800548 return c;
549}
550
551void container_destroy(struct container *c)
552{
Dylan Reid684975e2016-05-02 15:44:47 -0700553 if (c->cgroup)
554 container_cgroup_destroy(c->cgroup);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700555 if (c->jail)
556 minijail_destroy(c->jail);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700557 FREE_AND_NULL(c->name);
558 FREE_AND_NULL(c->rundir);
559 FREE_AND_NULL(c);
Dylan Reid837c74a2016-01-22 17:25:21 -0800560}
561
562static int make_dir(const char *path, int uid, int gid, int mode)
563{
564 if (mkdir(path, mode))
565 return -errno;
566 if (chmod(path, mode))
567 return -errno;
568 if (chown(path, uid, gid))
569 return -errno;
570 return 0;
571}
572
573static int touch_file(const char *path, int uid, int gid, int mode)
574{
575 int rc;
576 int fd = open(path, O_RDWR | O_CREAT, mode);
577 if (fd < 0)
578 return -errno;
579 rc = fchown(fd, uid, gid);
580 close(fd);
581
582 if (rc)
583 return -errno;
584 return 0;
585}
586
587/* Make sure the mount target exists in the new rootfs. Create if needed and
588 * possible.
589 */
590static int setup_mount_destination(const struct container_mount *mnt,
Dylan Reid2149be92016-04-28 18:38:57 -0700591 const char *source,
Dylan Reid837c74a2016-01-22 17:25:21 -0800592 const char *dest)
593{
594 int rc;
595 struct stat st_buf;
596
597 rc = stat(dest, &st_buf);
598 if (rc == 0) /* destination exists */
599 return 0;
600
601 /* Try to create the destination. Either make directory or touch a file
602 * depending on the source type.
603 */
Dylan Reid2149be92016-04-28 18:38:57 -0700604 rc = stat(source, &st_buf);
Dylan Reid837c74a2016-01-22 17:25:21 -0800605 if (rc || S_ISDIR(st_buf.st_mode) || S_ISBLK(st_buf.st_mode))
606 return make_dir(dest, mnt->uid, mnt->gid, mnt->mode);
607
608 return touch_file(dest, mnt->uid, mnt->gid, mnt->mode);
609}
610
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700611/* Fork and exec the setfiles command to configure the selinux policy. */
Dylan Reide040c6b2016-05-02 18:49:02 -0700612static int run_setfiles_command(const struct container *c,
613 const struct container_config *config,
614 const char *dest)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700615{
616 int rc;
617 int status;
618 int pid;
619 char *context_path;
620
Dylan Reide040c6b2016-05-02 18:49:02 -0700621 if (!config->run_setfiles)
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700622 return 0;
623
Dylan Reidb3621832016-03-24 10:24:57 -0700624 /* Really gross hack to avoid setfiles on /data, this should be removed
625 * when data isn't under /home/chronos/user where we can't access it as
626 * the android user.
627 * TODO(b/28705740) - Fix permission to the data directory.
628 */
629 if (strlen(dest) >= 5 && !strcmp(&dest[strlen(dest) - 5], "/data"))
630 return 0;
631
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700632 if (asprintf(&context_path, "%s/file_contexts",
633 c->runfsroot) < 0)
634 return -errno;
635
636 pid = fork();
637 if (pid == 0) {
638 const char *argv[] = {
Dylan Reide040c6b2016-05-02 18:49:02 -0700639 config->run_setfiles,
Dylan Reid2bd9ea92016-04-07 20:57:47 -0700640 "-r",
641 c->runfsroot,
642 context_path,
643 dest,
644 NULL,
645 };
646 const char *env[] = {
647 NULL,
648 };
649
650 execve(argv[0], (char *const*)argv, (char *const*)env);
651
652 /* Command failed to exec if execve returns. */
653 _exit(-errno);
654 }
655 free(context_path);
656 if (pid < 0)
657 return -errno;
658 do {
659 rc = waitpid(pid, &status, 0);
660 } while (rc == -1 && errno == EINTR);
661 if (rc < 0)
662 return -errno;
663 return status;
664}
665
Dylan Reide040c6b2016-05-02 18:49:02 -0700666/*
667 * Unmounts anything we mounted in this mount namespace in the opposite order
668 * that they were mounted.
669 */
670static int unmount_external_mounts(struct container *c)
671{
672 int ret = 0;
673
674 while (c->num_ext_mounts) {
675 c->num_ext_mounts--;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700676 if (!c->ext_mounts[c->num_ext_mounts])
677 continue;
Dylan Reide040c6b2016-05-02 18:49:02 -0700678 if (umount(c->ext_mounts[c->num_ext_mounts]))
679 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700680 FREE_AND_NULL(c->ext_mounts[c->num_ext_mounts]);
Dylan Reide040c6b2016-05-02 18:49:02 -0700681 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700682 FREE_AND_NULL(c->ext_mounts);
Dylan Reide040c6b2016-05-02 18:49:02 -0700683 return ret;
684}
685
Junichi Uekawa5d272772016-07-21 16:07:19 +0900686/*
687 * Match mount_one in minijail, mount one mountpoint with
688 * consideration for combination of MS_BIND/MS_RDONLY flag.
689 */
690static int mount_external(const char *src, const char *dest, const char *type,
691 unsigned long flags, const void *data)
692{
693 int remount_ro = 0;
694
695 /*
696 * R/O bind mounts have to be remounted since 'bind' and 'ro'
697 * can't both be specified in the original bind mount.
698 * Remount R/O after the initial mount.
699 */
700 if ((flags & MS_BIND) && (flags & MS_RDONLY)) {
701 remount_ro = 1;
702 flags &= ~MS_RDONLY;
703 }
704
705 if (mount(src, dest, type, flags, data) == -1)
706 return -1;
707
708 if (remount_ro) {
709 flags |= MS_RDONLY;
710 if (mount(src, dest, NULL, flags | MS_REMOUNT, data) == -1)
711 return -1;
712 }
713
714 return 0;
715}
716
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700717static int do_container_mount(struct container *c,
718 const struct container_mount *mnt)
719{
720 char *source = NULL;
721 char *dest = NULL;
722 int rc = 0;
723
724 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
725 return -errno;
726
727 /*
728 * If it's a bind mount relative to rootfs, append source to
729 * rootfs path, otherwise source path is absolute.
730 */
731 if ((mnt->flags & MS_BIND) && mnt->source[0] != '/') {
732 if (asprintf(&source, "%s/%s", c->runfsroot, mnt->source) < 0)
733 goto error_free_return;
734 } else {
735 if (asprintf(&source, "%s", mnt->source) < 0)
736 goto error_free_return;
737 }
738
739 if (mnt->create) {
740 rc = setup_mount_destination(mnt, source, dest);
741 if (rc)
742 goto error_free_return;
743 }
744 if (mnt->mount_in_ns) {
745 /* We can mount this with minijail. */
Dylan Reid36b9c012016-06-24 18:27:08 -0700746 rc = minijail_mount_with_data(c->jail, source, mnt->destination,
747 mnt->type, mnt->flags, mnt->data);
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700748 if (rc)
749 goto error_free_return;
750 } else {
751 /* Mount this externally and unmount it on exit. */
Junichi Uekawa5d272772016-07-21 16:07:19 +0900752 if (mount_external(source, dest, mnt->type, mnt->flags,
753 mnt->data))
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700754 goto error_free_return;
755 /* Save this to unmount when shutting down. */
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700756 rc = strdup_and_free(&c->ext_mounts[c->num_ext_mounts], dest);
757 if (rc)
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700758 goto error_free_return;
759 c->num_ext_mounts++;
760 }
761
762 goto exit;
763
764error_free_return:
765 if (!rc)
766 rc = -errno;
767exit:
768 free(source);
769 free(dest);
770 return rc;
771}
772
Dylan Reide040c6b2016-05-02 18:49:02 -0700773static int do_container_mounts(struct container *c,
774 const struct container_config *config)
Dylan Reid7daf9982016-04-28 16:55:42 -0700775{
776 unsigned int i;
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700777 int rc = 0;
Dylan Reid7daf9982016-04-28 16:55:42 -0700778
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700779 unmount_external_mounts(c);
Dylan Reide040c6b2016-05-02 18:49:02 -0700780 /*
781 * Allocate space to track anything we mount in our mount namespace.
782 * This over-allocates as it has space for all mounts.
783 */
784 c->ext_mounts = calloc(config->num_mounts, sizeof(*c->ext_mounts));
785 if (!c->ext_mounts)
786 return -errno;
787
788 for (i = 0; i < config->num_mounts; ++i) {
Luis Hector Chavez3341ed62016-06-06 08:04:04 -0700789 rc = do_container_mount(c, &config->mounts[i]);
790 if (rc)
791 goto error_free_return;
Dylan Reid7daf9982016-04-28 16:55:42 -0700792 }
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700793
Dylan Reid7daf9982016-04-28 16:55:42 -0700794 return 0;
Dylan Reid2149be92016-04-28 18:38:57 -0700795
796error_free_return:
Dylan Reide040c6b2016-05-02 18:49:02 -0700797 unmount_external_mounts(c);
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700798 return rc;
Dylan Reid7daf9982016-04-28 16:55:42 -0700799}
800
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700801static int container_create_device(const struct container *c,
802 const struct container_device *dev,
803 int minor)
804{
805 char *path = NULL;
806 int rc = 0;
807 int mode;
808
809 switch (dev->type) {
810 case 'b':
811 mode = S_IFBLK;
812 break;
813 case 'c':
814 mode = S_IFCHR;
815 break;
816 default:
817 return -EINVAL;
818 }
819 mode |= dev->fs_permissions;
820
821 if (asprintf(&path, "%s%s", c->runfsroot, dev->path) < 0)
822 goto error_free_return;
823 if (mknod(path, mode, makedev(dev->major, minor)) && errno != EEXIST)
824 goto error_free_return;
825 if (chown(path, dev->uid, dev->gid))
826 goto error_free_return;
827 if (chmod(path, dev->fs_permissions))
828 goto error_free_return;
829
830 goto exit;
831
832error_free_return:
833 rc = -errno;
834exit:
835 free(path);
836 return rc;
837}
838
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700839static int mount_runfs(struct container *c, const struct container_config *config)
Dylan Reid837c74a2016-01-22 17:25:21 -0800840{
Dylan Reidb3621832016-03-24 10:24:57 -0700841 static const mode_t root_dir_mode = 0660;
Dylan Reide040c6b2016-05-02 18:49:02 -0700842 const char *rootfs = config->rootfs;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700843 char *runfs_template = NULL;
Dylan Reid837c74a2016-01-22 17:25:21 -0800844
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700845 if (asprintf(&runfs_template, "%s/%s_XXXXXX", c->rundir, c->name) < 0)
846 return -ENOMEM;
847
848 c->runfs = mkdtemp(runfs_template);
849 if (!c->runfs) {
850 free(runfs_template);
851 return -errno;
852 }
853
854 /* Make sure the container uid can access the rootfs. */
855 if (chmod(c->runfs, 0700))
856 return -errno;
857 if (chown(c->runfs, config->uid, config->gid))
858 return -errno;
859
860 if (asprintf(&c->runfsroot, "%s/root", c->runfs) < 0)
861 return -errno;
862
863 if (mkdir(c->runfsroot, root_dir_mode))
864 return -errno;
865 if (chmod(c->runfsroot, root_dir_mode))
866 return -errno;
867
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700868 if (mount(rootfs, c->runfsroot, "", MS_BIND, NULL))
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700869 return -errno;
870
Luis Hector Chavezc240e7e2016-09-22 10:33:03 -0700871 /* MS_BIND ignores any flags passed to it (except MS_REC). We need a
872 * second call to mount() to actually set them.
873 */
874 if (config->rootfs_mount_flags &&
875 mount(rootfs, c->runfsroot, "",
876 config->rootfs_mount_flags, NULL)) {
877 return -errno;
878 }
879
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700880 return 0;
881}
882
Keshav Santhanam36485ff2016-08-02 16:21:02 -0700883static int get_userns_id(const char *map, int id)
884{
885 char *map_copy, *mapping, *saveptr1, *saveptr2;
886 int inside, outside, length;
887 int result = 0;
888 errno = 0;
889
890 if (asprintf(&map_copy, "%s", map) < 0)
891 return -ENOMEM;
892
893 mapping = strtok_r(map_copy, ",", &saveptr1);
894 while (mapping) {
895 inside = strtol(strtok_r(mapping, " ", &saveptr2), NULL, 10);
896 outside = strtol(strtok_r(NULL, " ", &saveptr2), NULL, 10);
897 length = strtol(strtok_r(NULL, "\0", &saveptr2), NULL, 10);
898 if (errno) {
899 goto error_free_return;
900 } else if (inside < 0 || outside < 0 || length < 0) {
901 errno = EINVAL;
902 goto error_free_return;
903 }
904
905 if (id >= outside && id <= (outside + length)) {
906 result = id - (outside - inside);
907 goto exit;
908 }
909
910 mapping = strtok_r(NULL, ",", &saveptr1);
911 }
912 errno = EINVAL;
913
914error_free_return:
915 result = -errno;
916exit:
917 free(map_copy);
918 return result;
919}
920
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700921int container_start(struct container *c, const struct container_config *config)
922{
923 int rc = 0;
924 unsigned int i;
Keshav Santhanam36485ff2016-08-02 16:21:02 -0700925 int uid_userns, gid_userns;
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700926
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700927 if (!c)
928 return -EINVAL;
Dylan Reide040c6b2016-05-02 18:49:02 -0700929 if (!config)
930 return -EINVAL;
931 if (!config->program_argv || !config->program_argv[0])
932 return -EINVAL;
933
Keshav Santhanam0e4c3282016-07-14 10:25:16 -0700934 if (config->premounted_runfs) {
935 c->runfs = NULL;
936 c->runfsroot = strdup(config->premounted_runfs);
937 if (!c->runfsroot) {
938 rc = -ENOMEM;
939 goto error_rmdir;
940 }
941 } else {
942 rc = mount_runfs(c, config);
943 if (rc)
944 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800945 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800946
947 c->jail = minijail_new();
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700948 if (!c->jail)
Luis Hector Chavez945af482016-06-03 08:39:34 -0700949 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800950
Luis Hector Chavez8e7b6d52016-06-02 20:40:43 -0700951 rc = do_container_mounts(c, config);
952 if (rc)
Dylan Reid7daf9982016-04-28 16:55:42 -0700953 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800954
Dylan Reida9966422016-07-21 10:11:34 -0700955 c->cgroup = container_cgroup_new(c->name,
956 "/sys/fs/cgroup",
957 config->cgroup_parent,
Dmitry Torokhov14eef722016-09-27 16:40:37 -0700958 config->cgroup_owner,
959 config->cgroup_group);
Dylan Reida9966422016-07-21 10:11:34 -0700960 if (!c->cgroup)
961 goto error_rmdir;
962
Keshav Santhanam268fa032016-07-14 09:59:24 -0700963 /* Must be root to modify device cgroup or mknod */
964 if (getuid() == 0) {
965 c->cgroup->ops->deny_all_devices(c->cgroup);
Dylan Reid837c74a2016-01-22 17:25:21 -0800966
Keshav Santhanam268fa032016-07-14 09:59:24 -0700967 for (i = 0; i < config->num_devices; i++) {
968 const struct container_device *dev = &config->devices[i];
969 int minor = dev->minor;
Dylan Reid837c74a2016-01-22 17:25:21 -0800970
Keshav Santhanam268fa032016-07-14 09:59:24 -0700971 if (dev->copy_minor) {
972 struct stat st_buff;
973 if (stat(dev->path, &st_buff) < 0)
974 continue;
975 /* Use the minor macro to extract the device number. */
976 minor = minor(st_buff.st_rdev);
977 }
978 if (minor >= 0) {
979 rc = container_create_device(c, dev, minor);
980 if (rc)
981 goto error_rmdir;
982 }
983
984 rc = c->cgroup->ops->add_device(c->cgroup, dev->major,
985 minor, dev->read_allowed,
986 dev->write_allowed,
987 dev->modify_allowed, dev->type);
Luis Hector Chavez479b95f2016-06-06 08:01:05 -0700988 if (rc)
Dylan Reid355d5e42016-04-29 16:53:31 -0700989 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -0800990 }
Dylan Reid837c74a2016-01-22 17:25:21 -0800991 }
992
Dylan Reidd7229582016-04-27 17:08:40 -0700993 /* Potentailly run setfiles on mounts configured outside of the jail */
Dylan Reide040c6b2016-05-02 18:49:02 -0700994 for (i = 0; i < config->num_mounts; i++) {
995 const struct container_mount *mnt = &config->mounts[i];
Dylan Reidd7229582016-04-27 17:08:40 -0700996 char *dest;
997
998 if (mnt->mount_in_ns)
999 continue;
Junichi Uekawa5d272772016-07-21 16:07:19 +09001000 if (mnt->flags & MS_RDONLY)
1001 continue;
Dylan Reidd7229582016-04-27 17:08:40 -07001002 if (asprintf(&dest, "%s%s", c->runfsroot, mnt->destination) < 0)
1003 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -07001004 rc = run_setfiles_command(c, config, dest);
Dylan Reidd7229582016-04-27 17:08:40 -07001005 free(dest);
1006 if (rc)
1007 goto error_rmdir;
1008 }
1009
Chinyue Chenfac909e2016-06-24 14:17:42 +08001010 /* Setup CPU cgroup params. */
1011 if (config->cpu_cgparams.shares) {
1012 rc = c->cgroup->ops->set_cpu_shares(
1013 c->cgroup, config->cpu_cgparams.shares);
1014 if (rc)
1015 goto error_rmdir;
1016 }
1017 if (config->cpu_cgparams.period) {
1018 rc = c->cgroup->ops->set_cpu_quota(
1019 c->cgroup, config->cpu_cgparams.quota);
1020 if (rc)
1021 goto error_rmdir;
1022 rc = c->cgroup->ops->set_cpu_period(
1023 c->cgroup, config->cpu_cgparams.period);
1024 if (rc)
1025 goto error_rmdir;
1026 }
1027 if (config->cpu_cgparams.rt_period) {
1028 rc = c->cgroup->ops->set_cpu_rt_runtime(
1029 c->cgroup, config->cpu_cgparams.rt_runtime);
1030 if (rc)
1031 goto error_rmdir;
1032 rc = c->cgroup->ops->set_cpu_rt_period(
1033 c->cgroup, config->cpu_cgparams.rt_period);
1034 if (rc)
1035 goto error_rmdir;
1036 }
1037
Dylan Reid837c74a2016-01-22 17:25:21 -08001038 /* Setup and start the container with libminijail. */
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001039 if (config->pid_file_path) {
1040 c->pid_file_path = strdup(config->pid_file_path);
1041 if (!c->pid_file_path) {
1042 rc = -ENOMEM;
1043 goto error_rmdir;
1044 }
1045 } else if (c->runfs) {
1046 if (asprintf(&c->pid_file_path, "%s/container.pid", c->runfs) < 0) {
1047 rc = -ENOMEM;
1048 goto error_rmdir;
1049 }
1050 }
1051
1052 if (c->pid_file_path)
1053 minijail_write_pid_file(c->jail, c->pid_file_path);
Dylan Reid837c74a2016-01-22 17:25:21 -08001054 minijail_reset_signal_mask(c->jail);
1055
1056 /* Setup container namespaces. */
1057 minijail_namespace_ipc(c->jail);
1058 minijail_namespace_vfs(c->jail);
Keshav Santhanam1b6bf672016-08-10 18:35:12 -07001059 if (!config->share_host_netns)
1060 minijail_namespace_net(c->jail);
Dylan Reid837c74a2016-01-22 17:25:21 -08001061 minijail_namespace_pids(c->jail);
Dylan Reid837c74a2016-01-22 17:25:21 -08001062 minijail_namespace_user(c->jail);
Dylan Reidc6ca1042016-07-11 15:03:27 -07001063 minijail_namespace_cgroups(c->jail);
Dylan Reide040c6b2016-05-02 18:49:02 -07001064 rc = minijail_uidmap(c->jail, config->uid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -08001065 if (rc)
1066 goto error_rmdir;
Dylan Reide040c6b2016-05-02 18:49:02 -07001067 rc = minijail_gidmap(c->jail, config->gid_map);
Dylan Reid837c74a2016-01-22 17:25:21 -08001068 if (rc)
1069 goto error_rmdir;
Dylan Reid837c74a2016-01-22 17:25:21 -08001070
Keshav Santhanam36485ff2016-08-02 16:21:02 -07001071 /* Set the UID/GID inside the container if not 0. */
1072 uid_userns = get_userns_id(config->uid_map, config->uid);
1073 if (uid_userns < 0)
1074 goto error_rmdir;
1075 else if (uid_userns > 0)
1076 minijail_change_uid(c->jail, (uid_t) uid_userns);
1077 gid_userns = get_userns_id(config->gid_map, config->gid);
1078 if (gid_userns < 0)
1079 goto error_rmdir;
1080 else if (gid_userns > 0)
1081 minijail_change_gid(c->jail, (gid_t) gid_userns);
1082
Dylan Reid837c74a2016-01-22 17:25:21 -08001083 rc = minijail_enter_pivot_root(c->jail, c->runfsroot);
1084 if (rc)
1085 goto error_rmdir;
1086
1087 /* Add the cgroups configured above. */
1088 rc = minijail_add_to_cgroup(c->jail, cgroup_cpu_tasks_path(c->cgroup));
1089 if (rc)
1090 goto error_rmdir;
1091 rc = minijail_add_to_cgroup(c->jail,
1092 cgroup_cpuacct_tasks_path(c->cgroup));
1093 if (rc)
1094 goto error_rmdir;
1095 rc = minijail_add_to_cgroup(c->jail,
Dmitry Torokhov7a022712016-09-18 11:26:10 -07001096 cgroup_cpuset_tasks_path(c->cgroup));
1097 if (rc)
1098 goto error_rmdir;
1099 rc = minijail_add_to_cgroup(c->jail,
Dylan Reid837c74a2016-01-22 17:25:21 -08001100 cgroup_devices_tasks_path(c->cgroup));
1101 if (rc)
1102 goto error_rmdir;
1103 rc = minijail_add_to_cgroup(c->jail,
1104 cgroup_freezer_tasks_path(c->cgroup));
1105 if (rc)
1106 goto error_rmdir;
1107
Dylan Reide040c6b2016-05-02 18:49:02 -07001108 if (config->alt_syscall_table)
1109 minijail_use_alt_syscall(c->jail, config->alt_syscall_table);
Dylan Reid837c74a2016-01-22 17:25:21 -08001110
1111 minijail_run_as_init(c->jail);
1112
Dylan Reid3da683b2016-04-05 03:35:35 -07001113 /* TODO(dgreid) - remove this once shared mounts are cleaned up. */
1114 minijail_skip_remount_private(c->jail);
1115
Dylan Reidc4335842016-11-11 10:24:52 -08001116 if (!config->keep_fds_open)
1117 minijail_close_open_fds(c->jail);
Luis Hector Chaveze18e7d42016-10-12 07:35:32 -07001118
Dylan Reid837c74a2016-01-22 17:25:21 -08001119 rc = minijail_run_pid_pipes_no_preload(c->jail,
Dylan Reide040c6b2016-05-02 18:49:02 -07001120 config->program_argv[0],
1121 config->program_argv,
Dylan Reid837c74a2016-01-22 17:25:21 -08001122 &c->init_pid, NULL, NULL,
1123 NULL);
1124 if (rc)
1125 goto error_rmdir;
1126 return 0;
1127
1128error_rmdir:
Luis Hector Chavez945af482016-06-03 08:39:34 -07001129 if (!rc)
1130 rc = -errno;
1131 container_teardown(c);
Dylan Reid837c74a2016-01-22 17:25:21 -08001132 return rc;
1133}
1134
1135const char *container_root(struct container *c)
1136{
1137 return c->runfs;
1138}
1139
1140int container_pid(struct container *c)
1141{
1142 return c->init_pid;
1143}
1144
1145static int container_teardown(struct container *c)
1146{
Dylan Reid837c74a2016-01-22 17:25:21 -08001147 int ret = 0;
1148
Dylan Reide040c6b2016-05-02 18:49:02 -07001149 unmount_external_mounts(c);
Keshav Santhanam0e4c3282016-07-14 10:25:16 -07001150 if (c->runfsroot && c->runfs) {
Luis Hector Chavez945af482016-06-03 08:39:34 -07001151 if (umount(c->runfsroot))
1152 ret = -errno;
1153 if (rmdir(c->runfsroot))
1154 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001155 FREE_AND_NULL(c->runfsroot);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001156 }
1157 if (c->pid_file_path) {
1158 if (unlink(c->pid_file_path))
1159 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001160 FREE_AND_NULL(c->pid_file_path);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001161 }
1162 if (c->runfs) {
1163 if (rmdir(c->runfs))
1164 ret = -errno;
Luis Hector Chavez479b95f2016-06-06 08:01:05 -07001165 FREE_AND_NULL(c->runfs);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001166 }
Dylan Reid837c74a2016-01-22 17:25:21 -08001167 return ret;
1168}
1169
1170int container_wait(struct container *c)
1171{
Dylan Reidcf745c52016-04-22 10:18:03 -07001172 int rc;
1173
1174 do {
1175 rc = minijail_wait(c->jail);
Luis Hector Chavez4641e852016-06-02 15:40:19 -07001176 } while (rc == -EINTR);
Dylan Reidcf745c52016-04-22 10:18:03 -07001177
Luis Hector Chavez945af482016-06-03 08:39:34 -07001178 // If the process had already been reaped, still perform teardown.
1179 if (rc == -ECHILD || rc >= 0) {
Dylan Reidcf745c52016-04-22 10:18:03 -07001180 rc = container_teardown(c);
Luis Hector Chavez945af482016-06-03 08:39:34 -07001181 }
Dylan Reidcf745c52016-04-22 10:18:03 -07001182 return rc;
Dylan Reid837c74a2016-01-22 17:25:21 -08001183}
1184
1185int container_kill(struct container *c)
1186{
Luis Hector Chavez945af482016-06-03 08:39:34 -07001187 if (kill(c->init_pid, SIGKILL) && errno != ESRCH)
Dylan Reid837c74a2016-01-22 17:25:21 -08001188 return -errno;
1189 return container_wait(c);
1190}