summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruekawa@chromium.org <uekawa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 22:00:21 +0000
committeruekawa@chromium.org <uekawa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-04-29 22:00:21 +0000
commit19d4f12a979c1d2f019c2431707f27175f055da9 (patch)
tree269c1fcaca4a6471189a5d7c12a15c98d37c476a
parent7fe37e2f3f8b5dd28918e2ca7898a1aa998c2f43 (diff)
downloadchromium_src-19d4f12a979c1d2f019c2431707f27175f055da9.zip
chromium_src-19d4f12a979c1d2f019c2431707f27175f055da9.tar.gz
chromium_src-19d4f12a979c1d2f019c2431707f27175f055da9.tar.bz2
NonSFI NaCl: Plumb Exception IRT enough for breakpad.
Implements irt_exception. This is enough to get breakpad start reporting minidumps on crash. Stack overflow case handling with sigaltstack will be handled in a followup change. BUG=356925 NOTRY=True Review URL: https://codereview.chromium.org/230413002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266968 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/test/data/nacl/irt_exception/irt_exception_test.cc46
-rw-r--r--chrome/test/data/nacl/irt_exception/irt_exception_test.html55
-rw-r--r--chrome/test/data/nacl/irt_exception/irt_exception_test.nmf7
-rw-r--r--chrome/test/data/nacl/nacl_test_data.gyp66
-rw-r--r--chrome/test/nacl/nacl_browsertest.cc16
-rw-r--r--chrome/test/nacl/nacl_browsertest_util.cc10
-rw-r--r--chrome/test/nacl/nacl_browsertest_util.h6
-rw-r--r--components/nacl.gyp1
-rw-r--r--components/nacl/loader/nacl_helper_linux.cc4
-rw-r--r--components/nacl/loader/nonsfi/DEPS2
-rw-r--r--components/nacl/loader/nonsfi/irt_exception_handling.cc106
-rw-r--r--components/nacl/loader/nonsfi/irt_exception_handling.h16
-rw-r--r--components/nacl/loader/nonsfi/irt_interfaces.cc1
-rw-r--r--components/nacl/loader/nonsfi/irt_interfaces.h1
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