blob: e5ca3d1f36f089ced2857c8b4ffe7b41eb7c36ae [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>
Elly Jonescd7a9042011-07-22 13:56:51 -04007#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10#include <unistd.h>
11
12#include "libminijail.h"
Will Drewry32ac9f52011-08-18 21:36:27 -050013#include "libsyscalls.h"
Elly Jonescd7a9042011-07-22 13:56:51 -040014
Lee Campbell1e4fc6a2014-06-06 17:40:02 -070015#include "elfparse.h"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070016#include "util.h"
17
Elly Jonese1749eb2011-10-07 13:54:59 -040018static void set_user(struct minijail *j, const char *arg)
19{
20 char *end = NULL;
21 int uid = strtod(arg, &end);
22 if (!*end && *arg) {
23 minijail_change_uid(j, uid);
24 return;
25 }
Elly Jonescd7a9042011-07-22 13:56:51 -040026
Elly Jonese1749eb2011-10-07 13:54:59 -040027 if (minijail_change_user(j, arg)) {
28 fprintf(stderr, "Bad user: '%s'\n", arg);
29 exit(1);
30 }
Elly Jonescd7a9042011-07-22 13:56:51 -040031}
32
Elly Jonese1749eb2011-10-07 13:54:59 -040033static void set_group(struct minijail *j, const char *arg)
34{
35 char *end = NULL;
36 int gid = strtod(arg, &end);
37 if (!*end && *arg) {
38 minijail_change_gid(j, gid);
39 return;
40 }
Elly Jonescd7a9042011-07-22 13:56:51 -040041
Elly Jonese1749eb2011-10-07 13:54:59 -040042 if (minijail_change_group(j, arg)) {
43 fprintf(stderr, "Bad group: '%s'\n", arg);
44 exit(1);
45 }
Elly Jonescd7a9042011-07-22 13:56:51 -040046}
47
Elly Jonese1749eb2011-10-07 13:54:59 -040048static void use_caps(struct minijail *j, const char *arg)
49{
50 uint64_t caps;
51 char *end = NULL;
52 caps = strtoull(arg, &end, 16);
53 if (*end) {
54 fprintf(stderr, "Invalid cap set: '%s'\n", arg);
55 exit(1);
56 }
57 minijail_use_caps(j, caps);
Elly Jonescd7a9042011-07-22 13:56:51 -040058}
59
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -070060static void add_binding(struct minijail *j, char *arg)
61{
Elly Jones51a5b6c2011-10-12 19:09:26 -040062 char *src = strtok(arg, ",");
Elly Jones5ba42b52011-12-07 13:31:43 -050063 char *dest = strtok(NULL, ",");
64 char *flags = strtok(NULL, ",");
Elly Jones51a5b6c2011-10-12 19:09:26 -040065 if (!src || !dest) {
66 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
67 exit(1);
68 }
69 if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -070070 fprintf(stderr, "Bind failure.\n");
Elly Jones51a5b6c2011-10-12 19:09:26 -040071 exit(1);
72 }
73}
74
Elly Jonese1749eb2011-10-07 13:54:59 -040075static void usage(const char *progn)
76{
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070077 size_t i;
78
Lee Campbell11af0622014-05-22 12:36:04 -070079 printf("Usage: %s [-Ghinprsvt] [-b <src>,<dest>[,<writeable>]] "
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070080 "[-c <caps>] [-C <dir>] [-g <group>] [-S <file>] [-u <user>] "
81 "<program> [args...]\n"
Elly Jonesa8d1e1b2011-10-21 15:38:00 -040082 " -b: binds <src> to <dest> in chroot. Multiple "
83 "instances allowed\n"
Elly Jonese1749eb2011-10-07 13:54:59 -040084 " -c <caps>: restrict caps to <caps>\n"
Elly Jonesa8d1e1b2011-10-21 15:38:00 -040085 " -C <dir>: chroot to <dir>\n"
Lee Campbell11af0622014-05-22 12:36:04 -070086 " -e: enter a network namespace\n"
Elly Jonese1749eb2011-10-07 13:54:59 -040087 " -G: inherit secondary groups from uid\n"
88 " -g <group>: change gid to <group>\n"
89 " -h: help (this message)\n"
90 " -H: seccomp filter help message\n"
Christopher Wiley88f76a72013-11-01 14:12:56 -070091 " -i: exit immediately after fork (do not act as init)\n"
92 " Not compatible with -p\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070093 " -L: log blocked syscalls when using seccomp filter. "
94 "Forces the following syscalls to be allowed:\n"
95 " ", progn);
96 for (i = 0; i < log_syscalls_len; i++)
97 printf("%s ", log_syscalls[i]);
98
99 printf("\n"
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700100 " -n: set no_new_privs\n"
Elly Jonese58176c2012-01-23 11:46:17 -0500101 " -p: use pid namespace (implies -vr)\n"
Elly Jonesfdd5f2d2012-01-23 13:27:43 -0500102 " -r: remount /proc readonly (implies -v)\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400103 " -s: use seccomp\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700104 " -S <file>: set seccomp filter using <file>\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400105 " E.g., -S /usr/share/filters/<prog>.$(uname -m)\n"
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -0700106 " -t: mount tmpfs at /tmp inside chroot\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400107 " -u <user>: change uid to <user>\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700108 " -v: use vfs namespace\n");
Elly Jonescd7a9042011-07-22 13:56:51 -0400109}
110
Elly Jonese1749eb2011-10-07 13:54:59 -0400111static void seccomp_filter_usage(const char *progn)
112{
113 const struct syscall_entry *entry = syscall_table;
114 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
115 "System call names supported:\n", progn);
116 for (; entry->name && entry->nr >= 0; ++entry)
117 printf(" %s [%d]\n", entry->name, entry->nr);
118 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500119}
120
Christopher Wiley88f76a72013-11-01 14:12:56 -0700121static int parse_args(struct minijail *j, int argc, char *argv[],
122 int *exit_immediately)
Elly Jonese1749eb2011-10-07 13:54:59 -0400123{
Elly Jonese1749eb2011-10-07 13:54:59 -0400124 int opt;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700125 int use_pid_ns = 0;
Lee Campbell11af0622014-05-22 12:36:04 -0700126 int chroot = 0;
127 int mount_tmp = 0;
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500128 if (argc > 1 && argv[1][0] != '-')
129 return 1;
Lee Campbell11af0622014-05-22 12:36:04 -0700130 while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHinpLet")) != -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400131 switch (opt) {
132 case 'u':
133 set_user(j, optarg);
134 break;
135 case 'g':
136 set_group(j, optarg);
137 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700138 case 'n':
139 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700140 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400141 case 's':
142 minijail_use_seccomp(j);
143 break;
144 case 'S':
145 minijail_parse_seccomp_filters(j, optarg);
146 minijail_use_seccomp_filter(j);
147 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700148 case 'L':
149 minijail_log_seccomp_filter_failures(j);
150 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400151 case 'b':
152 add_binding(j, optarg);
153 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400154 case 'c':
155 use_caps(j, optarg);
156 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400157 case 'C':
Lee Campbell11af0622014-05-22 12:36:04 -0700158 if (0 != minijail_enter_chroot(j, optarg))
159 exit(1);
160 chroot = 1;
161 break;
162 case 't':
163 minijail_mount_tmp(j);
164 mount_tmp = 1;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400165 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400166 case 'v':
167 minijail_namespace_vfs(j);
168 break;
169 case 'r':
170 minijail_remount_readonly(j);
171 break;
172 case 'G':
173 minijail_inherit_usergroups(j);
174 break;
175 case 'p':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700176 if (*exit_immediately) {
177 fprintf(stderr,
178 "Could not enter pid namespace because "
Lee Campbell11af0622014-05-22 12:36:04 -0700179 "'-i' was specified.\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700180 exit(1);
181 }
182 use_pid_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400183 minijail_namespace_pids(j);
184 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400185 case 'e':
186 minijail_namespace_net(j);
187 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700188 case 'i':
189 if (use_pid_ns) {
190 fprintf(stderr,
191 "Could not disable init loop because "
Lee Campbell11af0622014-05-22 12:36:04 -0700192 "'-p' was specified.\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700193 exit(1);
194 }
195 *exit_immediately = 1;
196 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400197 case 'H':
198 seccomp_filter_usage(argv[0]);
199 exit(1);
200 default:
201 usage(argv[0]);
202 exit(1);
203 }
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500204 if (optind < argc && argv[optind][0] != '-')
Lee Campbell11af0622014-05-22 12:36:04 -0700205 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400206 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400207
Elly Jonese1749eb2011-10-07 13:54:59 -0400208 if (argc == optind) {
209 usage(argv[0]);
210 exit(1);
211 }
Lee Campbell11af0622014-05-22 12:36:04 -0700212
213 if (mount_tmp && !chroot) {
214 fprintf(stderr,
215 "Could not mount tmpfs at /tmp "
216 "because '-C' was not specified.\n");
217 exit(1);
218 }
219
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500220 return optind;
221}
Elly Jonescd7a9042011-07-22 13:56:51 -0400222
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500223int main(int argc, char *argv[])
224{
225 struct minijail *j = minijail_new();
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800226 char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700227 int exit_immediately = 0;
228 int consumed = parse_args(j, argc, argv, &exit_immediately);
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700229 ElfType elftype = ELFERROR;
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500230 argc -= consumed;
231 argv += consumed;
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800232 /* Check that we can access the target program. */
Elly Fong-Jones6d717852013-03-19 16:29:03 -0400233 if (access(argv[0], X_OK)) {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -0700234 fprintf(stderr, "Target program '%s' is not accessible.\n",
Jorge Lucangeli Obesc8b21e12014-06-13 14:26:16 -0700235 argv[0]);
Elly Fong-Jones6d717852013-03-19 16:29:03 -0400236 return 1;
237 }
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700238 /* Check if target is statically or dynamically linked. */
239 elftype = get_elf_linkage(argv[0]);
240 if (elftype == ELFSTATIC) {
241 /* Target binary is static. */
242 minijail_run_static(j, argv[0], argv);
243 } else if (elftype == ELFDYNAMIC) {
244 /*
245 * Target binary is dynamically linked so we can
246 * inject libminijailpreload.so into it.
247 */
248
249 /* Check that we can dlopen() libminijailpreload.so. */
250 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
251 dl_mesg = dlerror();
252 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
253 return 1;
254 }
255 minijail_run(j, argv[0], argv);
256 } else {
Jorge Lucangeli Obes2f61ee42014-06-16 11:08:18 -0700257 fprintf(stderr,
258 "Target program '%s' is not a valid ELF file.\n",
259 argv[0]);
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800260 return 1;
261 }
Lee Campbell1e4fc6a2014-06-06 17:40:02 -0700262
Christopher Wiley88f76a72013-11-01 14:12:56 -0700263 if (exit_immediately) {
264 info("not running init loop, exiting immediately");
265 return 0;
266 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400267 return minijail_wait(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400268}