blob: e857ea4fbc4263c38ef1e082a4797837e7347501 [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
Christopher Wiley88f76a72013-11-01 14:12:56 -070077 printf("Usage: %s [-Ghinprsv] [-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"
Christopher Wiley88f76a72013-11-01 14:12:56 -070084 " -e enter a network namespace\n"
Elly Jonese1749eb2011-10-07 13:54:59 -040085 " -G: inherit secondary groups from uid\n"
86 " -g <group>: change gid to <group>\n"
87 " -h: help (this message)\n"
88 " -H: seccomp filter help message\n"
Christopher Wiley88f76a72013-11-01 14:12:56 -070089 " -i: exit immediately after fork (do not act as init)\n"
90 " Not compatible with -p\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -070091 " -L: log blocked syscalls when using seccomp filter. "
92 "Forces the following syscalls to be allowed:\n"
93 " ", progn);
94 for (i = 0; i < log_syscalls_len; i++)
95 printf("%s ", log_syscalls[i]);
96
97 printf("\n"
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -070098 " -n: set no_new_privs\n"
Elly Jonese58176c2012-01-23 11:46:17 -050099 " -p: use pid namespace (implies -vr)\n"
Elly Jonesfdd5f2d2012-01-23 13:27:43 -0500100 " -r: remount /proc readonly (implies -v)\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400101 " -s: use seccomp\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700102 " -S <file>: set seccomp filter using <file>\n"
Elly Jonese1749eb2011-10-07 13:54:59 -0400103 " E.g., -S /usr/share/filters/<prog>.$(uname -m)\n"
104 " -u <user>: change uid to <user>\n"
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700105 " -v: use vfs namespace\n");
Elly Jonescd7a9042011-07-22 13:56:51 -0400106}
107
Elly Jonese1749eb2011-10-07 13:54:59 -0400108static void seccomp_filter_usage(const char *progn)
109{
110 const struct syscall_entry *entry = syscall_table;
111 printf("Usage: %s -S <policy.file> <program> [args...]\n\n"
112 "System call names supported:\n", progn);
113 for (; entry->name && entry->nr >= 0; ++entry)
114 printf(" %s [%d]\n", entry->name, entry->nr);
115 printf("\nSee minijail0(5) for example policies.\n");
Will Drewry32ac9f52011-08-18 21:36:27 -0500116}
117
Christopher Wiley88f76a72013-11-01 14:12:56 -0700118static int parse_args(struct minijail *j, int argc, char *argv[],
119 int *exit_immediately)
Elly Jonese1749eb2011-10-07 13:54:59 -0400120{
Elly Jonese1749eb2011-10-07 13:54:59 -0400121 int opt;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700122 int use_pid_ns = 0;
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500123 if (argc > 1 && argv[1][0] != '-')
124 return 1;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700125 while ((opt = getopt(argc, argv, "u:g:sS:c:C:b:vrGhHinpLe")) != -1) {
Elly Jonese1749eb2011-10-07 13:54:59 -0400126 switch (opt) {
127 case 'u':
128 set_user(j, optarg);
129 break;
130 case 'g':
131 set_group(j, optarg);
132 break;
Jorge Lucangeli Obesc2c9bcc2012-05-01 09:30:24 -0700133 case 'n':
134 minijail_no_new_privs(j);
Jorge Lucangeli Obes0341d6c2012-07-16 15:27:31 -0700135 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400136 case 's':
137 minijail_use_seccomp(j);
138 break;
139 case 'S':
140 minijail_parse_seccomp_filters(j, optarg);
141 minijail_use_seccomp_filter(j);
142 break;
Jorge Lucangeli Obesbda833c2012-07-31 16:25:56 -0700143 case 'L':
144 minijail_log_seccomp_filter_failures(j);
145 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400146 case 'b':
147 add_binding(j, optarg);
148 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400149 case 'c':
150 use_caps(j, optarg);
151 break;
Elly Jones51a5b6c2011-10-12 19:09:26 -0400152 case 'C':
153 minijail_enter_chroot(j, optarg);
154 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400155 case 'v':
156 minijail_namespace_vfs(j);
157 break;
158 case 'r':
159 minijail_remount_readonly(j);
160 break;
161 case 'G':
162 minijail_inherit_usergroups(j);
163 break;
164 case 'p':
Christopher Wiley88f76a72013-11-01 14:12:56 -0700165 if (*exit_immediately) {
166 fprintf(stderr,
167 "Could not enter pid namespace because "
168 "'-i' was specified.");
169 exit(1);
170 }
171 use_pid_ns = 1;
Elly Jonese1749eb2011-10-07 13:54:59 -0400172 minijail_namespace_pids(j);
173 break;
Elly Fong-Jones6c086302013-03-20 17:15:28 -0400174 case 'e':
175 minijail_namespace_net(j);
176 break;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700177 case 'i':
178 if (use_pid_ns) {
179 fprintf(stderr,
180 "Could not disable init loop because "
181 "'-p' was specified.");
182 exit(1);
183 }
184 *exit_immediately = 1;
185 break;
Elly Jonese1749eb2011-10-07 13:54:59 -0400186 case 'H':
187 seccomp_filter_usage(argv[0]);
188 exit(1);
189 default:
190 usage(argv[0]);
191 exit(1);
192 }
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500193 if (optind < argc && argv[optind][0] != '-')
194 return optind;
Elly Jonese1749eb2011-10-07 13:54:59 -0400195 }
Elly Jonescd7a9042011-07-22 13:56:51 -0400196
Elly Jonese1749eb2011-10-07 13:54:59 -0400197 if (argc == optind) {
198 usage(argv[0]);
199 exit(1);
200 }
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500201 return optind;
202}
Elly Jonescd7a9042011-07-22 13:56:51 -0400203
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500204int main(int argc, char *argv[])
205{
206 struct minijail *j = minijail_new();
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800207 char *dl_mesg = NULL;
Christopher Wiley88f76a72013-11-01 14:12:56 -0700208 int exit_immediately = 0;
209 int consumed = parse_args(j, argc, argv, &exit_immediately);
Elly Fong-Jonesf65c9fe2013-01-22 13:55:02 -0500210 argc -= consumed;
211 argv += consumed;
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800212 /* Check that we can access the target program. */
Elly Fong-Jones6d717852013-03-19 16:29:03 -0400213 if (access(argv[0], X_OK)) {
214 fprintf(stderr, "Target program '%s' not accessible\n",
215 argv[0]);
216 return 1;
217 }
Jorge Lucangeli Obes4b2d5ee2014-01-09 15:47:47 -0800218 /* Check that we can dlopen() libminijailpreload.so. */
219 if (!dlopen(PRELOADPATH, RTLD_LAZY | RTLD_LOCAL)) {
220 dl_mesg = dlerror();
221 fprintf(stderr, "dlopen(): %s\n", dl_mesg);
222 return 1;
223 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400224 minijail_run(j, argv[0], argv);
Christopher Wiley88f76a72013-11-01 14:12:56 -0700225 if (exit_immediately) {
226 info("not running init loop, exiting immediately");
227 return 0;
228 }
Elly Jonese1749eb2011-10-07 13:54:59 -0400229 return minijail_wait(j);
Elly Jonescd7a9042011-07-22 13:56:51 -0400230}