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.
14 #include "native_client/src/public/chrome_main.h"
15 #include "native_client/src/public/nacl_app.h"
16 #include "native_client/src/public/nacl_file_info.h"
17 #include "native_client/src/shared/platform/nacl_check.h"
18 #include "native_client/src/shared/platform/nacl_threads.h"
19 #include "native_client/src/shared/srpc/nacl_srpc.h"
20 #include "native_client/src/trusted/desc/nacl_desc_custom.h"
21 #include "native_client/src/trusted/desc/nacl_desc_file_info.h"
22 #include "native_client/src/trusted/nonnacl_util/sel_ldr_launcher.h"
23 #include "native_client/src/trusted/service_runtime/include/sys/fcntl.h"
24 #include "native_client/src/trusted/service_runtime/nacl_all_modules.h"
25 #include "native_client/src/trusted/service_runtime/nacl_config.h"
26 #include "native_client/src/trusted/service_runtime/nacl_valgrind_hooks.h"
27 #include "native_client/src/trusted/service_runtime/sel_addrspace.h"
28 #include "native_client/src/trusted/service_runtime/sel_ldr.h"
29 #include "native_client/src/trusted/validator/validation_cache.h"
31 // A global variable that specifies whether the module should be loaded via
32 // SRPC. Its value is controlled by a command line flag kNoSrpcLoadModule.
33 bool g_load_module_srpc = true;
34 const char kNoSrpcLoadModule[] = "--no_srpc_load_module";
36 // A global variable that specifies whether or not the test should set
37 // the irt_load_optional flag in NaClChromeMainArgs.
38 bool g_irt_load_optional = false;
39 const char kIrtLoadOptional[] = "--irt_load_optional";
41 // A global variable that specifies whether or not to test validation
42 // caching of the main nexe.
43 bool g_test_validation_cache = false;
44 const char kTestValidationCache[] = "--test_validation_cache";
46 int OpenFileReadOnly(const char *filename) {
48 return _open(filename, _O_RDONLY);
50 return open(filename, O_RDONLY);
54 int32_t OpenFileHandleReadExec(const char *filename) {
56 HANDLE h = CreateFileA(filename,
57 GENERIC_READ | GENERIC_EXECUTE,
61 FILE_ATTRIBUTE_NORMAL,
63 // On Windows, valid handles are 32 bit unsigned integers so this is safe.
64 return reinterpret_cast<int32_t>(h);
66 return open(filename, O_RDONLY);
70 // This launcher class does not actually launch a process, but we
71 // reuse SelLdrLauncherBase in order to use its helper methods.
72 class DummyLauncher : public nacl::SelLdrLauncherBase {
74 explicit DummyLauncher(NaClHandle channel) {
78 virtual bool Start(const char *url) {
79 UNREFERENCED_PARAMETER(url);
84 // Fake validation cache methods for testing.
85 struct TestValidationHandle {
86 uint64_t expected_token_lo;
87 uint64_t expected_token_hi;
88 int32_t expected_file_handle;
89 char *expected_file_path;
92 struct TestValidationQuery {
93 bool known_to_validate;
96 static void *TestCreateQuery(void *handle) {
97 UNREFERENCED_PARAMETER(handle);
98 return static_cast<void *>(new TestValidationQuery());
101 static void TestAddData(void *query, const unsigned char *data,
103 UNREFERENCED_PARAMETER(query);
104 UNREFERENCED_PARAMETER(data);
105 UNREFERENCED_PARAMETER(length);
108 static int TestQueryKnownToValidate(void *query) {
109 TestValidationQuery *s = static_cast<TestValidationQuery *>(query);
110 return s->known_to_validate;
113 static void TestSetKnownToValidate(void *query) {
114 TestValidationQuery *s = static_cast<TestValidationQuery *>(query);
115 s->known_to_validate = 1;
118 static void TestDestroyQuery(void *query) {
119 delete static_cast<TestValidationQuery *>(query);
122 static int TestCachingIsInexpensive(const struct NaClValidationMetadata *m) {
123 UNREFERENCED_PARAMETER(m);
127 static int TestResolveFileToken(void *handle, struct NaClFileToken *file_token,
128 int32_t *fd, char **file_path,
129 uint32_t *file_path_length) {
130 TestValidationHandle *h = static_cast<TestValidationHandle *>(handle);
131 CHECK(h->expected_token_lo == file_token->lo);
132 CHECK(h->expected_token_hi == file_token->hi);
133 *fd = h->expected_file_handle;
134 *file_path = h->expected_file_path;
135 *file_path_length = static_cast<uint32_t>(strlen(h->expected_file_path));
141 NaClFileInfo file_info;
144 void WINAPI DummyRendererThread(void *thread_arg) {
145 struct ThreadArgs *args = (struct ThreadArgs *) thread_arg;
147 nacl::DescWrapperFactory desc_wrapper_factory;
148 DummyLauncher launcher(args->channel);
149 NaClSrpcChannel trusted_channel;
150 NaClSrpcChannel untrusted_channel;
151 if (g_load_module_srpc) {
152 struct NaClDesc *desc = NaClDescIoFromFileInfo(args->file_info,
155 nacl::DescWrapper *nexe_desc =
156 desc_wrapper_factory.MakeGenericCleanup(desc);
157 CHECK(nexe_desc != NULL);
158 CHECK(launcher.SetupCommandAndLoad(&trusted_channel, nexe_desc));
160 CHECK(launcher.SetupCommand(&trusted_channel));
162 CHECK(launcher.StartModuleAndSetupAppChannel(&trusted_channel,
163 &untrusted_channel));
166 void ExampleDescDestroy(void *handle) {
167 UNREFERENCED_PARAMETER(handle);
170 ssize_t ExampleDescSendMsg(void *handle,
171 const struct NaClImcTypedMsgHdr *msg,
173 UNREFERENCED_PARAMETER(handle);
174 UNREFERENCED_PARAMETER(msg);
175 UNREFERENCED_PARAMETER(flags);
177 NaClLog(LOG_FATAL, "ExampleDescSendMsg: Not implemented\n");
181 ssize_t ExampleDescRecvMsg(void *handle,
182 struct NaClImcTypedMsgHdr *msg,
184 UNREFERENCED_PARAMETER(handle);
185 UNREFERENCED_PARAMETER(msg);
186 UNREFERENCED_PARAMETER(flags);
188 NaClLog(LOG_FATAL, "ExampleDescRecvMsg: Not implemented\n");
192 struct NaClDesc *MakeExampleDesc() {
193 struct NaClDescCustomFuncs funcs = NACL_DESC_CUSTOM_FUNCS_INITIALIZER;
194 funcs.Destroy = ExampleDescDestroy;
195 funcs.SendMsg = ExampleDescSendMsg;
196 funcs.RecvMsg = ExampleDescRecvMsg;
197 return NaClDescMakeCustomDesc(NULL, &funcs);
200 // Process commandline options and return the index where non-option
201 // commandline arguments begin. Assumes all options are in the front.
202 int NaClHandleArguments(int argc, char **argv) {
203 static const struct TestArguments {
204 const char *flag_name;
205 bool *flag_reference;
208 {kNoSrpcLoadModule, &g_load_module_srpc, false},
209 {kIrtLoadOptional, &g_irt_load_optional, true},
210 {kTestValidationCache, &g_test_validation_cache, true},
214 while (cur_arg < argc) {
216 bool matched = false;
217 while (long_opts[i].flag_name != NULL) {
218 if (strcmp(long_opts[i].flag_name, argv[cur_arg]) == 0) {
219 *long_opts[i].flag_reference = long_opts[i].value_to_set;
233 int main(int argc, char **argv) {
234 // Note that we deliberately do not call NaClAllModulesInit() here,
235 // in order to mimic what we expect the Chromium side to do.
236 NaClChromeMainInit();
237 struct NaClChromeMainArgs *args = NaClChromeMainArgsCreate();
238 struct NaClApp *nap = NaClAppCreate();
239 struct ThreadArgs thread_args;
241 NaClHandleBootstrapArgs(&argc, &argv);
242 int last_option_index = NaClHandleArguments(argc, argv);
244 args->prereserved_sandbox_size = g_prereserved_sandbox_size;
246 // There should be two more arguments after parsing the optional ones.
247 if (last_option_index + 2 != argc) {
250 "NaClHandleArguments stopped at opt %d (expected %d == argc(%d)-2\n",
251 last_option_index, argc - 2, argc);
253 const char *irt_filename = argv[last_option_index];
254 const char *nexe_filename = argv[last_option_index + 1];
257 "SelMainChromeTest configuration:\n"
258 "g_load_module_srpc: %d\n"
259 "g_irt_load_optional: %d\n"
260 "g_test_validation_cache: %d\n",
261 g_load_module_srpc, g_irt_load_optional, g_test_validation_cache);
263 args->irt_fd = OpenFileReadOnly(irt_filename);
264 args->irt_load_optional = g_irt_load_optional;
265 CHECK(args->irt_fd >= 0);
267 memset(&thread_args.file_info, 0, sizeof thread_args.file_info);
268 thread_args.file_info.desc = OpenFileReadOnly(nexe_filename);
269 CHECK(thread_args.file_info.desc >= 0);
270 NaClFileNameForValgrind(nexe_filename);
272 NaClHandle socketpair[2];
273 CHECK(NaClSocketPair(socketpair) == 0);
274 args->imc_bootstrap_handle = socketpair[0];
275 thread_args.channel = socketpair[1];
277 // Check that NaClDescMakeCustomDesc() works when called in this context.
278 NaClAppSetDesc(nap, NACL_CHROME_DESC_BASE, MakeExampleDesc());
280 // Set up mock validation cache.
281 struct TestValidationHandle test_handle;
282 struct NaClValidationCache test_cache;
283 if (g_test_validation_cache) {
284 test_handle.expected_token_lo = 0xabcdef123456789LL;
285 test_handle.expected_token_hi = 0x101010101010101LL;
286 test_handle.expected_file_handle = OpenFileHandleReadExec(nexe_filename);
287 test_handle.expected_file_path = strdup(nexe_filename);
288 test_cache.handle = &test_handle;
289 test_cache.CreateQuery = &TestCreateQuery;
290 test_cache.AddData = &TestAddData;
291 test_cache.QueryKnownToValidate = &TestQueryKnownToValidate;
292 test_cache.SetKnownToValidate = &TestSetKnownToValidate;
293 test_cache.DestroyQuery = &TestDestroyQuery;
294 test_cache.CachingIsInexpensive = &TestCachingIsInexpensive;
295 test_cache.ResolveFileToken = &TestResolveFileToken;
296 args->validation_cache = &test_cache;
297 thread_args.file_info.file_token.lo = test_handle.expected_token_lo;
298 thread_args.file_info.file_token.hi = test_handle.expected_token_hi;
300 if (!g_load_module_srpc) {
302 info.desc = OpenFileHandleReadExec(nexe_filename);
304 info.desc = _open_osfhandle(info.desc, _O_RDONLY | _O_BINARY);
306 if (g_test_validation_cache) {
307 info.file_token.lo = test_handle.expected_token_lo;
308 info.file_token.hi = test_handle.expected_token_hi;
310 info.file_token.lo = 0;
311 info.file_token.hi = 0;
313 args->nexe_desc = NaClDescIoFromFileInfo(info, NACL_ABI_O_RDONLY);
317 CHECK(NaClThreadCtor(&thread, DummyRendererThread, &thread_args,
318 NACL_KERN_STACK_SIZE));
320 NaClChromeMainStartApp(nap, args);
321 NaClLog(LOG_FATAL, "NaClChromeMainStartApp() should never return\n");