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 <pwd.h> // For struct passwd. | 8 #include <pwd.h> // For struct passwd. |
9 #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. | 9 #include <sys/types.h> // For getpwuid_r, getgrnam_r, WEXITSTATUS. |
10 | 10 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
61 our_path_ = our_path; | 61 our_path_ = our_path; |
62 initialized_ = true; | 62 initialized_ = true; |
63 generate_diagnostics_ = generate_diagnostics; | 63 generate_diagnostics_ = generate_diagnostics; |
64 } | 64 } |
65 | 65 |
66 UserCollector::~UserCollector() { | 66 UserCollector::~UserCollector() { |
67 } | 67 } |
68 | 68 |
69 std::string UserCollector::GetPattern(bool enabled) const { | 69 std::string UserCollector::GetPattern(bool enabled) const { |
70 if (enabled) { | 70 if (enabled) { |
71 return StringPrintf("|%s --signal=%%s --pid=%%p", our_path_.c_str()); | 71 return StringPrintf("|%s --signal=%%s --pid=%%p --exec_name=%%e", |
72 our_path_.c_str()); | |
72 } else { | 73 } else { |
73 return "core"; | 74 return "core"; |
74 } | 75 } |
75 } | 76 } |
76 | 77 |
77 bool UserCollector::SetUpInternal(bool enabled) { | 78 bool UserCollector::SetUpInternal(bool enabled) { |
78 CHECK(initialized_); | 79 CHECK(initialized_); |
79 logger_->LogInfo("%s user crash handling", | 80 logger_->LogInfo("%s user crash handling", |
80 enabled ? "Enabling" : "Disabling"); | 81 enabled ? "Enabling" : "Disabling"); |
81 if (file_util::WriteFile(FilePath(core_pipe_limit_file_), | 82 if (file_util::WriteFile(FilePath(core_pipe_limit_file_), |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
162 return false; | 163 return false; |
163 } | 164 } |
164 const char *number = ids[kind].c_str(); | 165 const char *number = ids[kind].c_str(); |
165 char *end_number = NULL; | 166 char *end_number = NULL; |
166 *id = strtol(number, &end_number, 10); | 167 *id = strtol(number, &end_number, 10); |
167 if (*end_number != '\0') | 168 if (*end_number != '\0') |
168 return false; | 169 return false; |
169 return true; | 170 return true; |
170 } | 171 } |
171 | 172 |
172 void UserCollector::LogCollectionError(const std::string &error_message) { | |
173 error_log_.append(error_message.c_str()); | |
174 error_log_.append("\n"); | |
175 logger_->LogError(error_message.c_str()); | |
176 } | |
177 | |
178 void UserCollector::EnqueueCollectionErrorLog(pid_t pid, | 173 void UserCollector::EnqueueCollectionErrorLog(pid_t pid, |
179 const std::string &exec) { | 174 const std::string &exec) { |
180 FilePath crash_path; | 175 FilePath crash_path; |
181 logger_->LogInfo("Writing conversion problems as separate crash report."); | 176 logger_->LogInfo("Writing conversion problems as separate crash report."); |
182 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) { | 177 if (!GetCreatedCrashDirectoryByEuid(0, &crash_path, NULL)) { |
183 logger_->LogError("Could not even get log directory; out of space?"); | 178 logger_->LogError("Could not even get log directory; out of space?"); |
184 return; | 179 return; |
185 } | 180 } |
186 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); | 181 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); |
187 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); | 182 FilePath log_path = GetCrashPath(crash_path, dump_basename, "log"); |
188 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); | 183 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); |
189 // We must use WriteNewFile instead of file_util::WriteFile as we do | 184 // We must use WriteNewFile instead of file_util::WriteFile as we do |
190 // not want to write with root access to a symlink that an attacker | 185 // not want to write with root access to a symlink that an attacker |
191 // might have created. | 186 // might have created. |
192 WriteNewFile(log_path, error_log_.data(), error_log_.length()); | 187 WriteNewFile(log_path, error_log_.data(), error_log_.length()); |
193 AddCrashMetaData("sig", kCollectionErrorSignature); | 188 AddCrashMetaData("sig", kCollectionErrorSignature); |
194 WriteCrashMetaData(meta_path, exec, log_path.value()); | 189 WriteCrashMetaData(meta_path, exec, log_path.value()); |
195 } | 190 } |
196 | 191 |
197 bool UserCollector::CopyOffProcFiles(pid_t pid, | 192 bool UserCollector::CopyOffProcFiles(pid_t pid, |
198 const FilePath &container_dir) { | 193 const FilePath &container_dir) { |
199 if (!file_util::CreateDirectory(container_dir)) { | 194 if (!file_util::CreateDirectory(container_dir)) { |
200 LogCollectionError(StringPrintf("Could not create %s", | 195 logger_->LogError("Could not create %s", |
201 container_dir.value().c_str())); | 196 container_dir.value().c_str()); |
202 return false; | 197 return false; |
203 } | 198 } |
204 FilePath process_path = GetProcessPath(pid); | 199 FilePath process_path = GetProcessPath(pid); |
205 if (!file_util::PathExists(process_path)) { | 200 if (!file_util::PathExists(process_path)) { |
206 LogCollectionError(StringPrintf("Path %s does not exist", | 201 logger_->LogError("Path %s does not exist", process_path.value().c_str()); |
207 process_path.value().c_str())); | |
208 return false; | 202 return false; |
209 } | 203 } |
210 static const char *proc_files[] = { | 204 static const char *proc_files[] = { |
211 "auxv", | 205 "auxv", |
212 "cmdline", | 206 "cmdline", |
213 "environ", | 207 "environ", |
214 "maps", | 208 "maps", |
215 "status" | 209 "status" |
216 }; | 210 }; |
217 for (unsigned i = 0; i < arraysize(proc_files); ++i) { | 211 for (unsigned i = 0; i < arraysize(proc_files); ++i) { |
218 if (!file_util::CopyFile(process_path.Append(proc_files[i]), | 212 if (!file_util::CopyFile(process_path.Append(proc_files[i]), |
219 container_dir.Append(proc_files[i]))) { | 213 container_dir.Append(proc_files[i]))) { |
220 LogCollectionError(StringPrintf("Could not copy %s file", | 214 logger_->LogError("Could not copy %s file", proc_files[i]); |
221 proc_files[i])); | |
222 return false; | 215 return false; |
223 } | 216 } |
224 } | 217 } |
225 return true; | 218 return true; |
226 } | 219 } |
227 | 220 |
228 bool UserCollector::GetCreatedCrashDirectory(pid_t pid, | 221 bool UserCollector::GetCreatedCrashDirectory(pid_t pid, |
229 FilePath *crash_file_path, | 222 FilePath *crash_file_path, |
230 bool *out_of_capacity) { | 223 bool *out_of_capacity) { |
231 FilePath process_path = GetProcessPath(pid); | 224 FilePath process_path = GetProcessPath(pid); |
232 std::string status; | 225 std::string status; |
233 if (FLAGS_directory_failure_test) { | 226 if (FLAGS_directory_failure_test) { |
234 LogCollectionError("Purposefully failing to create spool directory"); | 227 logger_->LogError("Purposefully failing to create spool directory"); |
235 return false; | 228 return false; |
236 } | 229 } |
237 if (!file_util::ReadFileToString(process_path.Append("status"), | 230 if (!file_util::ReadFileToString(process_path.Append("status"), |
238 &status)) { | 231 &status)) { |
239 LogCollectionError("Could not read status file"); | 232 logger_->LogError("Could not read status file"); |
233 logger_->LogInfo("Path %s FileExists: %d", | |
234 process_path.value().c_str(), | |
235 file_util::DirectoryExists(process_path)); | |
240 return false; | 236 return false; |
241 } | 237 } |
242 int process_euid; | 238 int process_euid; |
243 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) { | 239 if (!GetIdFromStatus(kUserId, kIdEffective, status, &process_euid)) { |
244 LogCollectionError("Could not find euid in status file"); | 240 logger_->LogError("Could not find euid in status file"); |
245 return false; | 241 return false; |
246 } | 242 } |
247 if (!GetCreatedCrashDirectoryByEuid(process_euid, | 243 if (!GetCreatedCrashDirectoryByEuid(process_euid, |
248 crash_file_path, | 244 crash_file_path, |
249 out_of_capacity)) { | 245 out_of_capacity)) { |
250 LogCollectionError("Could not create crash directory"); | 246 logger_->LogError("Could not create crash directory"); |
251 return false; | 247 return false; |
252 } | 248 } |
253 return true; | 249 return true; |
254 } | 250 } |
255 | 251 |
256 bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { | 252 bool UserCollector::CopyStdinToCoreFile(const FilePath &core_path) { |
257 // Copy off all stdin to a core file. | 253 // Copy off all stdin to a core file. |
258 FilePath stdin_path("/dev/fd/0"); | 254 FilePath stdin_path("/dev/fd/0"); |
259 if (file_util::CopyFile(stdin_path, core_path)) { | 255 if (file_util::CopyFile(stdin_path, core_path)) { |
260 return true; | 256 return true; |
261 } | 257 } |
262 | 258 |
263 LogCollectionError("Could not write core file"); | 259 logger_->LogError("Could not write core file"); |
264 // If the file system was full, make sure we remove any remnants. | 260 // If the file system was full, make sure we remove any remnants. |
265 file_util::Delete(core_path, false); | 261 file_util::Delete(core_path, false); |
266 return false; | 262 return false; |
267 } | 263 } |
268 | 264 |
269 bool UserCollector::RunCoreToMinidump(const FilePath &core_path, | 265 bool UserCollector::RunCoreToMinidump(const FilePath &core_path, |
270 const FilePath &procfs_directory, | 266 const FilePath &procfs_directory, |
271 const FilePath &minidump_path, | 267 const FilePath &minidump_path, |
272 const FilePath &temp_directory) { | 268 const FilePath &temp_directory) { |
273 FilePath output_path = temp_directory.Append("output"); | 269 FilePath output_path = temp_directory.Append("output"); |
274 std::vector<const char *> core2md_arguments; | 270 std::vector<const char *> core2md_arguments; |
275 core2md_arguments.push_back(kCoreToMinidumpConverterPath); | 271 core2md_arguments.push_back(kCoreToMinidumpConverterPath); |
276 core2md_arguments.push_back(core_path.value().c_str()); | 272 core2md_arguments.push_back(core_path.value().c_str()); |
277 core2md_arguments.push_back(procfs_directory.value().c_str()); | 273 core2md_arguments.push_back(procfs_directory.value().c_str()); |
278 core2md_arguments.push_back(minidump_path.value().c_str()); | 274 core2md_arguments.push_back(minidump_path.value().c_str()); |
279 | 275 |
280 if (FLAGS_core2md_failure_test) { | 276 if (FLAGS_core2md_failure_test) { |
281 // To test how core2md errors are propagaged, cause an error | 277 // To test how core2md errors are propagaged, cause an error |
282 // by forgetting a required argument. | 278 // by forgetting a required argument. |
283 core2md_arguments.pop_back(); | 279 core2md_arguments.pop_back(); |
284 } | 280 } |
285 | 281 |
282 std::string errors_during_fork; | |
petkov
2011/01/18 19:18:20
unused?
kmixter1
2011/01/25 21:28:07
Done.
| |
286 int errorlevel = ForkExecAndPipe(core2md_arguments, | 283 int errorlevel = ForkExecAndPipe(core2md_arguments, |
287 output_path.value().c_str()); | 284 output_path.value().c_str()); |
288 | 285 |
289 std::string output; | 286 std::string output; |
290 file_util::ReadFileToString(output_path, &output); | 287 file_util::ReadFileToString(output_path, &output); |
291 if (errorlevel != 0) { | 288 if (errorlevel != 0) { |
292 LogCollectionError(StringPrintf("Problem during %s [result=%d]: %s", | 289 logger_->LogError("Problem during %s [result=%d]: %s", |
293 kCoreToMinidumpConverterPath, | 290 kCoreToMinidumpConverterPath, |
294 errorlevel, | 291 errorlevel, |
295 output.c_str())); | 292 output.c_str()); |
296 return false; | 293 return false; |
297 } | 294 } |
298 | 295 |
299 if (!file_util::PathExists(minidump_path)) { | 296 if (!file_util::PathExists(minidump_path)) { |
300 LogCollectionError(StringPrintf("Minidump file %s was not created", | 297 logger_->LogError("Minidump file %s was not created", |
301 minidump_path.value().c_str())); | 298 minidump_path.value().c_str()); |
302 return false; | 299 return false; |
303 } | 300 } |
304 return true; | 301 return true; |
305 } | 302 } |
306 | 303 |
307 bool UserCollector::ConvertCoreToMinidump(pid_t pid, | 304 bool UserCollector::ConvertCoreToMinidump(pid_t pid, |
308 const FilePath &container_dir, | 305 const FilePath &container_dir, |
309 const FilePath &core_path, | 306 const FilePath &core_path, |
310 const FilePath &minidump_path) { | 307 const FilePath &minidump_path) { |
311 if (!CopyOffProcFiles(pid, container_dir)) { | 308 if (!CopyOffProcFiles(pid, container_dir)) { |
(...skipping 15 matching lines...) Expand all Loading... | |
327 } | 324 } |
328 | 325 |
329 return conversion_result; | 326 return conversion_result; |
330 } | 327 } |
331 | 328 |
332 bool UserCollector::ConvertAndEnqueueCrash(int pid, | 329 bool UserCollector::ConvertAndEnqueueCrash(int pid, |
333 const std::string &exec, | 330 const std::string &exec, |
334 bool *out_of_capacity) { | 331 bool *out_of_capacity) { |
335 FilePath crash_path; | 332 FilePath crash_path; |
336 if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) { | 333 if (!GetCreatedCrashDirectory(pid, &crash_path, out_of_capacity)) { |
337 LogCollectionError("Unable to find/create process-specific crash path"); | 334 logger_->LogError("Unable to find/create process-specific crash path"); |
338 return false; | 335 return false; |
339 } | 336 } |
340 | 337 |
341 // Directory like /tmp/crash_reporter.1234 which contains the | 338 // Directory like /tmp/crash_reporter.1234 which contains the |
342 // procfs entries and other temporary files used during conversion. | 339 // procfs entries and other temporary files used during conversion. |
343 FilePath container_dir = FilePath("/tmp").Append( | 340 FilePath container_dir = FilePath("/tmp").Append( |
344 StringPrintf("crash_reporter.%d", pid)); | 341 StringPrintf("crash_reporter.%d", pid)); |
345 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); | 342 std::string dump_basename = FormatDumpBasename(exec, time(NULL), pid); |
346 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core"); | 343 FilePath core_path = GetCrashPath(crash_path, dump_basename, "core"); |
347 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); | 344 FilePath meta_path = GetCrashPath(crash_path, dump_basename, "meta"); |
(...skipping 21 matching lines...) Expand all Loading... | |
369 file_util::Delete(core_path, false); | 366 file_util::Delete(core_path, false); |
370 } else { | 367 } else { |
371 logger_->LogInfo("Leaving core file at %s due to developer image", | 368 logger_->LogInfo("Leaving core file at %s due to developer image", |
372 core_path.value().c_str()); | 369 core_path.value().c_str()); |
373 } | 370 } |
374 | 371 |
375 file_util::Delete(container_dir, true); | 372 file_util::Delete(container_dir, true); |
376 return true; | 373 return true; |
377 } | 374 } |
378 | 375 |
379 bool UserCollector::HandleCrash(int signal, int pid, const char *force_exec) { | 376 bool UserCollector::HandleCrash(int signal, int pid, |
377 const char *kernel_supplied_name, | |
378 const char *force_exec) { | |
380 CHECK(initialized_); | 379 CHECK(initialized_); |
381 std::string exec; | 380 std::string exec; |
382 if (force_exec) { | 381 if (force_exec) { |
383 exec.assign(force_exec); | 382 exec.assign(force_exec); |
384 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { | 383 } else if (!GetExecutableBaseNameFromPid(pid, &exec)) { |
385 // If for some reason we don't have the base name, avoid completely | 384 // If we cannot find the exec name, use the kernel supplied name. |
386 // failing by indicating an unknown name. | 385 // We don't always use the kernel's since it truncates the name to |
387 exec = "unknown"; | 386 // 16 characters. |
387 if (!kernel_supplied_name) | |
388 kernel_supplied_name = "null"; | |
389 exec = StringPrintf("supplied_%s", kernel_supplied_name); | |
388 } | 390 } |
389 | 391 |
390 // Allow us to test the crash reporting mechanism successfully even if | 392 // Allow us to test the crash reporting mechanism successfully even if |
391 // other parts of the system crash. | 393 // other parts of the system crash. |
392 if (!FLAGS_filter_in.empty() && | 394 if (!FLAGS_filter_in.empty() && |
393 (FLAGS_filter_in == "none" || | 395 (FLAGS_filter_in == "none" || |
394 FLAGS_filter_in != exec)) { | 396 FLAGS_filter_in != exec)) { |
395 // We use a different format message to make it more obvious in tests | 397 // We use a different format message to make it more obvious in tests |
396 // which crashes are test generated and which are real. | 398 // which crashes are test generated and which are real. |
397 logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s", | 399 logger_->LogWarning("Ignoring crash from %s[%d] while filter_in=%s", |
(...skipping 16 matching lines...) Expand all Loading... | |
414 } | 416 } |
415 | 417 |
416 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)", | 418 logger_->LogWarning("Received crash notification for %s[%d] sig %d (%s)", |
417 exec.c_str(), pid, signal, handling_string); | 419 exec.c_str(), pid, signal, handling_string); |
418 | 420 |
419 if (feedback) { | 421 if (feedback) { |
420 count_crash_function_(); | 422 count_crash_function_(); |
421 | 423 |
422 if (generate_diagnostics_) { | 424 if (generate_diagnostics_) { |
423 bool out_of_capacity = false; | 425 bool out_of_capacity = false; |
424 if (!ConvertAndEnqueueCrash(pid, exec, &out_of_capacity)) { | 426 logger_->set_accumulator(&error_log_); |
427 bool convert_and_enqueue_result = | |
428 ConvertAndEnqueueCrash(pid, exec, &out_of_capacity); | |
429 logger_->set_accumulator(NULL); | |
430 if (!convert_and_enqueue_result) { | |
425 if (!out_of_capacity) | 431 if (!out_of_capacity) |
426 EnqueueCollectionErrorLog(pid, exec); | 432 EnqueueCollectionErrorLog(pid, exec); |
427 return false; | 433 return false; |
428 } | 434 } |
429 } | 435 } |
430 } | 436 } |
431 | 437 |
432 return true; | 438 return true; |
433 } | 439 } |
OLD | NEW |