summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkmixter@chromium.org <kmixter@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-21 04:21:06 +0000
committerkmixter@chromium.org <kmixter@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-06-21 04:21:06 +0000
commitcb7d53e31de7cb61b190ab56f6136dd44a55aee9 (patch)
tree8df5e007f3eb983e2b6ab6ab0d088d893e53cf81
parentd01576c153e5a60a7a76340220bcb096180993b0 (diff)
downloadchromium_src-cb7d53e31de7cb61b190ab56f6136dd44a55aee9.zip
chromium_src-cb7d53e31de7cb61b190ab56f6136dd44a55aee9.tar.gz
chromium_src-cb7d53e31de7cb61b190ab56f6136dd44a55aee9.tar.bz2
Always search TIDs for the crashing processes.
Kernels newer than 2.6.32 support TID and PID namespacing where processes' view of their TIDs and PIDs are not globally unique or externally meaningful. We have workarounds to find the TID and PID of the crashing process from outside in the browser process. However, we were only assuming TID namespacing was happening if PID namespacing was enabled and the kernel had a bug that was fixed since 2.6.38. This change causes us to always treat the TID as subject to namespacing. Our trick to find the TID relies on a procfs feature added in 2008. We assume if that feature is not yet present that the TID translation is not necessary. This fixes the bug where all crashes of non-browser processes on Linux 2.6.38+ (Chrome OS r13+) are unusable (result in UnspecifiedStackSignature). BUG=chromium-os:15462 TEST=Do about:crash on 2.6.38 kernel and verify proper tid listed in MDException block Review URL: http://codereview.chromium.org/7190019 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@89795 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--base/linux_util.cc9
-rw-r--r--base/linux_util.h6
-rw-r--r--chrome/browser/crash_handler_host_linux.cc71
3 files changed, 50 insertions, 36 deletions
diff --git a/base/linux_util.cc b/base/linux_util.cc
index 2f9f862..a24f311 100644
--- a/base/linux_util.cc
+++ b/base/linux_util.cc
@@ -252,9 +252,14 @@ bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode) {
return already_found;
}
-pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data) {
+pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data,
+ bool* syscall_supported) {
char buf[256];
snprintf(buf, sizeof(buf), "/proc/%d/task", pid);
+
+ if (syscall_supported != NULL)
+ *syscall_supported = false;
+
DIR* task = opendir(buf);
if (!task) {
LOG(WARNING) << "Cannot open " << buf;
@@ -280,6 +285,8 @@ pid_t FindThreadIDWithSyscall(pid_t pid, const std::string& expected_data) {
int fd = open(buf, O_RDONLY);
if (fd < 0)
continue;
+ if (syscall_supported != NULL)
+ *syscall_supported = true;
bool read_ret =
file_util::ReadFromFD(fd, syscall_data.get(), expected_data.length());
close(fd);
diff --git a/base/linux_util.h b/base/linux_util.h
index de597db..d33cb88 100644
--- a/base/linux_util.h
+++ b/base/linux_util.h
@@ -37,9 +37,11 @@ BASE_API bool FindProcessHoldingSocket(pid_t* pid_out, ino_t socket_inode);
// For a given process |pid|, look through all its threads and find the first
// thread with /proc/[pid]/task/[thread_id]/syscall whose first N bytes matches
// |expected_data|, where N is the length of |expected_data|.
-// Returns the thread id or -1 on error.
+// Returns the thread id or -1 on error. If |syscall_supported| is
+// set to false the kernel does not support syscall in procfs.
BASE_API pid_t FindThreadIDWithSyscall(pid_t pid,
- const std::string& expected_data);
+ const std::string& expected_data,
+ bool* syscall_supported);
} // namespace base
diff --git a/chrome/browser/crash_handler_host_linux.cc b/chrome/browser/crash_handler_host_linux.cc
index 6138742..0249c95 100644
--- a/chrome/browser/crash_handler_host_linux.cc
+++ b/chrome/browser/crash_handler_host_linux.cc
@@ -221,11 +221,12 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
return;
}
- // Kernel bug workaround (broken in 2.6.30 at least):
+ // Kernel bug workaround (broken in 2.6.30 and 2.6.32, working in 2.6.38).
// The kernel doesn't translate PIDs in SCM_CREDENTIALS across PID
// namespaces. Thus |crashing_pid| might be garbage from our point of view.
// In the future we can remove this workaround, but we have to wait a couple
// of years to be sure that it's worked its way out into the world.
+ // TODO(thestig) Remove the workaround when Ubuntu Lucid is deprecated.
// The crashing process closes its copy of the signal_fd immediately after
// calling sendmsg(). We can thus not reliably look for with with
@@ -248,40 +249,44 @@ void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) {
return;
}
- if (actual_crashing_pid != crashing_pid) {
- crashing_pid = actual_crashing_pid;
-
- // The crashing TID set inside the compromised context via sys_gettid()
- // in ExceptionHandler::HandleSignal is also wrong and needs to be
- // translated.
- //
- // We expect the crashing thread to be in sys_read(), waiting for use to
- // write to |signal_fd|. Most newer kernels where we have the different pid
- // namespaces also have /proc/[pid]/syscall, so we can look through
- // |actual_crashing_pid|'s thread group and find the thread that's in the
- // read syscall with the right arguments.
-
- std::string expected_syscall_data;
- // /proc/[pid]/syscall is formatted as follows:
- // syscall_number arg1 ... arg6 sp pc
- // but we just check syscall_number through arg3.
- base::StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
- SYS_read, tid_fd, tid_buf_addr);
- pid_t crashing_tid =
- base::FindThreadIDWithSyscall(crashing_pid, expected_syscall_data);
- if (crashing_tid == -1) {
- // We didn't find the thread we want. Maybe it didn't reach sys_read()
- // yet, or the kernel doesn't support /proc/[pid]/syscall or the thread
- // went away. We'll just take a guess here and assume the crashing
- // thread is the thread group leader.
- crashing_tid = crashing_pid;
- }
-
- ExceptionHandler::CrashContext* bad_context =
- reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
- bad_context->tid = crashing_tid;
+ crashing_pid = actual_crashing_pid;
+
+ // The crashing TID set inside the compromised context via
+ // sys_gettid() in ExceptionHandler::HandleSignal might be wrong (if
+ // the kernel supports PID namespacing) and may need to be
+ // translated.
+ //
+ // We expect the crashing thread to be in sys_read(), waiting for us to
+ // write to |signal_fd|. Most newer kernels where we have the different pid
+ // namespaces also have /proc/[pid]/syscall, so we can look through
+ // |actual_crashing_pid|'s thread group and find the thread that's in the
+ // read syscall with the right arguments.
+
+ std::string expected_syscall_data;
+ // /proc/[pid]/syscall is formatted as follows:
+ // syscall_number arg1 ... arg6 sp pc
+ // but we just check syscall_number through arg3.
+ base::StringAppendF(&expected_syscall_data, "%d 0x%x %p 0x1 ",
+ SYS_read, tid_fd, tid_buf_addr);
+ bool syscall_supported = false;
+ pid_t crashing_tid =
+ base::FindThreadIDWithSyscall(crashing_pid,
+ expected_syscall_data,
+ &syscall_supported);
+ if (crashing_tid == -1 && syscall_supported) {
+ // We didn't find the thread we want. Maybe it didn't reach
+ // sys_read() yet or the thread went away. We'll just take a
+ // guess here and assume the crashing thread is the thread group
+ // leader. If procfs syscall is not supported by the kernel, then
+ // we assume the kernel also does not support TID namespacing and
+ // trust the TID passed by the crashing process.
+ crashing_tid = crashing_pid;
}
+ ExceptionHandler::CrashContext* bad_context =
+ reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context);
+ bad_context->tid = crashing_tid;
+
// Sanitize the string data a bit more
guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0;