OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #include <errno.h> |
| 6 #include <pwd.h> |
| 7 #include <sys/stat.h> |
| 8 #include <sys/types.h> |
| 9 #include <unistd.h> |
| 10 |
| 11 #include "base/file_path.h" |
| 12 #include "base/file_util.h" |
| 13 #include "base/logging.h" |
| 14 #include "client/linux/handler/exception_handler.h" |
| 15 #include "common/linux/linux_libc_support.h" |
| 16 #include "common/linux/linux_syscall_support.h" |
| 17 #include "crash/crash_dumper.h" |
| 18 |
| 19 // Define sys_mkdir (sys_open passes mode_t as int, so we do too). |
| 20 LSS_INLINE _syscall2(int, mkdir, const char *, pathname, int, mode); |
| 21 |
| 22 static const char kDefaultUser[] = "chronos"; |
| 23 static const char kSystemCrashParentPath[] = "/var/spool"; |
| 24 static const char kSystemCrashPath[] = "/var/spool/crash"; |
| 25 static const char kUserCrashParentPath[] = "/home/chronos/user"; |
| 26 static const char kUserCrashPath[] = "/home/chronos/user/crash"; |
| 27 |
| 28 // Pointers to paths, set when crash dumping is enabled. |
| 29 static const char *s_crash_path; |
| 30 static const char *s_crash_parent_path; |
| 31 static mode_t s_dump_directory_mode; |
| 32 |
| 33 static bool s_any_crashes_occurred = false; |
| 34 static scoped_ptr<google_breakpad::ExceptionHandler> s_breakpad_handler; |
| 35 |
| 36 static bool s_enabled = false; |
| 37 |
| 38 |
| 39 // Prepare the crash path. Must avoid allocating memory. |
| 40 static bool PrepareCrashPath() { |
| 41 struct kernel_stat buf; |
| 42 if (sys_stat(s_crash_path, &buf) < 0) { |
| 43 // Dump directory does not exist, so create it and its parent now, |
| 44 // at the time of the crash. |
| 45 sys_mkdir(s_crash_parent_path, 755); |
| 46 sys_mkdir(s_crash_path, s_dump_directory_mode); |
| 47 } |
| 48 return sys_stat(s_crash_path, &buf) == 0; |
| 49 } |
| 50 |
| 51 // Use FilterCallback to avoid recursive crashing. |
| 52 // TODO(kmixter): Also use it to avoid enqueuing too many crash dumps |
| 53 // system wide - if we get in a crash/restart loop we don't want the entire |
| 54 // stateful partition to be filled up. |
| 55 static bool FilterCallback(void *) { |
| 56 // This function runs in a compromised context - a crash has already |
| 57 // occurred so memory allocation and libc should be avoided. |
| 58 bool old_any_crashes_occured = s_any_crashes_occurred; |
| 59 s_any_crashes_occurred = true; |
| 60 // The crash path may have been removed or mounted-over, so make sure |
| 61 // there is a container directory. If it fails, not much we can do. |
| 62 PrepareCrashPath(); |
| 63 return !old_any_crashes_occured; |
| 64 } |
| 65 |
| 66 static bool GetEffectiveUser(std::string *result) { |
| 67 char storage[256]; |
| 68 struct passwd passwd_storage; |
| 69 struct passwd *passwd_result = NULL; |
| 70 |
| 71 if (getpwuid_r(geteuid(), &passwd_storage, storage, sizeof(storage), |
| 72 &passwd_result) != 0 || passwd_result == NULL) { |
| 73 return false; |
| 74 } |
| 75 |
| 76 *result = passwd_result->pw_name; |
| 77 return true; |
| 78 } |
| 79 |
| 80 void CrashDumper::Enable() { |
| 81 CHECK(!s_enabled) << "Crash handling already enabled"; |
| 82 |
| 83 std::string name; |
| 84 CHECK(GetEffectiveUser(&name)) |
| 85 << "getpwuid_r failed - " << errno |
| 86 << " - crash reporting cannot be enabled"; |
| 87 |
| 88 if (name == kDefaultUser) { |
| 89 // Crashes as "chronos" when the user is not yet logged in will |
| 90 // still be recorded to /home/chronos/user/crash in the |
| 91 // stateful partition (outside cryptohome). These will eventually |
| 92 // be uploaded when no user is logged in. |
| 93 s_crash_path = kUserCrashPath; |
| 94 s_crash_parent_path = kUserCrashParentPath; |
| 95 s_dump_directory_mode = 0755; |
| 96 } else { |
| 97 s_crash_path = kSystemCrashPath; |
| 98 s_crash_parent_path = kSystemCrashParentPath; |
| 99 // Make the dump directory sticky so any UID can write to |
| 100 // it but not remove another UID's crashes. |
| 101 s_dump_directory_mode = 01777; |
| 102 } |
| 103 |
| 104 CHECK(PrepareCrashPath()) << "Unable to create path " << s_crash_path; |
| 105 |
| 106 // Begin collecting crashes |
| 107 s_breakpad_handler.reset(new google_breakpad::ExceptionHandler( |
| 108 s_crash_path, |
| 109 FilterCallback, |
| 110 NULL, // No minidump callback - sending happens asynchronously to writing |
| 111 NULL, // No callback context necessary |
| 112 true)); // Install handler now. |
| 113 |
| 114 s_enabled = true; |
| 115 } |
| 116 |
| 117 bool CrashDumper::IsEnabled() { |
| 118 return s_enabled; |
| 119 } |
| 120 |
| 121 void CrashDumper::Disable() { |
| 122 CHECK(s_enabled) << "Crash handling was not enabled"; |
| 123 s_breakpad_handler.reset(NULL); |
| 124 s_crash_path = NULL; |
| 125 s_crash_parent_path = NULL; |
| 126 s_enabled = false; |
| 127 } |
OLD | NEW |