Commit 19d4f12a authored by uekawa@chromium.org's avatar uekawa@chromium.org

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
parent 7fe37e2f
// 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() {}
<!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>
{
"program": {
"x86-32-nonsfi": {
"url": "irt_exception_test_pnacl_newlib_x32_nonsfi.nexe"
}
}
}
......@@ -618,6 +618,72 @@
'nacl_ppapi_util',
],
},
{
'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',
......
......@@ -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"));
})
......
......@@ -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);
}
......@@ -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 {
......
......@@ -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',
......
......@@ -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.
......
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",
]
// 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
// 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_
......@@ -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
......
......@@ -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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment