blob: b0daed2b5887d5dff04b7691adcc3cd5c0bb7809 [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>
Stephen Barber5dd5b1b2017-10-16 23:02:39 -07007#include <errno.h>
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -04008#include <getopt.h>
Elly Jonescd7a9042011-07-22 13:56:51 -04009#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
Luis Hector Chavez71323552017-09-05 09:17:22 -070012#include <sys/capability.h>
13#include <sys/types.h>
Elly Jonescd7a9042011-07-22 13:56:51 -040014#include <unistd.h>
15
16#include "libminijail.h"
Will Drewry32ac9f52011-08-18 21:36:27 -050017#include "libsyscalls.h"
Elly Jonescd7a9042011-07-22 13:56:51 -040018
Lee Campbell1e4fc6a2014-06-06 17:40:02 -070019#include "elfparse.h"
Luis Hector Chavez71323552017-09-05 09:17:22 -070020#include "system.h"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070021#include "util.h"
22
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -040023#define IDMAP_LEN 32U
Luis Hector Chavezd45fc422017-10-25 15:11:53 -070024#define DEFAULT_TMP_SIZE (64 * 1024 * 1024)
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -040025
Luis Hector Chavez71323552017-09-05 09:17:22 -070026static void set_user(struct minijail *j, const char *arg, uid_t *out_uid,
27 gid_t *out_gid)
Elly Jonese1749eb2011-10-07 13:54:59 -040028{
29 char *end = NULL;
30 int uid = strtod(arg, &end);
31 if (!*end && *arg) {
Luis Hector Chavez71323552017-09-05 09:17:22 -070032 *out_uid = uid;
Elly Jonese1749eb2011-10-07 13:54:59 -040033 minijail_change_uid(j, uid);
34 return;
35 }
Elly Jonescd7a9042011-07-22 13:56:51 -040036
Luis Hector Chavez71323552017-09-05 09:17:22 -070037 if (lookup_user(arg, out_uid, out_gid)) {
38 fprintf(stderr, "Bad user: '%s'\n", arg);
39 exit(1);
40 }
41
Elly Jonese1749eb2011-10-07 13:54:59 -040042 if (minijail_change_user(j, arg)) {
43 fprintf(stderr, "Bad user: '%s'\n", arg);
44 exit(1);
45 }
Elly Jonescd7a9042011-07-22 13:56:51 -040046}
47
Luis Hector Chavez71323552017-09-05 09:17:22 -070048static void set_group(struct minijail *j, const char *arg, gid_t *out_gid)
Elly Jonese1749eb2011-10-07 13:54:59 -040049{
50 char *end = NULL;
51 int gid = strtod(arg, &end);
52 if (!*end && *arg) {
Luis Hector Chavez71323552017-09-05 09:17:22 -070053 *out_gid = gid;
Elly Jonese1749eb2011-10-07 13:54:59 -040054 minijail_change_gid(j, gid);
55 return;
56 }
Elly Jonescd7a9042011-07-22 13:56:51 -040057
Luis Hector Chavez71323552017-09-05 09:17:22 -070058 if (lookup_group(arg, out_gid)) {
59 fprintf(stderr, "Bad group: '%s'\n", arg);
60 exit(1);
61 }
62
Elly Jonese1749eb2011-10-07 13:54:59 -040063 if (minijail_change_group(j, arg)) {
64 fprintf(stderr, "Bad group: '%s'\n", arg);
65 exit(1);
66 }
Elly Jonescd7a9042011-07-22 13:56:51 -040067}
68
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -070069static void skip_securebits(struct minijail *j, const char *arg)
70{
71 uint64_t securebits_skip_mask;
72 char *end = NULL;
73 securebits_skip_mask = strtoull(arg, &end, 16);
74 if (*end) {
75 fprintf(stderr, "Invalid securebit mask: '%s'\n", arg);
76 exit(1);
77 }
78 minijail_skip_setting_securebits(j, securebits_skip_mask);
79}
80
Elly Jonese1749eb2011-10-07 13:54:59 -040081static void use_caps(struct minijail *j, const char *arg)
82{
83 uint64_t caps;
84 char *end = NULL;
85 caps = strtoull(arg, &end, 16);
86 if (*end) {
87 fprintf(stderr, "Invalid cap set: '%s'\n", arg);
88 exit(1);
89 }
90 minijail_use_caps(j, caps);
Elly Jonescd7a9042011-07-22 13:56:51 -040091}
92
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -070093static void add_binding(struct minijail *j, char *arg)
94{
Elly Jones51a5b6c2011-10-12 19:09:26 -040095 char *src = strtok(arg, ",");
Elly Jones5ba42b52011-12-07 13:31:43 -050096 char *dest = strtok(NULL, ",");
97 char *flags = strtok(NULL, ",");
Elly Jones51a5b6c2011-10-12 19:09:26 -040098 if (!src || !dest) {
99 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
100 exit(1);
101 }
102 if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800103 fprintf(stderr, "minijail_bind failed.\n");
Elly Jones51a5b6c2011-10-12 19:09:26 -0400104 exit(1);
105 }
106}
107
Dylan Reid0f72ef42017-06-06 15:42:49 -0700108static void add_rlimit(struct minijail *j, char *arg)
109{
110 char *type = strtok(arg, ",");
111 char *cur = strtok(NULL, ",");
112 char *max = strtok(NULL, ",");
113 if (!type || !cur || !max) {
114 fprintf(stderr, "Bad rlimit '%s'.\n", arg);
115 exit(1);
116 }
117 if (minijail_rlimit(j, atoi(type), atoi(cur), atoi(max))) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700118 fprintf(stderr, "minijail_rlimit '%s,%s,%s' failed.\n", type,
119 cur, max);
Dylan Reid0f72ef42017-06-06 15:42:49 -0700120 exit(1);
121 }
122}
123
Dylan Reid648b2202015-10-23 00:50:00 -0700124static void add_mount(struct minijail *j, char *arg)
125{
126 char *src = strtok(arg, ",");
127 char *dest = strtok(NULL, ",");
128 char *type = strtok(NULL, ",");
129 char *flags = strtok(NULL, ",");
Dylan Reid81e23972016-05-18 14:06:35 -0700130 char *data = strtok(NULL, ",");
Dylan Reid648b2202015-10-23 00:50:00 -0700131 if (!src || !dest || !type) {
132 fprintf(stderr, "Bad mount: %s %s %s\n", src, dest, type);
133 exit(1);
134 }
Dylan Reid81e23972016-05-18 14:06:35 -0700135 if (minijail_mount_with_data(j, src, dest, type,
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400136 flags ? strtoul(flags, NULL, 16) : 0,
137 data)) {
Dylan Reid648b2202015-10-23 00:50:00 -0700138 fprintf(stderr, "minijail_mount failed.\n");
139 exit(1);
140 }
141}
142
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400143static char *build_idmap(id_t id, id_t lowerid)
144{
145 int ret;
146 char *idmap = malloc(IDMAP_LEN);
147 ret = snprintf(idmap, IDMAP_LEN, "%d %d 1", id, lowerid);
148 if (ret < 0 || (size_t)ret >= IDMAP_LEN) {
149 free(idmap);
150 fprintf(stderr, "Could not build id map.\n");
151 exit(1);
152 }
153 return idmap;
154}
155
Luis Hector Chavez71323552017-09-05 09:17:22 -0700156static int has_cap_setgid()
157{
158 cap_t caps;
159 cap_flag_value_t cap_value;
160
161 if (!CAP_IS_SUPPORTED(CAP_SETGID))
162 return 0;
163
164 caps = cap_get_proc();
165 if (!caps) {
166 fprintf(stderr, "Could not get process' capabilities: %m\n");
167 exit(1);
168 }
169
170 if (cap_get_flag(caps, CAP_SETGID, CAP_EFFECTIVE, &cap_value)) {
171 fprintf(stderr, "Could not get the value of CAP_SETGID: %m\n");
172 exit(1);
173 }
174
175 if (cap_free(caps)) {
176 fprintf(stderr, "Could not free capabilities: %m\n");
177 exit(1);
178 }
179
180 return cap_value == CAP_SET;
181}
182
183static void set_ugid_mapping(struct minijail *j, int set_uidmap, uid_t uid,
184 char *uidmap, int set_gidmap, gid_t gid,
185 char *gidmap)
186{
187 if (set_uidmap) {
188 minijail_namespace_user(j);
189 minijail_namespace_pids(j);
190
191 if (!uidmap) {
192 /*
193 * If no map is passed, map the current uid to the
194 * chosen uid in the target namespace (or root, if none
195 * was chosen).
196 */
197 uidmap = build_idmap(uid, getuid());
198 }
199 if (0 != minijail_uidmap(j, uidmap)) {
200 fprintf(stderr, "Could not set uid map.\n");
201 exit(1);
202 }
203 free(uidmap);
204 }
205 if (set_gidmap) {
206 minijail_namespace_user(j);
207 minijail_namespace_pids(j);
208
209 if (!gidmap) {
210 /*
211 * If no map is passed, map the current gid to the
212 * chosen gid in the target namespace.
213 */
214 gidmap = build_idmap(gid, getgid());
215 }
216 if (!has_cap_setgid()) {
217 /*
218 * This means that we are not running as root,
219 * so we also have to disable setgroups(2) to
220 * be able to set the gid map.
221 * See
222 * http://man7.org/linux/man-pages/man7/user_namespaces.7.html
223 */
224 minijail_namespace_user_disable_setgroups(j);
225 }
226 if (0 != minijail_gidmap(j, gidmap)) {
227 fprintf(stderr, "Could not set gid map.\n");
228 exit(1);
229 }
230 free(gidmap);
231 }
232}
233
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700234static void use_chroot(struct minijail *j, const char *path, int *chroot,
235 int pivot_root)
236{
237 if (pivot_root) {
238 fprintf(stderr, "Could not set chroot because "
239 "'-P' was specified.\n");
240 exit(1);
241 }
242 if (minijail_enter_chroot(j, path)) {
243 fprintf(stderr, "Could not set chroot.\n");
244 exit(1);
245 }
246 *chroot = 1;
247}
248
249static void use_pivot_root(struct minijail *j, const char *path,
250 int *pivot_root, int chroot)
251{
252 if (chroot) {
253 fprintf(stderr, "Could not set pivot_root because "
254 "'-C' was specified.\n");
255 exit(1);
256 }
257 if (minijail_enter_pivot_root(j, path)) {
258 fprintf(stderr, "Could not set pivot_root.\n");
259 exit(1);
260 }
261 minijail_namespace_vfs(j);
262 *pivot_root = 1;
263}
264
265static void use_profile(struct minijail *j, const char *profile,
266 int *pivot_root, int chroot, size_t *tmp_size)
267{
268 if (!strcmp(profile, "minimalistic-mountns")) {
269 minijail_namespace_vfs(j);
270 if (minijail_bind(j, "/", "/", 0)) {
271 fprintf(stderr, "minijail_bind failed.\n");
272 exit(1);
273 }
274 if (minijail_bind(j, "/proc", "/proc", 0)) {
275 fprintf(stderr, "minijail_bind failed.\n");
276 exit(1);
277 }
278 minijail_mount_dev(j);
279 if (!*tmp_size) {
280 /* Avoid clobbering |tmp_size| if it was already set. */
281 *tmp_size = DEFAULT_TMP_SIZE;
282 }
283 minijail_remount_proc_readonly(j);
284 use_pivot_root(j, "/var/empty", pivot_root, chroot);
285 } else {
286 fprintf(stderr, "Unrecognized profile name '%s'\n", profile);
287 exit(1);
288 }
289}
290
Elly Jonese1749eb2011-10-07 13:54:59 -0400291static void usage(const char *progn)
292{
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700293 size_t i;
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700294 /* clang-format off */
Mike Frysinger33ffef32017-01-13 19:53:19 -0500295 printf("Usage: %s [-dGhHiIKlLnNprRstUvyYz]\n"
Jorge Lucangeli Obesa32e8392016-09-01 16:52:40 -0400296 " [-a <table>]\n"
297 " [-b <src>,<dest>[,<writeable>]] [-k <src>,<dest>,<type>[,<flags>][,<data>]]\n"
298 " [-c <caps>] [-C <dir>] [-P <dir>] [-e[file]] [-f <file>] [-g <group>]\n"
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700299 " [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*] [--profile <name>]\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700300 " [-R <type,cur,max>] [-S <file>] [-t[size]] [-T <type>] [-u <user>] [-V <file>]\n"
Jorge Lucangeli Obes9dd256e2016-02-16 15:31:02 -0800301 " <program> [args...]\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400302 " -a <table>: Use alternate syscall table <table>.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400303 " -b <...>: Bind <src> to <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400304 " Multiple instances allowed.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400305 " -B <mask>: Skip setting securebits in <mask> when restricting capabilities (-c).\n"
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700306 " By default, SECURE_NOROOT, SECURE_NO_SETUID_FIXUP, and \n"
307 " SECURE_KEEP_CAPS (together with their respective locks) are set.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400308 " -k <...>: Mount <src> at <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400309 " <flags> and <data> can be specified as in mount(2).\n"
310 " Multiple instances allowed.\n"
311 " -c <caps>: Restrict caps to <caps>.\n"
312 " -C <dir>: chroot(2) to <dir>.\n"
313 " Not compatible with -P.\n"
314 " -P <dir>: pivot_root(2) to <dir> (implies -v).\n"
315 " Not compatible with -C.\n"
Mike Frysinger33ffef32017-01-13 19:53:19 -0500316 " --mount-dev, Create a new /dev with a minimal set of device nodes (implies -v).\n"
Luis Hector Chavezd775f4c2017-10-25 11:36:57 -0700317 " -d: See the minijail0(1) man page for the exact set.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400318 " -e[file]: Enter new network namespace, or existing one if |file| is provided.\n"
319 " -f <file>: Write the pid of the jailed process to <file>.\n"
320 " -g <group>: Change gid to <group>.\n"
321 " -G: Inherit supplementary groups from uid.\n"
322 " Not compatible with -y.\n"
323 " -y: Keep uid's supplementary groups.\n"
324 " Not compatible with -G.\n"
325 " -h: Help (this message).\n"
326 " -H: Seccomp filter help message.\n"
327 " -i: Exit immediately after fork (do not act as init).\n"
328 " -I: Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
329 " -K: Don't mark all existing mounts as MS_PRIVATE.\n"
330 " -l: Enter new IPC namespace.\n"
331 " -L: Report blocked syscalls to syslog when using seccomp filter.\n"
332 " Forces the following syscalls to be allowed:\n"
Kees Cook03b2af22014-12-18 17:11:13 -0800333 " ", progn);
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700334 /* clang-format on */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700335 for (i = 0; i < log_syscalls_len; i++)
336 printf("%s ", log_syscalls[i]);
337
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700338 /* clang-format off */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700339 printf("\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400340 " -m[map]: Set the uid map of a user namespace (implies -pU).\n"
341 " Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
342 " With no mapping, map the current uid to root inside the user namespace.\n"
343 " Not compatible with -b without the 'writable' option.\n"
344 " -M[map]: Set the gid map of a user namespace (implies -pU).\n"
345 " Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
346 " With no mapping, map the current gid to root inside the user namespace.\n"
347 " Not compatible with -b without the 'writable' option.\n"
348 " -n: Set no_new_privs.\n"
349 " -N: Enter a new cgroup namespace.\n"
350 " -p: Enter new pid namespace (implies -vr).\n"
351 " -r: Remount /proc read-only (implies -v).\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700352 " -R: Set rlimits, can be specified multiple times.\n"
Mike Frysingere61fd662017-06-20 14:07:41 -0400353 " -s: Use seccomp mode 1 (not the same as -S).\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400354 " -S <file>: Set seccomp filter using <file>.\n"
355 " E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
356 " Requires -n when not running as root.\n"
357 " -t[size]: Mount tmpfs at /tmp (implies -v).\n"
358 " Optional argument specifies size (default \"64M\").\n"
Graziano Misuraca58602a82017-08-28 17:33:15 -0700359 " -T <type>: Assume <program> is a <type> ELF binary; <type> can be 'static' or 'dynamic'.\n"
360 " This will avoid accessing <program> binary before execve(2).\n"
361 " Type 'static' will avoid preload hooking.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400362 " -u <user>: Change uid to <user>.\n"
363 " -U: Enter new user namespace (implies -p).\n"
364 " -v: Enter new mount namespace.\n"
365 " -V <file>: Enter specified mount namespace.\n"
366 " -w: Create and join a new anonymous session keyring.\n"
367 " -Y: Synchronize seccomp filters across thread group.\n"
368 " -z: Don't forward signals to jailed process.\n"
369 " --ambient: Raise ambient capabilities. Requires -c.\n"
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700370 " --uts[=name]: Enter a new UTS namespace (and set hostname).\n"
371 " --logging=<s>:Use <s> as the logging system.\n"
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700372 " <s> must be 'syslog' (default) or 'stderr'.\n"
373 " --profile <p>,Configure minijail0 to run with the <p> sandboxing profile,\n"
374 " which is a convenient way to express multiple flags\n"
375 " that are typically used together.\n"
376 " See the minijail0(1) man page for the full list.\n");
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700377 /* clang-format on */
Elly Jonescd7a9042011-07-22 13:56:51 -0400378}
379
Elly Jonese1749eb2011-10-07 13:54:59 -0400380static void seccomp_filter_usage(const char *progn)
381{
382 const struct syscall_entry *entry = syscall_table;
383 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400384 "System call names supported:\n",
385 progn);
Elly Jonese1749eb2011-10-07 13:54:59 -0400386 for (; entry->name && entry->nr >= 0; ++entry)
387 printf(" %s [%d]\n", entry->name, entry->nr);
388 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500389}
390
Christopher Wiley88f76a72013-11-01 14:12:56 -0700391static int parse_args(struct minijail *j, int argc, char *argv[],
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800392 int *exit_immediately, ElfType *elftype)
Elly Jonese1749eb2011-10-07 13:54:59 -0400393{
Elly Jonese1749eb2011-10-07 13:54:59 -0400394 int opt;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700395 int use_seccomp_filter = 0;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400396 int forward = 1;
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800397 int binding = 0;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400398 int chroot = 0, pivot_root = 0;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800399 int mount_ns = 0, skip_remount = 0;
Lutz Justen13807cb2017-01-03 17:11:55 +0100400 int inherit_suppl_gids = 0, keep_suppl_gids = 0;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400401 int caps = 0, ambient_caps = 0;
Mike Frysingere61fd662017-06-20 14:07:41 -0400402 int seccomp = -1;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700403 const size_t path_max = 4096;
Luis Hector Chavez71323552017-09-05 09:17:22 -0700404 uid_t uid = 0;
405 gid_t gid = 0;
406 char *uidmap = NULL, *gidmap = NULL;
407 int set_uidmap = 0, set_gidmap = 0;
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700408 size_t tmp_size = 0;
Luis Hector Chavez95582e72017-09-05 09:13:25 -0700409 const char *filter_path = NULL;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700410 int log_to_stderr = 0;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400411
412 const char *optstring =
Mike Frysinger33ffef32017-01-13 19:53:19 -0500413 "+u:g:sS:c:C:P:b:B:V:f:m::M::k:a:e::R:T:vrGhHinNplLt::IUKwyYzd";
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400414 /* clang-format off */
415 const struct option long_options[] = {
Mike Frysinger227c2912017-10-04 14:27:04 -0400416 {"help", no_argument, 0, 'h'},
Mike Frysinger33ffef32017-01-13 19:53:19 -0500417 {"mount-dev", no_argument, 0, 'd'},
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400418 {"ambient", no_argument, 0, 128},
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400419 {"uts", optional_argument, 0, 129},
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700420 {"logging", required_argument, 0, 130},
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700421 {"profile", required_argument, 0, 131},
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400422 {0, 0, 0, 0},
423 };
424 /* clang-format on */
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400425
Mike Frysinger99becbd2017-10-04 14:26:52 -0400426 while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) !=
427 -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400428 switch (opt) {
429 case 'u':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700430 set_user(j, optarg, &uid, &gid);
Elly Jonese1749eb2011-10-07 13:54:59 -0400431 break;
432 case 'g':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700433 set_group(j, optarg, &gid);
Elly Jonese1749eb2011-10-07 13:54:59 -0400434 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700435 case 'n':
436 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700437 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400438 case 's':
Mike Frysingere61fd662017-06-20 14:07:41 -0400439 if (seccomp != -1 && seccomp != 1) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700440 fprintf(stderr,
441 "Do not use -s & -S together.\n");
Mike Frysingere61fd662017-06-20 14:07:41 -0400442 exit(1);
443 }
444 seccomp = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400445 minijail_use_seccomp(j);
446 break;
447 case 'S':
Mike Frysingere61fd662017-06-20 14:07:41 -0400448 if (seccomp != -1 && seccomp != 2) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700449 fprintf(stderr,
450 "Do not use -s & -S together.\n");
Mike Frysingere61fd662017-06-20 14:07:41 -0400451 exit(1);
452 }
453 seccomp = 2;
Elly Jonese1749eb2011-10-07 13:54:59 -0400454 minijail_use_seccomp_filter(j);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700455 if (strlen(optarg) >= path_max) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800456 fprintf(stderr, "Filter path is too long.\n");
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700457 exit(1);
458 }
459 filter_path = strndup(optarg, path_max);
460 if (!filter_path) {
461 fprintf(stderr,
462 "Could not strndup(3) filter path.\n");
463 exit(1);
464 }
465 use_seccomp_filter = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400466 break;
Dylan Reidf7942472015-11-18 17:55:26 -0800467 case 'l':
468 minijail_namespace_ipc(j);
469 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700470 case 'L':
471 minijail_log_seccomp_filter_failures(j);
472 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400473 case 'b':
474 add_binding(j, optarg);
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800475 binding = 1;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400476 break;
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700477 case 'B':
478 skip_securebits(j, optarg);
479 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400480 case 'c':
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400481 caps = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400482 use_caps(j, optarg);
483 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400484 case 'C':
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700485 use_chroot(j, optarg, &chroot, pivot_root);
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800486 break;
Dylan Reid648b2202015-10-23 00:50:00 -0700487 case 'k':
488 add_mount(j, optarg);
489 break;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800490 case 'K':
491 minijail_skip_remount_private(j);
492 skip_remount = 1;
493 break;
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800494 case 'P':
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700495 use_pivot_root(j, optarg, &pivot_root, chroot);
Lee Campbell11af0622014-05-22 12:36:04 -0700496 break;
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800497 case 'f':
498 if (0 != minijail_write_pid_file(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800499 fprintf(stderr,
500 "Could not prepare pid file path.\n");
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800501 exit(1);
502 }
503 break;
Lee Campbell11af0622014-05-22 12:36:04 -0700504 case 't':
Mike Frysingerec7def22017-01-13 18:44:45 -0500505 minijail_namespace_vfs(j);
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700506 if (!tmp_size) {
507 /*
508 * Avoid clobbering |tmp_size| if it was already
509 * set.
510 */
511 tmp_size = DEFAULT_TMP_SIZE;
512 }
513 if (optarg != NULL &&
514 0 != parse_size(&tmp_size, optarg)) {
Martin Pelikánab9eb442017-01-25 11:53:58 +1100515 fprintf(stderr, "Invalid /tmp tmpfs size.\n");
516 exit(1);
517 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400518 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400519 case 'v':
520 minijail_namespace_vfs(j);
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800521 mount_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400522 break;
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700523 case 'V':
524 minijail_namespace_enter_vfs(j, optarg);
525 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400526 case 'r':
Dylan Reid791f5772015-09-14 20:02:42 -0700527 minijail_remount_proc_readonly(j);
Elly Jonese1749eb2011-10-07 13:54:59 -0400528 break;
529 case 'G':
Lutz Justen13807cb2017-01-03 17:11:55 +0100530 if (keep_suppl_gids) {
531 fprintf(stderr,
532 "-y and -G are not compatible.\n");
533 exit(1);
534 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400535 minijail_inherit_usergroups(j);
Lutz Justen13807cb2017-01-03 17:11:55 +0100536 inherit_suppl_gids = 1;
537 break;
538 case 'y':
539 if (inherit_suppl_gids) {
540 fprintf(stderr,
541 "-y and -G are not compatible.\n");
542 exit(1);
543 }
544 minijail_keep_supplementary_gids(j);
545 keep_suppl_gids = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400546 break;
Dylan Reid4cbc2a52016-06-17 19:06:07 -0700547 case 'N':
548 minijail_namespace_cgroups(j);
549 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400550 case 'p':
551 minijail_namespace_pids(j);
552 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400553 case 'e':
Dylan Reid1102f5a2015-09-15 11:52:20 -0700554 if (optarg)
555 minijail_namespace_enter_net(j, optarg);
556 else
557 minijail_namespace_net(j);
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400558 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700559 case 'i':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700560 *exit_immediately = 1;
561 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400562 case 'H':
563 seccomp_filter_usage(argv[0]);
564 exit(1);
Yu-Hsi Chiang3e954ec2015-07-28 16:48:14 +0800565 case 'I':
566 minijail_namespace_pids(j);
567 minijail_run_as_init(j);
568 break;
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800569 case 'U':
570 minijail_namespace_user(j);
571 minijail_namespace_pids(j);
572 break;
573 case 'm':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700574 set_uidmap = 1;
575 if (uidmap) {
576 free(uidmap);
577 uidmap = NULL;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400578 }
Luis Hector Chavez71323552017-09-05 09:17:22 -0700579 if (optarg)
580 uidmap = strdup(optarg);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800581 break;
582 case 'M':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700583 set_gidmap = 1;
584 if (gidmap) {
585 free(gidmap);
586 gidmap = NULL;
Jorge Lucangeli Obes200299c2016-09-23 15:21:57 -0400587 }
Luis Hector Chavez71323552017-09-05 09:17:22 -0700588 if (optarg)
589 gidmap = strdup(optarg);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800590 break;
Andrew Brestickereac28942015-11-11 16:04:46 -0800591 case 'a':
592 if (0 != minijail_use_alt_syscall(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800593 fprintf(stderr,
594 "Could not set alt-syscall table.\n");
Andrew Brestickereac28942015-11-11 16:04:46 -0800595 exit(1);
596 }
597 break;
Dylan Reid0f72ef42017-06-06 15:42:49 -0700598 case 'R':
599 add_rlimit(j, optarg);
600 break;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800601 case 'T':
602 if (!strcmp(optarg, "static"))
603 *elftype = ELFSTATIC;
604 else if (!strcmp(optarg, "dynamic"))
605 *elftype = ELFDYNAMIC;
606 else {
Jorge Lucangeli Obes768d42b2016-02-17 10:28:25 -0800607 fprintf(stderr, "ELF type must be 'static' or "
608 "'dynamic'.\n");
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800609 exit(1);
610 }
611 break;
Chirantan Ekbote866bb3a2017-02-07 12:26:42 -0800612 case 'w':
613 minijail_new_session_keyring(j);
614 break;
Jorge Lucangeli Obes13650612016-09-02 11:27:29 -0400615 case 'Y':
616 minijail_set_seccomp_filter_tsync(j);
617 break;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400618 case 'z':
619 forward = 0;
620 break;
Mike Frysinger33ffef32017-01-13 19:53:19 -0500621 case 'd':
622 minijail_namespace_vfs(j);
623 minijail_mount_dev(j);
624 break;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400625 /* Long options. */
626 case 128: /* Ambient caps. */
627 ambient_caps = 1;
628 minijail_set_ambient_caps(j);
629 break;
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400630 case 129: /* UTS/hostname namespace. */
631 minijail_namespace_uts(j);
632 if (optarg)
633 minijail_namespace_set_hostname(j, optarg);
634 break;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700635 case 130: /* Logging. */
636 if (!strcmp(optarg, "syslog"))
637 log_to_stderr = 0;
638 else if (!strcmp(optarg, "stderr")) {
639 log_to_stderr = 1;
640 } else {
641 fprintf(stderr, "--logger must be 'syslog' or "
642 "'stderr'.\n");
643 exit(1);
644 }
645 break;
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700646 case 131: /* Profile */
647 use_profile(j, optarg, &pivot_root, chroot, &tmp_size);
648 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400649 default:
650 usage(argv[0]);
Mike Frysinger227c2912017-10-04 14:27:04 -0400651 exit(opt == 'h' ? 0 : 1);
Elly Jonese1749eb2011-10-07 13:54:59 -0400652 }
653 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400654
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700655 if (log_to_stderr) {
656 init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
657 /*
658 * When logging to stderr, ensure the FD survives the jailing.
659 */
660 if (0 !=
661 minijail_preserve_fd(j, STDERR_FILENO, STDERR_FILENO)) {
662 fprintf(stderr, "Could not preserve stderr.\n");
663 exit(1);
664 }
665 }
666
Luis Hector Chavez71323552017-09-05 09:17:22 -0700667 /* Set up uid/gid mapping. */
668 if (set_uidmap || set_gidmap) {
669 set_ugid_mapping(j, set_uidmap, uid, uidmap, set_gidmap, gid,
670 gidmap);
671 }
672
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400673 /* Can only set ambient caps when using regular caps. */
674 if (ambient_caps && !caps) {
675 fprintf(stderr, "Can't set ambient capabilities (--ambient) "
676 "without actually using capabilities (-c).\n");
677 exit(1);
678 }
679
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400680 /* Set up signal handlers in minijail unless asked not to. */
681 if (forward)
682 minijail_forward_signals(j);
683
Mike Frysingerac08a682017-10-10 02:04:50 -0400684 /*
685 * Only allow bind mounts when entering a chroot, using pivot_root, or
686 * a new mount namespace.
687 */
688 if (binding && !(chroot || pivot_root || mount_ns)) {
689 fprintf(stderr, "Bind mounts require a chroot, pivot_root, or "
690 " new mount namespace.\n");
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800691 exit(1);
692 }
693
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700694 /*
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800695 * Remounting / as MS_PRIVATE only happens when entering a new mount
696 * namespace, so skipping it only applies in that case.
697 */
698 if (skip_remount && !mount_ns) {
699 fprintf(stderr, "Can't skip marking mounts as MS_PRIVATE"
700 " without mount namespaces.\n");
701 exit(1);
702 }
703
704 /*
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700705 * We parse seccomp filters here to make sure we've collected all
706 * cmdline options.
707 */
708 if (use_seccomp_filter) {
709 minijail_parse_seccomp_filters(j, filter_path);
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400710 free((void *)filter_path);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700711 }
712
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700713 /* Mount a tmpfs under /tmp and set its size. */
714 if (tmp_size)
715 minijail_mount_tmp_size(j, tmp_size);
716
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700717 /*
718 * There should be at least one additional unparsed argument: the
719 * executable name.
720 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400721 if (argc == optind) {
722 usage(argv[0]);
723 exit(1);
724 }
Lee Campbell11af0622014-05-22 12:36:04 -0700725
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700726 if (*elftype == ELFERROR) {
727 /*
728 * -T was not specified.
729 * Get the path to the program adjusted for changing root.
730 */
731 char *program_path =
732 minijail_get_original_path(j, argv[optind]);
733
734 /* Check that we can access the target program. */
735 if (access(program_path, X_OK)) {
736 fprintf(stderr,
737 "Target program '%s' is not accessible.\n",
738 argv[optind]);
739 exit(1);
740 }
741
742 /* Check if target is statically or dynamically linked. */
743 *elftype = get_elf_linkage(program_path);
744 free(program_path);
745 }
746
747 /*
748 * Setting capabilities need either a dynamically-linked binary, or the
749 * use of ambient capabilities for them to be able to survive an
750 * execve(2).
751 */
752 if (caps && *elftype == ELFSTATIC && !ambient_caps) {
753 fprintf(stderr, "Can't run statically-linked binaries with "
754 "capabilities (-c) without also setting "
755 "ambient capabilities. Try passing "
756 "--ambient.\n");
757 exit(1);
758 }
759
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500760 return optind;
761}
Elly Jonescd7a9042011-07-22 13:56:51 -0400762
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500763int main(int argc, char *argv[])
764{
765 struct minijail *j = minijail_new();
Jorge Lucangeli Obesd99a40d2016-01-26 13:50:44 -0800766 const char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700767 int exit_immediately = 0;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700768 ElfType elftype = ELFERROR;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800769 int consumed = parse_args(j, argc, argv, &exit_immediately, &elftype);
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500770 argc -= consumed;
771 argv += consumed;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700772
Stephen Barber5dd5b1b2017-10-16 23:02:39 -0700773 /*
774 * Make the process group ID of this process equal to its PID.
775 * In the non-interactive case (e.g. when minijail0 is started from
776 * init) this ensures the parent process and the jailed process
777 * can be killed together.
778 *
779 * Don't fail on EPERM, since setpgid(0, 0) can only EPERM when
780 * the process is already a process group leader.
781 */
782 if (setpgid(0 /* use calling PID */, 0 /* make PGID = PID */)) {
783 if (errno != EPERM) {
784 fprintf(stderr, "setpgid(0, 0) failed\n");
785 exit(1);
786 }
787 }
788
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700789 if (elftype == ELFSTATIC) {
Jorge Lucangeli Obes54714502015-09-30 10:08:45 -0700790 /*
791 * Target binary is statically linked so we cannot use
792 * libminijailpreload.so.
793 */
794 minijail_run_no_preload(j, argv[0], argv);
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700795 } else if (elftype == ELFDYNAMIC) {
796 /*
797 * Target binary is dynamically linked so we can
798 * inject libminijailpreload.so into it.
799 */
800
801 /* Check that we can dlopen() libminijailpreload.so. */
802 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800803 dl_mesg = dlerror();
804 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
805 return 1;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700806 }
807 minijail_run(j, argv[0], argv);
808 } else {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -0700809 fprintf(stderr,
810 "Target program '%s' is not a valid ELF file.\n",
811 argv[0]);
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800812 return 1;
813 }
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700814
Christopher Wiley88f76a72013-11-01 14:12:56 -0700815 if (exit_immediately) {
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700816 info("not running init loop, exiting immediately\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700817 return 0;
818 }
lhchavez6c8d8202017-09-01 03:55:11 +0000819 int ret = minijail_wait(j);
820#if defined(__SANITIZE_ADDRESS__)
821 minijail_destroy(j);
822#endif /* __SANITIZE_ADDRESS__ */
823 return ret;
Elly Jonescd7a9042011-07-22 13:56:51 -0400824}