blob: 32995ab6864d3d4e06bfc19768a2feae25814e8a [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, ",");
Mike Frysinger8f0665b2018-01-17 14:26:09 -050098 if (!src) {
Elly Jones51a5b6c2011-10-12 19:09:26 -040099 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
100 exit(1);
101 }
Mike Frysinger8f0665b2018-01-17 14:26:09 -0500102 if (!dest)
103 dest = src;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400104 if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800105 fprintf(stderr, "minijail_bind failed.\n");
Elly Jones51a5b6c2011-10-12 19:09:26 -0400106 exit(1);
107 }
108}
109
Dylan Reid0f72ef42017-06-06 15:42:49 -0700110static void add_rlimit(struct minijail *j, char *arg)
111{
112 char *type = strtok(arg, ",");
113 char *cur = strtok(NULL, ",");
114 char *max = strtok(NULL, ",");
115 if (!type || !cur || !max) {
116 fprintf(stderr, "Bad rlimit '%s'.\n", arg);
117 exit(1);
118 }
119 if (minijail_rlimit(j, atoi(type), atoi(cur), atoi(max))) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700120 fprintf(stderr, "minijail_rlimit '%s,%s,%s' failed.\n", type,
121 cur, max);
Dylan Reid0f72ef42017-06-06 15:42:49 -0700122 exit(1);
123 }
124}
125
Dylan Reid648b2202015-10-23 00:50:00 -0700126static void add_mount(struct minijail *j, char *arg)
127{
128 char *src = strtok(arg, ",");
129 char *dest = strtok(NULL, ",");
130 char *type = strtok(NULL, ",");
131 char *flags = strtok(NULL, ",");
Dylan Reid81e23972016-05-18 14:06:35 -0700132 char *data = strtok(NULL, ",");
Dylan Reid648b2202015-10-23 00:50:00 -0700133 if (!src || !dest || !type) {
134 fprintf(stderr, "Bad mount: %s %s %s\n", src, dest, type);
135 exit(1);
136 }
Dylan Reid81e23972016-05-18 14:06:35 -0700137 if (minijail_mount_with_data(j, src, dest, type,
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400138 flags ? strtoul(flags, NULL, 16) : 0,
139 data)) {
Dylan Reid648b2202015-10-23 00:50:00 -0700140 fprintf(stderr, "minijail_mount failed.\n");
141 exit(1);
142 }
143}
144
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400145static char *build_idmap(id_t id, id_t lowerid)
146{
147 int ret;
148 char *idmap = malloc(IDMAP_LEN);
149 ret = snprintf(idmap, IDMAP_LEN, "%d %d 1", id, lowerid);
150 if (ret < 0 || (size_t)ret >= IDMAP_LEN) {
151 free(idmap);
152 fprintf(stderr, "Could not build id map.\n");
153 exit(1);
154 }
155 return idmap;
156}
157
Luis Hector Chavez71323552017-09-05 09:17:22 -0700158static int has_cap_setgid()
159{
160 cap_t caps;
161 cap_flag_value_t cap_value;
162
163 if (!CAP_IS_SUPPORTED(CAP_SETGID))
164 return 0;
165
166 caps = cap_get_proc();
167 if (!caps) {
168 fprintf(stderr, "Could not get process' capabilities: %m\n");
169 exit(1);
170 }
171
172 if (cap_get_flag(caps, CAP_SETGID, CAP_EFFECTIVE, &cap_value)) {
173 fprintf(stderr, "Could not get the value of CAP_SETGID: %m\n");
174 exit(1);
175 }
176
177 if (cap_free(caps)) {
178 fprintf(stderr, "Could not free capabilities: %m\n");
179 exit(1);
180 }
181
182 return cap_value == CAP_SET;
183}
184
185static void set_ugid_mapping(struct minijail *j, int set_uidmap, uid_t uid,
186 char *uidmap, int set_gidmap, gid_t gid,
187 char *gidmap)
188{
189 if (set_uidmap) {
190 minijail_namespace_user(j);
191 minijail_namespace_pids(j);
192
193 if (!uidmap) {
194 /*
195 * If no map is passed, map the current uid to the
196 * chosen uid in the target namespace (or root, if none
197 * was chosen).
198 */
199 uidmap = build_idmap(uid, getuid());
200 }
201 if (0 != minijail_uidmap(j, uidmap)) {
202 fprintf(stderr, "Could not set uid map.\n");
203 exit(1);
204 }
205 free(uidmap);
206 }
207 if (set_gidmap) {
208 minijail_namespace_user(j);
209 minijail_namespace_pids(j);
210
211 if (!gidmap) {
212 /*
213 * If no map is passed, map the current gid to the
214 * chosen gid in the target namespace.
215 */
216 gidmap = build_idmap(gid, getgid());
217 }
218 if (!has_cap_setgid()) {
219 /*
220 * This means that we are not running as root,
221 * so we also have to disable setgroups(2) to
222 * be able to set the gid map.
223 * See
224 * http://man7.org/linux/man-pages/man7/user_namespaces.7.html
225 */
226 minijail_namespace_user_disable_setgroups(j);
227 }
228 if (0 != minijail_gidmap(j, gidmap)) {
229 fprintf(stderr, "Could not set gid map.\n");
230 exit(1);
231 }
232 free(gidmap);
233 }
234}
235
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700236static void use_chroot(struct minijail *j, const char *path, int *chroot,
237 int pivot_root)
238{
239 if (pivot_root) {
240 fprintf(stderr, "Could not set chroot because "
241 "'-P' was specified.\n");
242 exit(1);
243 }
244 if (minijail_enter_chroot(j, path)) {
245 fprintf(stderr, "Could not set chroot.\n");
246 exit(1);
247 }
248 *chroot = 1;
249}
250
251static void use_pivot_root(struct minijail *j, const char *path,
252 int *pivot_root, int chroot)
253{
254 if (chroot) {
255 fprintf(stderr, "Could not set pivot_root because "
256 "'-C' was specified.\n");
257 exit(1);
258 }
259 if (minijail_enter_pivot_root(j, path)) {
260 fprintf(stderr, "Could not set pivot_root.\n");
261 exit(1);
262 }
263 minijail_namespace_vfs(j);
264 *pivot_root = 1;
265}
266
267static void use_profile(struct minijail *j, const char *profile,
268 int *pivot_root, int chroot, size_t *tmp_size)
269{
270 if (!strcmp(profile, "minimalistic-mountns")) {
271 minijail_namespace_vfs(j);
272 if (minijail_bind(j, "/", "/", 0)) {
273 fprintf(stderr, "minijail_bind failed.\n");
274 exit(1);
275 }
276 if (minijail_bind(j, "/proc", "/proc", 0)) {
277 fprintf(stderr, "minijail_bind failed.\n");
278 exit(1);
279 }
280 minijail_mount_dev(j);
281 if (!*tmp_size) {
282 /* Avoid clobbering |tmp_size| if it was already set. */
283 *tmp_size = DEFAULT_TMP_SIZE;
284 }
285 minijail_remount_proc_readonly(j);
286 use_pivot_root(j, "/var/empty", pivot_root, chroot);
287 } else {
288 fprintf(stderr, "Unrecognized profile name '%s'\n", profile);
289 exit(1);
290 }
291}
292
Elly Jonese1749eb2011-10-07 13:54:59 -0400293static void usage(const char *progn)
294{
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700295 size_t i;
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700296 /* clang-format off */
Mike Frysinger33ffef32017-01-13 19:53:19 -0500297 printf("Usage: %s [-dGhHiIKlLnNprRstUvyYz]\n"
Jorge Lucangeli Obesa32e8392016-09-01 16:52:40 -0400298 " [-a <table>]\n"
Mike Frysinger8f0665b2018-01-17 14:26:09 -0500299 " [-b <src>[,<dest>[,<writeable>]]] [-k <src>,<dest>,<type>[,<flags>][,<data>]]\n"
Jorge Lucangeli Obesa32e8392016-09-01 16:52:40 -0400300 " [-c <caps>] [-C <dir>] [-P <dir>] [-e[file]] [-f <file>] [-g <group>]\n"
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700301 " [-m[<uid> <loweruid> <count>]*] [-M[<gid> <lowergid> <count>]*] [--profile <name>]\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700302 " [-R <type,cur,max>] [-S <file>] [-t[size]] [-T <type>] [-u <user>] [-V <file>]\n"
Jorge Lucangeli Obes9dd256e2016-02-16 15:31:02 -0800303 " <program> [args...]\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400304 " -a <table>: Use alternate syscall table <table>.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400305 " -b <...>: Bind <src> to <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400306 " Multiple instances allowed.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400307 " -B <mask>: Skip setting securebits in <mask> when restricting capabilities (-c).\n"
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700308 " By default, SECURE_NOROOT, SECURE_NO_SETUID_FIXUP, and \n"
309 " SECURE_KEEP_CAPS (together with their respective locks) are set.\n"
Mike Frysingereaab4202017-08-14 14:57:21 -0400310 " -k <...>: Mount <src> at <dest> in chroot.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400311 " <flags> and <data> can be specified as in mount(2).\n"
312 " Multiple instances allowed.\n"
313 " -c <caps>: Restrict caps to <caps>.\n"
314 " -C <dir>: chroot(2) to <dir>.\n"
315 " Not compatible with -P.\n"
316 " -P <dir>: pivot_root(2) to <dir> (implies -v).\n"
317 " Not compatible with -C.\n"
Mike Frysinger33ffef32017-01-13 19:53:19 -0500318 " --mount-dev, Create a new /dev with a minimal set of device nodes (implies -v).\n"
Luis Hector Chavezd775f4c2017-10-25 11:36:57 -0700319 " -d: See the minijail0(1) man page for the exact set.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400320 " -e[file]: Enter new network namespace, or existing one if |file| is provided.\n"
321 " -f <file>: Write the pid of the jailed process to <file>.\n"
322 " -g <group>: Change gid to <group>.\n"
323 " -G: Inherit supplementary groups from uid.\n"
324 " Not compatible with -y.\n"
325 " -y: Keep uid's supplementary groups.\n"
326 " Not compatible with -G.\n"
327 " -h: Help (this message).\n"
328 " -H: Seccomp filter help message.\n"
329 " -i: Exit immediately after fork (do not act as init).\n"
330 " -I: Run <program> as init (pid 1) inside a new pid namespace (implies -p).\n"
331 " -K: Don't mark all existing mounts as MS_PRIVATE.\n"
332 " -l: Enter new IPC namespace.\n"
333 " -L: Report blocked syscalls to syslog when using seccomp filter.\n"
334 " Forces the following syscalls to be allowed:\n"
Kees Cook03b2af22014-12-18 17:11:13 -0800335 " ", progn);
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700336 /* clang-format on */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700337 for (i = 0; i < log_syscalls_len; i++)
338 printf("%s ", log_syscalls[i]);
339
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700340 /* clang-format off */
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700341 printf("\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400342 " -m[map]: Set the uid map of a user namespace (implies -pU).\n"
343 " Same arguments as newuidmap(1), multiple mappings should be separated by ',' (comma).\n"
344 " With no mapping, map the current uid to root inside the user namespace.\n"
345 " Not compatible with -b without the 'writable' option.\n"
346 " -M[map]: Set the gid map of a user namespace (implies -pU).\n"
347 " Same arguments as newgidmap(1), multiple mappings should be separated by ',' (comma).\n"
348 " With no mapping, map the current gid to root inside the user namespace.\n"
349 " Not compatible with -b without the 'writable' option.\n"
350 " -n: Set no_new_privs.\n"
351 " -N: Enter a new cgroup namespace.\n"
352 " -p: Enter new pid namespace (implies -vr).\n"
353 " -r: Remount /proc read-only (implies -v).\n"
Dylan Reid0f72ef42017-06-06 15:42:49 -0700354 " -R: Set rlimits, can be specified multiple times.\n"
Mike Frysingere61fd662017-06-20 14:07:41 -0400355 " -s: Use seccomp mode 1 (not the same as -S).\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400356 " -S <file>: Set seccomp filter using <file>.\n"
357 " E.g., '-S /usr/share/filters/<prog>.$(uname -m)'.\n"
358 " Requires -n when not running as root.\n"
359 " -t[size]: Mount tmpfs at /tmp (implies -v).\n"
360 " Optional argument specifies size (default \"64M\").\n"
Graziano Misuraca58602a82017-08-28 17:33:15 -0700361 " -T <type>: Assume <program> is a <type> ELF binary; <type> can be 'static' or 'dynamic'.\n"
362 " This will avoid accessing <program> binary before execve(2).\n"
363 " Type 'static' will avoid preload hooking.\n"
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400364 " -u <user>: Change uid to <user>.\n"
365 " -U: Enter new user namespace (implies -p).\n"
366 " -v: Enter new mount namespace.\n"
367 " -V <file>: Enter specified mount namespace.\n"
368 " -w: Create and join a new anonymous session keyring.\n"
369 " -Y: Synchronize seccomp filters across thread group.\n"
370 " -z: Don't forward signals to jailed process.\n"
371 " --ambient: Raise ambient capabilities. Requires -c.\n"
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700372 " --uts[=name]: Enter a new UTS namespace (and set hostname).\n"
373 " --logging=<s>:Use <s> as the logging system.\n"
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700374 " <s> must be 'syslog' (default) or 'stderr'.\n"
375 " --profile <p>,Configure minijail0 to run with the <p> sandboxing profile,\n"
376 " which is a convenient way to express multiple flags\n"
377 " that are typically used together.\n"
378 " See the minijail0(1) man page for the full list.\n");
Luis Hector Chavezfb449ab2016-10-14 09:49:22 -0700379 /* clang-format on */
Elly Jonescd7a9042011-07-22 13:56:51 -0400380}
381
Elly Jonese1749eb2011-10-07 13:54:59 -0400382static void seccomp_filter_usage(const char *progn)
383{
384 const struct syscall_entry *entry = syscall_table;
385 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400386 "System call names supported:\n",
387 progn);
Elly Jonese1749eb2011-10-07 13:54:59 -0400388 for (; entry->name && entry->nr >= 0; ++entry)
389 printf(" %s [%d]\n", entry->name, entry->nr);
390 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500391}
392
Christopher Wiley88f76a72013-11-01 14:12:56 -0700393static int parse_args(struct minijail *j, int argc, char *argv[],
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800394 int *exit_immediately, ElfType *elftype)
Elly Jonese1749eb2011-10-07 13:54:59 -0400395{
Elly Jonese1749eb2011-10-07 13:54:59 -0400396 int opt;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700397 int use_seccomp_filter = 0;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400398 int forward = 1;
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800399 int binding = 0;
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400400 int chroot = 0, pivot_root = 0;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800401 int mount_ns = 0, skip_remount = 0;
Lutz Justen13807cb2017-01-03 17:11:55 +0100402 int inherit_suppl_gids = 0, keep_suppl_gids = 0;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400403 int caps = 0, ambient_caps = 0;
Mike Frysingere61fd662017-06-20 14:07:41 -0400404 int seccomp = -1;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700405 const size_t path_max = 4096;
Luis Hector Chavez71323552017-09-05 09:17:22 -0700406 uid_t uid = 0;
407 gid_t gid = 0;
408 char *uidmap = NULL, *gidmap = NULL;
409 int set_uidmap = 0, set_gidmap = 0;
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700410 size_t tmp_size = 0;
Luis Hector Chavez95582e72017-09-05 09:13:25 -0700411 const char *filter_path = NULL;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700412 int log_to_stderr = 0;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400413
414 const char *optstring =
Mike Frysinger33ffef32017-01-13 19:53:19 -0500415 "+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 -0400416 /* clang-format off */
417 const struct option long_options[] = {
Mike Frysinger227c2912017-10-04 14:27:04 -0400418 {"help", no_argument, 0, 'h'},
Mike Frysinger33ffef32017-01-13 19:53:19 -0500419 {"mount-dev", no_argument, 0, 'd'},
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400420 {"ambient", no_argument, 0, 128},
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400421 {"uts", optional_argument, 0, 129},
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700422 {"logging", required_argument, 0, 130},
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700423 {"profile", required_argument, 0, 131},
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400424 {0, 0, 0, 0},
425 };
426 /* clang-format on */
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400427
Mike Frysinger99becbd2017-10-04 14:26:52 -0400428 while ((opt = getopt_long(argc, argv, optstring, long_options, NULL)) !=
429 -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400430 switch (opt) {
431 case 'u':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700432 set_user(j, optarg, &uid, &gid);
Elly Jonese1749eb2011-10-07 13:54:59 -0400433 break;
434 case 'g':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700435 set_group(j, optarg, &gid);
Elly Jonese1749eb2011-10-07 13:54:59 -0400436 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700437 case 'n':
438 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700439 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400440 case 's':
Mike Frysingere61fd662017-06-20 14:07:41 -0400441 if (seccomp != -1 && seccomp != 1) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700442 fprintf(stderr,
443 "Do not use -s & -S together.\n");
Mike Frysingere61fd662017-06-20 14:07:41 -0400444 exit(1);
445 }
446 seccomp = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400447 minijail_use_seccomp(j);
448 break;
449 case 'S':
Mike Frysingere61fd662017-06-20 14:07:41 -0400450 if (seccomp != -1 && seccomp != 2) {
Luis Hector Chavez71323552017-09-05 09:17:22 -0700451 fprintf(stderr,
452 "Do not use -s & -S together.\n");
Mike Frysingere61fd662017-06-20 14:07:41 -0400453 exit(1);
454 }
455 seccomp = 2;
Elly Jonese1749eb2011-10-07 13:54:59 -0400456 minijail_use_seccomp_filter(j);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700457 if (strlen(optarg) >= path_max) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800458 fprintf(stderr, "Filter path is too long.\n");
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700459 exit(1);
460 }
461 filter_path = strndup(optarg, path_max);
462 if (!filter_path) {
463 fprintf(stderr,
464 "Could not strndup(3) filter path.\n");
465 exit(1);
466 }
467 use_seccomp_filter = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400468 break;
Dylan Reidf7942472015-11-18 17:55:26 -0800469 case 'l':
470 minijail_namespace_ipc(j);
471 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700472 case 'L':
473 minijail_log_seccomp_filter_failures(j);
474 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400475 case 'b':
476 add_binding(j, optarg);
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800477 binding = 1;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400478 break;
Luis Hector Chavezec0a2c12017-06-29 20:29:57 -0700479 case 'B':
480 skip_securebits(j, optarg);
481 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400482 case 'c':
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400483 caps = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400484 use_caps(j, optarg);
485 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400486 case 'C':
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700487 use_chroot(j, optarg, &chroot, pivot_root);
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800488 break;
Dylan Reid648b2202015-10-23 00:50:00 -0700489 case 'k':
490 add_mount(j, optarg);
491 break;
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800492 case 'K':
493 minijail_skip_remount_private(j);
494 skip_remount = 1;
495 break;
Yu-Hsi Chiang64d65a72015-08-13 17:43:27 +0800496 case 'P':
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700497 use_pivot_root(j, optarg, &pivot_root, chroot);
Lee Campbell11af0622014-05-22 12:36:04 -0700498 break;
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800499 case 'f':
500 if (0 != minijail_write_pid_file(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800501 fprintf(stderr,
502 "Could not prepare pid file path.\n");
Yu-Hsi Chiang3cc05ea2015-08-11 11:23:17 +0800503 exit(1);
504 }
505 break;
Lee Campbell11af0622014-05-22 12:36:04 -0700506 case 't':
Mike Frysingerec7def22017-01-13 18:44:45 -0500507 minijail_namespace_vfs(j);
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700508 if (!tmp_size) {
509 /*
510 * Avoid clobbering |tmp_size| if it was already
511 * set.
512 */
513 tmp_size = DEFAULT_TMP_SIZE;
514 }
515 if (optarg != NULL &&
516 0 != parse_size(&tmp_size, optarg)) {
Martin Pelikánab9eb442017-01-25 11:53:58 +1100517 fprintf(stderr, "Invalid /tmp tmpfs size.\n");
518 exit(1);
519 }
Elly Jones51a5b6c2011-10-12 19:09:26 -0400520 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400521 case 'v':
522 minijail_namespace_vfs(j);
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800523 mount_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400524 break;
Jorge Lucangeli Obes1563b5b2014-07-10 07:01:53 -0700525 case 'V':
526 minijail_namespace_enter_vfs(j, optarg);
527 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400528 case 'r':
Dylan Reid791f5772015-09-14 20:02:42 -0700529 minijail_remount_proc_readonly(j);
Elly Jonese1749eb2011-10-07 13:54:59 -0400530 break;
531 case 'G':
Lutz Justen13807cb2017-01-03 17:11:55 +0100532 if (keep_suppl_gids) {
533 fprintf(stderr,
534 "-y and -G are not compatible.\n");
535 exit(1);
536 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400537 minijail_inherit_usergroups(j);
Lutz Justen13807cb2017-01-03 17:11:55 +0100538 inherit_suppl_gids = 1;
539 break;
540 case 'y':
541 if (inherit_suppl_gids) {
542 fprintf(stderr,
543 "-y and -G are not compatible.\n");
544 exit(1);
545 }
546 minijail_keep_supplementary_gids(j);
547 keep_suppl_gids = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400548 break;
Dylan Reid4cbc2a52016-06-17 19:06:07 -0700549 case 'N':
550 minijail_namespace_cgroups(j);
551 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400552 case 'p':
553 minijail_namespace_pids(j);
554 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400555 case 'e':
Dylan Reid1102f5a2015-09-15 11:52:20 -0700556 if (optarg)
557 minijail_namespace_enter_net(j, optarg);
558 else
559 minijail_namespace_net(j);
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400560 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700561 case 'i':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700562 *exit_immediately = 1;
563 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400564 case 'H':
565 seccomp_filter_usage(argv[0]);
566 exit(1);
Yu-Hsi Chiang3e954ec2015-07-28 16:48:14 +0800567 case 'I':
568 minijail_namespace_pids(j);
569 minijail_run_as_init(j);
570 break;
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800571 case 'U':
572 minijail_namespace_user(j);
573 minijail_namespace_pids(j);
574 break;
575 case 'm':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700576 set_uidmap = 1;
577 if (uidmap) {
578 free(uidmap);
579 uidmap = NULL;
Jorge Lucangeli Obesab6fa6f2016-08-04 15:42:48 -0400580 }
Luis Hector Chavez71323552017-09-05 09:17:22 -0700581 if (optarg)
582 uidmap = strdup(optarg);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800583 break;
584 case 'M':
Luis Hector Chavez71323552017-09-05 09:17:22 -0700585 set_gidmap = 1;
586 if (gidmap) {
587 free(gidmap);
588 gidmap = NULL;
Jorge Lucangeli Obes200299c2016-09-23 15:21:57 -0400589 }
Luis Hector Chavez71323552017-09-05 09:17:22 -0700590 if (optarg)
591 gidmap = strdup(optarg);
Yu-Hsi Chiang10e91232015-08-05 14:40:45 +0800592 break;
Andrew Brestickereac28942015-11-11 16:04:46 -0800593 case 'a':
594 if (0 != minijail_use_alt_syscall(j, optarg)) {
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800595 fprintf(stderr,
596 "Could not set alt-syscall table.\n");
Andrew Brestickereac28942015-11-11 16:04:46 -0800597 exit(1);
598 }
599 break;
Dylan Reid0f72ef42017-06-06 15:42:49 -0700600 case 'R':
601 add_rlimit(j, optarg);
602 break;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800603 case 'T':
604 if (!strcmp(optarg, "static"))
605 *elftype = ELFSTATIC;
606 else if (!strcmp(optarg, "dynamic"))
607 *elftype = ELFDYNAMIC;
608 else {
Jorge Lucangeli Obes768d42b2016-02-17 10:28:25 -0800609 fprintf(stderr, "ELF type must be 'static' or "
610 "'dynamic'.\n");
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800611 exit(1);
612 }
613 break;
Chirantan Ekbote866bb3a2017-02-07 12:26:42 -0800614 case 'w':
615 minijail_new_session_keyring(j);
616 break;
Jorge Lucangeli Obes13650612016-09-02 11:27:29 -0400617 case 'Y':
618 minijail_set_seccomp_filter_tsync(j);
619 break;
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400620 case 'z':
621 forward = 0;
622 break;
Mike Frysinger33ffef32017-01-13 19:53:19 -0500623 case 'd':
624 minijail_namespace_vfs(j);
625 minijail_mount_dev(j);
626 break;
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400627 /* Long options. */
628 case 128: /* Ambient caps. */
629 ambient_caps = 1;
630 minijail_set_ambient_caps(j);
631 break;
Mike Frysingerb9a7b162017-05-30 15:25:49 -0400632 case 129: /* UTS/hostname namespace. */
633 minijail_namespace_uts(j);
634 if (optarg)
635 minijail_namespace_set_hostname(j, optarg);
636 break;
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700637 case 130: /* Logging. */
638 if (!strcmp(optarg, "syslog"))
639 log_to_stderr = 0;
640 else if (!strcmp(optarg, "stderr")) {
641 log_to_stderr = 1;
642 } else {
643 fprintf(stderr, "--logger must be 'syslog' or "
644 "'stderr'.\n");
645 exit(1);
646 }
647 break;
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700648 case 131: /* Profile */
649 use_profile(j, optarg, &pivot_root, chroot, &tmp_size);
650 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400651 default:
652 usage(argv[0]);
Mike Frysinger227c2912017-10-04 14:27:04 -0400653 exit(opt == 'h' ? 0 : 1);
Elly Jonese1749eb2011-10-07 13:54:59 -0400654 }
655 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400656
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700657 if (log_to_stderr) {
658 init_logging(LOG_TO_FD, STDERR_FILENO, LOG_INFO);
659 /*
660 * When logging to stderr, ensure the FD survives the jailing.
661 */
662 if (0 !=
663 minijail_preserve_fd(j, STDERR_FILENO, STDERR_FILENO)) {
664 fprintf(stderr, "Could not preserve stderr.\n");
665 exit(1);
666 }
667 }
668
Luis Hector Chavez71323552017-09-05 09:17:22 -0700669 /* Set up uid/gid mapping. */
670 if (set_uidmap || set_gidmap) {
671 set_ugid_mapping(j, set_uidmap, uid, uidmap, set_gidmap, gid,
672 gidmap);
673 }
674
Jorge Lucangeli Obesa6eb21a2017-04-20 10:44:00 -0400675 /* Can only set ambient caps when using regular caps. */
676 if (ambient_caps && !caps) {
677 fprintf(stderr, "Can't set ambient capabilities (--ambient) "
678 "without actually using capabilities (-c).\n");
679 exit(1);
680 }
681
Jorge Lucangeli Obesdba62092017-05-18 17:10:23 -0400682 /* Set up signal handlers in minijail unless asked not to. */
683 if (forward)
684 minijail_forward_signals(j);
685
Mike Frysingerac08a682017-10-10 02:04:50 -0400686 /*
687 * Only allow bind mounts when entering a chroot, using pivot_root, or
688 * a new mount namespace.
689 */
690 if (binding && !(chroot || pivot_root || mount_ns)) {
691 fprintf(stderr, "Bind mounts require a chroot, pivot_root, or "
692 " new mount namespace.\n");
Jorge Lucangeli Obes2b12ba42016-01-26 10:37:51 -0800693 exit(1);
694 }
695
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700696 /*
Jorge Lucangeli Obesa521bee2016-03-03 13:47:57 -0800697 * Remounting / as MS_PRIVATE only happens when entering a new mount
698 * namespace, so skipping it only applies in that case.
699 */
700 if (skip_remount && !mount_ns) {
701 fprintf(stderr, "Can't skip marking mounts as MS_PRIVATE"
702 " without mount namespaces.\n");
703 exit(1);
704 }
705
706 /*
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700707 * We parse seccomp filters here to make sure we've collected all
708 * cmdline options.
709 */
710 if (use_seccomp_filter) {
711 minijail_parse_seccomp_filters(j, filter_path);
Jorge Lucangeli Obes0b208772017-04-19 14:15:46 -0400712 free((void *)filter_path);
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700713 }
714
Luis Hector Chavezd45fc422017-10-25 15:11:53 -0700715 /* Mount a tmpfs under /tmp and set its size. */
716 if (tmp_size)
717 minijail_mount_tmp_size(j, tmp_size);
718
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700719 /*
720 * There should be at least one additional unparsed argument: the
721 * executable name.
722 */
Elly Jonese1749eb2011-10-07 13:54:59 -0400723 if (argc == optind) {
724 usage(argv[0]);
725 exit(1);
726 }
Lee Campbell11af0622014-05-22 12:36:04 -0700727
Luis Hector Chavezfe5fb8e2017-06-29 10:41:27 -0700728 if (*elftype == ELFERROR) {
729 /*
730 * -T was not specified.
731 * Get the path to the program adjusted for changing root.
732 */
733 char *program_path =
734 minijail_get_original_path(j, argv[optind]);
735
736 /* Check that we can access the target program. */
737 if (access(program_path, X_OK)) {
738 fprintf(stderr,
739 "Target program '%s' is not accessible.\n",
740 argv[optind]);
741 exit(1);
742 }
743
744 /* Check if target is statically or dynamically linked. */
745 *elftype = get_elf_linkage(program_path);
746 free(program_path);
747 }
748
749 /*
750 * Setting capabilities need either a dynamically-linked binary, or the
751 * use of ambient capabilities for them to be able to survive an
752 * execve(2).
753 */
754 if (caps && *elftype == ELFSTATIC && !ambient_caps) {
755 fprintf(stderr, "Can't run statically-linked binaries with "
756 "capabilities (-c) without also setting "
757 "ambient capabilities. Try passing "
758 "--ambient.\n");
759 exit(1);
760 }
761
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500762 return optind;
763}
Elly Jonescd7a9042011-07-22 13:56:51 -0400764
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500765int main(int argc, char *argv[])
766{
767 struct minijail *j = minijail_new();
Jorge Lucangeli Obesd99a40d2016-01-26 13:50:44 -0800768 const char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700769 int exit_immediately = 0;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700770 ElfType elftype = ELFERROR;
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800771 int consumed = parse_args(j, argc, argv, &exit_immediately, &elftype);
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500772 argc -= consumed;
773 argv += consumed;
Jorge Lucangeli Obes482cb9d2014-07-23 15:16:04 -0700774
Stephen Barber5dd5b1b2017-10-16 23:02:39 -0700775 /*
776 * Make the process group ID of this process equal to its PID.
777 * In the non-interactive case (e.g. when minijail0 is started from
778 * init) this ensures the parent process and the jailed process
779 * can be killed together.
780 *
781 * Don't fail on EPERM, since setpgid(0, 0) can only EPERM when
782 * the process is already a process group leader.
783 */
784 if (setpgid(0 /* use calling PID */, 0 /* make PGID = PID */)) {
785 if (errno != EPERM) {
786 fprintf(stderr, "setpgid(0, 0) failed\n");
787 exit(1);
788 }
789 }
790
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700791 if (elftype == ELFSTATIC) {
Jorge Lucangeli Obes54714502015-09-30 10:08:45 -0700792 /*
793 * Target binary is statically linked so we cannot use
794 * libminijailpreload.so.
795 */
796 minijail_run_no_preload(j, argv[0], argv);
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700797 } else if (elftype == ELFDYNAMIC) {
798 /*
799 * Target binary is dynamically linked so we can
800 * inject libminijailpreload.so into it.
801 */
802
803 /* Check that we can dlopen() libminijailpreload.so. */
804 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
Matthew Dempsky2ed09122016-02-11 09:43:37 -0800805 dl_mesg = dlerror();
806 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
807 return 1;
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700808 }
809 minijail_run(j, argv[0], argv);
810 } else {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -0700811 fprintf(stderr,
812 "Target program '%s' is not a valid ELF file.\n",
813 argv[0]);
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800814 return 1;
815 }
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700816
Christopher Wiley88f76a72013-11-01 14:12:56 -0700817 if (exit_immediately) {
Luis Hector Chavez114a9302017-09-05 20:36:58 -0700818 info("not running init loop, exiting immediately\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700819 return 0;
820 }
lhchavez6c8d8202017-09-01 03:55:11 +0000821 int ret = minijail_wait(j);
822#if defined(__SANITIZE_ADDRESS__)
823 minijail_destroy(j);
824#endif /* __SANITIZE_ADDRESS__ */
825 return ret;
Elly Jonescd7a9042011-07-22 13:56:51 -0400826}