blob: a40397ce53526da80a5a13fdfa8576ea0104ade5 [file] [log] [blame]
drewry@google.combd940e92009-12-07 19:13:27 +00001// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4// Some portions Copyright (c) 2009 The Chromium Authors.
5//
6// Driver program for applying a minijail from the commandline to
7// a process and its children (depending on the feature).
8
9#include "minijail/minijail.h"
10
11#include <errno.h>
12#include <linux/capability.h>
13#include <stdio.h>
14#include <sys/prctl.h>
15#include <unistd.h>
16
17#include <iostream>
18#include <new>
19#include <string>
20#include <vector>
21
22#include <base/basictypes.h>
23#include <base/command_line.h>
24#include <base/logging.h>
25#include <base/string_util.h>
26
27namespace switches {
28static const char kAddReadonlyMounts[] = "add-readonly-mounts";
29static const char kDisableTracing[] = "disable-tracing";
30static const char kEnforceSyscallsBenchmark[] = "enforce-syscall-benchmark";
31static const char kEnforceSyscallsBySource[] = "enforce-syscall-by-source";
32static const char kGid[] = "gid";
33static const char kNamespaceVfs[] = "namespace-vfs";
34static const char kNamespacePid[] = "namespace-pid";
35static const char kSanitizeEnvironment[] = "sanitize-environment";
36static const char kUid[] = "uid";
37static const char kUseCapabilities[] = "use-capabilities";
38static const char kHelp[] = "help";
39
40static const char kHelpMessage[] = "Available Switches:\n"
41" --add-readonly-mounts\n"
42" Mounts a read-only /proc. (implies namespace-vfs)\n"
43" (TODO other read-only/special mounts)\n"
44" --disable-tracing\n"
45" Disables ptrace() and core dumps.\n"
46" This may break debugging helpers\n"
Will Drewry7fff6522009-12-07 18:15:36 -080047" --enforce-syscall-benchmark\n"
drewry@google.combd940e92009-12-07 19:13:27 +000048" Runs system call filtering in a pass-through capacity only for\n"
49" benchmarking\n"
50" --enforce-syscall-by-source\n"
51" Enables kernel enforcement that system calls originate from read-only\n"
52" memory areas\n"
53" --gid [number]\n"
54" Numeric gid to transition to prior to execution.\n"
55" (TODO: Supplemental groups will be cleared.)\n"
56" --namespace-vfs\n"
57" Enables a process-tree specific VFS view.\n"
58" --namespace-pid\n"
59" Makes the executed process into procss id 1 in its own process view.\n"
60" With --add-readonly-mounts, other processes will not be visible\n"
61" --sanitize-environment\n"
62" Scrubs the environment clean of potentially dangerous values.\n"
63" (Note, this is a blacklist and not a whitelist so it may need attention)\n"
64" --uid [number]\n"
65" Numeric uid to transition to prior to execution.\n"
66" --use-capabilities\n"
67" Restricts all root-level capabilities to CAP_SETPCAP and enables\n"
68" SECURE_NOROOT.\n"
69" -- /path/to/program [arg1 [arg2 [ . . . ] ] ]\n"
70" Supplies the required program to execute and its arguments.\n"
71" At present, an empty environment will be passed.\n"
72"\n";
73
74} // namespace switches
75
76static void ProcessSwitches(CommandLine *cl,
77 chromeos::MiniJailOptions *jail_opts) {
78 if (cl->HasSwitch(switches::kHelp)) {
79 std::cerr << switches::kHelpMessage;
80 exit(0);
81 }
82
83 // Configure the jail options
84 jail_opts->set_namespace_pid(cl->HasSwitch(switches::kNamespacePid));
85 jail_opts->set_namespace_vfs(cl->HasSwitch(switches::kNamespaceVfs));
86 jail_opts->set_add_readonly_mounts(
87 cl->HasSwitch(switches::kAddReadonlyMounts));
88 jail_opts->set_disable_tracing(cl->HasSwitch(switches::kDisableTracing));
Will Drewry7fff6522009-12-07 18:15:36 -080089 jail_opts->set_enforce_syscalls_benchmark(
90 cl->HasSwitch(switches::kEnforceSyscallsBenchmark));
drewry@google.combd940e92009-12-07 19:13:27 +000091 jail_opts->set_enforce_syscalls_by_source(
92 cl->HasSwitch(switches::kEnforceSyscallsBySource));
93 jail_opts->set_use_capabilities(cl->HasSwitch(switches::kUseCapabilities));
94 jail_opts->set_sanitize_environment(
95 cl->HasSwitch(switches::kSanitizeEnvironment));
96
97 std::string uid_string = cl->GetSwitchValueASCII(switches::kUid);
98 if (!uid_string.empty()) {
99 errno = 0;
100 uid_t uid = static_cast<uid_t>(strtol(uid_string.c_str(), NULL, 0));
101 PLOG_IF(WARNING, errno) << "failed to parse uid";
102 jail_opts->set_uid(uid);
103 }
104
105 std::string gid_string = cl->GetSwitchValueASCII(switches::kGid);
106 if (!gid_string.empty()) {
107 errno = 0;
108 gid_t gid = static_cast<gid_t>(strtol(gid_string.c_str(), NULL, 0));
109 PLOG_IF(WARNING, errno) << "failed to parse gid";
110 jail_opts->set_gid(gid);
111 }
112
113 if (!jail_opts->FixUpDependencies()) {
114 LOG(FATAL) << "Irreconcilable jail options given. Aborting.";
115 }
116
117 // Grab the loose args to use as the command line.
118 // We have to wstring->argv[][] manually. Ugh.
Chris Masone7b634ba2010-08-12 10:41:16 -0700119 std::vector<std::string> loose_args = cl->args();
120 char const* *jailed_argv = new char const*[loose_args.size() + 1];
121 std::vector<std::string>::const_iterator arg_it = loose_args.begin();
drewry@google.combd940e92009-12-07 19:13:27 +0000122 char const* *ja = jailed_argv;
Chris Masone7b634ba2010-08-12 10:41:16 -0700123 for (; arg_it != loose_args.end(); ++arg_it) {
drewry@google.combd940e92009-12-07 19:13:27 +0000124 // XXX: clean up this leak even though it doesn't matter.
Chris Masone7b634ba2010-08-12 10:41:16 -0700125 *ja++ = strdup(arg_it->c_str());
drewry@google.combd940e92009-12-07 19:13:27 +0000126 }
127 *ja = 0;
128
129 jail_opts->set_executable_path(jailed_argv[0]);
130 jail_opts->set_arguments(const_cast<char * const*>(jailed_argv),
131 loose_args.size());
132 // XXX We just leak this since we're going to exec anyhow.
133 // delete jailed_argv;
134}
135
136int main(int argc, char *argv[], char **envp) {
137 CommandLine::Init(argc, argv);
138 logging::InitLogging(NULL,
139 logging::LOG_ONLY_TO_SYSTEM_DEBUG_LOG,
140 logging::DONT_LOCK_LOG_FILE,
141 logging::APPEND_TO_OLD_LOG_FILE);
142
143 chromeos::MiniJailOptions jail_opts;
144 CommandLine *cl = CommandLine::ForCurrentProcess();
145 ProcessSwitches(cl, &jail_opts);
146 jail_opts.set_environment(envp);
147
148 LOG_IF(FATAL, !jail_opts.executable_path()) << "No executable given";
149
150 chromeos::MiniJail jail;
151 jail.Initialize(&jail_opts);
152 bool ok = jail.Jail() && jail.Run();
153 return !ok;
154}