Bug 1080077 - For sandbox failures with no crash reporter, log the C stack. r=kang
This is mostly for ASAN builds, which --disable-crash-reporter, but also
fixes a related papercut: debug builds don't use the crash reporter
unless overridden with an environment variable.
Note: this is Linux-only, so NS_StackWalk is always part of the build;
see also
bug 1063455.
--- a/security/sandbox/linux/glue/SandboxCrash.cpp
+++ b/security/sandbox/linux/glue/SandboxCrash.cpp
@@ -14,22 +14,22 @@
#include <unistd.h>
#include <sys/syscall.h>
#include "mozilla/NullPtr.h"
#include "mozilla/unused.h"
#include "mozilla/dom/Exceptions.h"
#include "nsContentUtils.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-
#ifdef MOZ_CRASHREPORTER
#include "nsExceptionHandler.h"
#endif
+#include "nsStackWalk.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)
@@ -69,27 +69,56 @@ SandboxLogJSStack(void)
nsCOMPtr<nsIStackFrame> nextFrame;
nsresult rv = frame->GetCaller(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];
+ nsCodeAddressDetails details;
+
+ NS_DescribeCodeAddress(aPC, &details);
+ NS_FormatCodeAddressDetails(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. NS_StackWalk
+ // can't walk past the signal trampoline on ARM (bug 968531), and
+ // x86 frame pointer walking may or may not work (bug 1082276).
+
+ NS_StackWalk(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
- bool dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
+ dumped = CrashReporter::WriteMinidumpForSigInfo(nr, info, void_context);
+#endif
if (!dumped) {
- SANDBOX_LOG_ERROR("Failed to write minidump");
+ SANDBOX_LOG_ERROR("crash reporter is disabled (or failed);"
+ " trying stack trace:");
+ SandboxLogCStack();
}
-#endif
// 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);