Bug 1080077 - For sandbox failures with no crash reporter, log the C stack. r=kang
authorJed Davis <jld@mozilla.com>
Mon, 13 Oct 2014 18:48:17 -0700
changeset 210275 809b3ec41a5dbdcae1358b4be1d202203b548f29
parent 210274 35029c909c0307af693ebbc94e9191f56c581e8e
child 210276 3e08f81eed80e0152bec5050efc79ea66fa96d25
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewerskang
bugs1080077, 1063455
milestone35.0a1
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.
security/sandbox/linux/glue/SandboxCrash.cpp
--- 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);