1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : // Second generation sel_universal implemented in C++
8 :
9 : #include <stdio.h>
10 :
11 : #include <fstream>
12 : #include <map>
13 : #include <sstream>
14 : #include <string>
15 : #include <vector>
16 :
17 : #include "native_client/src/include/nacl_string.h"
18 : #include "native_client/src/include/nacl_macros.h"
19 : #include "native_client/src/include/nacl_scoped_ptr.h"
20 : #include "native_client/src/include/portability.h"
21 : #include "native_client/src/include/portability_io.h"
22 : #include "native_client/src/public/secure_service.h"
23 : #include "native_client/src/shared/platform/nacl_log.h"
24 : #include "native_client/src/shared/platform/scoped_ptr_refcount.h"
25 : #include "native_client/src/shared/srpc/nacl_srpc.h"
26 : #include "native_client/src/trusted/desc/nacl_desc_wrapper.h"
27 : #include "native_client/src/trusted/desc/nrd_all_modules.h"
28 : #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
29 : #include "native_client/src/trusted/reverse_service/reverse_service.h"
30 : #include "native_client/src/trusted/sel_universal/pnacl_emu_handler.h"
31 : #include "native_client/src/trusted/sel_universal/reverse_emulate.h"
32 : #include "native_client/src/trusted/sel_universal/replay_handler.h"
33 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
34 : #include "native_client/src/trusted/service_runtime/nacl_error_code.h"
35 :
36 : #include "native_client/src/trusted/nonnacl_util/launcher_factory.h"
37 : #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher_zygote.h"
38 :
39 : using std::ifstream;
40 : using std::map;
41 : using std::string;
42 : using std::vector;
43 : using nacl::DescWrapper;
44 :
45 : // TODO(robertm): add explanation for flags
46 : static const char* kUsage =
47 : "Usage:\n"
48 : "\n"
49 : "sel_universal <sel_universal_arg> <sel_ldr_arg>* [-- <nexe> <nexe_arg>*]\n"
50 : "\n"
51 : "Exactly one nexe argument is required.\n"
52 : "After startup the user is prompted for interactive commands.\n"
53 : "For sample commands have a look at: tests/srpc/srpc_basic_test.stdin\n"
54 : "\n"
55 : "sel_universal arguments are:\n"
56 : "\n"
57 : " --help\n"
58 : " --event_record <file>\n"
59 : " --event_replay <file>\n"
60 : " --debug\n"
61 : " --abort_on_error\n"
62 : " --silence_nexe\n"
63 : " --command_prefix <prefix>\n"
64 : " --command_file <file>\n"
65 : " --var <tag> <value>\n"
66 : " --url_alias <url> <filename>\n"
67 : " --uses_reverse_service\n"
68 : " --no_app_channel\n"
69 : "\n"
70 : "The following sel_ldr arguments might be useful:\n"
71 : " -v increase verbosity\n"
72 : " -E NACL_SRPC_DEBUG=1 even more verbosity for srpc debugging\n";
73 :
74 :
75 : // NOTE: this used to be stack allocated inside main which cause
76 : // problems on ARM (probably a tool chain bug).
77 : // NaClSrpcChannel is pretty big (> 256kB)
78 : static NaClSrpcChannel command_channel;
79 : static NaClSrpcChannel channel;
80 :
81 : // variables set via command line
82 14 : static map<string, string> initial_vars;
83 28 : static vector<string> initial_commands;
84 : static bool abort_on_error = false;
85 : static bool silence_nexe = false;
86 28 : static vector<string> command_prefix;
87 : static bool uses_reverse_service = false;
88 : static bool app_channel = true;
89 :
90 : // When given argc and argv this function (a) extracts the nexe argument,
91 : // (b) populates sel_ldr_argv with sel_ldr arguments, and (c) populates
92 : // app_argv with nexe module args. Also see kUsage above for details.
93 : // It will call exit with codes 0 (help message) and 1 (incorrect args).
94 14 : static nacl::string ProcessArguments(int argc,
95 14 : char* argv[],
96 14 : vector<nacl::string>* const sel_ldr_argv,
97 14 : vector<nacl::string>* const app_argv) {
98 14 : if (argc == 1) {
99 0 : printf("%s", kUsage);
100 0 : exit(0);
101 : }
102 :
103 14 : int debug_level = 0;
104 : // Extract sel_universal arguments and transfer the rest to sel_ldr_argv
105 14 : nacl::string app_name;
106 116 : for (int i = 1; i < argc; i++) {
107 88 : const string flag(argv[i]);
108 88 : if (flag == "--help") {
109 0 : printf("%s", kUsage);
110 0 : exit(0);
111 88 : } else if (flag == "--debug") {
112 0 : ++debug_level;
113 88 : } else if (flag == "--abort_on_error") {
114 0 : abort_on_error = true;
115 88 : } else if (flag == "--silence_nexe") {
116 0 : silence_nexe = true;
117 88 : } else if (flag == "--command_prefix") {
118 0 : if (argc <= i + 1) {
119 0 : NaClLog(LOG_FATAL,
120 : "not enough args for --command_prefix option\n");
121 0 : }
122 0 : ++i;
123 0 : command_prefix.push_back(argv[i]);
124 88 : } else if (flag == "--command_file") {
125 6 : if (argc <= i + 1) {
126 0 : NaClLog(LOG_FATAL, "not enough args for --command_file option\n");
127 0 : }
128 6 : NaClLog(LOG_INFO, "reading commands from %s\n", argv[i + 1]);
129 6 : ifstream f;
130 6 : f.open(argv[i + 1]);
131 6 : ++i;
132 88 : while (!f.eof()) {
133 35 : string s;
134 35 : getline(f, s);
135 35 : initial_commands.push_back(s);
136 70 : }
137 6 : f.close();
138 6 : NaClLog(LOG_INFO, "total commands now: %d\n",
139 12 : static_cast<int>(initial_commands.size()));
140 88 : } else if (flag == "--var") {
141 2 : if (argc <= i + 2) {
142 0 : NaClLog(LOG_FATAL, "not enough args for --var option\n");
143 0 : }
144 :
145 4 : const string tag = string(argv[i + 1]);
146 4 : const string val = string(argv[i + 2]);
147 2 : i += 2;
148 4 : initial_vars[tag] = val;
149 78 : } else if (flag == "--uses_reverse_service") {
150 5 : uses_reverse_service = true;
151 67 : } else if (flag == "--no_app_channel") {
152 3 : app_channel = false;
153 59 : } else if (flag == "--") {
154 : // Done processing sel_ldr args. The first argument after '--' is the
155 : // nexe.
156 14 : i++;
157 42 : if (app_name == "" && i < argc) {
158 14 : app_name = argv[i++];
159 14 : }
160 : // The remaining arguments are passed to the executable.
161 28 : for (; i < argc; i++) {
162 0 : app_argv->push_back(argv[i]);
163 0 : }
164 14 : } else {
165 : // NOTE: most sel_ldr args start with a single hyphen so there is not
166 : // much confusion with sel_universal args. But this remains a hack.
167 56 : sel_ldr_argv->push_back(argv[i]);
168 : }
169 88 : }
170 :
171 14 : if (debug_level > 0) {
172 0 : NaClLogSetVerbosity(debug_level);
173 0 : }
174 :
175 28 : if (app_name == "") {
176 0 : NaClLog(LOG_FATAL, "missing app\n");
177 0 : }
178 :
179 14 : return app_name;
180 28 : }
181 :
182 :
183 2 : static bool HandlerHardShutdown(NaClCommandLoop* ncl,
184 2 : const vector<string>& args) {
185 4 : UNREFERENCED_PARAMETER(ncl);
186 4 : UNREFERENCED_PARAMETER(args);
187 2 : NaClSrpcInvokeBySignature(&command_channel,
188 : NACL_SECURE_SERVICE_HARD_SHUTDOWN);
189 2 : return true;
190 : }
191 :
192 :
193 0 : static bool HandlerForceShutdown(NaClCommandLoop* ncl,
194 0 : const vector<string>& args) {
195 0 : UNREFERENCED_PARAMETER(ncl);
196 0 : UNREFERENCED_PARAMETER(args);
197 0 : NaClSrpcDtor(&command_channel);
198 0 : return true;
199 : }
200 :
201 :
202 14 : int raii_main(int argc, char* argv[]) {
203 : // Get the arguments to sed_ldr and the nexe module
204 28 : vector<nacl::string> sel_ldr_argv;
205 28 : vector<nacl::string> app_argv;
206 14 : nacl::string app_name =
207 14 : ProcessArguments(argc, argv, &sel_ldr_argv, &app_argv);
208 :
209 14 : if (silence_nexe) {
210 : // redirect stdout/stderr in the nexe to /dev/null
211 0 : std::stringstream ss_stdout;
212 0 : std::stringstream ss_stderr;
213 :
214 0 : int fd = open(PORTABLE_DEV_NULL, O_RDWR);
215 0 : sel_ldr_argv.push_back("-w");
216 0 : ss_stdout << "1:" << fd;
217 0 : sel_ldr_argv.push_back(ss_stdout.str());
218 0 : sel_ldr_argv.push_back("-w");
219 0 : ss_stderr << "2:" << fd;
220 0 : sel_ldr_argv.push_back(ss_stderr.str());
221 0 : }
222 14 : nacl::Zygote zygote;
223 28 : if (!zygote.Init()) {
224 0 : NaClLog(LOG_FATAL, "sel_universal: cannot spawn zygote process\n");
225 0 : }
226 14 : NaClLog(4, "sel_universal: zygote.Init() okay\n");
227 14 : nacl::SelLdrLauncherStandaloneFactory launcher_factory(&zygote);
228 14 : NaClLog(4, "sel_universal: launcher_factory ctor() okay\n");
229 :
230 : // Start sel_ldr with the given application and arguments.
231 28 : nacl::scoped_ptr<nacl::SelLdrLauncherStandalone> launcher(
232 14 : launcher_factory.MakeSelLdrLauncherStandalone());
233 14 : NaClLog(4, "sel_universal: MakeSelLdrLauncherStandalone() okay\n");
234 14 : nacl::DescWrapperFactory factory; // DescWrapper "namespace"
235 :
236 42 : if (!launcher->StartViaCommandLine(command_prefix, sel_ldr_argv, app_argv)) {
237 0 : NaClLog(LOG_FATAL, "sel_universal: Failed to launch sel_ldr\n");
238 0 : }
239 :
240 42 : if (!launcher->SetupCommand(&command_channel)) {
241 0 : NaClLog(LOG_ERROR, "sel_universal: set up command failed\n");
242 0 : exit(1);
243 : }
244 :
245 42 : DescWrapper *host_file = factory.OpenHostFile(app_name.c_str(), O_RDONLY, 0);
246 14 : if (NULL == host_file) {
247 0 : NaClLog(LOG_ERROR, "Could not open %s\n", app_name.c_str());
248 0 : exit(1);
249 : }
250 :
251 42 : if (!launcher->LoadModule(&command_channel, host_file)) {
252 0 : NaClLog(LOG_ERROR, "sel_universal: load module failed\n");
253 0 : exit(1);
254 : }
255 :
256 42 : delete host_file;
257 :
258 14 : if (uses_reverse_service) {
259 10 : ReverseEmulateInit(&command_channel, launcher.get(), &launcher_factory,
260 : command_prefix, sel_ldr_argv);
261 5 : }
262 :
263 42 : if (!launcher->StartModule(&command_channel)) {
264 0 : NaClLog(LOG_ERROR,
265 : "sel_universal: start module failed\n");
266 0 : exit(1);
267 : }
268 :
269 14 : if (app_channel) {
270 33 : if (!launcher->SetupAppChannel(&channel)) {
271 1 : NaClLog(LOG_ERROR,
272 : "sel_universal: set up app channel failed\n");
273 0 : exit(1);
274 : }
275 10 : }
276 :
277 26 : NaClCommandLoop loop(channel.client,
278 : &channel,
279 39 : launcher->socket_addr()->desc());
280 :
281 : // Sample built-in commands accepted by sel_universal:
282 : //
283 : // install_upcalls service
284 : // show_variables
285 : // show_descriptors
286 : // rpc <name> <in-arg>* "*" <out-arg>*
287 : //
288 : // TODO(robertm): add more documentation
289 : //
290 : // More custom command handlers are installed below:
291 :
292 52 : loop.AddHandler("replay_activate", HandlerReplayActivate);
293 52 : loop.AddHandler("replay", HandlerReplay);
294 52 : loop.AddHandler("replay_unused", HandlerUnusedReplays);
295 :
296 : // possible platform specific stuff
297 52 : loop.AddHandler("readonly_file", HandlerReadonlyFile);
298 52 : loop.AddHandler("readwrite_file", HandlerReadwriteFile);
299 52 : loop.AddHandler("readwrite_quota_file", HandlerReadwriteFileQuota);
300 52 : loop.AddHandler("sleep", HandlerSleep);
301 52 : loop.AddHandler("save_to_file", HandlerSaveToFile);
302 52 : loop.AddHandler("load_from_file", HandlerLoadFromFile);
303 52 : loop.AddHandler("file_size", HandlerFileSize);
304 52 : loop.AddHandler("sync_socket_create", HandlerSyncSocketCreate);
305 52 : loop.AddHandler("sync_socket_write", HandlerSyncSocketWrite);
306 : // new names
307 52 : loop.AddHandler("pnacl_emu_initialize", HandlerPnaclEmuInitialize);
308 52 : loop.AddHandler("pnacl_emu_add_varname_mapping",
309 : HandlerPnaclEmuAddVarnameMapping);
310 52 : loop.AddHandler("reverse_service_add_manifest_mapping",
311 : HandlerReverseEmuAddManifestMapping);
312 52 : loop.AddHandler("reverse_service_dump_manifest_mappings",
313 : HandlerReverseEmuDumpManifestMappings);
314 52 : loop.AddHandler("stream_file", HandlerPnaclFileStream);
315 52 : loop.AddHandler("wait_for_exit", HandlerWaitForExit);
316 :
317 52 : loop.AddHandler("hard_shutdown", HandlerHardShutdown);
318 52 : loop.AddHandler("force_shutdown", HandlerForceShutdown);
319 :
320 13 : NaClLog(1, "populating initial vars\n");
321 26 : for (map<string, string>::iterator it = initial_vars.begin();
322 45 : it != initial_vars.end();
323 4 : ++it) {
324 14 : loop.SetVariable(it->first, it->second);
325 2 : }
326 :
327 26 : const bool success = initial_commands.size() > 0 ?
328 12 : loop.ProcessCommands(initial_commands) :
329 27 : loop.StartInteractiveLoop(abort_on_error);
330 :
331 : // Close the connections to sel_ldr.
332 13 : NaClSrpcDtor(&command_channel);
333 13 : NaClSrpcDtor(&channel);
334 :
335 13 : if (uses_reverse_service) {
336 5 : ReverseEmulateFini();
337 5 : }
338 :
339 13 : return success ? 0 : -1;
340 104 : }
341 :
342 14 : int main(int argc, char* argv[]) {
343 : // Descriptor transfer requires the following
344 14 : NaClSrpcModuleInit();
345 14 : NaClNrdAllModulesInit();
346 :
347 14 : int exit_status = raii_main(argc, argv);
348 :
349 14 : NaClSrpcModuleFini();
350 14 : NaClNrdAllModulesFini();
351 :
352 14 : return exit_status;
353 : }
|