blob: 82f67c116f7ddbb34b07e2832621995ea61155ed [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
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070015#include "util.h"
16
Elly Jonese1749eb2011-10-07 13:54:59 -040017static void set_user(struct minijail *j, const char *arg)
18{
19 char *end = NULL;
20 int uid = strtod(arg, &end);
21 if (!*end && *arg) {
22 minijail_change_uid(j, uid);
23 return;
24 }
Elly Jonescd7a9042011-07-22 13:56:51 -040025
Elly Jonese1749eb2011-10-07 13:54:59 -040026 if (minijail_change_user(j, arg)) {
27 fprintf(stderr, "Bad user: '%s'\n", arg);
28 exit(1);
29 }
Elly Jonescd7a9042011-07-22 13:56:51 -040030}
31
Elly Jonese1749eb2011-10-07 13:54:59 -040032static void set_group(struct minijail *j, const char *arg)
33{
34 char *end = NULL;
35 int gid = strtod(arg, &end);
36 if (!*end && *arg) {
37 minijail_change_gid(j, gid);
38 return;
39 }
Elly Jonescd7a9042011-07-22 13:56:51 -040040
Elly Jonese1749eb2011-10-07 13:54:59 -040041 if (minijail_change_group(j, arg)) {
42 fprintf(stderr, "Bad group: '%s'\n", arg);
43 exit(1);
44 }
Elly Jonescd7a9042011-07-22 13:56:51 -040045}
46
Elly Jonese1749eb2011-10-07 13:54:59 -040047static void use_caps(struct minijail *j, const char *arg)
48{
49 uint64_t caps;
50 char *end = NULL;
51 caps = strtoull(arg, &end, 16);
52 if (*end) {
53 fprintf(stderr, "Invalid cap set: '%s'\n", arg);
54 exit(1);
55 }
56 minijail_use_caps(j, caps);
Elly Jonescd7a9042011-07-22 13:56:51 -040057}
58
Elly Jones51a5b6c2011-10-12 19:09:26 -040059static void add_binding(struct minijail *j, char *arg) {
60 char *src = strtok(arg, ",");
Elly Jones5ba42b52011-12-07 13:31:43 -050061 char *dest = strtok(NULL, ",");
62 char *flags = strtok(NULL, ",");
Elly Jones51a5b6c2011-10-12 19:09:26 -040063 if (!src || !dest) {
64 fprintf(stderr, "Bad binding: %s %s\n", src, dest);
65 exit(1);
66 }
67 if (minijail_bind(j, src, dest, flags ? atoi(flags) : 0)) {
68 fprintf(stderr, "Bind failure\n");
69 exit(1);
70 }
71}
72
Elly Jonese1749eb2011-10-07 13:54:59 -040073static void usage(const char *progn)
74{
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070075 size_t i;
76
Lee Campbell11af0622014-05-22 12:36:04 -070077 printf("Usage: %s [-Ghinprsvt] [-b <src>,<dest>[,<writeable>]] "
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070078 "[-c <caps>] [-C <dir>] [-g <group>] [-S <file>] [-u <user>] "
79 "<program> [args...]\n"
Elly Jonesa8d1e1b2011-10-21 15:38:00 -040080 " -b: binds <src> to <dest> in chroot. Multiple "
81 "instances allowed\n"
Elly Jonese1749eb2011-10-07 13:54:59 -040082 " -c <caps>: restrict caps to <caps>\n"
Elly Jonesa8d1e1b2011-10-21 15:38:00 -040083 " -C <dir>: chroot to <dir>\n"
Lee Campbell11af0622014-05-22 12:36:04 -070084 " -t: mount tmpfs at /tmp inside chroot\n"
85 " -e: enter a network namespace\n"
Elly Jonese1749eb2011-10-07 13:54:59 -040086 " -G: inherit secondary groups from uid\n"
87 " -g <group>: change gid to <group>\n"
88 " -h: help (this message)\n"
89 " -H: seccomp filter help message\n"
Christopher Wiley88f76a72013-11-01 14:12:56 -070090 " -i: exit immediately after fork (do not act as init)\n"
91 " Not compatible with -p\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070092 " -L: log blocked syscalls when using seccomp filter. "
93 "Forces the following syscalls to be allowed:\n"
94 " ", progn);
95 for (i = 0; i < log_syscalls_len; i++)
96 printf("%s ", log_syscalls[i]);
97
98 printf("\n"
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070099 " -n: set no_new_privs\n"
Elly Jonese58176c2012-01-23 11:46:17 -0500100 " -p: use pid namespace (implies -vr)\n"
Elly Jonesfdd5f2d2012-01-23 13:27:43 -0500101 " -r: remount /proc readonly (implies -v)\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400102 " -s: use seccomp\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700103 " -S <file>: set seccomp filter using <file>\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400104 " E.g., -S /usr/share/filters/<prog>.$(uname -m)\n"
105 " -u <user>: change uid to <user>\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700106 " -v: use vfs namespace\n");
Elly Jonescd7a9042011-07-22 13:56:51 -0400107}
108
Elly Jonese1749eb2011-10-07 13:54:59 -0400109static void seccomp_filter_usage(const char *progn)
110{
111 const struct syscall_entry *entry = syscall_table;
112 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
113 "System call names supported:\n", progn);
114 for (; entry->name && entry->nr >= 0; ++entry)
115 printf(" %s [%d]\n", entry->name, entry->nr);
116 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500117}
118
Christopher Wiley88f76a72013-11-01 14:12:56 -0700119static int parse_args(struct minijail *j, int argc, char *argv[],
120 int *exit_immediately)
Elly Jonese1749eb2011-10-07 13:54:59 -0400121{
Elly Jonese1749eb2011-10-07 13:54:59 -0400122 int opt;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700123 int use_pid_ns = 0;
Lee Campbell11af0622014-05-22 12:36:04 -0700124 int chroot = 0;
125 int mount_tmp = 0;
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500126 if (argc > 1 && argv[1][0] != '-')
127 return 1;
Lee Campbell11af0622014-05-22 12:36:04 -0700128 while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHinpLet")) != -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400129 switch (opt) {
130 case 'u':
131 set_user(j, optarg);
132 break;
133 case 'g':
134 set_group(j, optarg);
135 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700136 case 'n':
137 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700138 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400139 case 's':
140 minijail_use_seccomp(j);
141 break;
142 case 'S':
143 minijail_parse_seccomp_filters(j, optarg);
144 minijail_use_seccomp_filter(j);
145 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700146 case 'L':
147 minijail_log_seccomp_filter_failures(j);
148 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400149 case 'b':
150 add_binding(j, optarg);
151 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400152 case 'c':
153 use_caps(j, optarg);
154 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400155 case 'C':
Lee Campbell11af0622014-05-22 12:36:04 -0700156 if (0 != minijail_enter_chroot(j, optarg))
157 exit(1);
158 chroot = 1;
159 break;
160 case 't':
161 minijail_mount_tmp(j);
162 mount_tmp = 1;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400163 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400164 case 'v':
165 minijail_namespace_vfs(j);
166 break;
167 case 'r':
168 minijail_remount_readonly(j);
169 break;
170 case 'G':
171 minijail_inherit_usergroups(j);
172 break;
173 case 'p':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700174 if (*exit_immediately) {
175 fprintf(stderr,
176 "Could not enter pid namespace because "
Lee Campbell11af0622014-05-22 12:36:04 -0700177 "'-i' was specified.\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700178 exit(1);
179 }
180 use_pid_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400181 minijail_namespace_pids(j);
182 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400183 case 'e':
184 minijail_namespace_net(j);
185 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700186 case 'i':
187 if (use_pid_ns) {
188 fprintf(stderr,
189 "Could not disable init loop because "
Lee Campbell11af0622014-05-22 12:36:04 -0700190 "'-p' was specified.\n");
Christopher Wiley88f76a72013-11-01 14:12:56 -0700191 exit(1);
192 }
193 *exit_immediately = 1;
194 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400195 case 'H':
196 seccomp_filter_usage(argv[0]);
197 exit(1);
198 default:
199 usage(argv[0]);
200 exit(1);
201 }
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500202 if (optind < argc && argv[optind][0] != '-')
Lee Campbell11af0622014-05-22 12:36:04 -0700203 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400204 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400205
Elly Jonese1749eb2011-10-07 13:54:59 -0400206 if (argc == optind) {
207 usage(argv[0]);
208 exit(1);
209 }
Lee Campbell11af0622014-05-22 12:36:04 -0700210
211 if (mount_tmp && !chroot) {
212 fprintf(stderr,
213 "Could not mount tmpfs at /tmp "
214 "because '-C' was not specified.\n");
215 exit(1);
216 }
217
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500218 return optind;
219}
Elly Jonescd7a9042011-07-22 13:56:51 -0400220
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500221int main(int argc, char *argv[])
222{
223 struct minijail *j = minijail_new();
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800224 char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700225 int exit_immediately = 0;
226 int consumed = parse_args(j, argc, argv, &exit_immediately);
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500227 argc -= consumed;
228 argv += consumed;
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800229 /* Check that we can access the target program. */
Elly Fong-Jones6d717852013-03-19 16:29:03 -0400230 if (access(argv[0], X_OK)) {
231 fprintf(stderr, "Target program '%s' not accessible\n",
232 argv[0]);
233 return 1;
234 }
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800235 /* Check that we can dlopen() libminijailpreload.so. */
236 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
237 dl_mesg = dlerror();
238 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
239 return 1;
240 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400241 minijail_run(j, argv[0], argv);
Christopher Wiley88f76a72013-11-01 14:12:56 -0700242 if (exit_immediately) {
243 info("not running init loop, exiting immediately");
244 return 0;
245 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400246 return minijail_wait(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400247}