| OLD | NEW |
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium 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 <fcntl.h> | 5 #include <fcntl.h> |
| 6 #include <sys/socket.h> | 6 #include <sys/socket.h> |
| 7 #include <sys/uio.h> | 7 #include <sys/uio.h> |
| 8 #include <unistd.h> | 8 #include <unistd.h> |
| 9 | 9 |
| 10 #include <string> | 10 #include <string> |
| (...skipping 18 matching lines...) Expand all Loading... |
| 29 // |output|. | 29 // |output|. |
| 30 static void write_uint64_hex(char* output, uint64_t v) { | 30 static void write_uint64_hex(char* output, uint64_t v) { |
| 31 static const char hextable[] = "0123456789abcdef"; | 31 static const char hextable[] = "0123456789abcdef"; |
| 32 | 32 |
| 33 for (int i = 15; i >= 0; --i) { | 33 for (int i = 15; i >= 0; --i) { |
| 34 output[i] = hextable[v & 15]; | 34 output[i] = hextable[v & 15]; |
| 35 v >>= 4; | 35 v >>= 4; |
| 36 } | 36 } |
| 37 } | 37 } |
| 38 | 38 |
| 39 pid_t UploadCrashDump(const char* filename, const char* crash_url, | 39 pid_t UploadCrashDump(const char* filename, |
| 40 unsigned crash_url_length) { | 40 const char* crash_url, |
| 41 unsigned crash_url_length, |
| 42 const char* guid, |
| 43 unsigned guid_length) { |
| 41 // WARNING: this code runs in a compromised context. It may not call into | 44 // WARNING: this code runs in a compromised context. It may not call into |
| 42 // libc nor allocate memory normally. | 45 // libc nor allocate memory normally. |
| 43 | 46 |
| 44 const int dumpfd = sys_open(filename, O_RDONLY, 0); | 47 const int dumpfd = sys_open(filename, O_RDONLY, 0); |
| 45 if (dumpfd < 0) { | 48 if (dumpfd < 0) { |
| 46 static const char msg[] = "Cannot upload crash dump: failed to open\n"; | 49 static const char msg[] = "Cannot upload crash dump: failed to open\n"; |
| 47 sys_write(2, msg, sizeof(msg)); | 50 sys_write(2, msg, sizeof(msg)); |
| 48 return -1; | 51 return -1; |
| 49 } | 52 } |
| 50 struct kernel_stat st; | 53 struct kernel_stat st; |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 121 version_msg[i] = static_cast<char>(version[i]); | 124 version_msg[i] = static_cast<char>(version[i]); |
| 122 | 125 |
| 123 // The MIME block looks like this: | 126 // The MIME block looks like this: |
| 124 // BOUNDARY \r\n (0, 1) | 127 // BOUNDARY \r\n (0, 1) |
| 125 // Content-Disposition: form-data; name="prod" \r\n \r\n (2..6) | 128 // Content-Disposition: form-data; name="prod" \r\n \r\n (2..6) |
| 126 // Chrome_Linux \r\n (7, 8) | 129 // Chrome_Linux \r\n (7, 8) |
| 127 // BOUNDARY \r\n (9, 10) | 130 // BOUNDARY \r\n (9, 10) |
| 128 // Content-Disposition: form-data; name="ver" \r\n \r\n (11..15) | 131 // Content-Disposition: form-data; name="ver" \r\n \r\n (11..15) |
| 129 // 1.2.3.4 \r\n (16, 17) | 132 // 1.2.3.4 \r\n (16, 17) |
| 130 // BOUNDARY \r\n (18, 19) | 133 // BOUNDARY \r\n (18, 19) |
| 134 // Content-Disposition: form-data; name="guid" \r\n \r\n (20..24) |
| 135 // 1.2.3.4 \r\n (25, 26) |
| 136 // BOUNDARY \r\n (27, 28) |
| 131 // | 137 // |
| 132 // zero or more: | 138 // zero or more: |
| 133 // Content-Disposition: form-data; name="url-chunk-1" \r\n \r\n (0..5) | 139 // Content-Disposition: form-data; name="url-chunk-1" \r\n \r\n (0..5) |
| 134 // abcdef \r\n (6, 7) | 140 // abcdef \r\n (6, 7) |
| 135 // BOUNDARY \r\n (8, 9) | 141 // BOUNDARY \r\n (8, 9) |
| 136 // | 142 // |
| 137 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n (0,1,2) | 143 // Content-Disposition: form-data; name="dump"; filename="dump" \r\n (0,1,2) |
| 138 // Content-Type: application/octet-stream \r\n \r\n (3,4,5) | 144 // Content-Type: application/octet-stream \r\n \r\n (3,4,5) |
| 139 // <dump contents> (6) | 145 // <dump contents> (6) |
| 140 // \r\n BOUNDARY -- \r\n (7,8,9,10) | 146 // \r\n BOUNDARY -- \r\n (7,8,9,10) |
| 141 | 147 |
| 142 static const char rn[] = {'\r', '\n'}; | 148 static const char rn[] = {'\r', '\n'}; |
| 143 static const char form_data_msg[] = "Content-Disposition: form-data; name=\""; | 149 static const char form_data_msg[] = "Content-Disposition: form-data; name=\""; |
| 144 static const char prod_msg[] = "prod"; | 150 static const char prod_msg[] = "prod"; |
| 145 static const char quote_msg[] = {'"'}; | 151 static const char quote_msg[] = {'"'}; |
| 146 static const char chrome_linux_msg[] = "Chrome_Linux"; | 152 static const char chrome_linux_msg[] = "Chrome_Linux"; |
| 147 static const char ver_msg[] = "ver"; | 153 static const char ver_msg[] = "ver"; |
| 154 static const char guid_msg[] = "guid"; |
| 148 static const char dashdash_msg[] = {'-', '-'}; | 155 static const char dashdash_msg[] = {'-', '-'}; |
| 149 static const char dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; | 156 static const char dump_msg[] = "upload_file_minidump\"; filename=\"dump\""; |
| 150 static const char content_type_msg[] = | 157 static const char content_type_msg[] = |
| 151 "Content-Type: application/octet-stream"; | 158 "Content-Type: application/octet-stream"; |
| 152 static const char url_chunk_msg[] = "url-chunk-"; | 159 static const char url_chunk_msg[] = "url-chunk-"; |
| 153 | 160 |
| 154 struct kernel_iovec iov[20]; | 161 struct kernel_iovec iov[29]; |
| 155 iov[0].iov_base = mime_boundary; | 162 iov[0].iov_base = mime_boundary; |
| 156 iov[0].iov_len = sizeof(mime_boundary) - 1; | 163 iov[0].iov_len = sizeof(mime_boundary) - 1; |
| 157 iov[1].iov_base = const_cast<char*>(rn); | 164 iov[1].iov_base = const_cast<char*>(rn); |
| 158 iov[1].iov_len = sizeof(rn); | 165 iov[1].iov_len = sizeof(rn); |
| 159 | 166 |
| 160 iov[2].iov_base = const_cast<char*>(form_data_msg); | 167 iov[2].iov_base = const_cast<char*>(form_data_msg); |
| 161 iov[2].iov_len = sizeof(form_data_msg) - 1; | 168 iov[2].iov_len = sizeof(form_data_msg) - 1; |
| 162 iov[3].iov_base = const_cast<char*>(prod_msg); | 169 iov[3].iov_base = const_cast<char*>(prod_msg); |
| 163 iov[3].iov_len = sizeof(prod_msg) - 1; | 170 iov[3].iov_len = sizeof(prod_msg) - 1; |
| 164 iov[4].iov_base = const_cast<char*>(quote_msg); | 171 iov[4].iov_base = const_cast<char*>(quote_msg); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 192 iov[16].iov_base = const_cast<char*>(version_msg); | 199 iov[16].iov_base = const_cast<char*>(version_msg); |
| 193 iov[16].iov_len = sizeof(version_msg) - 1; | 200 iov[16].iov_len = sizeof(version_msg) - 1; |
| 194 iov[17].iov_base = const_cast<char*>(rn); | 201 iov[17].iov_base = const_cast<char*>(rn); |
| 195 iov[17].iov_len = sizeof(rn); | 202 iov[17].iov_len = sizeof(rn); |
| 196 | 203 |
| 197 iov[18].iov_base = mime_boundary; | 204 iov[18].iov_base = mime_boundary; |
| 198 iov[18].iov_len = sizeof(mime_boundary) - 1; | 205 iov[18].iov_len = sizeof(mime_boundary) - 1; |
| 199 iov[19].iov_base = const_cast<char*>(rn); | 206 iov[19].iov_base = const_cast<char*>(rn); |
| 200 iov[19].iov_len = sizeof(rn); | 207 iov[19].iov_len = sizeof(rn); |
| 201 | 208 |
| 202 sys_writev(fd, iov, 20); | 209 iov[20].iov_base = const_cast<char*>(form_data_msg); |
| 210 iov[20].iov_len = sizeof(form_data_msg) - 1; |
| 211 iov[21].iov_base = const_cast<char*>(guid_msg); |
| 212 iov[21].iov_len = sizeof(guid_msg) - 1; |
| 213 iov[22].iov_base = const_cast<char*>(quote_msg); |
| 214 iov[22].iov_len = sizeof(quote_msg); |
| 215 iov[23].iov_base = const_cast<char*>(rn); |
| 216 iov[23].iov_len = sizeof(rn); |
| 217 iov[24].iov_base = const_cast<char*>(rn); |
| 218 iov[24].iov_len = sizeof(rn); |
| 219 |
| 220 iov[25].iov_base = const_cast<char*>(guid); |
| 221 iov[25].iov_len = guid_length; |
| 222 iov[26].iov_base = const_cast<char*>(rn); |
| 223 iov[26].iov_len = sizeof(rn); |
| 224 |
| 225 iov[27].iov_base = mime_boundary; |
| 226 iov[27].iov_len = sizeof(mime_boundary) - 1; |
| 227 iov[28].iov_base = const_cast<char*>(rn); |
| 228 iov[28].iov_len = sizeof(rn); |
| 229 |
| 230 sys_writev(fd, iov, 29); |
| 203 | 231 |
| 204 if (crash_url_length) { | 232 if (crash_url_length) { |
| 205 unsigned i = 0, done = 0; | 233 unsigned i = 0, done = 0; |
| 206 static const unsigned kMaxCrashChunkSize = 64; | 234 static const unsigned kMaxCrashChunkSize = 64; |
| 207 static const unsigned kMaxUrlLength = 8 * kMaxCrashChunkSize; | 235 static const unsigned kMaxUrlLength = 8 * kMaxCrashChunkSize; |
| 208 if (crash_url_length > kMaxUrlLength) | 236 if (crash_url_length > kMaxUrlLength) |
| 209 crash_url_length = kMaxUrlLength; | 237 crash_url_length = kMaxUrlLength; |
| 210 | 238 |
| 211 while (crash_url_length) { | 239 while (crash_url_length) { |
| 212 char num[16]; | 240 char num[16]; |
| (...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 331 | 359 |
| 332 const pid_t child = sys_fork(); | 360 const pid_t child = sys_fork(); |
| 333 if (child) { | 361 if (child) { |
| 334 sys_close(fds[1]); | 362 sys_close(fds[1]); |
| 335 char id_buf[17]; | 363 char id_buf[17]; |
| 336 const int len = HANDLE_EINTR(read(fds[0], id_buf, sizeof(id_buf) - 1)); | 364 const int len = HANDLE_EINTR(read(fds[0], id_buf, sizeof(id_buf) - 1)); |
| 337 if (len > 0) { | 365 if (len > 0) { |
| 338 id_buf[len] = 0; | 366 id_buf[len] = 0; |
| 339 static const char msg[] = "\nCrash dump id: "; | 367 static const char msg[] = "\nCrash dump id: "; |
| 340 sys_write(2, msg, sizeof(msg) - 1); | 368 sys_write(2, msg, sizeof(msg) - 1); |
| 341 sys_write(2, id_buf, my_strlen(buf)); | 369 sys_write(2, id_buf, my_strlen(id_buf)); |
| 342 sys_write(2, "\n", 1); | 370 sys_write(2, "\n", 1); |
| 343 } | 371 } |
| 344 sys_unlink(filename); | 372 sys_unlink(filename); |
| 345 sys_unlink(buf); | 373 sys_unlink(buf); |
| 346 sys__exit(0); | 374 sys__exit(0); |
| 347 } | 375 } |
| 348 | 376 |
| 349 sys_close(fds[0]); | 377 sys_close(fds[0]); |
| 350 sys_dup2(fds[1], 3); | 378 sys_dup2(fds[1], 3); |
| 351 static const char* const kWgetBinary = "/usr/bin/wget"; | 379 static const char* const kWgetBinary = "/usr/bin/wget"; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 362 execv("/usr/bin/wget", const_cast<char**>(args)); | 390 execv("/usr/bin/wget", const_cast<char**>(args)); |
| 363 static const char msg[] = "Cannot upload crash dump: cannot exec " | 391 static const char msg[] = "Cannot upload crash dump: cannot exec " |
| 364 "/usr/bin/wget\n"; | 392 "/usr/bin/wget\n"; |
| 365 sys_write(2, msg, sizeof(msg) - 1); | 393 sys_write(2, msg, sizeof(msg) - 1); |
| 366 sys__exit(1); | 394 sys__exit(1); |
| 367 } | 395 } |
| 368 | 396 |
| 369 return child; | 397 return child; |
| 370 } | 398 } |
| 371 | 399 |
| 400 // This is defined in chrome/browser/google_update_settings_linux.cc, it's the |
| 401 // static string containing the user's unique GUID. We send this in the crash |
| 402 // report. |
| 403 namespace google_update { |
| 404 extern std::string linux_guid; |
| 405 } |
| 406 |
| 372 static bool CrashDone(const char* dump_path, | 407 static bool CrashDone(const char* dump_path, |
| 373 const char* minidump_id, | 408 const char* minidump_id, |
| 374 void* context, | 409 void* context, |
| 375 bool succeeded) { | 410 bool succeeded) { |
| 376 // WARNING: this code runs in a compromised context. It may not call into | 411 // WARNING: this code runs in a compromised context. It may not call into |
| 377 // libc nor allocate memory normally. | 412 // libc nor allocate memory normally. |
| 378 if (!succeeded) | 413 if (!succeeded) |
| 379 return false; | 414 return false; |
| 380 | 415 |
| 381 google_breakpad::PageAllocator allocator; | 416 google_breakpad::PageAllocator allocator; |
| 382 const unsigned dump_path_len = my_strlen(dump_path); | 417 const unsigned dump_path_len = my_strlen(dump_path); |
| 383 const unsigned minidump_id_len = my_strlen(minidump_id); | 418 const unsigned minidump_id_len = my_strlen(minidump_id); |
| 384 char *const path = reinterpret_cast<char*>(allocator.Alloc( | 419 char *const path = reinterpret_cast<char*>(allocator.Alloc( |
| 385 dump_path_len + 1 /* '/' */ + minidump_id_len + | 420 dump_path_len + 1 /* '/' */ + minidump_id_len + |
| 386 4 /* ".dmp" */ + 1 /* NUL */)); | 421 4 /* ".dmp" */ + 1 /* NUL */)); |
| 387 memcpy(path, dump_path, dump_path_len); | 422 memcpy(path, dump_path, dump_path_len); |
| 388 path[dump_path_len] = '/'; | 423 path[dump_path_len] = '/'; |
| 389 memcpy(path + dump_path_len + 1, minidump_id, minidump_id_len); | 424 memcpy(path + dump_path_len + 1, minidump_id, minidump_id_len); |
| 390 memcpy(path + dump_path_len + 1 + minidump_id_len, ".dmp", 4); | 425 memcpy(path + dump_path_len + 1 + minidump_id_len, ".dmp", 4); |
| 391 path[dump_path_len + 1 + minidump_id_len + 4] = 0; | 426 path[dump_path_len + 1 + minidump_id_len + 4] = 0; |
| 392 | 427 |
| 393 UploadCrashDump(path, NULL, 0); | 428 UploadCrashDump(path, NULL, 0, google_update::linux_guid.data(), |
| 429 google_update::linux_guid.length()); |
| 394 | 430 |
| 395 return true; | 431 return true; |
| 396 } | 432 } |
| 397 | 433 |
| 398 void EnableCrashDumping() { | 434 void EnableCrashDumping() { |
| 399 // We leak this object. | 435 // We leak this object. |
| 400 | 436 |
| 401 new google_breakpad::ExceptionHandler("/tmp", NULL, CrashDone, NULL, | 437 new google_breakpad::ExceptionHandler("/tmp", NULL, CrashDone, NULL, |
| 402 true /* install handlers */); | 438 true /* install handlers */); |
| 403 } | 439 } |
| (...skipping 14 matching lines...) Expand all Loading... |
| 418 | 454 |
| 419 // The length of the control message: | 455 // The length of the control message: |
| 420 static const unsigned kControlMsgSize = | 456 static const unsigned kControlMsgSize = |
| 421 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); | 457 CMSG_SPACE(sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); |
| 422 | 458 |
| 423 union { | 459 union { |
| 424 struct kernel_msghdr msg; | 460 struct kernel_msghdr msg; |
| 425 struct msghdr sys_msg; | 461 struct msghdr sys_msg; |
| 426 }; | 462 }; |
| 427 my_memset(&msg, 0, sizeof(struct kernel_msghdr)); | 463 my_memset(&msg, 0, sizeof(struct kernel_msghdr)); |
| 428 struct kernel_iovec iov[2]; | 464 struct kernel_iovec iov[3]; |
| 429 iov[0].iov_base = const_cast<void*>(crash_context); | 465 iov[0].iov_base = const_cast<void*>(crash_context); |
| 430 iov[0].iov_len = crash_context_size; | 466 iov[0].iov_len = crash_context_size; |
| 431 iov[1].iov_base = const_cast<char*>(renderer_logging::active_url.data()); | 467 iov[1].iov_base = const_cast<char*>(google_update::linux_guid.data()); |
| 432 iov[1].iov_len = renderer_logging::active_url.size(); | 468 iov[1].iov_len = google_update::linux_guid.size(); |
| 469 iov[2].iov_base = const_cast<char*>(renderer_logging::active_url.data()); |
| 470 iov[2].iov_len = renderer_logging::active_url.size(); |
| 433 | 471 |
| 434 msg.msg_iov = iov; | 472 msg.msg_iov = iov; |
| 435 msg.msg_iovlen = 2; | 473 msg.msg_iovlen = 3; |
| 436 char cmsg[kControlMsgSize]; | 474 char cmsg[kControlMsgSize]; |
| 437 memset(cmsg, 0, kControlMsgSize); | 475 memset(cmsg, 0, kControlMsgSize); |
| 438 msg.msg_control = cmsg; | 476 msg.msg_control = cmsg; |
| 439 msg.msg_controllen = sizeof(cmsg); | 477 msg.msg_controllen = sizeof(cmsg); |
| 440 | 478 |
| 441 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); | 479 struct cmsghdr *hdr = CMSG_FIRSTHDR(&msg); |
| 442 hdr->cmsg_level = SOL_SOCKET; | 480 hdr->cmsg_level = SOL_SOCKET; |
| 443 hdr->cmsg_type = SCM_RIGHTS; | 481 hdr->cmsg_type = SCM_RIGHTS; |
| 444 hdr->cmsg_len = CMSG_LEN(sizeof(int)); | 482 hdr->cmsg_len = CMSG_LEN(sizeof(int)); |
| 445 *((int*) CMSG_DATA(hdr)) = fds[1]; | 483 *((int*) CMSG_DATA(hdr)) = fds[1]; |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 479 | 517 |
| 480 // Determine the process type and take appropriate action. | 518 // Determine the process type and take appropriate action. |
| 481 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); | 519 const CommandLine& parsed_command_line = *CommandLine::ForCurrentProcess(); |
| 482 const std::wstring process_type = | 520 const std::wstring process_type = |
| 483 parsed_command_line.GetSwitchValue(switches::kProcessType); | 521 parsed_command_line.GetSwitchValue(switches::kProcessType); |
| 484 if (process_type.empty()) | 522 if (process_type.empty()) |
| 485 EnableCrashDumping(); | 523 EnableCrashDumping(); |
| 486 else if (process_type == switches::kRendererProcess) | 524 else if (process_type == switches::kRendererProcess) |
| 487 EnableRendererCrashDumping(); | 525 EnableRendererCrashDumping(); |
| 488 } | 526 } |
| OLD | NEW |