1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
// This file needs to be linked into libxul, so it can access the JS
// stack and the crash reporter. Everything else in this directory
// should be able to be linked into its own shared library, in order
// to be able to isolate sandbox/chromium from ipc/chromium.
#include "SandboxInternal.h"
#include "SandboxLogging.h"
#include <unistd.h>
#include <sys/syscall.h>
#include "mozilla/Unused.h"
#include "mozilla/dom/Exceptions.h"
#include "nsContentUtils.h"
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
#include "mozilla/StackWalk.h"
#include "nsString.h"
#include "nsThreadUtils.h"
namespace mozilla {
// Log JS stack info in the same place as the sandbox violation
// message. Useful in case the responsible code is JS and all we have
// are logs and a minidump with the C++ stacks (e.g., on TBPL).
static void
SandboxLogJSStack(void)
{
if (!NS_IsMainThread()) {
// This might be a worker thread... or it might be a non-JS
// thread, or a non-NSPR thread. There's isn't a good API for
// dealing with this, yet.
return;
}
if (!nsContentUtils::XPConnect()) {
// There is no content (e.g., the process is a media plugin), in
// which case this will probably crash and definitely not work.
return;
}
nsCOMPtr<nsIStackFrame> frame = dom::GetCurrentJSStack();
// If we got a stack, we must have a current JSContext. This is icky. :(
// Would be better if GetCurrentJSStack() handed out the JSContext it ended up
// using or something.
JSContext* cx = frame ? nsContentUtils::GetCurrentJSContext() : nullptr;
for (int i = 0; frame != nullptr; ++i) {
nsAutoString fileName, funName;
int32_t lineNumber;
// Don't stop unwinding if an attribute can't be read.
fileName.SetIsVoid(true);
Unused << frame->GetFilename(cx, fileName);
lineNumber = 0;
Unused << frame->GetLineNumber(cx, &lineNumber);
funName.SetIsVoid(true);
Unused << frame->GetName(cx, funName);
if (!funName.IsVoid() || !fileName.IsVoid()) {
SANDBOX_LOG_ERROR("JS frame %d: %s %s line %d", i,
funName.IsVoid() ?
"(anonymous)" : NS_ConvertUTF16toUTF8(funName).get(),
fileName.IsVoid() ?
"(no file)" : NS_ConvertUTF16toUTF8(fileName).get(),
lineNumber);
}
nsCOMPtr<nsIStackFrame> nextFrame;
nsresult rv = frame->GetCaller(cx, getter_AddRefs(nextFrame));
NS_ENSURE_SUCCESS_VOID(rv);
frame = nextFrame;
}
}
static void SandboxPrintStackFrame(uint32_t aFrameNumber, void *aPC, void *aSP,
void *aClosure)
{
char buf[1024];
MozCodeAddressDetails details;
MozDescribeCodeAddress(aPC, &details);
MozFormatCodeAddressDetails(buf, sizeof(buf), aFrameNumber, aPC, &details);
SANDBOX_LOG_ERROR("frame %s", buf);
}
static void
SandboxLogCStack()
{
// Skip 3 frames: one for this module, one for the signal handler in
// libmozsandbox, and one for the signal trampoline.
//
// Warning: this might not print any stack frames. MozStackWalk
// can't walk past the signal trampoline on ARM (bug 968531), and
// x86 frame pointer walking may or may not work (bug 1082276).
MozStackWalk(SandboxPrintStackFrame, /* skip */ 3, /* max */ 0,
nullptr, 0, nullptr);
SANDBOX_LOG_ERROR("end of stack.");
}
static void
SandboxCrash(int nr, siginfo_t *info, void *void_context)
{
pid_t pid = getpid(), tid = syscall(__NR_gettid);
bool dumped = false;
#ifdef MOZ_CRASHREPORTER
dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
#endif
if (!dumped) {
SANDBOX_LOG_ERROR("crash reporter is disabled (or failed);"
" trying stack trace:");
SandboxLogCStack();
}
// Do this last, in case it crashes or deadlocks.
SandboxLogJSStack();
// Try to reraise, so the parent sees that this process crashed.
// (If tgkill is forbidden, then seccomp will raise SIGSYS, which
// also accomplishes that goal.)
signal(SIGSYS, SIG_DFL);
syscall(__NR_tgkill, pid, tid, nr);
}
static void __attribute__((constructor))
SandboxSetCrashFunc()
{
gSandboxCrashFunc = SandboxCrash;
}
} // namespace mozilla
|