blob: 8d3240e7352fa8ad6cb991d0559019fda87e704f [file] [log] [blame]
Mike Frysinger5ef22ca2018-01-20 13:42:10 -05001/* Copyright 2018 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#include <dlfcn.h>
7#include <errno.h>
8#include <getopt.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/capability.h>
13#include <sys/types.h>
14#include <unistd.h>
15
16#include "libminijail.h"
17#include "libsyscalls.h"
18
19#include "elfparse.h"
20#include "minijail0_cli.h"
21#include "system.h"
22#include "util.h"
23
24#define IDMAP_LEN 32U
25#define DEFAULT_TMP_SIZE (64 * 1024 * 1024)
26
27static void set_user(struct minijail *j, const char *arg, uid_t *out_uid,
28 gid_t *out_gid)
29{
30 char *end = NULL;
31 int uid = strtod(arg, &end);
32 if (!*end && *arg) {
33 *out_uid = uid;
34 minijail_change_uid(j, uid);
35 return;
36 }
37
38 if (lookup_user(arg, out_uid, out_gid)) {
39 fprintf(stderr, "Bad user: '%s'\n", arg);
40 exit(1);
41 }
42
43 if (minijail_change_user(j, arg)) {
44 fprintf(stderr, "Bad user: '%s'\n", arg);
45 exit(1);
46 }
47}
48
49static void set_group(struct minijail *j, const char *arg, gid_t *out_gid)
50{
51 char *end = NULL;
52 int gid = strtod(arg, &end);
53 if (!*end && *arg) {
54 *out_gid = gid;
55 minijail_change_gid(j, gid);
56 return;
57 }
58
59 if (lookup_group(arg, out_gid)) {
60 fprintf(stderr, "Bad group: '%s'\n", arg);
61 exit(1);
62 }
63
64 if (minijail_change_group(j, arg)) {
65 fprintf(stderr, "Bad group: '%s'\n", arg);
66 exit(1);
67 }
68}
69
70static void skip_securebits(struct minijail *j, const char *arg)
71{
72 uint64_t securebits_skip_mask;
73 char *end = NULL;
74 securebits_skip_mask = strtoull(arg, &end, 16);
75 if (*end) {
76 fprintf(stderr, "Invalid securebit mask: '%s'\n", arg);
77 exit(1);
78 }
79 minijail_skip_setting_securebits(j, securebits_skip_mask);
80}
81
82static void use_caps(struct minijail *j, const char *arg)
83{
84 uint64_t caps;
85 char *end = NULL;
86 caps = strtoull(arg, &end, 16);
87 if (*end) {
88 fprintf(stderr, "Invalid cap set: '%s'\n", arg);
89 exit(1);
90 }
91 minijail_use_caps(j, caps);
92}
93
94static void add_binding(struct minijail *j, char *arg)
95{
96 char *src = tokenize(&arg, ",");
97 char *dest = tokenize(&arg, ",");
98 char *flags = tokenize(&arg, ",");
99 if (!src || src[0] == '\0' || arg != NULL) {
100 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
101 exit(1);
102 }
103 if (dest == NULL || dest[0] == '\0')
104 dest = src;
105 if (flags == NULL || flags[0] == '\0')
106 flags = "0";
107 if (minijail_bind(j, src, dest, atoi(flags))) {
108 fprintf(stderr, "minijail_bind failed.\n");
109 exit(1);
110 }
111}
112
113static void add_rlimit(struct minijail *j, char *arg)
114{
115 char *type = tokenize(&arg, ",");
116 char *cur = tokenize(&arg, ",");
117 char *max = tokenize(&arg, ",");
Luis Hector Chavez7058a2d2018-01-29 08:41:34 -0800118 char *end;
Mike Frysinger5ef22ca2018-01-20 13:42:10 -0500119 if (!type || type[0] == '\0' || !cur || cur[0] == '\0' ||
120 !max || max[0] == '\0' || arg != NULL) {
121 fprintf(stderr, "Bad rlimit '%s'.\n", arg);
122 exit(1);
123 }
Luis Hector Chavez7058a2d2018-01-29 08:41:34 -0800124 rlim_t cur_rlim;
125 rlim_t max_rlim;
126 if (!strcmp(cur, "unlimited")) {
127 cur_rlim = RLIM_INFINITY;
128 } else {
129 end = NULL;
130 cur_rlim = strtoul(cur, &end, 10);
131 if (*end) {
132 fprintf(stderr, "Bad soft limit: '%s'.\n", cur);
133 exit(1);
134 }
135 }
136 if (!strcmp(max, "unlimited")) {
137 max_rlim = RLIM_INFINITY;
138 } else {
139 end = NULL;
140 max_rlim = strtoul(max, &end, 10);
141 if (*end) {
142 fprintf(stderr, "Bad hard limit: '%s'.\n", max);
143 exit(1);
144 }
145 }
146 if (minijail_rlimit(j, atoi(type), cur_rlim, max_rlim)) {
Mike Frysinger5ef22ca2018-01-20 13:42:10 -0500147 fprintf(stderr, "minijail_rlimit '%s,%s,%s' failed.\n", type,
148 cur, max);
149 exit(1);
150 }
151}
152
153static void add_mount(struct minijail *j, char *arg)
154{
155 char *src = tokenize(&arg, ",");
156 char *dest = tokenize(&arg, ",");
157 char *type = tokenize(&arg, ",");
158 char *flags = tokenize(&arg, ",");
159 char *data = tokenize(&arg, ",");
160 if (!src || src[0] == '\0' || !dest || dest[0] == '\0' ||
Mike Frysinger4f3e09f2018-01-24 18:01:16 -0500161 !type || type[0] == '\0') {
Mike Frysinger5ef22ca2018-01-20 13:42:10 -0500162 fprintf(stderr, "Bad mount: %s %s %s\n", src, dest, type);
163 exit(1);
164 }
Mike Frysinger4f3e09f2018-01-24 18:01:16 -0500165
166 /*
167 * Fun edge case: the data option itself is comma delimited. If there
168 * were no more options, then arg would be set to NULL. But if we had
169 * more pending, it'll be pointing to the next token. Back up and undo
170 * the null byte so it'll be merged back.
171 * An example:
172 * none,/tmp,tmpfs,0xe,mode=0755,uid=10,gid=10
173 * The tokenize calls above will turn this memory into:
174 * none\0/tmp\0tmpfs\00xe\0mode=0755\0uid=10,gid=10
175 * With data pointing at mode=0755 and arg pointing at uid=10,gid=10.
176 */
177 if (arg != NULL)
178 arg[-1] = ',';
179
Mike Frysinger5ef22ca2018-01-20 13:42:10 -0500180 if (minijail_mount_with_data(j, src, dest, type,
181 flags ? strtoul(flags, NULL, 16) : 0,
182 data)) {
183 fprintf(stderr, "minijail_mount failed.\n");
184 exit(1);
185 }
186}
187
188static char *build_idmap(id_t id, id_t lowerid)
189{
190 int ret;
191 char *idmap = malloc(IDMAP_LEN);
192 ret = snprintf(idmap, IDMAP_LEN, "%d %d 1", id, lowerid);
193 if (ret < 0 || (size_t)ret >= IDMAP_LEN) {
194 free(idmap);
195 fprintf(stderr, "Could not build id map.\n");
196 exit(1);
197 }
198 return idmap;
199}
200
201static int has_cap_setgid(void)
202{
203 cap_t caps;
204 cap_flag_value_t cap_value;
205
206 if (!CAP_IS_SUPPORTED(CAP_SETGID))
207 return 0;
208
209 caps = cap_get_proc();
210 if (!caps) {
211 fprintf(stderr, "Could not get process' capabilities: %m\n");
212 exit(1);
213 }
214
215 if (cap_get_flag(caps, CAP_SETGID, CAP_EFFECTIVE, &cap_value)) {
216 fprintf(stderr, "Could not get the value of CAP_SETGID: %m\n");
217 exit(1);
218 }
219
220 if (cap_free(caps)) {
221 fprintf(stderr, "Could not free capabilities: %m\n");
222 exit(1);
223 }
224
225 return cap_value == CAP_SET;
226}
227
228static void set_ugid_mapping(struct minijail *j, int set_uidmap, uid_t uid,
229 char *uidmap, int set_gidmap, gid_t gid,
230 char *gidmap)
231{
232 if (set_uidmap) {
233 minijail_namespace_user(j);
234 minijail_namespace_pids(j);
235
236 if (!uidmap) {
237 /*
238 * If no map is passed, map the current uid to the
239 * chosen uid in the target namespace (or root, if none
240 * was chosen).
241 */
242 uidmap = build_idmap(uid, getuid());
243 }
244 if (0 != minijail_uidmap(j, uidmap)) {
245 fprintf(stderr, "Could not set uid map.\n");
246 exit(1);
247 }
248 free(uidmap);
249 }
250 if (set_gidmap) {
251 minijail_namespace_user(j);
252 minijail_namespace_pids(j);
253
254 if (!gidmap) {
255 /*
256 * If no map is passed, map the current gid to the
257 * chosen gid in the target namespace.
258 */
259 gidmap = build_idmap(gid, getgid());
260 }
261 if (!has_cap_setgid()) {
262 /*
263 * This means that we are not running as root,
264 * so we also have to disable setgroups(2) to
265 * be able to set the gid map.
266 * See
267 * http://man7.org/linux/man-pages/man7/user_namespaces.7.html
268 */
269 minijail_namespace_user_disable_setgroups(j);
270 }
271 if (0 != minijail_gidmap(j, gidmap)) {
272 fprintf(stderr, "Could not set gid map.\n");
273 exit(1);
274 }
275 free(gidmap);
276 }
277}
278
279static void use_chroot(struct minijail *j, const char *path, int *chroot,
280 int pivot_root)
281{
282 if (pivot_root) {
283 fprintf(stderr, "Could not set chroot because "
284 "'-P' was specified.\n");
285 exit(1);
286 }
287 if (minijail_enter_chroot(j, path)) {
288 fprintf(stderr, "Could not set chroot.\n");
289 exit(1);
290 }
291 *chroot = 1;
292}
293
294static void use_pivot_root(struct minijail *j, const char *path,
295 int *pivot_root, int chroot)
296{
297 if (chroot) {
298 fprintf(stderr, "Could not set pivot_root because "
299 "'-C' was specified.\n");
300 exit(1);
301 }
302 if (minijail_enter_pivot_root(j, path)) {
303 fprintf(stderr, "Could not set pivot_root.\n");
304 exit(1);
305 }
306 minijail_namespace_vfs(j);
307 *pivot_root = 1;
308}
309
310static void use_profile(struct minijail *j, const char *profile,
311 int *pivot_root, int chroot, size_t *tmp_size)
312{
Mike Frysinger4d2a81e2018-01-22 16:43:33 -0500313 /* Note: New profiles should be added in minijail0_cli_unittest.cc. */
314
Mike Frysinger5ef22ca2018-01-20 13:42:10 -0500315 if (!strcmp(profile, "minimalistic-mountns")) {
316 minijail_namespace_vfs(j);
317 if (minijail_bind(j, "/", "/", 0)) {
318 fprintf(stderr, "minijail_bind failed.\n");
319 exit(1);
320 }
321 if (minijail_bind(j, "/proc", "/proc", 0)) {
322 fprintf(stderr, "minijail_bind failed.\n");
323 exit(1);
324 }
325 minijail_mount_dev(j);
326 if (!*tmp_size) {
327 /* Avoid clobbering |tmp_size| if it was already set. */
328 *tmp_size = DEFAULT_TMP_SIZE;
329 }
330 minijail_remount_proc_readonly(j);
331 use_pivot_root(j, "/var/empty", pivot_root, chroot);
332 } else {
333 fprintf(stderr, "Unrecognized profile name '%s'\n", profile);
334 exit(1);
335 }
336}
337
338static void usage(const char *progn)
339{
340 size_t i;
341 /* clang-format off */
342 printf("Usage: %s [-dGhHiIKlLnNprRstUvyYz]\n"
343 " [-a <table>]\n"
344 " [-b <src>[,<dest>[,<writeable>]]] [-k <src>,<dest>,<type>[,<flags>[,<data>]]]\n"
345 " [-c <caps>] [-C <dir>] [-P <dir>] [-e[file]] [-f <file>] [-g <group>]\n"
346 " [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*] [--profile <name>]\n"
347 " [-R <type,cur,max>] [-S <file>] [-t[size]] [-T <type>] [-u <user>] [-V <file>]\n"
348 " <program> [args...]\n"
349 " -a <table>: Use alternate syscall table <table>.\n"
350 " -b <...>: Bind <src> to <dest> in chroot.\n"
351 " Multiple instances allowed.\n"
352 " -B <mask>: Skip setting securebits in <mask> when restricting capabilities (-c).\n"
353 " By default, SECURE_NOROOT, SECURE_NO_SETUID_FIXUP, and \n"
354 " SECURE_KEEP_CAPS (together with their respective locks) are set.\n"
355 " -k <...>: Mount <src> at <dest> in chroot.\n"
356 " <flags> and <data> can be specified as in mount(2).\n"
357 " Multiple instances allowed.\n"
358 " -c <caps>: Restrict caps to <caps>.\n"
359 " -C <dir>: chroot(2) to <dir>.\n"
360 " Not compatible with -P.\n"
361 " -P <dir>: pivot_root(2) to <dir> (implies -v).\n"
362 " Not compatible with -C.\n"
363 " --mount-dev, Create a new /dev with a minimal set of device nodes (implies -v).\n"
364 " -d: See the minijail0(1) man page for the exact set.\n"
365 " -e[file]: Enter new network namespace, or existing one if |file| is provided.\n"
366 " -f <file>: Write the pid of the jailed process to <file>.\n"
367 " -g <group>: Change gid to <group>.\n"
368 " -G: Inherit supplementary groups from uid.\n"
369 " Not compatible with -y.\n"
370 " -y: Keep uid's supplementary groups.\n"
371 " Not compatible with -G.\n"
372 " -h: Help (this message).\n"
373 " -H: Seccomp filter help message.\n"
374 " -i: Exit immediately after fork (do not act as init).\n"
375 " -I: Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
376 " -K: Don't mark all existing mounts as MS_PRIVATE.\n"
377 " -l: Enter new IPC namespace.\n"
378 " -L: Report blocked syscalls to syslog when using seccomp filter.\n"
379 " Forces the following syscalls to be allowed:\n"
380 " ", progn);
381 /* clang-format on */
382 for (i = 0; i < log_syscalls_len; i++)
383 printf("%s ", log_syscalls[i]);
384
385 /* clang-format off */
386 printf("\n"
387 " -m[map]: Set the uid map of a user namespace (implies -pU).\n"
388 " Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
389 " With no mapping, map the current uid to root inside the user namespace.\n"
390 " Not compatible with -b without the 'writable' option.\n"
391 " -M[map]: Set the gid map of a user namespace (implies -pU).\n"
392 " Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
393 " With no mapping, map the current gid to root inside the user namespace.\n"
394 " Not compatible with -b without the 'writable' option.\n"
395 " -n: Set no_new_privs.\n"
396 " -N: Enter a new cgroup namespace.\n"
397 " -p: Enter new pid namespace (implies -vr).\n"
398 " -r: Remount /proc read-only (implies -v).\n"
399 " -R: Set rlimits, can be specified multiple times.\n"
400 " -s: Use seccomp mode 1 (not the same as -S).\n"
401 " -S <file>: Set seccomp filter using <file>.\n"
402 " E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
403 " Requires -n when not running as root.\n"
404 " -t[size]: Mount tmpfs at /tmp (implies -v).\n"
405 " Optional argument specifies size (default \"64M\").\n"
406 " -T <type>: Assume <program> is a <type> ELF binary; <type> can be 'static' or 'dynamic'.\n"
407 " This will avoid accessing <program> binary before execve(2).\n"
408 " Type 'static' will avoid preload hooking.\n"
409 " -u <user>: Change uid to <user>.\n"
410 " -U: Enter new user namespace (implies -p).\n"
411 " -v: Enter new mount namespace.\n"
412 " -V <file>: Enter specified mount namespace.\n"
413 " -w: Create and join a new anonymous session keyring.\n"
414 " -Y: Synchronize seccomp filters across thread group.\n"
415 " -z: Don't forward signals to jailed process.\n"
416 " --ambient: Raise ambient capabilities. Requires -c.\n"
417 " --uts[=name]: Enter a new UTS namespace (and set hostname).\n"
418 " --logging=<s>:Use <s> as the logging system.\n"
419 " <s> must be 'syslog' (default) or 'stderr'.\n"
420 " --profile <p>,Configure minijail0 to run with the <p> sandboxing profile,\n"
421 " which is a convenient way to express multiple flags\n"
422 " that are typically used together.\n"
423 " See the minijail0(1) man page for the full list.\n");
424 /* clang-format on */
425}
426
427static void seccomp_filter_usage(const char *progn)
428{
429 const struct syscall_entry *entry = syscall_table;
430 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
431 "System call names supported:\n",
432 progn);
433 for (; entry->name && entry->nr >= 0; ++entry)
434 printf(" %s [%d]\n", entry->name, entry->nr);
435 printf("\nSee minijail0(5) for example policies.\n");
436}
437
438int parse_args(struct minijail *j, int argc, char * const argv[],
439 int *exit_immediately, ElfType *elftype)
440{
441 int opt;
442 int use_seccomp_filter = 0;
443 int forward = 1;
444 int binding = 0;
445 int chroot = 0, pivot_root = 0;
446 int mount_ns = 0, skip_remount = 0;
447 int inherit_suppl_gids = 0, keep_suppl_gids = 0;
448 int caps = 0, ambient_caps = 0;
449 int seccomp = -1;
450 const size_t path_max = 4096;
451 uid_t uid = 0;
452 gid_t gid = 0;
453 char *uidmap = NULL, *gidmap = NULL;
454 int set_uidmap = 0, set_gidmap = 0;
455 size_t tmp_size = 0;
456 const char *filter_path = NULL;
457 int log_to_stderr = 0;
458
459 const char *optstring =
460 "+u:g:sS:c:C:P:b:B:V:f:m::M::k:a:e::R:T:vrGhHinNplLt::IUKwyYzd";
461 /* clang-format off */
462 const struct option long_options[] = {
463 {"help", no_argument, 0, 'h'},
464 {"mount-dev", no_argument, 0, 'd'},
465 {"ambient", no_argument, 0, 128},
466 {"uts", optional_argument, 0, 129},
467 {"logging", required_argument, 0, 130},
468 {"profile", required_argument, 0, 131},
469 {0, 0, 0, 0},
470 };
471 /* clang-format on */
472
473 while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) !=
474 -1) {
475 switch (opt) {
476 case 'u':
477 set_user(j, optarg, &uid, &gid);
478 break;
479 case 'g':
480 set_group(j, optarg, &gid);
481 break;
482 case 'n':
483 minijail_no_new_privs(j);
484 break;
485 case 's':
486 if (seccomp != -1 && seccomp != 1) {
487 fprintf(stderr,
488 "Do not use -s & -S together.\n");
489 exit(1);
490 }
491 seccomp = 1;
492 minijail_use_seccomp(j);
493 break;
494 case 'S':
495 if (seccomp != -1 && seccomp != 2) {
496 fprintf(stderr,
497 "Do not use -s & -S together.\n");
498 exit(1);
499 }
500 seccomp = 2;
501 minijail_use_seccomp_filter(j);
502 if (strlen(optarg) >= path_max) {
503 fprintf(stderr, "Filter path is too long.\n");
504 exit(1);
505 }
506 filter_path = strndup(optarg, path_max);
507 if (!filter_path) {
508 fprintf(stderr,
509 "Could not strndup(3) filter path.\n");
510 exit(1);
511 }
512 use_seccomp_filter = 1;
513 break;
514 case 'l':
515 minijail_namespace_ipc(j);
516 break;
517 case 'L':
518 minijail_log_seccomp_filter_failures(j);
519 break;
520 case 'b':
521 add_binding(j, optarg);
522 binding = 1;
523 break;
524 case 'B':
525 skip_securebits(j, optarg);
526 break;
527 case 'c':
528 caps = 1;
529 use_caps(j, optarg);
530 break;
531 case 'C':
532 use_chroot(j, optarg, &chroot, pivot_root);
533 break;
534 case 'k':
535 add_mount(j, optarg);
536 break;
537 case 'K':
538 minijail_skip_remount_private(j);
539 skip_remount = 1;
540 break;
541 case 'P':
542 use_pivot_root(j, optarg, &pivot_root, chroot);
543 break;
544 case 'f':
545 if (0 != minijail_write_pid_file(j, optarg)) {
546 fprintf(stderr,
547 "Could not prepare pid file path.\n");
548 exit(1);
549 }
550 break;
551 case 't':
552 minijail_namespace_vfs(j);
553 if (!tmp_size) {
554 /*
555 * Avoid clobbering |tmp_size| if it was already
556 * set.
557 */
558 tmp_size = DEFAULT_TMP_SIZE;
559 }
560 if (optarg != NULL &&
561 0 != parse_size(&tmp_size, optarg)) {
562 fprintf(stderr, "Invalid /tmp tmpfs size.\n");
563 exit(1);
564 }
565 break;
566 case 'v':
567 minijail_namespace_vfs(j);
568 mount_ns = 1;
569 break;
570 case 'V':
571 minijail_namespace_enter_vfs(j, optarg);
572 break;
573 case 'r':
574 minijail_remount_proc_readonly(j);
575 break;
576 case 'G':
577 if (keep_suppl_gids) {
578 fprintf(stderr,
579 "-y and -G are not compatible.\n");
580 exit(1);
581 }
582 minijail_inherit_usergroups(j);
583 inherit_suppl_gids = 1;
584 break;
585 case 'y':
586 if (inherit_suppl_gids) {
587 fprintf(stderr,
588 "-y and -G are not compatible.\n");
589 exit(1);
590 }
591 minijail_keep_supplementary_gids(j);
592 keep_suppl_gids = 1;
593 break;
594 case 'N':
595 minijail_namespace_cgroups(j);
596 break;
597 case 'p':
598 minijail_namespace_pids(j);
599 break;
600 case 'e':
601 if (optarg)
602 minijail_namespace_enter_net(j, optarg);
603 else
604 minijail_namespace_net(j);
605 break;
606 case 'i':
607 *exit_immediately = 1;
608 break;
609 case 'H':
610 seccomp_filter_usage(argv[0]);
611 exit(0);
612 case 'I':
613 minijail_namespace_pids(j);
614 minijail_run_as_init(j);
615 break;
616 case 'U':
617 minijail_namespace_user(j);
618 minijail_namespace_pids(j);
619 break;
620 case 'm':
621 set_uidmap = 1;
622 if (uidmap) {
623 free(uidmap);
624 uidmap = NULL;
625 }
626 if (optarg)
627 uidmap = strdup(optarg);
628 break;
629 case 'M':
630 set_gidmap = 1;
631 if (gidmap) {
632 free(gidmap);
633 gidmap = NULL;
634 }
635 if (optarg)
636 gidmap = strdup(optarg);
637 break;
638 case 'a':
639 if (0 != minijail_use_alt_syscall(j, optarg)) {
640 fprintf(stderr,
641 "Could not set alt-syscall table.\n");
642 exit(1);
643 }
644 break;
645 case 'R':
646 add_rlimit(j, optarg);
647 break;
648 case 'T':
649 if (!strcmp(optarg, "static"))
650 *elftype = ELFSTATIC;
651 else if (!strcmp(optarg, "dynamic"))
652 *elftype = ELFDYNAMIC;
653 else {
654 fprintf(stderr, "ELF type must be 'static' or "
655 "'dynamic'.\n");
656 exit(1);
657 }
658 break;
659 case 'w':
660 minijail_new_session_keyring(j);
661 break;
662 case 'Y':
663 minijail_set_seccomp_filter_tsync(j);
664 break;
665 case 'z':
666 forward = 0;
667 break;
668 case 'd':
669 minijail_namespace_vfs(j);
670 minijail_mount_dev(j);
671 break;
672 /* Long options. */
673 case 128: /* Ambient caps. */
674 ambient_caps = 1;
675 minijail_set_ambient_caps(j);
676 break;
677 case 129: /* UTS/hostname namespace. */
678 minijail_namespace_uts(j);
679 if (optarg)
680 minijail_namespace_set_hostname(j, optarg);
681 break;
682 case 130: /* Logging. */
683 if (!strcmp(optarg, "syslog"))
684 log_to_stderr = 0;
685 else if (!strcmp(optarg, "stderr")) {
686 log_to_stderr = 1;
687 } else {
688 fprintf(stderr, "--logger must be 'syslog' or "
689 "'stderr'.\n");
690 exit(1);
691 }
692 break;
693 case 131: /* Profile */
694 use_profile(j, optarg, &pivot_root, chroot, &tmp_size);
695 break;
696 default:
697 usage(argv[0]);
698 exit(opt == 'h' ? 0 : 1);
699 }
700 }
701
702 if (log_to_stderr) {
703 init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
704 /*
705 * When logging to stderr, ensure the FD survives the jailing.
706 */
707 if (0 !=
708 minijail_preserve_fd(j, STDERR_FILENO, STDERR_FILENO)) {
709 fprintf(stderr, "Could not preserve stderr.\n");
710 exit(1);
711 }
712 }
713
714 /* Set up uid/gid mapping. */
715 if (set_uidmap || set_gidmap) {
716 set_ugid_mapping(j, set_uidmap, uid, uidmap, set_gidmap, gid,
717 gidmap);
718 }
719
720 /* Can only set ambient caps when using regular caps. */
721 if (ambient_caps && !caps) {
722 fprintf(stderr, "Can't set ambient capabilities (--ambient) "
723 "without actually using capabilities (-c).\n");
724 exit(1);
725 }
726
727 /* Set up signal handlers in minijail unless asked not to. */
728 if (forward)
729 minijail_forward_signals(j);
730
731 /*
732 * Only allow bind mounts when entering a chroot, using pivot_root, or
733 * a new mount namespace.
734 */
735 if (binding && !(chroot || pivot_root || mount_ns)) {
736 fprintf(stderr, "Bind mounts require a chroot, pivot_root, or "
737 " new mount namespace.\n");
738 exit(1);
739 }
740
741 /*
742 * Remounting / as MS_PRIVATE only happens when entering a new mount
743 * namespace, so skipping it only applies in that case.
744 */
745 if (skip_remount && !mount_ns) {
746 fprintf(stderr, "Can't skip marking mounts as MS_PRIVATE"
747 " without mount namespaces.\n");
748 exit(1);
749 }
750
751 /*
752 * We parse seccomp filters here to make sure we've collected all
753 * cmdline options.
754 */
755 if (use_seccomp_filter) {
756 minijail_parse_seccomp_filters(j, filter_path);
757 free((void *)filter_path);
758 }
759
760 /* Mount a tmpfs under /tmp and set its size. */
761 if (tmp_size)
762 minijail_mount_tmp_size(j, tmp_size);
763
764 /*
765 * There should be at least one additional unparsed argument: the
766 * executable name.
767 */
768 if (argc == optind) {
769 usage(argv[0]);
770 exit(1);
771 }
772
773 if (*elftype == ELFERROR) {
774 /*
775 * -T was not specified.
776 * Get the path to the program adjusted for changing root.
777 */
778 char *program_path =
779 minijail_get_original_path(j, argv[optind]);
780
781 /* Check that we can access the target program. */
782 if (access(program_path, X_OK)) {
783 fprintf(stderr,
784 "Target program '%s' is not accessible.\n",
785 argv[optind]);
786 exit(1);
787 }
788
789 /* Check if target is statically or dynamically linked. */
790 *elftype = get_elf_linkage(program_path);
791 free(program_path);
792 }
793
794 /*
795 * Setting capabilities need either a dynamically-linked binary, or the
796 * use of ambient capabilities for them to be able to survive an
797 * execve(2).
798 */
799 if (caps && *elftype == ELFSTATIC && !ambient_caps) {
800 fprintf(stderr, "Can't run statically-linked binaries with "
801 "capabilities (-c) without also setting "
802 "ambient capabilities. Try passing "
803 "--ambient.\n");
804 exit(1);
805 }
806
807 return optind;
808}