blob: 088bc2789d45b0e84351c413e0ca58228846f409 [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>
Luis Hector Chavez71323552017-09-05 09:17:22 -070011#include <sys/capability.h>
12#include <sys/types.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040013#include <unistd.h>
14
15#include "libminijail.h"
Will Drewry32ac9f52011-08-18 21:36:27 -050016#include "libsyscalls.h"
Elly Jonescd7a9042011-07-22 13:56:51 -040017
Lee Campbell1e4fc6a2014-06-06 17:40:02 -070018#include "elfparse.h"
Luis Hector Chavez71323552017-09-05 09:17:22 -070019#include "system.h"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070020#include "util.h"
21
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -040022#define IDMAP_LEN 32U
23
Luis Hector Chavez71323552017-09-05 09:17:22 -070024static void set_user(struct minijail *j, const char *arg, uid_t *out_uid,
25 gid_t *out_gid)
Elly Jonese1749eb2011-10-07 13:54:59 -040026{
27 char *end = NULL;
28 int uid = strtod(arg, &end);
29 if (!*end && *arg) {
Luis Hector Chavez71323552017-09-05 09:17:22 -070030 *out_uid = uid;
Elly Jonese1749eb2011-10-07 13:54:59 -040031 minijail_change_uid(j, uid);
32 return;
33 }
Elly Jonescd7a9042011-07-22 13:56:51 -040034
Luis Hector Chavez71323552017-09-05 09:17:22 -070035 if (lookup_user(arg, out_uid, out_gid)) {
36 fprintf(stderr, "Bad user: '%s'\n", arg);
37 exit(1);
38 }
39
Elly Jonese1749eb2011-10-07 13:54:59 -040040 if (minijail_change_user(j, arg)) {
41 fprintf(stderr, "Bad user: '%s'\n", arg);
42 exit(1);
43 }
Elly Jonescd7a9042011-07-22 13:56:51 -040044}
45
Luis Hector Chavez71323552017-09-05 09:17:22 -070046static void set_group(struct minijail *j, const char *arg, gid_t *out_gid)
Elly Jonese1749eb2011-10-07 13:54:59 -040047{
48 char *end = NULL;
49 int gid = strtod(arg, &end);
50 if (!*end && *arg) {
Luis Hector Chavez71323552017-09-05 09:17:22 -070051 *out_gid = gid;
Elly Jonese1749eb2011-10-07 13:54:59 -040052 minijail_change_gid(j, gid);
53 return;
54 }
Elly Jonescd7a9042011-07-22 13:56:51 -040055
Luis Hector Chavez71323552017-09-05 09:17:22 -070056 if (lookup_group(arg, out_gid)) {
57 fprintf(stderr, "Bad group: '%s'\n", arg);
58 exit(1);
59 }
60
Elly Jonese1749eb2011-10-07 13:54:59 -040061 if (minijail_change_group(j, arg)) {
62 fprintf(stderr, "Bad group: '%s'\n", arg);
63 exit(1);
64 }
Elly Jonescd7a9042011-07-22 13:56:51 -040065}
66
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -070067static void skip_securebits(struct minijail *j, const char *arg)
68{
69 uint64_t securebits_skip_mask;
70 char *end = NULL;
71 securebits_skip_mask = strtoull(arg, &end, 16);
72 if (*end) {
73 fprintf(stderr, "Invalid securebit mask: '%s'\n", arg);
74 exit(1);
75 }
76 minijail_skip_setting_securebits(j, securebits_skip_mask);
77}
78
Elly Jonese1749eb2011-10-07 13:54:59 -040079static void use_caps(struct minijail *j, const char *arg)
80{
81 uint64_t caps;
82 char *end = NULL;
83 caps = strtoull(arg, &end, 16);
84 if (*end) {
85 fprintf(stderr, "Invalid cap set: '%s'\n", arg);
86 exit(1);
87 }
88 minijail_use_caps(j, caps);
Elly Jonescd7a9042011-07-22 13:56:51 -040089}
90
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -070091static void add_binding(struct minijail *j, char *arg)
92{
Elly Jones51a5b6c2011-10-12 19:09:26 -040093 char *src = strtok(arg, ",");
Elly Jones5ba42b52011-12-07 13:31:43 -050094 char *dest = strtok(NULL, ",");
95 char *flags = strtok(NULL, ",");
Elly Jones51a5b6c2011-10-12 19:09:26 -040096 if (!src || !dest) {
97 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
98 exit(1);
99 }
100 if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800101 fprintf(stderr, "minijail_bind failed.\n");
Elly Jones51a5b6c2011-10-12 19:09:26 -0400102 exit(1);
103 }
104}
105
Dylan Reid0f72ef42017-06-06 15:42:49 -0700106static void add_rlimit(struct minijail *j, char *arg)
107{
108 char *type = strtok(arg, ",");
109 char *cur = strtok(NULL, ",");
110 char *max = strtok(NULL, ",");
111 if (!type || !cur || !max) {
112 fprintf(stderr, "Bad rlimit '%s'.\n", arg);
113 exit(1);
114 }
115 if (minijail_rlimit(j, atoi(type), atoi(cur), atoi(max))) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700116 fprintf(stderr, "minijail_rlimit '%s,%s,%s' failed.\n", type,
117 cur, max);
Dylan Reid0f72ef42017-06-06 15:42:49 -0700118 exit(1);
119 }
120}
121
Dylan Reid648b2202015-10-23 00:50:00 -0700122static void add_mount(struct minijail *j, char *arg)
123{
124 char *src = strtok(arg, ",");
125 char *dest = strtok(NULL, ",");
126 char *type = strtok(NULL, ",");
127 char *flags = strtok(NULL, ",");
Dylan Reid81e23972016-05-18 14:06:35 -0700128 char *data = strtok(NULL, ",");
Dylan Reid648b2202015-10-23 00:50:00 -0700129 if (!src || !dest || !type) {
130 fprintf(stderr, "Bad mount: %s %s %s\n", src, dest, type);
131 exit(1);
132 }
Dylan Reid81e23972016-05-18 14:06:35 -0700133 if (minijail_mount_with_data(j, src, dest, type,
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400134 flags ? strtoul(flags, NULL, 16) : 0,
135 data)) {
Dylan Reid648b2202015-10-23 00:50:00 -0700136 fprintf(stderr, "minijail_mount failed.\n");
137 exit(1);
138 }
139}
140
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400141static char *build_idmap(id_t id, id_t lowerid)
142{
143 int ret;
144 char *idmap = malloc(IDMAP_LEN);
145 ret = snprintf(idmap, IDMAP_LEN, "%d %d 1", id, lowerid);
146 if (ret < 0 || (size_t)ret >= IDMAP_LEN) {
147 free(idmap);
148 fprintf(stderr, "Could not build id map.\n");
149 exit(1);
150 }
151 return idmap;
152}
153
Luis Hector Chavez71323552017-09-05 09:17:22 -0700154static int has_cap_setgid()
155{
156 cap_t caps;
157 cap_flag_value_t cap_value;
158
159 if (!CAP_IS_SUPPORTED(CAP_SETGID))
160 return 0;
161
162 caps = cap_get_proc();
163 if (!caps) {
164 fprintf(stderr, "Could not get process' capabilities: %m\n");
165 exit(1);
166 }
167
168 if (cap_get_flag(caps, CAP_SETGID, CAP_EFFECTIVE, &cap_value)) {
169 fprintf(stderr, "Could not get the value of CAP_SETGID: %m\n");
170 exit(1);
171 }
172
173 if (cap_free(caps)) {
174 fprintf(stderr, "Could not free capabilities: %m\n");
175 exit(1);
176 }
177
178 return cap_value == CAP_SET;
179}
180
181static void set_ugid_mapping(struct minijail *j, int set_uidmap, uid_t uid,
182 char *uidmap, int set_gidmap, gid_t gid,
183 char *gidmap)
184{
185 if (set_uidmap) {
186 minijail_namespace_user(j);
187 minijail_namespace_pids(j);
188
189 if (!uidmap) {
190 /*
191 * If no map is passed, map the current uid to the
192 * chosen uid in the target namespace (or root, if none
193 * was chosen).
194 */
195 uidmap = build_idmap(uid, getuid());
196 }
197 if (0 != minijail_uidmap(j, uidmap)) {
198 fprintf(stderr, "Could not set uid map.\n");
199 exit(1);
200 }
201 free(uidmap);
202 }
203 if (set_gidmap) {
204 minijail_namespace_user(j);
205 minijail_namespace_pids(j);
206
207 if (!gidmap) {
208 /*
209 * If no map is passed, map the current gid to the
210 * chosen gid in the target namespace.
211 */
212 gidmap = build_idmap(gid, getgid());
213 }
214 if (!has_cap_setgid()) {
215 /*
216 * This means that we are not running as root,
217 * so we also have to disable setgroups(2) to
218 * be able to set the gid map.
219 * See
220 * http://man7.org/linux/man-pages/man7/user_namespaces.7.html
221 */
222 minijail_namespace_user_disable_setgroups(j);
223 }
224 if (0 != minijail_gidmap(j, gidmap)) {
225 fprintf(stderr, "Could not set gid map.\n");
226 exit(1);
227 }
228 free(gidmap);
229 }
230}
231
Elly Jonese1749eb2011-10-07 13:54:59 -0400232static void usage(const char *progn)
233{
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700234 size_t i;
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700235 /* clang-format off */
Dylan Reid0f72ef42017-06-06 15:42:49 -0700236 printf("Usage: %s [-GhHiIKlLnNprRstUvyYz]\n"
Jorge Lucangeli Obesa32e8392016-09-01 16:52:40 -0400237 " [-a <table>]\n"
238 " [-b <src>,<dest>[,<writeable>]] [-k <src>,<dest>,<type>[,<flags>][,<data>]]\n"
239 " [-c <caps>] [-C <dir>] [-P <dir>] [-e[file]] [-f <file>] [-g <group>]\n"
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400240 " [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*]\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700241 " [-R <type,cur,max>] [-S <file>] [-t[size]] [-T <type>] [-u <user>] [-V <file>]\n"
Jorge Lucangeli Obes9dd256e2016-02-16 15:31:02 -0800242 " <program> [args...]\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400243 " -a <table>: Use alternate syscall table <table>.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400244 " -b <...>: Bind <src> to <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400245 " Multiple instances allowed.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400246 " -B <mask>: Skip setting securebits in <mask> when restricting capabilities (-c).\n"
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700247 " By default, SECURE_NOROOT, SECURE_NO_SETUID_FIXUP, and \n"
248 " SECURE_KEEP_CAPS (together with their respective locks) are set.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400249 " -k <...>: Mount <src> at <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400250 " <flags> and <data> can be specified as in mount(2).\n"
251 " Multiple instances allowed.\n"
252 " -c <caps>: Restrict caps to <caps>.\n"
253 " -C <dir>: chroot(2) to <dir>.\n"
254 " Not compatible with -P.\n"
255 " -P <dir>: pivot_root(2) to <dir> (implies -v).\n"
256 " Not compatible with -C.\n"
257 " -e[file]: Enter new network namespace, or existing one if |file| is provided.\n"
258 " -f <file>: Write the pid of the jailed process to <file>.\n"
259 " -g <group>: Change gid to <group>.\n"
260 " -G: Inherit supplementary groups from uid.\n"
261 " Not compatible with -y.\n"
262 " -y: Keep uid's supplementary groups.\n"
263 " Not compatible with -G.\n"
264 " -h: Help (this message).\n"
265 " -H: Seccomp filter help message.\n"
266 " -i: Exit immediately after fork (do not act as init).\n"
267 " -I: Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
268 " -K: Don't mark all existing mounts as MS_PRIVATE.\n"
269 " -l: Enter new IPC namespace.\n"
270 " -L: Report blocked syscalls to syslog when using seccomp filter.\n"
271 " Forces the following syscalls to be allowed:\n"
Kees Cook03b2af22014-12-18 17:11:13 -0800272 " ", progn);
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700273 /* clang-format on */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700274 for (i = 0; i < log_syscalls_len; i++)
275 printf("%s ", log_syscalls[i]);
276
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700277 /* clang-format off */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700278 printf("\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400279 " -m[map]: Set the uid map of a user namespace (implies -pU).\n"
280 " Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
281 " With no mapping, map the current uid to root inside the user namespace.\n"
282 " Not compatible with -b without the 'writable' option.\n"
283 " -M[map]: Set the gid map of a user namespace (implies -pU).\n"
284 " Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
285 " With no mapping, map the current gid to root inside the user namespace.\n"
286 " Not compatible with -b without the 'writable' option.\n"
287 " -n: Set no_new_privs.\n"
288 " -N: Enter a new cgroup namespace.\n"
289 " -p: Enter new pid namespace (implies -vr).\n"
290 " -r: Remount /proc read-only (implies -v).\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700291 " -R: Set rlimits, can be specified multiple times.\n"
Mike Frysingere61fd662017-06-20 14:07:41 -0400292 " -s: Use seccomp mode 1 (not the same as -S).\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400293 " -S <file>: Set seccomp filter using <file>.\n"
294 " E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
295 " Requires -n when not running as root.\n"
296 " -t[size]: Mount tmpfs at /tmp (implies -v).\n"
297 " Optional argument specifies size (default \"64M\").\n"
Graziano Misuraca58602a82017-08-28 17:33:15 -0700298 " -T <type>: Assume <program> is a <type> ELF binary; <type> can be 'static' or 'dynamic'.\n"
299 " This will avoid accessing <program> binary before execve(2).\n"
300 " Type 'static' will avoid preload hooking.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400301 " -u <user>: Change uid to <user>.\n"
302 " -U: Enter new user namespace (implies -p).\n"
303 " -v: Enter new mount namespace.\n"
304 " -V <file>: Enter specified mount namespace.\n"
305 " -w: Create and join a new anonymous session keyring.\n"
306 " -Y: Synchronize seccomp filters across thread group.\n"
307 " -z: Don't forward signals to jailed process.\n"
308 " --ambient: Raise ambient capabilities. Requires -c.\n"
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700309 " --uts[=name]: Enter a new UTS namespace (and set hostname).\n"
310 " --logging=<s>:Use <s> as the logging system.\n"
311 " <s> must be 'syslog' (default) or 'stderr'.\n");
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700312 /* clang-format on */
Elly Jonescd7a9042011-07-22 13:56:51 -0400313}
314
Elly Jonese1749eb2011-10-07 13:54:59 -0400315static void seccomp_filter_usage(const char *progn)
316{
317 const struct syscall_entry *entry = syscall_table;
318 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400319 "System call names supported:\n",
320 progn);
Elly Jonese1749eb2011-10-07 13:54:59 -0400321 for (; entry->name && entry->nr >= 0; ++entry)
322 printf(" %s [%d]\n", entry->name, entry->nr);
323 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500324}
325
Christopher Wiley88f76a72013-11-01 14:12:56 -0700326static int parse_args(struct minijail *j, int argc, char *argv[],
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800327 int *exit_immediately, ElfType *elftype)
Elly Jonese1749eb2011-10-07 13:54:59 -0400328{
Elly Jonese1749eb2011-10-07 13:54:59 -0400329 int opt;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700330 int use_seccomp_filter = 0;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400331 int forward = 1;
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800332 int binding = 0;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400333 int chroot = 0, pivot_root = 0;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800334 int mount_ns = 0, skip_remount = 0;
Lutz Justen13807cb2017-01-03 17:11:55 +0100335 int inherit_suppl_gids = 0, keep_suppl_gids = 0;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400336 int caps = 0, ambient_caps = 0;
Mike Frysingere61fd662017-06-20 14:07:41 -0400337 int seccomp = -1;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700338 const size_t path_max = 4096;
Luis Hector Chavez71323552017-09-05 09:17:22 -0700339 uid_t uid = 0;
340 gid_t gid = 0;
341 char *uidmap = NULL, *gidmap = NULL;
342 int set_uidmap = 0, set_gidmap = 0;
Martin Pelikánab9eb442017-01-25 11:53:58 +1100343 size_t size;
Luis Hector Chavez95582e72017-09-05 09:13:25 -0700344 const char *filter_path = NULL;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700345 int log_to_stderr = 0;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400346
347 const char *optstring =
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700348 "+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 -0400349 int longoption_index = 0;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400350 /* clang-format off */
351 const struct option long_options[] = {
352 {"ambient", no_argument, 0, 128},
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400353 {"uts", optional_argument, 0, 129},
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700354 {"logging", required_argument, 0, 130},
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400355 {0, 0, 0, 0},
356 };
357 /* clang-format on */
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400358
359 while ((opt = getopt_long(argc, argv, optstring, long_options,
360 &longoption_index)) != -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400361 switch (opt) {
362 case 'u':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700363 set_user(j, optarg, &uid, &gid);
Elly Jonese1749eb2011-10-07 13:54:59 -0400364 break;
365 case 'g':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700366 set_group(j, optarg, &gid);
Elly Jonese1749eb2011-10-07 13:54:59 -0400367 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700368 case 'n':
369 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700370 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400371 case 's':
Mike Frysingere61fd662017-06-20 14:07:41 -0400372 if (seccomp != -1 && seccomp != 1) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700373 fprintf(stderr,
374 "Do not use -s & -S together.\n");
Mike Frysingere61fd662017-06-20 14:07:41 -0400375 exit(1);
376 }
377 seccomp = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400378 minijail_use_seccomp(j);
379 break;
380 case 'S':
Mike Frysingere61fd662017-06-20 14:07:41 -0400381 if (seccomp != -1 && seccomp != 2) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700382 fprintf(stderr,
383 "Do not use -s & -S together.\n");
Mike Frysingere61fd662017-06-20 14:07:41 -0400384 exit(1);
385 }
386 seccomp = 2;
Elly Jonese1749eb2011-10-07 13:54:59 -0400387 minijail_use_seccomp_filter(j);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700388 if (strlen(optarg) >= path_max) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800389 fprintf(stderr, "Filter path is too long.\n");
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700390 exit(1);
391 }
392 filter_path = strndup(optarg, path_max);
393 if (!filter_path) {
394 fprintf(stderr,
395 "Could not strndup(3) filter path.\n");
396 exit(1);
397 }
398 use_seccomp_filter = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400399 break;
Dylan Reidf7942472015-11-18 17:55:26 -0800400 case 'l':
401 minijail_namespace_ipc(j);
402 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700403 case 'L':
404 minijail_log_seccomp_filter_failures(j);
405 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400406 case 'b':
407 add_binding(j, optarg);
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800408 binding = 1;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400409 break;
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700410 case 'B':
411 skip_securebits(j, optarg);
412 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400413 case 'c':
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400414 caps = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400415 use_caps(j, optarg);
416 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400417 case 'C':
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800418 if (pivot_root) {
419 fprintf(stderr, "Could not set chroot because "
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800420 "'-P' was specified.\n");
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800421 exit(1);
422 }
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700423 if (0 != minijail_enter_chroot(j, optarg)) {
424 fprintf(stderr, "Could not set chroot.\n");
Lee Campbell11af0622014-05-22 12:36:04 -0700425 exit(1);
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700426 }
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800427 chroot = 1;
428 break;
Dylan Reid648b2202015-10-23 00:50:00 -0700429 case 'k':
430 add_mount(j, optarg);
431 break;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800432 case 'K':
433 minijail_skip_remount_private(j);
434 skip_remount = 1;
435 break;
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800436 case 'P':
437 if (chroot) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800438 fprintf(stderr,
439 "Could not set pivot_root because "
440 "'-C' was specified.\n");
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800441 exit(1);
442 }
443 if (0 != minijail_enter_pivot_root(j, optarg)) {
444 fprintf(stderr, "Could not set pivot_root.\n");
445 exit(1);
446 }
447 minijail_namespace_vfs(j);
448 pivot_root = 1;
Lee Campbell11af0622014-05-22 12:36:04 -0700449 break;
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800450 case 'f':
451 if (0 != minijail_write_pid_file(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800452 fprintf(stderr,
453 "Could not prepare pid file path.\n");
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800454 exit(1);
455 }
456 break;
Lee Campbell11af0622014-05-22 12:36:04 -0700457 case 't':
Mike Frysingerec7def22017-01-13 18:44:45 -0500458 minijail_namespace_vfs(j);
Martin Pelikánab9eb442017-01-25 11:53:58 +1100459 size = 64 * 1024 * 1024;
460 if (optarg != NULL && 0 != parse_size(&size, optarg)) {
461 fprintf(stderr, "Invalid /tmp tmpfs size.\n");
462 exit(1);
463 }
464 minijail_mount_tmp_size(j, size);
Elly Jones51a5b6c2011-10-12 19:09:26 -0400465 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400466 case 'v':
467 minijail_namespace_vfs(j);
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800468 mount_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400469 break;
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700470 case 'V':
471 minijail_namespace_enter_vfs(j, optarg);
472 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400473 case 'r':
Dylan Reid791f5772015-09-14 20:02:42 -0700474 minijail_remount_proc_readonly(j);
Elly Jonese1749eb2011-10-07 13:54:59 -0400475 break;
476 case 'G':
Lutz Justen13807cb2017-01-03 17:11:55 +0100477 if (keep_suppl_gids) {
478 fprintf(stderr,
479 "-y and -G are not compatible.\n");
480 exit(1);
481 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400482 minijail_inherit_usergroups(j);
Lutz Justen13807cb2017-01-03 17:11:55 +0100483 inherit_suppl_gids = 1;
484 break;
485 case 'y':
486 if (inherit_suppl_gids) {
487 fprintf(stderr,
488 "-y and -G are not compatible.\n");
489 exit(1);
490 }
491 minijail_keep_supplementary_gids(j);
492 keep_suppl_gids = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400493 break;
Dylan Reid4cbc2a52016-06-17 19:06:07 -0700494 case 'N':
495 minijail_namespace_cgroups(j);
496 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400497 case 'p':
498 minijail_namespace_pids(j);
499 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400500 case 'e':
Dylan Reid1102f5a2015-09-15 11:52:20 -0700501 if (optarg)
502 minijail_namespace_enter_net(j, optarg);
503 else
504 minijail_namespace_net(j);
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400505 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700506 case 'i':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700507 *exit_immediately = 1;
508 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400509 case 'H':
510 seccomp_filter_usage(argv[0]);
511 exit(1);
Yu-Hsi Chiang3e954ec2015-07-28 16:48:14 +0800512 case 'I':
513 minijail_namespace_pids(j);
514 minijail_run_as_init(j);
515 break;
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800516 case 'U':
517 minijail_namespace_user(j);
518 minijail_namespace_pids(j);
519 break;
520 case 'm':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700521 set_uidmap = 1;
522 if (uidmap) {
523 free(uidmap);
524 uidmap = NULL;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400525 }
Luis Hector Chavez71323552017-09-05 09:17:22 -0700526 if (optarg)
527 uidmap = strdup(optarg);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800528 break;
529 case 'M':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700530 set_gidmap = 1;
531 if (gidmap) {
532 free(gidmap);
533 gidmap = NULL;
Jorge Lucangeli Obes200299c2016-09-23 15:21:57 -0400534 }
Luis Hector Chavez71323552017-09-05 09:17:22 -0700535 if (optarg)
536 gidmap = strdup(optarg);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800537 break;
Andrew Brestickereac28942015-11-11 16:04:46 -0800538 case 'a':
539 if (0 != minijail_use_alt_syscall(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800540 fprintf(stderr,
541 "Could not set alt-syscall table.\n");
Andrew Brestickereac28942015-11-11 16:04:46 -0800542 exit(1);
543 }
544 break;
Dylan Reid0f72ef42017-06-06 15:42:49 -0700545 case 'R':
546 add_rlimit(j, optarg);
547 break;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800548 case 'T':
549 if (!strcmp(optarg, "static"))
550 *elftype = ELFSTATIC;
551 else if (!strcmp(optarg, "dynamic"))
552 *elftype = ELFDYNAMIC;
553 else {
Jorge Lucangeli Obes768d42b2016-02-17 10:28:25 -0800554 fprintf(stderr, "ELF type must be 'static' or "
555 "'dynamic'.\n");
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800556 exit(1);
557 }
558 break;
Chirantan Ekbote866bb3a2017-02-07 12:26:42 -0800559 case 'w':
560 minijail_new_session_keyring(j);
561 break;
Jorge Lucangeli Obes13650612016-09-02 11:27:29 -0400562 case 'Y':
563 minijail_set_seccomp_filter_tsync(j);
564 break;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400565 case 'z':
566 forward = 0;
567 break;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400568 /* Long options. */
569 case 128: /* Ambient caps. */
570 ambient_caps = 1;
571 minijail_set_ambient_caps(j);
572 break;
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400573 case 129: /* UTS/hostname namespace. */
574 minijail_namespace_uts(j);
575 if (optarg)
576 minijail_namespace_set_hostname(j, optarg);
577 break;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700578 case 130: /* Logging. */
579 if (!strcmp(optarg, "syslog"))
580 log_to_stderr = 0;
581 else if (!strcmp(optarg, "stderr")) {
582 log_to_stderr = 1;
583 } else {
584 fprintf(stderr, "--logger must be 'syslog' or "
585 "'stderr'.\n");
586 exit(1);
587 }
588 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400589 default:
590 usage(argv[0]);
591 exit(1);
592 }
593 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400594
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700595 if (log_to_stderr) {
596 init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
597 /*
598 * When logging to stderr, ensure the FD survives the jailing.
599 */
600 if (0 !=
601 minijail_preserve_fd(j, STDERR_FILENO, STDERR_FILENO)) {
602 fprintf(stderr, "Could not preserve stderr.\n");
603 exit(1);
604 }
605 }
606
Luis Hector Chavez71323552017-09-05 09:17:22 -0700607 /* Set up uid/gid mapping. */
608 if (set_uidmap || set_gidmap) {
609 set_ugid_mapping(j, set_uidmap, uid, uidmap, set_gidmap, gid,
610 gidmap);
611 }
612
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400613 /* Can only set ambient caps when using regular caps. */
614 if (ambient_caps && !caps) {
615 fprintf(stderr, "Can't set ambient capabilities (--ambient) "
616 "without actually using capabilities (-c).\n");
617 exit(1);
618 }
619
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400620 /* Set up signal handlers in minijail unless asked not to. */
621 if (forward)
622 minijail_forward_signals(j);
623
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800624 /* Only allow bind mounts when entering a chroot or using pivot_root. */
625 if (binding && !(chroot || pivot_root)) {
626 fprintf(stderr, "Can't add bind mounts without chroot or"
627 " pivot_root.\n");
628 exit(1);
629 }
630
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700631 /*
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800632 * Remounting / as MS_PRIVATE only happens when entering a new mount
633 * namespace, so skipping it only applies in that case.
634 */
635 if (skip_remount && !mount_ns) {
636 fprintf(stderr, "Can't skip marking mounts as MS_PRIVATE"
637 " without mount namespaces.\n");
638 exit(1);
639 }
640
641 /*
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700642 * We parse seccomp filters here to make sure we've collected all
643 * cmdline options.
644 */
645 if (use_seccomp_filter) {
646 minijail_parse_seccomp_filters(j, filter_path);
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400647 free((void *)filter_path);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700648 }
649
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700650 /*
651 * There should be at least one additional unparsed argument: the
652 * executable name.
653 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400654 if (argc == optind) {
655 usage(argv[0]);
656 exit(1);
657 }
Lee Campbell11af0622014-05-22 12:36:04 -0700658
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700659 if (*elftype == ELFERROR) {
660 /*
661 * -T was not specified.
662 * Get the path to the program adjusted for changing root.
663 */
664 char *program_path =
665 minijail_get_original_path(j, argv[optind]);
666
667 /* Check that we can access the target program. */
668 if (access(program_path, X_OK)) {
669 fprintf(stderr,
670 "Target program '%s' is not accessible.\n",
671 argv[optind]);
672 exit(1);
673 }
674
675 /* Check if target is statically or dynamically linked. */
676 *elftype = get_elf_linkage(program_path);
677 free(program_path);
678 }
679
680 /*
681 * Setting capabilities need either a dynamically-linked binary, or the
682 * use of ambient capabilities for them to be able to survive an
683 * execve(2).
684 */
685 if (caps && *elftype == ELFSTATIC && !ambient_caps) {
686 fprintf(stderr, "Can't run statically-linked binaries with "
687 "capabilities (-c) without also setting "
688 "ambient capabilities. Try passing "
689 "--ambient.\n");
690 exit(1);
691 }
692
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500693 return optind;
694}
Elly Jonescd7a9042011-07-22 13:56:51 -0400695
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500696int main(int argc, char *argv[])
697{
698 struct minijail *j = minijail_new();
Jorge Lucangeli Obesd99a40d2016-01-26 13:50:44 -0800699 const char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700700 int exit_immediately = 0;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700701 ElfType elftype = ELFERROR;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800702 int consumed = parse_args(j, argc, argv, &exit_immediately, &elftype);
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500703 argc -= consumed;
704 argv += consumed;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700705
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700706 if (elftype == ELFSTATIC) {
Jorge Lucangeli Obes54714502015-09-30 10:08:45 -0700707 /*
708 * Target binary is statically linked so we cannot use
709 * libminijailpreload.so.
710 */
711 minijail_run_no_preload(j, argv[0], argv);
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700712 } else if (elftype == ELFDYNAMIC) {
713 /*
714 * Target binary is dynamically linked so we can
715 * inject libminijailpreload.so into it.
716 */
717
718 /* Check that we can dlopen() libminijailpreload.so. */
719 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800720 dl_mesg = dlerror();
721 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
722 return 1;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700723 }
724 minijail_run(j, argv[0], argv);
725 } else {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -0700726 fprintf(stderr,
727 "Target program '%s' is not a valid ELF file.\n",
728 argv[0]);
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800729 return 1;
730 }
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700731
Christopher Wiley88f76a72013-11-01 14:12:56 -0700732 if (exit_immediately) {
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700733 info("not running init loop, exiting immediately\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700734 return 0;
735 }
lhchavez6c8d8202017-09-01 03:55:11 +0000736 int ret = minijail_wait(j);
737#if defined(__SANITIZE_ADDRESS__)
738 minijail_destroy(j);
739#endif /* __SANITIZE_ADDRESS__ */
740 return ret;
Elly Jonescd7a9042011-07-22 13:56:51 -0400741}