| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium OS Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "crash-reporter/user_collector.h" | 5 #include "crash-reporter/user_collector.h" |
| 6 | 6 |
| 7 #include <grp.h> // For struct group. | 7 #include <grp.h> // For struct group. |
| 8 #include <pcrecpp.h> | 8 #include <pcrecpp.h> |
| 9 #include <pcrecpp.h> | 9 #include <pcrecpp.h> |
| 10 #include <pwd.h> // For struct passwd. | 10 #include <pwd.h> // For struct passwd. |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 } | 107 } |
| 108 | 108 |
| 109 bool UserCollector::GetSymlinkTarget(const FilePath &symlink, | 109 bool UserCollector::GetSymlinkTarget(const FilePath &symlink, |
| 110 FilePath *target) { | 110 FilePath *target) { |
| 111 int max_size = 32; | 111 int max_size = 32; |
| 112 scoped_array<char> buffer; | 112 scoped_array<char> buffer; |
| 113 while (true) { | 113 while (true) { |
| 114 buffer.reset(new char[max_size + 1]); | 114 buffer.reset(new char[max_size + 1]); |
| 115 ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size); | 115 ssize_t size = readlink(symlink.value().c_str(), buffer.get(), max_size); |
| 116 if (size < 0) { | 116 if (size < 0) { |
| 117 int saved_errno = errno; |
| 118 logger_->LogError("Readlink failed on %s with %d", |
| 119 symlink.value().c_str(), saved_errno); |
| 117 return false; | 120 return false; |
| 118 } | 121 } |
| 119 buffer[size] = 0; | 122 buffer[size] = 0; |
| 120 if (size == max_size) { | 123 if (size == max_size) { |
| 121 // Avoid overflow when doubling. | 124 // Avoid overflow when doubling. |
| 122 if (max_size * 2 > max_size) { | 125 if (max_size * 2 > max_size) { |
| 123 max_size *= 2; | 126 max_size *= 2; |
| 124 continue; | 127 continue; |
| 125 } else { | 128 } else { |
| 126 return false; | 129 return false; |
| 127 } | 130 } |
| 128 } | 131 } |
| 129 break; | 132 break; |
| 130 } | 133 } |
| 131 | 134 |
| 132 *target = FilePath(buffer.get()); | 135 *target = FilePath(buffer.get()); |
| 133 return true; | 136 return true; |
| 134 } | 137 } |
| 135 | 138 |
| 136 bool UserCollector::GetExecutableBaseNameFromPid(uid_t pid, | 139 bool UserCollector::GetExecutableBaseNameFromPid(uid_t pid, |
| 137 std::string *base_name) { | 140 std::string *base_name) { |
| 138 FilePath target; | 141 FilePath target; |
| 139 if (!GetSymlinkTarget(GetProcessPath(pid).Append("exe"), &target)) | 142 FilePath process_path = GetProcessPath(pid); |
| 143 FilePath exe_path = process_path.Append("exe"); |
| 144 if (!GetSymlinkTarget(exe_path, &target)) { |
| 145 logger_->LogInfo("GetSymlinkTarget failed - Path %s DirectoryExists: %d", |
| 146 process_path.value().c_str(), |
| 147 file_util::DirectoryExists(process_path)); |
| 148 // Try to further diagnose exe readlink failure cause. |
| 149 struct stat buf; |
| 150 int stat_result = stat(exe_path.value().c_str(), &buf); |
| 151 int saved_errno = errno; |
| 152 if (stat_result < 0) { |
| 153 logger_->LogInfo("stat %s failed: %d %d", exe_path.value().c_str(), |
| 154 stat_result, saved_errno); |
| 155 } else { |
| 156 logger_->LogInfo("stat %s succeeded: st_mode=%d", |
| 157 exe_path.value().c_str(), buf.st_mode); |
| 158 } |
| 140 return false; | 159 return false; |
| 160 } |
| 141 *base_name = target.BaseName().value(); | 161 *base_name = target.BaseName().value(); |
| 142 return true; | 162 return true; |
| 143 } | 163 } |
| 144 | 164 |
| 145 bool UserCollector::GetIdFromStatus(const char *prefix, | 165 bool UserCollector::GetIdFromStatus(const char *prefix, |
| 146 IdKind kind, | 166 IdKind kind, |
| 147 const std::string &status_contents, | 167 const std::string &status_contents, |
| 148 int *id) { | 168 int *id) { |
| 149 // From fs/proc/array.c:task_state(), this file contains: | 169 // From fs/proc/array.c:task_state(), this file contains: |
| 150 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n | 170 // \nUid:\t<uid>\t<euid>\t<suid>\t<fsuid>\n |
| (...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 240 bool *out_of_capacity) { | 260 bool *out_of_capacity) { |
| 241 FilePath process_path = GetProcessPath(pid); | 261 FilePath process_path = GetProcessPath(pid); |
| 242 std::string status; | 262 std::string status; |
| 243 if (FLAGS_directory_failure) { | 263 if (FLAGS_directory_failure) { |
| 244 logger_->LogError("Purposefully failing to create spool directory"); | 264 logger_->LogError("Purposefully failing to create spool directory"); |
| 245 return false; | 265 return false; |
| 246 } | 266 } |
| 247 if (!file_util::ReadFileToString(process_path.Append("status"), | 267 if (!file_util::ReadFileToString(process_path.Append("status"), |
| 248 &status)) { | 268 &status)) { |
| 249 logger_->LogError("Could not read status file"); | 269 logger_->LogError("Could not read status file"); |
| 250 logger_->LogInfo("Path %s FileExists: %d", | 270 logger_->LogInfo("Path %s DirectoryExists: %d", |
| 251 process_path.value().c_str(), | 271 process_path.value().c_str(), |
| 252 file_util::DirectoryExists(process_path)); | 272 file_util::DirectoryExists(process_path)); |
| 253 return false; | 273 return false; |
| 254 } | 274 } |
| 255 int process_euid; | 275 int process_euid; |
| 256 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) { | 276 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) { |
| 257 logger_->LogError("Could not find euid in status file"); | 277 logger_->LogError("Could not find euid in status file"); |
| 258 return false; | 278 return false; |
| 259 } | 279 } |
| 260 if (!GetCreatedCrashDirectoryByEuid(process_euid, | 280 if (!GetCreatedCrashDirectoryByEuid(process_euid, |
| (...skipping 176 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 437 | 457 |
| 438 bool feedback = is_feedback_allowed_function_(); | 458 bool feedback = is_feedback_allowed_function_(); |
| 439 const char *handling_string = "handling"; | 459 const char *handling_string = "handling"; |
| 440 if (!feedback) { | 460 if (!feedback) { |
| 441 handling_string = "ignoring - no consent"; | 461 handling_string = "ignoring - no consent"; |
| 442 } | 462 } |
| 443 | 463 |
| 444 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome | 464 // Treat Chrome crashes as if the user opted-out. We stop counting Chrome |
| 445 // crashes towards user crashes, so user crashes really mean non-Chrome | 465 // crashes towards user crashes, so user crashes really mean non-Chrome |
| 446 // user-space crashes. | 466 // user-space crashes. |
| 447 if (exec == "chrome") { | 467 if (exec == "chrome" || exec == "supplied_chrome") { |
| 448 feedback = false; | 468 feedback = false; |
| 449 handling_string = "ignoring - chrome crash"; | 469 handling_string = "ignoring - chrome crash"; |
| 450 } | 470 } |
| 451 | 471 |
| 452 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)", | 472 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)", |
| 453 exec.c_str(), pid, signal, handling_string); | 473 exec.c_str(), pid, signal, handling_string); |
| 454 | 474 |
| 455 if (feedback) { | 475 if (feedback) { |
| 456 count_crash_function_(); | 476 count_crash_function_(); |
| 457 | 477 |
| 458 if (generate_diagnostics_) { | 478 if (generate_diagnostics_) { |
| 459 bool out_of_capacity = false; | 479 bool out_of_capacity = false; |
| 460 logger_->set_accumulating(true); | |
| 461 bool convert_and_enqueue_result = | 480 bool convert_and_enqueue_result = |
| 462 ConvertAndEnqueueCrash(pid, exec, &out_of_capacity); | 481 ConvertAndEnqueueCrash(pid, exec, &out_of_capacity); |
| 463 logger_->set_accumulating(false); | |
| 464 if (!convert_and_enqueue_result) { | 482 if (!convert_and_enqueue_result) { |
| 465 if (!out_of_capacity) | 483 if (!out_of_capacity) |
| 466 EnqueueCollectionErrorLog(pid, exec); | 484 EnqueueCollectionErrorLog(pid, exec); |
| 467 return false; | 485 return false; |
| 468 } | 486 } |
| 469 } | 487 } |
| 470 } | 488 } |
| 471 | 489 |
| 472 return true; | 490 return true; |
| 473 } | 491 } |
| OLD | NEW |