blob: d47aad565e50b3816489d66f5f745666cd78dceb [file] [log] [blame]
Elly Jonese58176c2012-01-23 11:46:17 -05001/* Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
Elly Jonescd7a9042011-07-22 13:56:51 -04002 * Use of this source code is governed by a BSD-style license that can be
Will Drewry32ac9f52011-08-18 21:36:27 -05003 * found in the LICENSE file.
4 */
Elly Jonescd7a9042011-07-22 13:56:51 -04005
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -08006#include <dlfcn.h>
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -04007#include <getopt.h>
Elly Jonescd7a9042011-07-22 13:56:51 -04008#include <stdio.h>
9#include <stdlib.h>
10#include <string.h>
11#include <unistd.h>
12
13#include "libminijail.h"
Will Drewry32ac9f52011-08-18 21:36:27 -050014#include "libsyscalls.h"
Elly Jonescd7a9042011-07-22 13:56:51 -040015
Lee Campbell1e4fc6a2014-06-06 17:40:02 -070016#include "elfparse.h"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070017#include "util.h"
18
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -040019#define IDMAP_LEN 32U
20
Elly Jonese1749eb2011-10-07 13:54:59 -040021static void set_user(struct minijail *j, const char *arg)
22{
23 char *end = NULL;
24 int uid = strtod(arg, &end);
25 if (!*end && *arg) {
26 minijail_change_uid(j, uid);
27 return;
28 }
Elly Jonescd7a9042011-07-22 13:56:51 -040029
Elly Jonese1749eb2011-10-07 13:54:59 -040030 if (minijail_change_user(j, arg)) {
31 fprintf(stderr, "Bad user: '%s'\n", arg);
32 exit(1);
33 }
Elly Jonescd7a9042011-07-22 13:56:51 -040034}
35
Elly Jonese1749eb2011-10-07 13:54:59 -040036static void set_group(struct minijail *j, const char *arg)
37{
38 char *end = NULL;
39 int gid = strtod(arg, &end);
40 if (!*end && *arg) {
41 minijail_change_gid(j, gid);
42 return;
43 }
Elly Jonescd7a9042011-07-22 13:56:51 -040044
Elly Jonese1749eb2011-10-07 13:54:59 -040045 if (minijail_change_group(j, arg)) {
46 fprintf(stderr, "Bad group: '%s'\n", arg);
47 exit(1);
48 }
Elly Jonescd7a9042011-07-22 13:56:51 -040049}
50
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -070051static void skip_securebits(struct minijail *j, const char *arg)
52{
53 uint64_t securebits_skip_mask;
54 char *end = NULL;
55 securebits_skip_mask = strtoull(arg, &end, 16);
56 if (*end) {
57 fprintf(stderr, "Invalid securebit mask: '%s'\n", arg);
58 exit(1);
59 }
60 minijail_skip_setting_securebits(j, securebits_skip_mask);
61}
62
Elly Jonese1749eb2011-10-07 13:54:59 -040063static void use_caps(struct minijail *j, const char *arg)
64{
65 uint64_t caps;
66 char *end = NULL;
67 caps = strtoull(arg, &end, 16);
68 if (*end) {
69 fprintf(stderr, "Invalid cap set: '%s'\n", arg);
70 exit(1);
71 }
72 minijail_use_caps(j, caps);
Elly Jonescd7a9042011-07-22 13:56:51 -040073}
74
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -070075static void add_binding(struct minijail *j, char *arg)
76{
Elly Jones51a5b6c2011-10-12 19:09:26 -040077 char *src = strtok(arg, ",");
Elly Jones5ba42b52011-12-07 13:31:43 -050078 char *dest = strtok(NULL, ",");
79 char *flags = strtok(NULL, ",");
Elly Jones51a5b6c2011-10-12 19:09:26 -040080 if (!src || !dest) {
81 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
82 exit(1);
83 }
84 if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -080085 fprintf(stderr, "minijail_bind failed.\n");
Elly Jones51a5b6c2011-10-12 19:09:26 -040086 exit(1);
87 }
88}
89
Dylan Reid0f72ef42017-06-06 15:42:49 -070090static void add_rlimit(struct minijail *j, char *arg)
91{
92 char *type = strtok(arg, ",");
93 char *cur = strtok(NULL, ",");
94 char *max = strtok(NULL, ",");
95 if (!type || !cur || !max) {
96 fprintf(stderr, "Bad rlimit '%s'.\n", arg);
97 exit(1);
98 }
99 if (minijail_rlimit(j, atoi(type), atoi(cur), atoi(max))) {
100 fprintf(stderr, "minijail_rlimit '%s,%s,%s' failed.\n",
101 type, cur, max);
102 exit(1);
103 }
104}
105
Dylan Reid648b2202015-10-23 00:50:00 -0700106static void add_mount(struct minijail *j, char *arg)
107{
108 char *src = strtok(arg, ",");
109 char *dest = strtok(NULL, ",");
110 char *type = strtok(NULL, ",");
111 char *flags = strtok(NULL, ",");
Dylan Reid81e23972016-05-18 14:06:35 -0700112 char *data = strtok(NULL, ",");
Dylan Reid648b2202015-10-23 00:50:00 -0700113 if (!src || !dest || !type) {
114 fprintf(stderr, "Bad mount: %s %s %s\n", src, dest, type);
115 exit(1);
116 }
Dylan Reid81e23972016-05-18 14:06:35 -0700117 if (minijail_mount_with_data(j, src, dest, type,
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400118 flags ? strtoul(flags, NULL, 16) : 0,
119 data)) {
Dylan Reid648b2202015-10-23 00:50:00 -0700120 fprintf(stderr, "minijail_mount failed.\n");
121 exit(1);
122 }
123}
124
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400125static char *build_idmap(id_t id, id_t lowerid)
126{
127 int ret;
128 char *idmap = malloc(IDMAP_LEN);
129 ret = snprintf(idmap, IDMAP_LEN, "%d %d 1", id, lowerid);
130 if (ret < 0 || (size_t)ret >= IDMAP_LEN) {
131 free(idmap);
132 fprintf(stderr, "Could not build id map.\n");
133 exit(1);
134 }
135 return idmap;
136}
137
Elly Jonese1749eb2011-10-07 13:54:59 -0400138static void usage(const char *progn)
139{
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700140 size_t i;
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700141 /* clang-format off */
Dylan Reid0f72ef42017-06-06 15:42:49 -0700142 printf("Usage: %s [-GhHiIKlLnNprRstUvyYz]\n"
Jorge Lucangeli Obesa32e8392016-09-01 16:52:40 -0400143 " [-a <table>]\n"
144 " [-b <src>,<dest>[,<writeable>]] [-k <src>,<dest>,<type>[,<flags>][,<data>]]\n"
145 " [-c <caps>] [-C <dir>] [-P <dir>] [-e[file]] [-f <file>] [-g <group>]\n"
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400146 " [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*]\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700147 " [-R <type,cur,max>] [-S <file>] [-t[size]] [-T <type>] [-u <user>] [-V <file>]\n"
Jorge Lucangeli Obes9dd256e2016-02-16 15:31:02 -0800148 " <program> [args...]\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400149 " -a <table>: Use alternate syscall table <table>.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400150 " -b <...>: Bind <src> to <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400151 " Multiple instances allowed.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400152 " -B <mask>: Skip setting securebits in <mask> when restricting capabilities (-c).\n"
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700153 " By default, SECURE_NOROOT, SECURE_NO_SETUID_FIXUP, and \n"
154 " SECURE_KEEP_CAPS (together with their respective locks) are set.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400155 " -k <...>: Mount <src> at <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400156 " <flags> and <data> can be specified as in mount(2).\n"
157 " Multiple instances allowed.\n"
158 " -c <caps>: Restrict caps to <caps>.\n"
159 " -C <dir>: chroot(2) to <dir>.\n"
160 " Not compatible with -P.\n"
161 " -P <dir>: pivot_root(2) to <dir> (implies -v).\n"
162 " Not compatible with -C.\n"
163 " -e[file]: Enter new network namespace, or existing one if |file| is provided.\n"
164 " -f <file>: Write the pid of the jailed process to <file>.\n"
165 " -g <group>: Change gid to <group>.\n"
166 " -G: Inherit supplementary groups from uid.\n"
167 " Not compatible with -y.\n"
168 " -y: Keep uid's supplementary groups.\n"
169 " Not compatible with -G.\n"
170 " -h: Help (this message).\n"
171 " -H: Seccomp filter help message.\n"
172 " -i: Exit immediately after fork (do not act as init).\n"
173 " -I: Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
174 " -K: Don't mark all existing mounts as MS_PRIVATE.\n"
175 " -l: Enter new IPC namespace.\n"
176 " -L: Report blocked syscalls to syslog when using seccomp filter.\n"
177 " Forces the following syscalls to be allowed:\n"
Kees Cook03b2af22014-12-18 17:11:13 -0800178 " ", progn);
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700179 /* clang-format on */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700180 for (i = 0; i < log_syscalls_len; i++)
181 printf("%s ", log_syscalls[i]);
182
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700183 /* clang-format off */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700184 printf("\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400185 " -m[map]: Set the uid map of a user namespace (implies -pU).\n"
186 " Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
187 " With no mapping, map the current uid to root inside the user namespace.\n"
188 " Not compatible with -b without the 'writable' option.\n"
189 " -M[map]: Set the gid map of a user namespace (implies -pU).\n"
190 " Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
191 " With no mapping, map the current gid to root inside the user namespace.\n"
192 " Not compatible with -b without the 'writable' option.\n"
193 " -n: Set no_new_privs.\n"
194 " -N: Enter a new cgroup namespace.\n"
195 " -p: Enter new pid namespace (implies -vr).\n"
196 " -r: Remount /proc read-only (implies -v).\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700197 " -R: Set rlimits, can be specified multiple times.\n"
Mike Frysingere61fd662017-06-20 14:07:41 -0400198 " -s: Use seccomp mode 1 (not the same as -S).\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400199 " -S <file>: Set seccomp filter using <file>.\n"
200 " E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
201 " Requires -n when not running as root.\n"
202 " -t[size]: Mount tmpfs at /tmp (implies -v).\n"
203 " Optional argument specifies size (default \"64M\").\n"
Graziano Misuraca58602a82017-08-28 17:33:15 -0700204 " -T <type>: Assume <program> is a <type> ELF binary; <type> can be 'static' or 'dynamic'.\n"
205 " This will avoid accessing <program> binary before execve(2).\n"
206 " Type 'static' will avoid preload hooking.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400207 " -u <user>: Change uid to <user>.\n"
208 " -U: Enter new user namespace (implies -p).\n"
209 " -v: Enter new mount namespace.\n"
210 " -V <file>: Enter specified mount namespace.\n"
211 " -w: Create and join a new anonymous session keyring.\n"
212 " -Y: Synchronize seccomp filters across thread group.\n"
213 " -z: Don't forward signals to jailed process.\n"
214 " --ambient: Raise ambient capabilities. Requires -c.\n"
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700215 " --uts[=name]: Enter a new UTS namespace (and set hostname).\n"
216 " --logging=<s>:Use <s> as the logging system.\n"
217 " <s> must be 'syslog' (default) or 'stderr'.\n");
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700218 /* clang-format on */
Elly Jonescd7a9042011-07-22 13:56:51 -0400219}
220
Elly Jonese1749eb2011-10-07 13:54:59 -0400221static void seccomp_filter_usage(const char *progn)
222{
223 const struct syscall_entry *entry = syscall_table;
224 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400225 "System call names supported:\n",
226 progn);
Elly Jonese1749eb2011-10-07 13:54:59 -0400227 for (; entry->name && entry->nr >= 0; ++entry)
228 printf(" %s [%d]\n", entry->name, entry->nr);
229 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500230}
231
Christopher Wiley88f76a72013-11-01 14:12:56 -0700232static int parse_args(struct minijail *j, int argc, char *argv[],
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800233 int *exit_immediately, ElfType *elftype)
Elly Jonese1749eb2011-10-07 13:54:59 -0400234{
Elly Jonese1749eb2011-10-07 13:54:59 -0400235 int opt;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700236 int use_seccomp_filter = 0;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400237 int forward = 1;
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800238 int binding = 0;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400239 int chroot = 0, pivot_root = 0;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800240 int mount_ns = 0, skip_remount = 0;
Lutz Justen13807cb2017-01-03 17:11:55 +0100241 int inherit_suppl_gids = 0, keep_suppl_gids = 0;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400242 int caps = 0, ambient_caps = 0;
Mike Frysingere61fd662017-06-20 14:07:41 -0400243 int seccomp = -1;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700244 const size_t path_max = 4096;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400245 char *map;
Martin Pelikánab9eb442017-01-25 11:53:58 +1100246 size_t size;
Luis Hector Chavez95582e72017-09-05 09:13:25 -0700247 const char *filter_path = NULL;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700248 int log_to_stderr = 0;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400249
250 const char *optstring =
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700251 "+u:g:sS:c:C:P:b:B:V:f:m::M::k:a:e::R:T:vrGhHinNplLt::IUKwyYz";
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400252 int longoption_index = 0;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400253 /* clang-format off */
254 const struct option long_options[] = {
255 {"ambient", no_argument, 0, 128},
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400256 {"uts", optional_argument, 0, 129},
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700257 {"logging", required_argument, 0, 130},
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400258 {0, 0, 0, 0},
259 };
260 /* clang-format on */
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400261
262 while ((opt = getopt_long(argc, argv, optstring, long_options,
263 &longoption_index)) != -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400264 switch (opt) {
265 case 'u':
266 set_user(j, optarg);
267 break;
268 case 'g':
269 set_group(j, optarg);
270 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700271 case 'n':
272 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700273 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400274 case 's':
Mike Frysingere61fd662017-06-20 14:07:41 -0400275 if (seccomp != -1 && seccomp != 1) {
276 fprintf(stderr, "Do not use -s & -S together.\n");
277 exit(1);
278 }
279 seccomp = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400280 minijail_use_seccomp(j);
281 break;
282 case 'S':
Mike Frysingere61fd662017-06-20 14:07:41 -0400283 if (seccomp != -1 && seccomp != 2) {
284 fprintf(stderr, "Do not use -s & -S together.\n");
285 exit(1);
286 }
287 seccomp = 2;
Elly Jonese1749eb2011-10-07 13:54:59 -0400288 minijail_use_seccomp_filter(j);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700289 if (strlen(optarg) >= path_max) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800290 fprintf(stderr, "Filter path is too long.\n");
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700291 exit(1);
292 }
293 filter_path = strndup(optarg, path_max);
294 if (!filter_path) {
295 fprintf(stderr,
296 "Could not strndup(3) filter path.\n");
297 exit(1);
298 }
299 use_seccomp_filter = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400300 break;
Dylan Reidf7942472015-11-18 17:55:26 -0800301 case 'l':
302 minijail_namespace_ipc(j);
303 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700304 case 'L':
305 minijail_log_seccomp_filter_failures(j);
306 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400307 case 'b':
308 add_binding(j, optarg);
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800309 binding = 1;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400310 break;
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700311 case 'B':
312 skip_securebits(j, optarg);
313 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400314 case 'c':
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400315 caps = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400316 use_caps(j, optarg);
317 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400318 case 'C':
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800319 if (pivot_root) {
320 fprintf(stderr, "Could not set chroot because "
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800321 "'-P' was specified.\n");
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800322 exit(1);
323 }
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700324 if (0 != minijail_enter_chroot(j, optarg)) {
325 fprintf(stderr, "Could not set chroot.\n");
Lee Campbell11af0622014-05-22 12:36:04 -0700326 exit(1);
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700327 }
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800328 chroot = 1;
329 break;
Dylan Reid648b2202015-10-23 00:50:00 -0700330 case 'k':
331 add_mount(j, optarg);
332 break;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800333 case 'K':
334 minijail_skip_remount_private(j);
335 skip_remount = 1;
336 break;
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800337 case 'P':
338 if (chroot) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800339 fprintf(stderr,
340 "Could not set pivot_root because "
341 "'-C' was specified.\n");
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800342 exit(1);
343 }
344 if (0 != minijail_enter_pivot_root(j, optarg)) {
345 fprintf(stderr, "Could not set pivot_root.\n");
346 exit(1);
347 }
348 minijail_namespace_vfs(j);
349 pivot_root = 1;
Lee Campbell11af0622014-05-22 12:36:04 -0700350 break;
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800351 case 'f':
352 if (0 != minijail_write_pid_file(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800353 fprintf(stderr,
354 "Could not prepare pid file path.\n");
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800355 exit(1);
356 }
357 break;
Lee Campbell11af0622014-05-22 12:36:04 -0700358 case 't':
Mike Frysingerec7def22017-01-13 18:44:45 -0500359 minijail_namespace_vfs(j);
Martin Pelikánab9eb442017-01-25 11:53:58 +1100360 size = 64 * 1024 * 1024;
361 if (optarg != NULL && 0 != parse_size(&size, optarg)) {
362 fprintf(stderr, "Invalid /tmp tmpfs size.\n");
363 exit(1);
364 }
365 minijail_mount_tmp_size(j, size);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400366 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400367 case 'v':
368 minijail_namespace_vfs(j);
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800369 mount_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400370 break;
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700371 case 'V':
372 minijail_namespace_enter_vfs(j, optarg);
373 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400374 case 'r':
Dylan Reid791f5772015-09-14 20:02:42 -0700375 minijail_remount_proc_readonly(j);
Elly Jonese1749eb2011-10-07 13:54:59 -0400376 break;
377 case 'G':
Lutz Justen13807cb2017-01-03 17:11:55 +0100378 if (keep_suppl_gids) {
379 fprintf(stderr,
380 "-y and -G are not compatible.\n");
381 exit(1);
382 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400383 minijail_inherit_usergroups(j);
Lutz Justen13807cb2017-01-03 17:11:55 +0100384 inherit_suppl_gids = 1;
385 break;
386 case 'y':
387 if (inherit_suppl_gids) {
388 fprintf(stderr,
389 "-y and -G are not compatible.\n");
390 exit(1);
391 }
392 minijail_keep_supplementary_gids(j);
393 keep_suppl_gids = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400394 break;
Dylan Reid4cbc2a52016-06-17 19:06:07 -0700395 case 'N':
396 minijail_namespace_cgroups(j);
397 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400398 case 'p':
399 minijail_namespace_pids(j);
400 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400401 case 'e':
Dylan Reid1102f5a2015-09-15 11:52:20 -0700402 if (optarg)
403 minijail_namespace_enter_net(j, optarg);
404 else
405 minijail_namespace_net(j);
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400406 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700407 case 'i':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700408 *exit_immediately = 1;
409 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400410 case 'H':
411 seccomp_filter_usage(argv[0]);
412 exit(1);
Yu-Hsi Chiang3e954ec2015-07-28 16:48:14 +0800413 case 'I':
414 minijail_namespace_pids(j);
415 minijail_run_as_init(j);
416 break;
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800417 case 'U':
418 minijail_namespace_user(j);
419 minijail_namespace_pids(j);
420 break;
421 case 'm':
422 minijail_namespace_user(j);
423 minijail_namespace_pids(j);
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400424
425 if (optarg) {
426 map = strdup(optarg);
427 } else {
428 /*
429 * If no map is passed, map the current uid to
430 * root.
431 */
432 map = build_idmap(0, getuid());
433 }
434 if (0 != minijail_uidmap(j, map)) {
435 fprintf(stderr, "Could not set uid map.\n");
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800436 exit(1);
437 }
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400438 free(map);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800439 break;
440 case 'M':
441 minijail_namespace_user(j);
442 minijail_namespace_pids(j);
Jorge Lucangeli Obes200299c2016-09-23 15:21:57 -0400443
444 if (optarg) {
445 map = strdup(optarg);
446 } else {
447 /*
448 * If no map is passed, map the current gid to
449 * root.
450 * This means that we're likely *not* running as
451 * root, so we also have to disable
452 * setgroups(2) to be able to set the gid map.
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400453 * See
454 * http://man7.org/linux/man-pages/man7/user_namespaces.7.html
Jorge Lucangeli Obes200299c2016-09-23 15:21:57 -0400455 */
456 minijail_namespace_user_disable_setgroups(j);
457
458 map = build_idmap(0, getgid());
459 }
460 if (0 != minijail_gidmap(j, map)) {
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400461 fprintf(stderr, "Could not set gid map.\n");
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800462 exit(1);
463 }
Jorge Lucangeli Obes200299c2016-09-23 15:21:57 -0400464 free(map);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800465 break;
Andrew Brestickereac28942015-11-11 16:04:46 -0800466 case 'a':
467 if (0 != minijail_use_alt_syscall(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800468 fprintf(stderr,
469 "Could not set alt-syscall table.\n");
Andrew Brestickereac28942015-11-11 16:04:46 -0800470 exit(1);
471 }
472 break;
Dylan Reid0f72ef42017-06-06 15:42:49 -0700473 case 'R':
474 add_rlimit(j, optarg);
475 break;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800476 case 'T':
477 if (!strcmp(optarg, "static"))
478 *elftype = ELFSTATIC;
479 else if (!strcmp(optarg, "dynamic"))
480 *elftype = ELFDYNAMIC;
481 else {
Jorge Lucangeli Obes768d42b2016-02-17 10:28:25 -0800482 fprintf(stderr, "ELF type must be 'static' or "
483 "'dynamic'.\n");
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800484 exit(1);
485 }
486 break;
Chirantan Ekbote866bb3a2017-02-07 12:26:42 -0800487 case 'w':
488 minijail_new_session_keyring(j);
489 break;
Jorge Lucangeli Obes13650612016-09-02 11:27:29 -0400490 case 'Y':
491 minijail_set_seccomp_filter_tsync(j);
492 break;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400493 case 'z':
494 forward = 0;
495 break;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400496 /* Long options. */
497 case 128: /* Ambient caps. */
498 ambient_caps = 1;
499 minijail_set_ambient_caps(j);
500 break;
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400501 case 129: /* UTS/hostname namespace. */
502 minijail_namespace_uts(j);
503 if (optarg)
504 minijail_namespace_set_hostname(j, optarg);
505 break;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700506 case 130: /* Logging. */
507 if (!strcmp(optarg, "syslog"))
508 log_to_stderr = 0;
509 else if (!strcmp(optarg, "stderr")) {
510 log_to_stderr = 1;
511 } else {
512 fprintf(stderr, "--logger must be 'syslog' or "
513 "'stderr'.\n");
514 exit(1);
515 }
516 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400517 default:
518 usage(argv[0]);
519 exit(1);
520 }
521 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400522
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700523 if (log_to_stderr) {
524 init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
525 /*
526 * When logging to stderr, ensure the FD survives the jailing.
527 */
528 if (0 !=
529 minijail_preserve_fd(j, STDERR_FILENO, STDERR_FILENO)) {
530 fprintf(stderr, "Could not preserve stderr.\n");
531 exit(1);
532 }
533 }
534
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400535 /* Can only set ambient caps when using regular caps. */
536 if (ambient_caps && !caps) {
537 fprintf(stderr, "Can't set ambient capabilities (--ambient) "
538 "without actually using capabilities (-c).\n");
539 exit(1);
540 }
541
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400542 /* Set up signal handlers in minijail unless asked not to. */
543 if (forward)
544 minijail_forward_signals(j);
545
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800546 /* Only allow bind mounts when entering a chroot or using pivot_root. */
547 if (binding && !(chroot || pivot_root)) {
548 fprintf(stderr, "Can't add bind mounts without chroot or"
549 " pivot_root.\n");
550 exit(1);
551 }
552
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700553 /*
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800554 * Remounting / as MS_PRIVATE only happens when entering a new mount
555 * namespace, so skipping it only applies in that case.
556 */
557 if (skip_remount && !mount_ns) {
558 fprintf(stderr, "Can't skip marking mounts as MS_PRIVATE"
559 " without mount namespaces.\n");
560 exit(1);
561 }
562
563 /*
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700564 * We parse seccomp filters here to make sure we've collected all
565 * cmdline options.
566 */
567 if (use_seccomp_filter) {
568 minijail_parse_seccomp_filters(j, filter_path);
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400569 free((void *)filter_path);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700570 }
571
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700572 /*
573 * There should be at least one additional unparsed argument: the
574 * executable name.
575 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400576 if (argc == optind) {
577 usage(argv[0]);
578 exit(1);
579 }
Lee Campbell11af0622014-05-22 12:36:04 -0700580
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700581 if (*elftype == ELFERROR) {
582 /*
583 * -T was not specified.
584 * Get the path to the program adjusted for changing root.
585 */
586 char *program_path =
587 minijail_get_original_path(j, argv[optind]);
588
589 /* Check that we can access the target program. */
590 if (access(program_path, X_OK)) {
591 fprintf(stderr,
592 "Target program '%s' is not accessible.\n",
593 argv[optind]);
594 exit(1);
595 }
596
597 /* Check if target is statically or dynamically linked. */
598 *elftype = get_elf_linkage(program_path);
599 free(program_path);
600 }
601
602 /*
603 * Setting capabilities need either a dynamically-linked binary, or the
604 * use of ambient capabilities for them to be able to survive an
605 * execve(2).
606 */
607 if (caps && *elftype == ELFSTATIC && !ambient_caps) {
608 fprintf(stderr, "Can't run statically-linked binaries with "
609 "capabilities (-c) without also setting "
610 "ambient capabilities. Try passing "
611 "--ambient.\n");
612 exit(1);
613 }
614
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500615 return optind;
616}
Elly Jonescd7a9042011-07-22 13:56:51 -0400617
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500618int main(int argc, char *argv[])
619{
620 struct minijail *j = minijail_new();
Jorge Lucangeli Obesd99a40d2016-01-26 13:50:44 -0800621 const char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700622 int exit_immediately = 0;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700623 ElfType elftype = ELFERROR;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800624 int consumed = parse_args(j, argc, argv, &exit_immediately, &elftype);
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500625 argc -= consumed;
626 argv += consumed;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700627
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700628 if (elftype == ELFSTATIC) {
Jorge Lucangeli Obes54714502015-09-30 10:08:45 -0700629 /*
630 * Target binary is statically linked so we cannot use
631 * libminijailpreload.so.
632 */
633 minijail_run_no_preload(j, argv[0], argv);
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700634 } else if (elftype == ELFDYNAMIC) {
635 /*
636 * Target binary is dynamically linked so we can
637 * inject libminijailpreload.so into it.
638 */
639
640 /* Check that we can dlopen() libminijailpreload.so. */
641 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800642 dl_mesg = dlerror();
643 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
644 return 1;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700645 }
646 minijail_run(j, argv[0], argv);
647 } else {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -0700648 fprintf(stderr,
649 "Target program '%s' is not a valid ELF file.\n",
650 argv[0]);
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800651 return 1;
652 }
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700653
Christopher Wiley88f76a72013-11-01 14:12:56 -0700654 if (exit_immediately) {
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700655 info("not running init loop, exiting immediately\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700656 return 0;
657 }
lhchavez6c8d8202017-09-01 03:55:11 +0000658 int ret = minijail_wait(j);
659#if defined(__SANITIZE_ADDRESS__)
660 minijail_destroy(j);
661#endif /* __SANITIZE_ADDRESS__ */
662 return ret;
Elly Jonescd7a9042011-07-22 13:56:51 -0400663}