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