diff options
-rw-r--r-- | chrome/test/data/nacl/irt_exception/irt_exception_test.cc | 46 | ||||
-rw-r--r-- | chrome/test/data/nacl/irt_exception/irt_exception_test.html | 55 | ||||
-rw-r--r-- | chrome/test/data/nacl/irt_exception/irt_exception_test.nmf | 7 | ||||
-rw-r--r-- | chrome/test/data/nacl/nacl_test_data.gyp | 66 | ||||
-rw-r--r-- | chrome/test/nacl/nacl_browsertest.cc | 16 | ||||
-rw-r--r-- | chrome/test/nacl/nacl_browsertest_util.cc | 10 | ||||
-rw-r--r-- | chrome/test/nacl/nacl_browsertest_util.h | 6 | ||||
-rw-r--r-- | components/nacl.gyp | 1 | ||||
-rw-r--r-- | components/nacl/loader/nacl_helper_linux.cc | 4 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/DEPS | 2 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/irt_exception_handling.cc | 106 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/irt_exception_handling.h | 16 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/irt_interfaces.cc | 1 | ||||
-rw-r--r-- | components/nacl/loader/nonsfi/irt_interfaces.h | 1 |
14 files changed, 337 insertions, 0 deletions
diff --git a/chrome/test/data/nacl/irt_exception/irt_exception_test.cc b/chrome/test/data/nacl/irt_exception/irt_exception_test.cc new file mode 100644 index 0000000..d333421 --- /dev/null +++ b/chrome/test/data/nacl/irt_exception/irt_exception_test.cc @@ -0,0 +1,46 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <setjmp.h> +#include <stdio.h> + +#include "native_client/src/include/nacl/nacl_exception.h" +#include "ppapi/native_client/tests/ppapi_test_lib/test_interface.h" + +namespace { + +jmp_buf g_jmp_buf; + +void MyNaClExceptionHandler(struct NaClExceptionContext* context) { + printf("--- MyNaClExceptionHandler\n"); + longjmp(g_jmp_buf, 1); +} + +void CrashViaSignalHandler() { + printf("--- CrashViaSignalHandler\n"); + + int retval = nacl_exception_set_handler(MyNaClExceptionHandler); + if (retval != 0) { + printf("Unexpected return value from nacl_exception_set_handler: %d\n", + retval); + TEST_FAILED; + return; + } + + if (setjmp(g_jmp_buf)) { + printf("Returned via longjmp\n"); + TEST_PASSED; + return; + } + printf("Going to crash\n"); + __builtin_trap(); +} + +} // namespace + +void SetupTests() { + RegisterTest("CrashViaSignalHandler", CrashViaSignalHandler); +} + +void SetupPluginInterfaces() {} diff --git a/chrome/test/data/nacl/irt_exception/irt_exception_test.html b/chrome/test/data/nacl/irt_exception/irt_exception_test.html new file mode 100644 index 0000000..1b31f6c --- /dev/null +++ b/chrome/test/data/nacl/irt_exception/irt_exception_test.html @@ -0,0 +1,55 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html> + <!-- + Copyright 2014 The Chromium Authors. All rights reserved. + Use of this source code is governed by a BSD-style license that can be + found in the LICENSE file. + --> + <head> + <meta http-equiv="Pragma" content="no-cache" /> + <meta http-equiv="Expires" content="-1" /> + <script type="text/javascript" src="nacltest.js"></script> + <title>Nexe Crash Test</title> + </head> + <body> + <h1>Nexe Crash Test</h1> + <script type="text/javascript"> + //<![CDATA[ + function createModule(id) { + return createNaClEmbed({ + id: id, + src: id + '.nmf', + width: 1, + height: 1, + type: 'application/x-nacl' + }); + } + var e = document.body; + e.appendChild(createModule('irt_exception_test')); + var tester = new Tester(); + + function AddTest(plugin, testName, expectedMessage) { + tester.addAsyncTest(testName, function(test) { + test.expectEvent(plugin, 'message', + function(e) { + if (e.data == expectedMessage) { + test.pass(); + } else { + test.fail(); + } + }); + test.expectEvent(plugin, 'crash', function() { test.fail(); }) + plugin.postMessage(testName); + }); + tester.waitFor(plugin); + } + + AddTest($('irt_exception_test'), + 'CrashViaSignalHandler', 'CrashViaSignalHandler:PASSED'); + + tester.run(); + //]]> + </script> + </body> +</html> diff --git a/chrome/test/data/nacl/irt_exception/irt_exception_test.nmf b/chrome/test/data/nacl/irt_exception/irt_exception_test.nmf new file mode 100644 index 0000000..cd4197a --- /dev/null +++ b/chrome/test/data/nacl/irt_exception/irt_exception_test.nmf @@ -0,0 +1,7 @@ +{ + "program": { + "x86-32-nonsfi": { + "url": "irt_exception_test_pnacl_newlib_x32_nonsfi.nexe" + } + } +} diff --git a/chrome/test/data/nacl/nacl_test_data.gyp b/chrome/test/data/nacl/nacl_test_data.gyp index 67596228..8a2fc93 100644 --- a/chrome/test/data/nacl/nacl_test_data.gyp +++ b/chrome/test/data/nacl/nacl_test_data.gyp @@ -619,6 +619,72 @@ ], }, { + 'target_name': 'irt_exception_test', + 'type': 'none', + 'variables': { + 'nexe_target': 'irt_exception_test', + 'build_newlib': 1, + 'generate_nmf': 1, + 'nexe_destination_dir': 'nacl_test_data', + 'build_pnacl_newlib': 1, + 'nonsfi_destination_dir': '<(PRODUCT_DIR)/>(nexe_destination_dir)/nonsfi', + # Workaround because generate_nmf doesn't work yet for NonSFI, + # explicitly specify the destination directory for NonSFI so + # that we don't have to move it around. + 'out_pnacl_newlib_x86_32_nonsfi_nexe': '>(nonsfi_destination_dir)/irt_exception_test_pnacl_newlib_x32_nonsfi.nexe', + 'link_flags': [ + '-lppapi', + '-lppapi_test_lib', + '-lplatform', + '-lgio', + '-lnacl_exception', + ], + 'sources': [ + 'irt_exception/irt_exception_test.cc', + ], + 'test_files': [ + # TODO(ncbray) move into chrome/test/data/nacl when all tests are + # converted. + 'irt_exception/irt_exception_test.html', + ], + }, + 'dependencies': [ + '<(DEPTH)/native_client/tools.gyp:prep_toolchain', + '<(DEPTH)/native_client/src/shared/platform/platform.gyp:platform_lib', + '<(DEPTH)/native_client/src/shared/gio/gio.gyp:gio_lib', + '<(DEPTH)/native_client/src/untrusted/nacl/nacl.gyp:nacl_exception_lib', + '<(DEPTH)/ppapi/native_client/native_client.gyp:ppapi_lib', + '<(DEPTH)/ppapi/ppapi_nacl.gyp:ppapi_cpp_lib', + 'ppapi_test_lib', + ], + 'conditions': [ + ['disable_pnacl==0 and target_arch=="ia32" and OS=="linux"', { + 'variables': { + 'enable_x86_32_nonsfi': 1, + # Files specifically for NonSFI NaCl. nmf file is + # hand-crafted until generate_nmf learns about NonSFI + # case, and generate_nmf is the one who usually copies + # those files. + 'nonsfi_test_files': [ + # TODO(ncbray) move into chrome/test/data/nacl when all tests are + # converted. + '<(DEPTH)/ppapi/native_client/tools/browser_tester/browserdata/nacltest.js', + 'irt_exception/irt_exception_test.html', + 'irt_exception/irt_exception_test.nmf', + ], + }, + 'copies': [ + { + 'destination': '>(nonsfi_destination_dir)', + 'files': [ + '>@(nonsfi_test_files)', + ], + }, + ], + }], + ], + }, + { 'target_name': 'pm_nameservice_test', 'type': 'none', 'variables': { diff --git a/chrome/test/nacl/nacl_browsertest.cc b/chrome/test/nacl/nacl_browsertest.cc index 9b6168c..cd31331 100644 --- a/chrome/test/nacl/nacl_browsertest.cc +++ b/chrome/test/nacl/nacl_browsertest.cc @@ -144,6 +144,22 @@ IN_PROC_BROWSER_TEST_F(NaClBrowserTestNewlib, IrtManifestFile) { RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_manifest_file_test.html")); } +// The NonSFI test is currently available only on linux-x86-32 +// architecture. +#if defined(OS_LINUX) && defined(ARCH_CPU_X86) +#define MAYBE_NONSFI(test_name) test_name +#else +#define MAYBE_NONSFI(test_name) DISABLED_##test_name +#endif + +IN_PROC_BROWSER_TEST_F(NaClBrowserTestNewlib, IrtException) { + RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_exception_test.html")); +} +IN_PROC_BROWSER_TEST_F(NaClBrowserTestPnaclNonSfi, + MAYBE_NONSFI(IrtException)) { + RunNaClIntegrationTest(FILE_PATH_LITERAL("irt_exception_test.html")); +} + NACL_BROWSER_TEST_F(NaClBrowserTest, Nameservice, { RunNaClIntegrationTest(FILE_PATH_LITERAL("pm_nameservice_test.html")); }) diff --git a/chrome/test/nacl/nacl_browsertest_util.cc b/chrome/test/nacl/nacl_browsertest_util.cc index 97058b8..8843aa9 100644 --- a/chrome/test/nacl/nacl_browsertest_util.cc +++ b/chrome/test/nacl/nacl_browsertest_util.cc @@ -338,3 +338,13 @@ bool NaClBrowserTestStatic::GetDocumentRoot(base::FilePath* document_root) { *document_root = base::FilePath(FILE_PATH_LITERAL("chrome/test/data/nacl")); return true; } + +base::FilePath::StringType NaClBrowserTestPnaclNonSfi::Variant() { + return FILE_PATH_LITERAL("nonsfi"); +} + +void NaClBrowserTestPnaclNonSfi::SetUpCommandLine( + base::CommandLine* command_line) { + NaClBrowserTestBase::SetUpCommandLine(command_line); + command_line->AppendSwitch(switches::kEnableNaClNonSfiMode); +} diff --git a/chrome/test/nacl/nacl_browsertest_util.h b/chrome/test/nacl/nacl_browsertest_util.h index 4176593..22fd852 100644 --- a/chrome/test/nacl/nacl_browsertest_util.h +++ b/chrome/test/nacl/nacl_browsertest_util.h @@ -123,6 +123,12 @@ class NaClBrowserTestPnacl : public NaClBrowserTestBase { virtual bool IsAPnaclTest() OVERRIDE; }; +class NaClBrowserTestPnaclNonSfi : public NaClBrowserTestBase { + public: + virtual base::FilePath::StringType Variant() OVERRIDE; + virtual void SetUpCommandLine(base::CommandLine* command_line) OVERRIDE; +}; + // Class used to test that when --disable-pnacl is specified the PNaCl mime // type is not available. class NaClBrowserTestPnaclDisabled : public NaClBrowserTestBase { diff --git a/components/nacl.gyp b/components/nacl.gyp index 7a5d035..c52a1f7 100644 --- a/components/nacl.gyp +++ b/components/nacl.gyp @@ -257,6 +257,7 @@ 'nacl/loader/nonsfi/elf_loader.h', 'nacl/loader/nonsfi/irt_basic.cc', 'nacl/loader/nonsfi/irt_clock.cc', + 'nacl/loader/nonsfi/irt_exception_handling.cc', 'nacl/loader/nonsfi/irt_fdio.cc', 'nacl/loader/nonsfi/irt_futex.cc', 'nacl/loader/nonsfi/irt_interfaces.cc', diff --git a/components/nacl/loader/nacl_helper_linux.cc b/components/nacl/loader/nacl_helper_linux.cc index 68d0ff6..1fbfdad 100644 --- a/components/nacl/loader/nacl_helper_linux.cc +++ b/components/nacl/loader/nacl_helper_linux.cc @@ -32,6 +32,7 @@ #include "base/rand_util.h" #include "components/nacl/common/nacl_switches.h" #include "components/nacl/loader/nacl_listener.h" +#include "components/nacl/loader/nonsfi/irt_exception_handling.h" #include "components/nacl/loader/sandbox_linux/nacl_sandbox_linux.h" #include "content/public/common/content_descriptors.h" #include "content/public/common/zygote_fork_delegate_linux.h" @@ -82,6 +83,9 @@ void BecomeNaClLoader(const std::vector<int>& child_fds, base::GlobalDescriptors::kBaseDescriptor + kSandboxIPCChannel; ReplaceFDWithDummy(sandbox_ipc_channel); + + // Install crash signal handlers before disallowing system calls. + nacl::nonsfi::InitializeSignalHandler(); } // Finish layer-1 sandbox initialization and initialize the layer-2 sandbox. diff --git a/components/nacl/loader/nonsfi/DEPS b/components/nacl/loader/nonsfi/DEPS index 18f97f5..6052a40 100644 --- a/components/nacl/loader/nonsfi/DEPS +++ b/components/nacl/loader/nonsfi/DEPS @@ -1,4 +1,6 @@ include_rules = [ "+ppapi/nacl_irt", "+sandbox/linux/seccomp-bpf-helpers", + "+native_client/src/trusted/service_runtime/nacl_exception.h", + "+native_client/src/trusted/service_runtime/nacl_signal.h", ] diff --git a/components/nacl/loader/nonsfi/irt_exception_handling.cc b/components/nacl/loader/nonsfi/irt_exception_handling.cc new file mode 100644 index 0000000..c6bd26f --- /dev/null +++ b/components/nacl/loader/nonsfi/irt_exception_handling.cc @@ -0,0 +1,106 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <errno.h> +#include <pthread.h> +#include <signal.h> + +#include "components/nacl/loader/nonsfi/irt_interfaces.h" +#include "native_client/src/include/nacl_macros.h" +#include "native_client/src/trusted/service_runtime/nacl_exception.h" +#include "native_client/src/trusted/service_runtime/nacl_signal.h" + +namespace nacl { +namespace nonsfi { +namespace { + +// This is NonSFI version of exception handling codebase, NaCl side of +// things resides in: +// native_client/src/trusted/service_runtime/linux/nacl_signal.c +// native_client/src/trusted/service_runtime/sys_exception.c + +// Crash signals to handle. The differences from SFI NaCl are that +// NonSFI NaCl does not use NACL_THREAD_SUSPEND_SIGNAL (==SIGUSR1), +// and SIGSYS is reserved for seccomp-bpf. +const int kSignals[] = { + SIGSTKFLT, + SIGINT, SIGQUIT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV, + // Handle SIGABRT in case someone sends it asynchronously using kill(). + SIGABRT +}; + +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +NaClExceptionHandler signal_handler_function_pointer = NULL; + +// Signal handler, responsible for calling the registered handler. +void SignalCatch(int sig, siginfo_t* info, void* uc) { + if (signal_handler_function_pointer) { + NaClSignalContext signal_context; + NaClSignalContextFromHandler(&signal_context, uc); + NaClExceptionFrame exception_frame; + NaClSignalSetUpExceptionFrame(&exception_frame, + &signal_context, + 0 /* context_user_addr, + not useful for NonSFI NaCl. */); + signal_handler_function_pointer(&exception_frame.context); + } + _exit(-1); +} + +int IrtExceptionHandler(NaClExceptionHandler handler, + NaClExceptionHandler* old_handler) { + pthread_mutex_lock(&mutex); + if (old_handler) + *old_handler = signal_handler_function_pointer; + signal_handler_function_pointer = handler; + pthread_mutex_unlock(&mutex); + return 0; +} + +int IrtExceptionStack(void* stack, size_t size) { + // TODO(uekawa): Implement this function so that the exception stack + // actually gets used for running an exception handler. Currently + // we don't switch stack, which means we can't handle stack overflow + // exceptions. + return 0; +} + +int IrtExceptionClearFlag(void) { + // TODO(uekawa): Implement clear_flag() to behave like SFI NaCl's + // implementation, so that a thread can handle a second exception + // after handling a first exception + return ENOSYS; +} + +} // namespace + +const struct nacl_irt_exception_handling kIrtExceptionHandling = { + IrtExceptionHandler, + IrtExceptionStack, + IrtExceptionClearFlag, +}; + +void InitializeSignalHandler() { + struct sigaction sa; + unsigned int a; + + memset(&sa, 0, sizeof(sa)); + sigemptyset(&sa.sa_mask); + sa.sa_sigaction = SignalCatch; + sa.sa_flags = SA_ONSTACK | SA_SIGINFO; + + // Mask all signals we catch to prevent re-entry. + for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) { + sigaddset(&sa.sa_mask, kSignals[a]); + } + + // Install all handlers. + for (a = 0; a < NACL_ARRAY_SIZE(kSignals); a++) { + if (sigaction(kSignals[a], &sa, NULL) != 0) + NaClLog(LOG_FATAL, "sigaction to register signals failed.\n"); + } +} + +} // namespace nonsfi +} // namespace nacl diff --git a/components/nacl/loader/nonsfi/irt_exception_handling.h b/components/nacl/loader/nonsfi/irt_exception_handling.h new file mode 100644 index 0000000..b6aafbd --- /dev/null +++ b/components/nacl/loader/nonsfi/irt_exception_handling.h @@ -0,0 +1,16 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_NACL_LOADER_NONSFI_IRT_EXCEPTION_HANDLING_H_ +#define COMPONENTS_NACL_LOADER_NONSFI_IRT_EXCEPTION_HANDLING_H_ + +namespace nacl { +namespace nonsfi { + +void InitializeSignalHandler(); + +} // namespace nonsfi +} // namespace nacl + +#endif // COMPONENTS_NACL_LOADER_NONSFI_IRT_EXCEPTION_HANDLING_H_ diff --git a/components/nacl/loader/nonsfi/irt_interfaces.cc b/components/nacl/loader/nonsfi/irt_interfaces.cc index a8d3285..79bb8f5 100644 --- a/components/nacl/loader/nonsfi/irt_interfaces.cc +++ b/components/nacl/loader/nonsfi/irt_interfaces.cc @@ -31,6 +31,7 @@ const NaClInterfaceTable kIrtInterfaces[] = { NACL_INTERFACE_TABLE(NACL_IRT_CLOCK_v0_1, kIrtClock), NACL_INTERFACE_TABLE(NACL_IRT_PPAPIHOOK_v0_1, kIrtPpapiHook), NACL_INTERFACE_TABLE(NACL_IRT_RANDOM_v0_1, kIrtRandom), + NACL_INTERFACE_TABLE(NACL_IRT_EXCEPTION_HANDLING_v0_1, kIrtExceptionHandling), }; #undef NACL_INTERFACE_TABLE diff --git a/components/nacl/loader/nonsfi/irt_interfaces.h b/components/nacl/loader/nonsfi/irt_interfaces.h index fae2d2d..6d723e6 100644 --- a/components/nacl/loader/nonsfi/irt_interfaces.h +++ b/components/nacl/loader/nonsfi/irt_interfaces.h @@ -24,6 +24,7 @@ extern const struct nacl_irt_tls kIrtTls; extern const struct nacl_irt_clock kIrtClock; extern const struct nacl_irt_ppapihook kIrtPpapiHook; extern const struct nacl_irt_random kIrtRandom; +extern const struct nacl_irt_exception_handling kIrtExceptionHandling; } // namespace nonsfi } // namespace nacl |