1// Copyright 2013 The Chromium 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// For linux_syscall_support.h. This makes it safe to call embedded system
6// calls when in seccomp mode.
7
8#include "components/crash/app/breakpad_linux.h"
9
10#include <fcntl.h>
11#include <poll.h>
12#include <signal.h>
13#include <stdlib.h>
14#include <sys/socket.h>
15#include <sys/time.h>
16#include <sys/types.h>
17#include <sys/uio.h>
18#include <sys/wait.h>
19#include <time.h>
20#include <unistd.h>
21
22#include <algorithm>
23#include <string>
24
25#include "base/base_switches.h"
26#include "base/command_line.h"
27#include "base/debug/crash_logging.h"
28#include "base/debug/dump_without_crashing.h"
29#include "base/files/file_path.h"
30#include "base/linux_util.h"
31#include "base/path_service.h"
32#include "base/posix/eintr_wrapper.h"
33#include "base/posix/global_descriptors.h"
34#include "base/process/memory.h"
35#include "base/strings/string_util.h"
36#include "breakpad/src/client/linux/crash_generation/crash_generation_client.h"
37#include "breakpad/src/client/linux/handler/exception_handler.h"
38#include "breakpad/src/client/linux/minidump_writer/directory_reader.h"
39#include "breakpad/src/common/linux/linux_libc_support.h"
40#include "breakpad/src/common/memory.h"
41#include "components/crash/app/breakpad_linux_impl.h"
42#include "components/crash/app/crash_reporter_client.h"
43#include "content/public/common/content_descriptors.h"
44
45#if defined(OS_ANDROID)
46#include <android/log.h>
47#include <sys/stat.h>
48
49#include "base/android/build_info.h"
50#include "base/android/path_utils.h"
51#endif
52#include "third_party/lss/linux_syscall_support.h"
53
54#if defined(ADDRESS_SANITIZER)
55#include <ucontext.h>  // for getcontext().
56#endif
57
58#if defined(OS_ANDROID)
59#define STAT_STRUCT struct stat
60#define FSTAT_FUNC fstat
61#else
62#define STAT_STRUCT struct kernel_stat
63#define FSTAT_FUNC sys_fstat
64#endif
65
66// Some versions of gcc are prone to warn about unused return values. In cases
67// where we either a) know the call cannot fail, or b) there is nothing we
68// can do when a call fails, we mark the return code as ignored. This avoids
69// spurious compiler warnings.
70#define IGNORE_RET(x) do { if (x); } while (0)
71
72using crash_reporter::GetCrashReporterClient;
73using google_breakpad::ExceptionHandler;
74using google_breakpad::MinidumpDescriptor;
75
76namespace breakpad {
77
78namespace {
79
80#if !defined(OS_CHROMEOS)
81const char kUploadURL[] = "https://clients2.google.com/cr/report";
82#endif
83
84bool g_is_crash_reporter_enabled = false;
85uint64_t g_process_start_time = 0;
86pid_t g_pid = 0;
87char* g_crash_log_path = NULL;
88ExceptionHandler* g_breakpad = NULL;
89
90#if defined(ADDRESS_SANITIZER)
91const char* g_asan_report_str = NULL;
92#endif
93#if defined(OS_ANDROID)
94char* g_process_type = NULL;
95#endif
96
97CrashKeyStorage* g_crash_keys = NULL;
98
99// Writes the value |v| as 16 hex characters to the memory pointed at by
100// |output|.
101void write_uint64_hex(char* output, uint64_t v) {
102  static const char hextable[] = "0123456789abcdef";
103
104  for (int i = 15; i >= 0; --i) {
105    output[i] = hextable[v & 15];
106    v >>= 4;
107  }
108}
109
110// The following helper functions are for calculating uptime.
111
112// Converts a struct timeval to milliseconds.
113uint64_t timeval_to_ms(struct timeval *tv) {
114  uint64_t ret = tv->tv_sec;  // Avoid overflow by explicitly using a uint64_t.
115  ret *= 1000;
116  ret += tv->tv_usec / 1000;
117  return ret;
118}
119
120// Converts a struct timeval to milliseconds.
121uint64_t kernel_timeval_to_ms(struct kernel_timeval *tv) {
122  uint64_t ret = tv->tv_sec;  // Avoid overflow by explicitly using a uint64_t.
123  ret *= 1000;
124  ret += tv->tv_usec / 1000;
125  return ret;
126}
127
128// String buffer size to use to convert a uint64_t to string.
129const size_t kUint64StringSize = 21;
130
131void SetProcessStartTime() {
132  // Set the base process start time value.
133  struct timeval tv;
134  if (!gettimeofday(&tv, NULL))
135    g_process_start_time = timeval_to_ms(&tv);
136  else
137    g_process_start_time = 0;
138}
139
140// uint64_t version of my_int_len() from
141// breakpad/src/common/linux/linux_libc_support.h. Return the length of the
142// given, non-negative integer when expressed in base 10.
143unsigned my_uint64_len(uint64_t i) {
144  if (!i)
145    return 1;
146
147  unsigned len = 0;
148  while (i) {
149    len++;
150    i /= 10;
151  }
152
153  return len;
154}
155
156// uint64_t version of my_uitos() from
157// breakpad/src/common/linux/linux_libc_support.h. Convert a non-negative
158// integer to a string (not null-terminated).
159void my_uint64tos(char* output, uint64_t i, unsigned i_len) {
160  for (unsigned index = i_len; index; --index, i /= 10)
161    output[index - 1] = '0' + (i % 10);
162}
163
164#if defined(OS_ANDROID)
165char* my_strncpy(char* dst, const char* src, size_t len) {
166  int i = len;
167  char* p = dst;
168  if (!dst || !src)
169    return dst;
170  while (i != 0 && *src != '\0') {
171    *p++ = *src++;
172    i--;
173  }
174  while (i != 0) {
175    *p++ = '\0';
176    i--;
177  }
178  return dst;
179}
180
181char* my_strncat(char *dest, const char* src, size_t len) {
182  char* ret = dest;
183  while (*dest)
184      dest++;
185  while (len--)
186    if (!(*dest++ = *src++))
187      return ret;
188  *dest = 0;
189  return ret;
190}
191#endif
192
193#if !defined(OS_CHROMEOS)
194bool my_isxdigit(char c) {
195  return (c >= '0' && c <= '9') || ((c | 0x20) >= 'a' && (c | 0x20) <= 'f');
196}
197#endif
198
199size_t LengthWithoutTrailingSpaces(const char* str, size_t len) {
200  while (len > 0 && str[len - 1] == ' ') {
201    len--;
202  }
203  return len;
204}
205
206void SetClientIdFromCommandLine(const CommandLine& command_line) {
207  // Get the guid from the command line switch.
208  std::string switch_value =
209      command_line.GetSwitchValueASCII(switches::kEnableCrashReporter);
210  GetCrashReporterClient()->SetCrashReporterClientIdFromGUID(switch_value);
211}
212
213// MIME substrings.
214#if defined(OS_CHROMEOS)
215const char g_sep[] = ":";
216#endif
217const char g_rn[] = "\r\n";
218const char g_form_data_msg[] = "Content-Disposition: form-data; name=\"";
219const char g_quote_msg[] = "\"";
220const char g_dashdash_msg[] = "--";
221const char g_dump_msg[] = "upload_file_minidump\"; filename=\"dump\"";
222#if defined(ADDRESS_SANITIZER)
223const char g_log_msg[] = "upload_file_log\"; filename=\"log\"";
224#endif
225const char g_content_type_msg[] = "Content-Type: application/octet-stream";
226
227// MimeWriter manages an iovec for writing MIMEs to a file.
228class MimeWriter {
229 public:
230  static const int kIovCapacity = 30;
231  static const size_t kMaxCrashChunkSize = 64;
232
233  MimeWriter(int fd, const char* const mime_boundary);
234  ~MimeWriter();
235
236  // Append boundary.
237  virtual void AddBoundary();
238
239  // Append end of file boundary.
240  virtual void AddEnd();
241
242  // Append key/value pair with specified sizes.
243  virtual void AddPairData(const char* msg_type,
244                           size_t msg_type_size,
245                           const char* msg_data,
246                           size_t msg_data_size);
247
248  // Append key/value pair.
249  void AddPairString(const char* msg_type,
250                     const char* msg_data) {
251    AddPairData(msg_type, my_strlen(msg_type), msg_data, my_strlen(msg_data));
252  }
253
254  // Append key/value pair, splitting value into chunks no larger than
255  // |chunk_size|. |chunk_size| cannot be greater than |kMaxCrashChunkSize|.
256  // The msg_type string will have a counter suffix to distinguish each chunk.
257  virtual void AddPairDataInChunks(const char* msg_type,
258                                   size_t msg_type_size,
259                                   const char* msg_data,
260                                   size_t msg_data_size,
261                                   size_t chunk_size,
262                                   bool strip_trailing_spaces);
263
264  // Add binary file contents to be uploaded with the specified filename.
265  virtual void AddFileContents(const char* filename_msg,
266                               uint8_t* file_data,
267                               size_t file_size);
268
269  // Flush any pending iovecs to the output file.
270  void Flush() {
271    IGNORE_RET(sys_writev(fd_, iov_, iov_index_));
272    iov_index_ = 0;
273  }
274
275 protected:
276  void AddItem(const void* base, size_t size);
277  // Minor performance trade-off for easier-to-maintain code.
278  void AddString(const char* str) {
279    AddItem(str, my_strlen(str));
280  }
281  void AddItemWithoutTrailingSpaces(const void* base, size_t size);
282
283  struct kernel_iovec iov_[kIovCapacity];
284  int iov_index_;
285
286  // Output file descriptor.
287  int fd_;
288
289  const char* const mime_boundary_;
290
291 private:
292  DISALLOW_COPY_AND_ASSIGN(MimeWriter);
293};
294
295MimeWriter::MimeWriter(int fd, const char* const mime_boundary)
296    : iov_index_(0),
297      fd_(fd),
298      mime_boundary_(mime_boundary) {
299}
300
301MimeWriter::~MimeWriter() {
302}
303
304void MimeWriter::AddBoundary() {
305  AddString(mime_boundary_);
306  AddString(g_rn);
307}
308
309void MimeWriter::AddEnd() {
310  AddString(mime_boundary_);
311  AddString(g_dashdash_msg);
312  AddString(g_rn);
313}
314
315void MimeWriter::AddPairData(const char* msg_type,
316                             size_t msg_type_size,
317                             const char* msg_data,
318                             size_t msg_data_size) {
319  AddString(g_form_data_msg);
320  AddItem(msg_type, msg_type_size);
321  AddString(g_quote_msg);
322  AddString(g_rn);
323  AddString(g_rn);
324  AddItem(msg_data, msg_data_size);
325  AddString(g_rn);
326}
327
328void MimeWriter::AddPairDataInChunks(const char* msg_type,
329                                     size_t msg_type_size,
330                                     const char* msg_data,
331                                     size_t msg_data_size,
332                                     size_t chunk_size,
333                                     bool strip_trailing_spaces) {
334  if (chunk_size > kMaxCrashChunkSize)
335    return;
336
337  unsigned i = 0;
338  size_t done = 0, msg_length = msg_data_size;
339
340  while (msg_length) {
341    char num[kUint64StringSize];
342    const unsigned num_len = my_uint_len(++i);
343    my_uitos(num, i, num_len);
344
345    size_t chunk_len = std::min(chunk_size, msg_length);
346
347    AddString(g_form_data_msg);
348    AddItem(msg_type, msg_type_size);
349    AddItem(num, num_len);
350    AddString(g_quote_msg);
351    AddString(g_rn);
352    AddString(g_rn);
353    if (strip_trailing_spaces) {
354      AddItemWithoutTrailingSpaces(msg_data + done, chunk_len);
355    } else {
356      AddItem(msg_data + done, chunk_len);
357    }
358    AddString(g_rn);
359    AddBoundary();
360    Flush();
361
362    done += chunk_len;
363    msg_length -= chunk_len;
364  }
365}
366
367void MimeWriter::AddFileContents(const char* filename_msg, uint8_t* file_data,
368                                 size_t file_size) {
369  AddString(g_form_data_msg);
370  AddString(filename_msg);
371  AddString(g_rn);
372  AddString(g_content_type_msg);
373  AddString(g_rn);
374  AddString(g_rn);
375  AddItem(file_data, file_size);
376  AddString(g_rn);
377}
378
379void MimeWriter::AddItem(const void* base, size_t size) {
380  // Check if the iovec is full and needs to be flushed to output file.
381  if (iov_index_ == kIovCapacity) {
382    Flush();
383  }
384  iov_[iov_index_].iov_base = const_cast<void*>(base);
385  iov_[iov_index_].iov_len = size;
386  ++iov_index_;
387}
388
389void MimeWriter::AddItemWithoutTrailingSpaces(const void* base, size_t size) {
390  AddItem(base, LengthWithoutTrailingSpaces(static_cast<const char*>(base),
391                                            size));
392}
393
394#if defined(OS_CHROMEOS)
395// This subclass is used on Chromium OS to report crashes in a format easy for
396// the central crash reporting facility to understand.
397// Format is <name>:<data length in decimal>:<data>
398class CrashReporterWriter : public MimeWriter {
399 public:
400  explicit CrashReporterWriter(int fd);
401
402  virtual void AddBoundary() OVERRIDE;
403
404  virtual void AddEnd() OVERRIDE;
405
406  virtual void AddPairData(const char* msg_type,
407                           size_t msg_type_size,
408                          const char* msg_data,
409                           size_t msg_data_size) OVERRIDE;
410
411  virtual void AddPairDataInChunks(const char* msg_type,
412                                   size_t msg_type_size,
413                                   const char* msg_data,
414                                   size_t msg_data_size,
415                                   size_t chunk_size,
416                                   bool strip_trailing_spaces) OVERRIDE;
417
418  virtual void AddFileContents(const char* filename_msg,
419                               uint8_t* file_data,
420                               size_t file_size) OVERRIDE;
421
422 private:
423  DISALLOW_COPY_AND_ASSIGN(CrashReporterWriter);
424};
425
426
427CrashReporterWriter::CrashReporterWriter(int fd) : MimeWriter(fd, "") {}
428
429// No-ops.
430void CrashReporterWriter::AddBoundary() {}
431void CrashReporterWriter::AddEnd() {}
432
433void CrashReporterWriter::AddPairData(const char* msg_type,
434                                      size_t msg_type_size,
435                                      const char* msg_data,
436                                      size_t msg_data_size) {
437  char data[kUint64StringSize];
438  const unsigned data_len = my_uint_len(msg_data_size);
439  my_uitos(data, msg_data_size, data_len);
440
441  AddItem(msg_type, msg_type_size);
442  AddString(g_sep);
443  AddItem(data, data_len);
444  AddString(g_sep);
445  AddItem(msg_data, msg_data_size);
446  Flush();
447}
448
449void CrashReporterWriter::AddPairDataInChunks(const char* msg_type,
450                                              size_t msg_type_size,
451                                              const char* msg_data,
452                                              size_t msg_data_size,
453                                              size_t chunk_size,
454                                              bool strip_trailing_spaces) {
455  if (chunk_size > kMaxCrashChunkSize)
456    return;
457
458  unsigned i = 0;
459  size_t done = 0;
460  size_t msg_length = msg_data_size;
461
462  while (msg_length) {
463    char num[kUint64StringSize];
464    const unsigned num_len = my_uint_len(++i);
465    my_uitos(num, i, num_len);
466
467    size_t chunk_len = std::min(chunk_size, msg_length);
468
469    size_t write_len = chunk_len;
470    if (strip_trailing_spaces) {
471      // Take care of this here because we need to know the exact length of
472      // what is going to be written.
473      write_len = LengthWithoutTrailingSpaces(msg_data + done, write_len);
474    }
475
476    char data[kUint64StringSize];
477    const unsigned data_len = my_uint_len(write_len);
478    my_uitos(data, write_len, data_len);
479
480    AddItem(msg_type, msg_type_size);
481    AddItem(num, num_len);
482    AddString(g_sep);
483    AddItem(data, data_len);
484    AddString(g_sep);
485    AddItem(msg_data + done, write_len);
486    Flush();
487
488    done += chunk_len;
489    msg_length -= chunk_len;
490  }
491}
492
493void CrashReporterWriter::AddFileContents(const char* filename_msg,
494                                          uint8_t* file_data,
495                                          size_t file_size) {
496  char data[kUint64StringSize];
497  const unsigned data_len = my_uint_len(file_size);
498  my_uitos(data, file_size, data_len);
499
500  AddString(filename_msg);
501  AddString(g_sep);
502  AddItem(data, data_len);
503  AddString(g_sep);
504  AddItem(file_data, file_size);
505  Flush();
506}
507#endif  // defined(OS_CHROMEOS)
508
509void DumpProcess() {
510  if (g_breakpad)
511    g_breakpad->WriteMinidump();
512}
513
514#if defined(OS_ANDROID)
515const char kGoogleBreakpad[] = "google-breakpad";
516#endif
517
518size_t WriteLog(const char* buf, size_t nbytes) {
519#if defined(OS_ANDROID)
520  return __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad, buf);
521#else
522  return sys_write(2, buf, nbytes);
523#endif
524}
525
526size_t WriteNewline() {
527  return WriteLog("\n", 1);
528}
529
530#if defined(OS_ANDROID)
531// Android's native crash handler outputs a diagnostic tombstone to the device
532// log. By returning false from the HandlerCallbacks, breakpad will reinstall
533// the previous (i.e. native) signal handlers before returning from its own
534// handler. A Chrome build fingerprint is written to the log, so that the
535// specific build of Chrome and the location of the archived Chrome symbols can
536// be determined directly from it.
537bool FinalizeCrashDoneAndroid() {
538  base::android::BuildInfo* android_build_info =
539      base::android::BuildInfo::GetInstance();
540
541  __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
542                      "### ### ### ### ### ### ### ### ### ### ### ### ###");
543  __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
544                      "Chrome build fingerprint:");
545  __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
546                      android_build_info->package_version_name());
547  __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
548                      android_build_info->package_version_code());
549  __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
550                      CHROME_BUILD_ID);
551  __android_log_write(ANDROID_LOG_WARN, kGoogleBreakpad,
552                      "### ### ### ### ### ### ### ### ### ### ### ### ###");
553  return false;
554}
555#endif
556
557bool CrashDone(const MinidumpDescriptor& minidump,
558               const bool upload,
559               const bool succeeded) {
560  // WARNING: this code runs in a compromised context. It may not call into
561  // libc nor allocate memory normally.
562  if (!succeeded) {
563    const char msg[] = "Failed to generate minidump.";
564    WriteLog(msg, sizeof(msg) - 1);
565    return false;
566  }
567
568  DCHECK(!minidump.IsFD());
569
570  BreakpadInfo info = {0};
571  info.filename = minidump.path();
572  info.fd = minidump.fd();
573#if defined(ADDRESS_SANITIZER)
574  google_breakpad::PageAllocator allocator;
575  const size_t log_path_len = my_strlen(minidump.path());
576  char* log_path = reinterpret_cast<char*>(allocator.Alloc(log_path_len + 1));
577  my_memcpy(log_path, minidump.path(), log_path_len);
578  my_memcpy(log_path + log_path_len - 4, ".log", 4);
579  log_path[log_path_len] = '\0';
580  info.log_filename = log_path;
581#endif
582  info.process_type = "browser";
583  info.process_type_length = 7;
584  info.distro = base::g_linux_distro;
585  info.distro_length = my_strlen(base::g_linux_distro);
586  info.upload = upload;
587  info.process_start_time = g_process_start_time;
588  info.oom_size = base::g_oom_size;
589  info.pid = g_pid;
590  info.crash_keys = g_crash_keys;
591  HandleCrashDump(info);
592#if defined(OS_ANDROID)
593  return FinalizeCrashDoneAndroid();
594#else
595  return true;
596#endif
597}
598
599// Wrapper function, do not add more code here.
600bool CrashDoneNoUpload(const MinidumpDescriptor& minidump,
601                       void* context,
602                       bool succeeded) {
603  return CrashDone(minidump, false, succeeded);
604}
605
606#if !defined(OS_ANDROID)
607// Wrapper function, do not add more code here.
608bool CrashDoneUpload(const MinidumpDescriptor& minidump,
609                     void* context,
610                     bool succeeded) {
611  return CrashDone(minidump, true, succeeded);
612}
613#endif
614
615#if defined(ADDRESS_SANITIZER)
616extern "C"
617void __asan_set_error_report_callback(void (*cb)(const char*));
618
619extern "C"
620void AsanLinuxBreakpadCallback(const char* report) {
621  g_asan_report_str = report;
622  // Send minidump here.
623  g_breakpad->SimulateSignalDelivery(SIGKILL);
624}
625#endif
626
627void EnableCrashDumping(bool unattended) {
628  g_is_crash_reporter_enabled = true;
629
630  base::FilePath tmp_path("/tmp");
631  PathService::Get(base::DIR_TEMP, &tmp_path);
632
633  base::FilePath dumps_path(tmp_path);
634  if (GetCrashReporterClient()->GetCrashDumpLocation(&dumps_path)) {
635    base::FilePath logfile =
636        dumps_path.Append(GetCrashReporterClient()->GetReporterLogFilename());
637    std::string logfile_str = logfile.value();
638    const size_t crash_log_path_len = logfile_str.size() + 1;
639    g_crash_log_path = new char[crash_log_path_len];
640    strncpy(g_crash_log_path, logfile_str.c_str(), crash_log_path_len);
641  }
642  DCHECK(!g_breakpad);
643  MinidumpDescriptor minidump_descriptor(dumps_path.value());
644  minidump_descriptor.set_size_limit(kMaxMinidumpFileSize);
645#if defined(OS_ANDROID)
646  unattended = true;  // Android never uploads directly.
647#endif
648  if (unattended) {
649    g_breakpad = new ExceptionHandler(
650        minidump_descriptor,
651        NULL,
652        CrashDoneNoUpload,
653        NULL,
654        true,  // Install handlers.
655        -1);   // Server file descriptor. -1 for in-process.
656    return;
657  }
658
659#if !defined(OS_ANDROID)
660  // Attended mode
661  g_breakpad = new ExceptionHandler(
662      minidump_descriptor,
663      NULL,
664      CrashDoneUpload,
665      NULL,
666      true,  // Install handlers.
667      -1);   // Server file descriptor. -1 for in-process.
668#endif
669}
670
671#if defined(OS_ANDROID)
672bool CrashDoneInProcessNoUpload(
673    const google_breakpad::MinidumpDescriptor& descriptor,
674    void* context,
675    const bool succeeded) {
676  // WARNING: this code runs in a compromised context. It may not call into
677  // libc nor allocate memory normally.
678  if (!succeeded) {
679    static const char msg[] = "Crash dump generation failed.\n";
680    WriteLog(msg, sizeof(msg) - 1);
681    return false;
682  }
683
684  // Start constructing the message to send to the browser.
685  BreakpadInfo info = {0};
686  info.filename = NULL;
687  info.fd = descriptor.fd();
688  info.process_type = g_process_type;
689  info.process_type_length = my_strlen(g_process_type);
690  info.distro = NULL;
691  info.distro_length = 0;
692  info.upload = false;
693  info.process_start_time = g_process_start_time;
694  info.pid = g_pid;
695  info.crash_keys = g_crash_keys;
696  HandleCrashDump(info);
697  bool finalize_result = FinalizeCrashDoneAndroid();
698  base::android::BuildInfo* android_build_info =
699      base::android::BuildInfo::GetInstance();
700  if (android_build_info->sdk_int() >= 18 &&
701      my_strcmp(android_build_info->build_type(), "eng") != 0 &&
702      my_strcmp(android_build_info->build_type(), "userdebug") != 0) {
703    // On JB MR2 and later, the system crash handler displays a dialog. For
704    // renderer crashes, this is a bad user experience and so this is disabled
705    // for user builds of Android.
706    // TODO(cjhopman): There should be some way to recover the crash stack from
707    // non-uploading user clients. See http://crbug.com/273706.
708    __android_log_write(ANDROID_LOG_WARN,
709                        kGoogleBreakpad,
710                        "Tombstones are disabled on JB MR2+ user builds.");
711    __android_log_write(ANDROID_LOG_WARN,
712                        kGoogleBreakpad,
713                        "### ### ### ### ### ### ### ### ### ### ### ### ###");
714    return true;
715  } else {
716    return finalize_result;
717  }
718}
719
720void EnableNonBrowserCrashDumping(const std::string& process_type,
721                                  int minidump_fd) {
722  // This will guarantee that the BuildInfo has been initialized and subsequent
723  // calls will not require memory allocation.
724  base::android::BuildInfo::GetInstance();
725  SetClientIdFromCommandLine(*CommandLine::ForCurrentProcess());
726
727  // On Android, the current sandboxing uses process isolation, in which the
728  // child process runs with a different UID. That breaks the normal crash
729  // reporting where the browser process generates the minidump by inspecting
730  // the child process. This is because the browser process now does not have
731  // the permission to access the states of the child process (as it has a
732  // different UID).
733  // TODO(jcivelli): http://b/issue?id=6776356 we should use a watchdog
734  // process forked from the renderer process that generates the minidump.
735  if (minidump_fd == -1) {
736    LOG(ERROR) << "Minidump file descriptor not found, crash reporting will "
737        " not work.";
738    return;
739  }
740  SetProcessStartTime();
741  g_pid = getpid();
742
743  g_is_crash_reporter_enabled = true;
744  // Save the process type (it is leaked).
745  const size_t process_type_len = process_type.size() + 1;
746  g_process_type = new char[process_type_len];
747  strncpy(g_process_type, process_type.c_str(), process_type_len);
748  new google_breakpad::ExceptionHandler(MinidumpDescriptor(minidump_fd),
749      NULL, CrashDoneInProcessNoUpload, NULL, true, -1);
750}
751#else
752// Non-Browser = Extension, Gpu, Plugins, Ppapi and Renderer
753class NonBrowserCrashHandler : public google_breakpad::CrashGenerationClient {
754 public:
755  NonBrowserCrashHandler()
756      : server_fd_(base::GlobalDescriptors::GetInstance()->Get(
757            kCrashDumpSignal)) {
758  }
759
760  virtual ~NonBrowserCrashHandler() {}
761
762  virtual bool RequestDump(const void* crash_context,
763                           size_t crash_context_size) OVERRIDE {
764    int fds[2] = { -1, -1 };
765    if (sys_socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) {
766      static const char msg[] = "Failed to create socket for crash dumping.\n";
767      WriteLog(msg, sizeof(msg) - 1);
768      return false;
769    }
770
771    // Start constructing the message to send to the browser.
772    char b;  // Dummy variable for sys_read below.
773    const char* b_addr = &b;  // Get the address of |b| so we can create the
774                              // expected /proc/[pid]/syscall content in the
775                              // browser to convert namespace tids.
776
777    // The length of the control message:
778    static const unsigned kControlMsgSize = sizeof(int);
779    static const unsigned kControlMsgSpaceSize = CMSG_SPACE(kControlMsgSize);
780    static const unsigned kControlMsgLenSize = CMSG_LEN(kControlMsgSize);
781
782    struct kernel_msghdr msg;
783    my_memset(&msg, 0, sizeof(struct kernel_msghdr));
784    struct kernel_iovec iov[kCrashIovSize];
785    iov[0].iov_base = const_cast<void*>(crash_context);
786    iov[0].iov_len = crash_context_size;
787    iov[1].iov_base = &b_addr;
788    iov[1].iov_len = sizeof(b_addr);
789    iov[2].iov_base = &fds[0];
790    iov[2].iov_len = sizeof(fds[0]);
791    iov[3].iov_base = &g_process_start_time;
792    iov[3].iov_len = sizeof(g_process_start_time);
793    iov[4].iov_base = &base::g_oom_size;
794    iov[4].iov_len = sizeof(base::g_oom_size);
795    google_breakpad::SerializedNonAllocatingMap* serialized_map;
796    iov[5].iov_len = g_crash_keys->Serialize(
797        const_cast<const google_breakpad::SerializedNonAllocatingMap**>(
798            &serialized_map));
799    iov[5].iov_base = serialized_map;
800#if !defined(ADDRESS_SANITIZER)
801    COMPILE_ASSERT(5 == kCrashIovSize - 1, Incorrect_Number_Of_Iovec_Members);
802#else
803    iov[6].iov_base = const_cast<char*>(g_asan_report_str);
804    iov[6].iov_len = kMaxAsanReportSize + 1;
805    COMPILE_ASSERT(6 == kCrashIovSize - 1, Incorrect_Number_Of_Iovec_Members);
806#endif
807
808    msg.msg_iov = iov;
809    msg.msg_iovlen = kCrashIovSize;
810    char cmsg[kControlMsgSpaceSize];
811    my_memset(cmsg, 0, kControlMsgSpaceSize);
812    msg.msg_control = cmsg;
813    msg.msg_controllen = sizeof(cmsg);
814
815    struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg);
816    hdr->cmsg_level = SOL_SOCKET;
817    hdr->cmsg_type = SCM_RIGHTS;
818    hdr->cmsg_len = kControlMsgLenSize;
819    ((int*)CMSG_DATA(hdr))[0] = fds[1];
820
821    if (HANDLE_EINTR(sys_sendmsg(server_fd_, &msg, 0)) < 0) {
822      static const char errmsg[] = "Failed to tell parent about crash.\n";
823      WriteLog(errmsg, sizeof(errmsg) - 1);
824      IGNORE_RET(sys_close(fds[0]));
825      IGNORE_RET(sys_close(fds[1]));
826      return false;
827    }
828    IGNORE_RET(sys_close(fds[1]));
829
830    if (HANDLE_EINTR(sys_read(fds[0], &b, 1)) != 1) {
831      static const char errmsg[] = "Parent failed to complete crash dump.\n";
832      WriteLog(errmsg, sizeof(errmsg) - 1);
833    }
834    IGNORE_RET(sys_close(fds[0]));
835
836    return true;
837  }
838
839 private:
840  // The pipe FD to the browser process, which will handle the crash dumping.
841  const int server_fd_;
842
843  DISALLOW_COPY_AND_ASSIGN(NonBrowserCrashHandler);
844};
845
846void EnableNonBrowserCrashDumping() {
847  g_is_crash_reporter_enabled = true;
848  // We deliberately leak this object.
849  DCHECK(!g_breakpad);
850
851  g_breakpad = new ExceptionHandler(
852      MinidumpDescriptor("/tmp"),  // Unused but needed or Breakpad will assert.
853      NULL,
854      NULL,
855      NULL,
856      true,
857      -1);
858  g_breakpad->set_crash_generation_client(new NonBrowserCrashHandler());
859}
860#endif  // defined(OS_ANDROID)
861
862void SetCrashKeyValue(const base::StringPiece& key,
863                      const base::StringPiece& value) {
864  g_crash_keys->SetKeyValue(key.data(), value.data());
865}
866
867void ClearCrashKey(const base::StringPiece& key) {
868  g_crash_keys->RemoveKey(key.data());
869}
870
871// GetCrashReporterClient() cannot call any Set methods until after
872// InitCrashKeys().
873void InitCrashKeys() {
874  g_crash_keys = new CrashKeyStorage;
875  GetCrashReporterClient()->RegisterCrashKeys();
876  base::debug::SetCrashKeyReportingFunctions(&SetCrashKeyValue, &ClearCrashKey);
877}
878
879// Miscellaneous initialization functions to call after Breakpad has been
880// enabled.
881void PostEnableBreakpadInitialization() {
882  SetProcessStartTime();
883  g_pid = getpid();
884
885  base::debug::SetDumpWithoutCrashingFunction(&DumpProcess);
886#if defined(ADDRESS_SANITIZER)
887  // Register the callback for AddressSanitizer error reporting.
888  __asan_set_error_report_callback(AsanLinuxBreakpadCallback);
889#endif
890}
891
892}  // namespace
893
894void LoadDataFromFD(google_breakpad::PageAllocator& allocator,
895                    int fd, bool close_fd, uint8_t** file_data, size_t* size) {
896  STAT_STRUCT st;
897  if (FSTAT_FUNC(fd, &st) != 0) {
898    static const char msg[] = "Cannot upload crash dump: stat failed\n";
899    WriteLog(msg, sizeof(msg) - 1);
900    if (close_fd)
901      IGNORE_RET(sys_close(fd));
902    return;
903  }
904
905  *file_data = reinterpret_cast<uint8_t*>(allocator.Alloc(st.st_size));
906  if (!(*file_data)) {
907    static const char msg[] = "Cannot upload crash dump: cannot alloc\n";
908    WriteLog(msg, sizeof(msg) - 1);
909    if (close_fd)
910      IGNORE_RET(sys_close(fd));
911    return;
912  }
913  my_memset(*file_data, 0xf, st.st_size);
914
915  *size = st.st_size;
916  int byte_read = sys_read(fd, *file_data, *size);
917  if (byte_read == -1) {
918    static const char msg[] = "Cannot upload crash dump: read failed\n";
919    WriteLog(msg, sizeof(msg) - 1);
920    if (close_fd)
921      IGNORE_RET(sys_close(fd));
922    return;
923  }
924
925  if (close_fd)
926    IGNORE_RET(sys_close(fd));
927}
928
929void LoadDataFromFile(google_breakpad::PageAllocator& allocator,
930                      const char* filename,
931                      int* fd, uint8_t** file_data, size_t* size) {
932  // WARNING: this code runs in a compromised context. It may not call into
933  // libc nor allocate memory normally.
934  *fd = sys_open(filename, O_RDONLY, 0);
935  *size = 0;
936
937  if (*fd < 0) {
938    static const char msg[] = "Cannot upload crash dump: failed to open\n";
939    WriteLog(msg, sizeof(msg) - 1);
940    return;
941  }
942
943  LoadDataFromFD(allocator, *fd, true, file_data, size);
944}
945
946// Spawn the appropriate upload process for the current OS:
947// - generic Linux invokes wget.
948// - ChromeOS invokes crash_reporter.
949// |dumpfile| is the path to the dump data file.
950// |mime_boundary| is only used on Linux.
951// |exe_buf| is only used on CrOS and is the crashing process' name.
952void ExecUploadProcessOrTerminate(const BreakpadInfo& info,
953                                  const char* dumpfile,
954                                  const char* mime_boundary,
955                                  const char* exe_buf,
956                                  google_breakpad::PageAllocator* allocator) {
957#if defined(OS_CHROMEOS)
958  // CrOS uses crash_reporter instead of wget to report crashes,
959  // it needs to know where the crash dump lives and the pid and uid of the
960  // crashing process.
961  static const char kCrashReporterBinary[] = "/sbin/crash_reporter";
962
963  char pid_buf[kUint64StringSize];
964  uint64_t pid_str_length = my_uint64_len(info.pid);
965  my_uint64tos(pid_buf, info.pid, pid_str_length);
966  pid_buf[pid_str_length] = '\0';
967
968  char uid_buf[kUint64StringSize];
969  uid_t uid = geteuid();
970  uint64_t uid_str_length = my_uint64_len(uid);
971  my_uint64tos(uid_buf, uid, uid_str_length);
972  uid_buf[uid_str_length] = '\0';
973  const char* args[] = {
974    kCrashReporterBinary,
975    "--chrome",
976    dumpfile,
977    "--pid",
978    pid_buf,
979    "--uid",
980    uid_buf,
981    "--exe",
982    exe_buf,
983    NULL,
984  };
985  static const char msg[] = "Cannot upload crash dump: cannot exec "
986                            "/sbin/crash_reporter\n";
987#else
988  // The --header argument to wget looks like:
989  //   --header=Content-Type: multipart/form-data; boundary=XYZ
990  // where the boundary has two fewer leading '-' chars
991  static const char header_msg[] =
992      "--header=Content-Type: multipart/form-data; boundary=";
993  char* const header = reinterpret_cast<char*>(allocator->Alloc(
994      sizeof(header_msg) - 1 + strlen(mime_boundary) - 2 + 1));
995  memcpy(header, header_msg, sizeof(header_msg) - 1);
996  memcpy(header + sizeof(header_msg) - 1, mime_boundary + 2,
997         strlen(mime_boundary) - 2);
998  // We grab the NUL byte from the end of |mime_boundary|.
999
1000  // The --post-file argument to wget looks like:
1001  //   --post-file=/tmp/...
1002  static const char post_file_msg[] = "--post-file=";
1003  char* const post_file = reinterpret_cast<char*>(allocator->Alloc(
1004       sizeof(post_file_msg) - 1 + strlen(dumpfile) + 1));
1005  memcpy(post_file, post_file_msg, sizeof(post_file_msg) - 1);
1006  memcpy(post_file + sizeof(post_file_msg) - 1, dumpfile, strlen(dumpfile));
1007
1008  static const char kWgetBinary[] = "/usr/bin/wget";
1009  const char* args[] = {
1010    kWgetBinary,
1011    header,
1012    post_file,
1013    kUploadURL,
1014    "--timeout=10",  // Set a timeout so we don't hang forever.
1015    "--tries=1",     // Don't retry if the upload fails.
1016    "-O",  // output reply to fd 3
1017    "/dev/fd/3",
1018    NULL,
1019  };
1020  static const char msg[] = "Cannot upload crash dump: cannot exec "
1021                            "/usr/bin/wget\n";
1022#endif
1023  execve(args[0], const_cast<char**>(args), environ);
1024  WriteLog(msg, sizeof(msg) - 1);
1025  sys__exit(1);
1026}
1027
1028// Runs in the helper process to wait for the upload process running
1029// ExecUploadProcessOrTerminate() to finish. Returns the number of bytes written
1030// to |fd| and save the written contents to |buf|.
1031// |buf| needs to be big enough to hold |bytes_to_read| + 1 characters.
1032size_t WaitForCrashReportUploadProcess(int fd, size_t bytes_to_read,
1033                                       char* buf) {
1034  size_t bytes_read = 0;
1035
1036  // Upload should finish in about 10 seconds. Add a few more 500 ms
1037  // internals to account for process startup time.
1038  for (size_t wait_count = 0; wait_count < 24; ++wait_count) {
1039    struct kernel_pollfd poll_fd;
1040    poll_fd.fd = fd;
1041    poll_fd.events = POLLIN | POLLPRI | POLLERR;
1042    int ret = sys_poll(&poll_fd, 1, 500);
1043    if (ret < 0) {
1044      // Error
1045      break;
1046    } else if (ret > 0) {
1047      // There is data to read.
1048      ssize_t len = HANDLE_EINTR(
1049          sys_read(fd, buf + bytes_read, bytes_to_read - bytes_read));
1050      if (len < 0)
1051        break;
1052      bytes_read += len;
1053      if (bytes_read == bytes_to_read)
1054        break;
1055    }
1056    // |ret| == 0 -> timed out, continue waiting.
1057    // or |bytes_read| < |bytes_to_read| still, keep reading.
1058  }
1059  buf[bytes_to_read] = 0;  // Always NUL terminate the buffer.
1060  return bytes_read;
1061}
1062
1063// |buf| should be |expected_len| + 1 characters in size and NULL terminated.
1064bool IsValidCrashReportId(const char* buf, size_t bytes_read,
1065                          size_t expected_len) {
1066  if (bytes_read != expected_len)
1067    return false;
1068#if defined(OS_CHROMEOS)
1069  return my_strcmp(buf, "_sys_cr_finished") == 0;
1070#else
1071  for (size_t i = 0; i < bytes_read; ++i) {
1072    if (!my_isxdigit(buf[i]))
1073      return false;
1074  }
1075  return true;
1076#endif
1077}
1078
1079// |buf| should be |expected_len| + 1 characters in size and NULL terminated.
1080void HandleCrashReportId(const char* buf, size_t bytes_read,
1081                         size_t expected_len) {
1082  WriteNewline();
1083  if (!IsValidCrashReportId(buf, bytes_read, expected_len)) {
1084#if defined(OS_CHROMEOS)
1085    static const char msg[] =
1086        "System crash-reporter failed to process crash report.";
1087#else
1088    static const char msg[] = "Failed to get crash dump id.";
1089#endif
1090    WriteLog(msg, sizeof(msg) - 1);
1091    WriteNewline();
1092
1093    static const char id_msg[] = "Report Id: ";
1094    WriteLog(id_msg, sizeof(id_msg) - 1);
1095    WriteLog(buf, bytes_read);
1096    WriteNewline();
1097    return;
1098  }
1099
1100#if defined(OS_CHROMEOS)
1101  static const char msg[] = "Crash dump received by crash_reporter\n";
1102  WriteLog(msg, sizeof(msg) - 1);
1103#else
1104  // Write crash dump id to stderr.
1105  static const char msg[] = "Crash dump id: ";
1106  WriteLog(msg, sizeof(msg) - 1);
1107  WriteLog(buf, my_strlen(buf));
1108  WriteNewline();
1109
1110  // Write crash dump id to crash log as: seconds_since_epoch,crash_id
1111  struct kernel_timeval tv;
1112  if (g_crash_log_path && !sys_gettimeofday(&tv, NULL)) {
1113    uint64_t time = kernel_timeval_to_ms(&tv) / 1000;
1114    char time_str[kUint64StringSize];
1115    const unsigned time_len = my_uint64_len(time);
1116    my_uint64tos(time_str, time, time_len);
1117
1118    const int kLogOpenFlags = O_CREAT | O_WRONLY | O_APPEND | O_CLOEXEC;
1119    int log_fd = sys_open(g_crash_log_path, kLogOpenFlags, 0600);
1120    if (log_fd > 0) {
1121      sys_write(log_fd, time_str, time_len);
1122      sys_write(log_fd, ",", 1);
1123      sys_write(log_fd, buf, my_strlen(buf));
1124      sys_write(log_fd, "\n", 1);
1125      IGNORE_RET(sys_close(log_fd));
1126    }
1127  }
1128#endif
1129}
1130
1131#if defined(OS_CHROMEOS)
1132const char* GetCrashingProcessName(const BreakpadInfo& info,
1133                                   google_breakpad::PageAllocator* allocator) {
1134  // Symlink to process binary is at /proc/###/exe.
1135  char linkpath[kUint64StringSize + sizeof("/proc/") + sizeof("/exe")] =
1136    "/proc/";
1137  uint64_t pid_value_len = my_uint64_len(info.pid);
1138  my_uint64tos(linkpath + sizeof("/proc/") - 1, info.pid, pid_value_len);
1139  linkpath[sizeof("/proc/") - 1 + pid_value_len] = '\0';
1140  my_strlcat(linkpath, "/exe", sizeof(linkpath));
1141
1142  const int kMaxSize = 4096;
1143  char* link = reinterpret_cast<char*>(allocator->Alloc(kMaxSize));
1144  if (link) {
1145    ssize_t size = readlink(linkpath, link, kMaxSize);
1146    if (size < kMaxSize && size > 0) {
1147      // readlink(2) doesn't add a terminating NUL, so do it now.
1148      link[size] = '\0';
1149
1150      const char* name = my_strrchr(link, '/');
1151      if (name)
1152        return name + 1;
1153      return link;
1154    }
1155  }
1156  // Either way too long, or a read error.
1157  return "chrome-crash-unknown-process";
1158}
1159#endif
1160
1161void HandleCrashDump(const BreakpadInfo& info) {
1162  int dumpfd;
1163  bool keep_fd = false;
1164  size_t dump_size;
1165  uint8_t* dump_data;
1166  google_breakpad::PageAllocator allocator;
1167  const char* exe_buf = NULL;
1168
1169#if defined(OS_CHROMEOS)
1170  // Grab the crashing process' name now, when it should still be available.
1171  // If we try to do this later in our grandchild the crashing process has
1172  // already terminated.
1173  exe_buf = GetCrashingProcessName(info, &allocator);
1174#endif
1175
1176  if (info.fd != -1) {
1177    // Dump is provided with an open FD.
1178    keep_fd = true;
1179    dumpfd = info.fd;
1180
1181    // The FD is pointing to the end of the file.
1182    // Rewind, we'll read the data next.
1183    if (lseek(dumpfd, 0, SEEK_SET) == -1) {
1184      static const char msg[] = "Cannot upload crash dump: failed to "
1185          "reposition minidump FD\n";
1186      WriteLog(msg, sizeof(msg) - 1);
1187      IGNORE_RET(sys_close(dumpfd));
1188      return;
1189    }
1190    LoadDataFromFD(allocator, info.fd, false, &dump_data, &dump_size);
1191  } else {
1192    // Dump is provided with a path.
1193    keep_fd = false;
1194    LoadDataFromFile(allocator, info.filename, &dumpfd, &dump_data, &dump_size);
1195  }
1196
1197  // TODO(jcivelli): make log work when using FDs.
1198#if defined(ADDRESS_SANITIZER)
1199  int logfd;
1200  size_t log_size;
1201  uint8_t* log_data;
1202  // Load the AddressSanitizer log into log_data.
1203  LoadDataFromFile(allocator, info.log_filename, &logfd, &log_data, &log_size);
1204#endif
1205
1206  // We need to build a MIME block for uploading to the server. Since we are
1207  // going to fork and run wget, it needs to be written to a temp file.
1208  const int ufd = sys_open("/dev/urandom", O_RDONLY, 0);
1209  if (ufd < 0) {
1210    static const char msg[] = "Cannot upload crash dump because /dev/urandom"
1211                              " is missing\n";
1212    WriteLog(msg, sizeof(msg) - 1);
1213    return;
1214  }
1215
1216  static const char temp_file_template[] =
1217      "/tmp/chromium-upload-XXXXXXXXXXXXXXXX";
1218  char temp_file[sizeof(temp_file_template)];
1219  int temp_file_fd = -1;
1220  if (keep_fd) {
1221    temp_file_fd = dumpfd;
1222    // Rewind the destination, we are going to overwrite it.
1223    if (lseek(dumpfd, 0, SEEK_SET) == -1) {
1224      static const char msg[] = "Cannot upload crash dump: failed to "
1225          "reposition minidump FD (2)\n";
1226      WriteLog(msg, sizeof(msg) - 1);
1227      IGNORE_RET(sys_close(dumpfd));
1228      return;
1229    }
1230  } else {
1231    if (info.upload) {
1232      memcpy(temp_file, temp_file_template, sizeof(temp_file_template));
1233
1234      for (unsigned i = 0; i < 10; ++i) {
1235        uint64_t t;
1236        sys_read(ufd, &t, sizeof(t));
1237        write_uint64_hex(temp_file + sizeof(temp_file) - (16 + 1), t);
1238
1239        temp_file_fd = sys_open(temp_file, O_WRONLY | O_CREAT | O_EXCL, 0600);
1240        if (temp_file_fd >= 0)
1241          break;
1242      }
1243
1244      if (temp_file_fd < 0) {
1245        static const char msg[] = "Failed to create temporary file in /tmp: "
1246            "cannot upload crash dump\n";
1247        WriteLog(msg, sizeof(msg) - 1);
1248        IGNORE_RET(sys_close(ufd));
1249        return;
1250      }
1251    } else {
1252      temp_file_fd = sys_open(info.filename, O_WRONLY, 0600);
1253      if (temp_file_fd < 0) {
1254        static const char msg[] = "Failed to save crash dump: failed to open\n";
1255        WriteLog(msg, sizeof(msg) - 1);
1256        IGNORE_RET(sys_close(ufd));
1257        return;
1258      }
1259    }
1260  }
1261
1262  // The MIME boundary is 28 hyphens, followed by a 64-bit nonce and a NUL.
1263  char mime_boundary[28 + 16 + 1];
1264  my_memset(mime_boundary, '-', 28);
1265  uint64_t boundary_rand;
1266  sys_read(ufd, &boundary_rand, sizeof(boundary_rand));
1267  write_uint64_hex(mime_boundary + 28, boundary_rand);
1268  mime_boundary[28 + 16] = 0;
1269  IGNORE_RET(sys_close(ufd));
1270
1271  // The MIME block looks like this:
1272  //   BOUNDARY \r\n
1273  //   Content-Disposition: form-data; name="prod" \r\n \r\n
1274  //   Chrome_Linux \r\n
1275  //   BOUNDARY \r\n
1276  //   Content-Disposition: form-data; name="ver" \r\n \r\n
1277  //   1.2.3.4 \r\n
1278  //   BOUNDARY \r\n
1279  //
1280  //   zero or one:
1281  //   Content-Disposition: form-data; name="ptime" \r\n \r\n
1282  //   abcdef \r\n
1283  //   BOUNDARY \r\n
1284  //
1285  //   zero or one:
1286  //   Content-Disposition: form-data; name="ptype" \r\n \r\n
1287  //   abcdef \r\n
1288  //   BOUNDARY \r\n
1289  //
1290  //   zero or one:
1291  //   Content-Disposition: form-data; name="lsb-release" \r\n \r\n
1292  //   abcdef \r\n
1293  //   BOUNDARY \r\n
1294  //
1295  //   zero or one:
1296  //   Content-Disposition: form-data; name="oom-size" \r\n \r\n
1297  //   1234567890 \r\n
1298  //   BOUNDARY \r\n
1299  //
1300  //   zero or more (up to CrashKeyStorage::num_entries = 64):
1301  //   Content-Disposition: form-data; name=crash-key-name \r\n
1302  //   crash-key-value \r\n
1303  //   BOUNDARY \r\n
1304  //
1305  //   Content-Disposition: form-data; name="dump"; filename="dump" \r\n
1306  //   Content-Type: application/octet-stream \r\n \r\n
1307  //   <dump contents>
1308  //   \r\n BOUNDARY -- \r\n
1309
1310#if defined(OS_CHROMEOS)
1311  CrashReporterWriter writer(temp_file_fd);
1312#else
1313  MimeWriter writer(temp_file_fd, mime_boundary);
1314#endif
1315  {
1316    // TODO(thestig) Do not use this inside a compromised context.
1317    std::string product_name;
1318    std::string version;
1319
1320    GetCrashReporterClient()->GetProductNameAndVersion(&product_name, &version);
1321
1322    writer.AddBoundary();
1323    writer.AddPairString("prod", product_name.c_str());
1324    writer.AddBoundary();
1325    writer.AddPairString("ver", version.c_str());
1326    writer.AddBoundary();
1327    if (info.pid > 0) {
1328      char pid_value_buf[kUint64StringSize];
1329      uint64_t pid_value_len = my_uint64_len(info.pid);
1330      my_uint64tos(pid_value_buf, info.pid, pid_value_len);
1331      static const char pid_key_name[] = "pid";
1332      writer.AddPairData(pid_key_name, sizeof(pid_key_name) - 1,
1333                         pid_value_buf, pid_value_len);
1334      writer.AddBoundary();
1335    }
1336#if defined(OS_ANDROID)
1337    // Addtional MIME blocks are added for logging on Android devices.
1338    static const char android_build_id[] = "android_build_id";
1339    static const char android_build_fp[] = "android_build_fp";
1340    static const char device[] = "device";
1341    static const char model[] = "model";
1342    static const char brand[] = "brand";
1343    static const char exception_info[] = "exception_info";
1344
1345    base::android::BuildInfo* android_build_info =
1346        base::android::BuildInfo::GetInstance();
1347    writer.AddPairString(
1348        android_build_id, android_build_info->android_build_id());
1349    writer.AddBoundary();
1350    writer.AddPairString(
1351        android_build_fp, android_build_info->android_build_fp());
1352    writer.AddBoundary();
1353    writer.AddPairString(device, android_build_info->device());
1354    writer.AddBoundary();
1355    writer.AddPairString(model, android_build_info->model());
1356    writer.AddBoundary();
1357    writer.AddPairString(brand, android_build_info->brand());
1358    writer.AddBoundary();
1359    if (android_build_info->java_exception_info() != NULL) {
1360      writer.AddPairString(exception_info,
1361                           android_build_info->java_exception_info());
1362      writer.AddBoundary();
1363    }
1364#endif
1365    writer.Flush();
1366  }
1367
1368  if (info.process_start_time > 0) {
1369    struct kernel_timeval tv;
1370    if (!sys_gettimeofday(&tv, NULL)) {
1371      uint64_t time = kernel_timeval_to_ms(&tv);
1372      if (time > info.process_start_time) {
1373        time -= info.process_start_time;
1374        char time_str[kUint64StringSize];
1375        const unsigned time_len = my_uint64_len(time);
1376        my_uint64tos(time_str, time, time_len);
1377
1378        static const char process_time_msg[] = "ptime";
1379        writer.AddPairData(process_time_msg, sizeof(process_time_msg) - 1,
1380                           time_str, time_len);
1381        writer.AddBoundary();
1382        writer.Flush();
1383      }
1384    }
1385  }
1386
1387  if (info.process_type_length) {
1388    writer.AddPairString("ptype", info.process_type);
1389    writer.AddBoundary();
1390    writer.Flush();
1391  }
1392
1393  if (info.distro_length) {
1394    static const char distro_msg[] = "lsb-release";
1395    writer.AddPairString(distro_msg, info.distro);
1396    writer.AddBoundary();
1397    writer.Flush();
1398  }
1399
1400  if (info.oom_size) {
1401    char oom_size_str[kUint64StringSize];
1402    const unsigned oom_size_len = my_uint64_len(info.oom_size);
1403    my_uint64tos(oom_size_str, info.oom_size, oom_size_len);
1404    static const char oom_size_msg[] = "oom-size";
1405    writer.AddPairData(oom_size_msg, sizeof(oom_size_msg) - 1,
1406                       oom_size_str, oom_size_len);
1407    writer.AddBoundary();
1408    writer.Flush();
1409  }
1410
1411  if (info.crash_keys) {
1412    CrashKeyStorage::Iterator crash_key_iterator(*info.crash_keys);
1413    const CrashKeyStorage::Entry* entry;
1414    while ((entry = crash_key_iterator.Next())) {
1415      writer.AddPairString(entry->key, entry->value);
1416      writer.AddBoundary();
1417      writer.Flush();
1418    }
1419  }
1420
1421  writer.AddFileContents(g_dump_msg, dump_data, dump_size);
1422#if defined(ADDRESS_SANITIZER)
1423  // Append a multipart boundary and the contents of the AddressSanitizer log.
1424  writer.AddBoundary();
1425  writer.AddFileContents(g_log_msg, log_data, log_size);
1426#endif
1427  writer.AddEnd();
1428  writer.Flush();
1429
1430  IGNORE_RET(sys_close(temp_file_fd));
1431
1432#if defined(OS_ANDROID)
1433  if (info.filename) {
1434    int filename_length = my_strlen(info.filename);
1435
1436    // If this was a file, we need to copy it to the right place and use the
1437    // right file name so it gets uploaded by the browser.
1438    const char msg[] = "Output crash dump file:";
1439    WriteLog(msg, sizeof(msg) - 1);
1440    WriteLog(info.filename, filename_length - 1);
1441
1442    char pid_buf[kUint64StringSize];
1443    uint64_t pid_str_length = my_uint64_len(info.pid);
1444    my_uint64tos(pid_buf, info.pid, pid_str_length);
1445
1446    // -1 because we won't need the null terminator on the original filename.
1447    unsigned done_filename_len = filename_length - 1 + pid_str_length;
1448    char* done_filename = reinterpret_cast<char*>(
1449        allocator.Alloc(done_filename_len));
1450    // Rename the file such that the pid is the suffix in order signal to other
1451    // processes that the minidump is complete. The advantage of using the pid
1452    // as the suffix is that it is trivial to associate the minidump with the
1453    // crashed process.
1454    // Finally, note strncpy prevents null terminators from
1455    // being copied. Pad the rest with 0's.
1456    my_strncpy(done_filename, info.filename, done_filename_len);
1457    // Append the suffix a null terminator should be added.
1458    my_strncat(done_filename, pid_buf, pid_str_length);
1459    // Rename the minidump file to signal that it is complete.
1460    if (rename(info.filename, done_filename)) {
1461      const char failed_msg[] = "Failed to rename:";
1462      WriteLog(failed_msg, sizeof(failed_msg) - 1);
1463      WriteLog(info.filename, filename_length - 1);
1464      const char to_msg[] = "to";
1465      WriteLog(to_msg, sizeof(to_msg) - 1);
1466      WriteLog(done_filename, done_filename_len - 1);
1467    }
1468  }
1469#endif
1470
1471  if (!info.upload)
1472    return;
1473
1474  const pid_t child = sys_fork();
1475  if (!child) {
1476    // Spawned helper process.
1477    //
1478    // This code is called both when a browser is crashing (in which case,
1479    // nothing really matters any more) and when a renderer/plugin crashes, in
1480    // which case we need to continue.
1481    //
1482    // Since we are a multithreaded app, if we were just to fork(), we might
1483    // grab file descriptors which have just been created in another thread and
1484    // hold them open for too long.
1485    //
1486    // Thus, we have to loop and try and close everything.
1487    const int fd = sys_open("/proc/self/fd", O_DIRECTORY | O_RDONLY, 0);
1488    if (fd < 0) {
1489      for (unsigned i = 3; i < 8192; ++i)
1490        IGNORE_RET(sys_close(i));
1491    } else {
1492      google_breakpad::DirectoryReader reader(fd);
1493      const char* name;
1494      while (reader.GetNextEntry(&name)) {
1495        int i;
1496        if (my_strtoui(&i, name) && i > 2 && i != fd)
1497          IGNORE_RET(sys_close(i));
1498        reader.PopEntry();
1499      }
1500
1501      IGNORE_RET(sys_close(fd));
1502    }
1503
1504    IGNORE_RET(sys_setsid());
1505
1506    // Leave one end of a pipe in the upload process and watch for it getting
1507    // closed by the upload process exiting.
1508    int fds[2];
1509    if (sys_pipe(fds) >= 0) {
1510      const pid_t upload_child = sys_fork();
1511      if (!upload_child) {
1512        // Upload process.
1513        IGNORE_RET(sys_close(fds[0]));
1514        IGNORE_RET(sys_dup2(fds[1], 3));
1515        ExecUploadProcessOrTerminate(info, temp_file, mime_boundary, exe_buf,
1516                                     &allocator);
1517      }
1518
1519      // Helper process.
1520      if (upload_child > 0) {
1521        IGNORE_RET(sys_close(fds[1]));
1522
1523        const size_t kCrashIdLength = 16;
1524        char id_buf[kCrashIdLength + 1];
1525        size_t bytes_read =
1526            WaitForCrashReportUploadProcess(fds[0], kCrashIdLength, id_buf);
1527        HandleCrashReportId(id_buf, bytes_read, kCrashIdLength);
1528
1529        if (sys_waitpid(upload_child, NULL, WNOHANG) == 0) {
1530          // Upload process is still around, kill it.
1531          sys_kill(upload_child, SIGKILL);
1532        }
1533      }
1534    }
1535
1536    // Helper process.
1537    IGNORE_RET(sys_unlink(info.filename));
1538#if defined(ADDRESS_SANITIZER)
1539    IGNORE_RET(sys_unlink(info.log_filename));
1540#endif
1541    IGNORE_RET(sys_unlink(temp_file));
1542    sys__exit(0);
1543  }
1544
1545  // Main browser process.
1546  if (child <= 0)
1547    return;
1548  (void) HANDLE_EINTR(sys_waitpid(child, NULL, 0));
1549}
1550
1551void InitCrashReporter(const std::string& process_type) {
1552#if defined(OS_ANDROID)
1553  // This will guarantee that the BuildInfo has been initialized and subsequent
1554  // calls will not require memory allocation.
1555  base::android::BuildInfo::GetInstance();
1556#endif
1557  // Determine the process type and take appropriate action.
1558  const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess();
1559  if (parsed_command_line.HasSwitch(switches::kDisableBreakpad))
1560    return;
1561
1562  if (process_type.empty()) {
1563    bool enable_breakpad = GetCrashReporterClient()->GetCollectStatsConsent() ||
1564                           GetCrashReporterClient()->IsRunningUnattended();
1565    enable_breakpad &=
1566        !parsed_command_line.HasSwitch(switches::kDisableBreakpad);
1567    if (!enable_breakpad) {
1568      enable_breakpad = parsed_command_line.HasSwitch(
1569          switches::kEnableCrashReporterForTesting);
1570    }
1571    if (!enable_breakpad) {
1572      VLOG(1) << "Breakpad disabled";
1573      return;
1574    }
1575
1576    InitCrashKeys();
1577    EnableCrashDumping(GetCrashReporterClient()->IsRunningUnattended());
1578  } else if (GetCrashReporterClient()->EnableBreakpadForProcess(process_type)) {
1579#if defined(OS_ANDROID)
1580    NOTREACHED() << "Breakpad initialized with InitCrashReporter() instead of "
1581      "InitNonBrowserCrashReporter in " << process_type << " process.";
1582    return;
1583#else
1584    // We might be chrooted in a zygote or renderer process so we cannot call
1585    // GetCollectStatsConsent because that needs access the the user's home
1586    // dir. Instead, we set a command line flag for these processes.
1587    // Even though plugins are not chrooted, we share the same code path for
1588    // simplicity.
1589    if (!parsed_command_line.HasSwitch(switches::kEnableCrashReporter))
1590      return;
1591    InitCrashKeys();
1592    SetClientIdFromCommandLine(parsed_command_line);
1593    EnableNonBrowserCrashDumping();
1594    VLOG(1) << "Non Browser crash dumping enabled for: " << process_type;
1595#endif  // #if defined(OS_ANDROID)
1596  }
1597
1598  PostEnableBreakpadInitialization();
1599}
1600
1601#if defined(OS_ANDROID)
1602void InitNonBrowserCrashReporterForAndroid(const std::string& process_type) {
1603  const CommandLine* command_line = CommandLine::ForCurrentProcess();
1604  if (command_line->HasSwitch(switches::kEnableCrashReporter)) {
1605    // On Android we need to provide a FD to the file where the minidump is
1606    // generated as the renderer and browser run with different UIDs
1607    // (preventing the browser from inspecting the renderer process).
1608    int minidump_fd = base::GlobalDescriptors::GetInstance()->MaybeGet(
1609        GetCrashReporterClient()->GetAndroidMinidumpDescriptor());
1610    if (minidump_fd < 0) {
1611      NOTREACHED() << "Could not find minidump FD, crash reporting disabled.";
1612    } else {
1613      EnableNonBrowserCrashDumping(process_type, minidump_fd);
1614    }
1615  }
1616}
1617#endif  // OS_ANDROID
1618
1619bool IsCrashReporterEnabled() {
1620  return g_is_crash_reporter_enabled;
1621}
1622
1623}  // namespace breakpad
1624