Home | History | Annotate | Download | only in crash_generation
      1 // Copyright (c) 2008, Google Inc.
      2 // All rights reserved.
      3 //
      4 // Redistribution and use in source and binary forms, with or without
      5 // modification, are permitted provided that the following conditions are
      6 // met:
      7 //
      8 //     * Redistributions of source code must retain the above copyright
      9 // notice, this list of conditions and the following disclaimer.
     10 //     * Redistributions in binary form must reproduce the above
     11 // copyright notice, this list of conditions and the following disclaimer
     12 // in the documentation and/or other materials provided with the
     13 // distribution.
     14 //     * Neither the name of Google Inc. nor the names of its
     15 // contributors may be used to endorse or promote products derived from
     16 // this software without specific prior written permission.
     17 //
     18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29 
     30 #include "client/windows/crash_generation/crash_generation_client.h"
     31 #include <cassert>
     32 #include <utility>
     33 #include "client/windows/common/ipc_protocol.h"
     34 
     35 namespace google_breakpad {
     36 
     37 const int kPipeBusyWaitTimeoutMs = 2000;
     38 
     39 #ifdef _DEBUG
     40 const DWORD kWaitForServerTimeoutMs = INFINITE;
     41 #else
     42 const DWORD kWaitForServerTimeoutMs = 15000;
     43 #endif
     44 
     45 const int kPipeConnectMaxAttempts = 2;
     46 
     47 const DWORD kPipeDesiredAccess = FILE_READ_DATA |
     48                                  FILE_WRITE_DATA |
     49                                  FILE_WRITE_ATTRIBUTES;
     50 
     51 const DWORD kPipeFlagsAndAttributes = SECURITY_IDENTIFICATION |
     52                                       SECURITY_SQOS_PRESENT;
     53 
     54 const DWORD kPipeMode = PIPE_READMODE_MESSAGE;
     55 
     56 const size_t kWaitEventCount = 2;
     57 
     58 // This function is orphan for production code. It can be used
     59 // for debugging to help repro some scenarios like the client
     60 // is slow in writing to the pipe after connecting, the client
     61 // is slow in reading from the pipe after writing, etc. The parameter
     62 // overlapped below is not used and it is present to match the signature
     63 // of this function to TransactNamedPipe Win32 API. Uncomment if needed
     64 // for debugging.
     65 /**
     66 static bool TransactNamedPipeDebugHelper(HANDLE pipe,
     67                                          const void* in_buffer,
     68                                          DWORD in_size,
     69                                          void* out_buffer,
     70                                          DWORD out_size,
     71                                          DWORD* bytes_count,
     72                                          LPOVERLAPPED) {
     73   // Uncomment the next sleep to create a gap before writing
     74   // to pipe.
     75   // Sleep(5000);
     76 
     77   if (!WriteFile(pipe,
     78                  in_buffer,
     79                  in_size,
     80                  bytes_count,
     81                  NULL)) {
     82     return false;
     83   }
     84 
     85   // Uncomment the next sleep to create a gap between write
     86   // and read.
     87   // Sleep(5000);
     88 
     89   return ReadFile(pipe, out_buffer, out_size, bytes_count, NULL) != FALSE;
     90 }
     91 **/
     92 
     93 CrashGenerationClient::CrashGenerationClient(
     94     const wchar_t* pipe_name,
     95     MINIDUMP_TYPE dump_type,
     96     const CustomClientInfo* custom_info)
     97         : pipe_name_(pipe_name),
     98           pipe_handle_(NULL),
     99           dump_type_(dump_type),
    100           thread_id_(0),
    101           server_process_id_(0),
    102           crash_event_(NULL),
    103           crash_generated_(NULL),
    104           server_alive_(NULL),
    105           exception_pointers_(NULL),
    106           custom_info_() {
    107   memset(&assert_info_, 0, sizeof(assert_info_));
    108   if (custom_info) {
    109     custom_info_ = *custom_info;
    110   }
    111 }
    112 
    113 CrashGenerationClient::CrashGenerationClient(
    114     HANDLE pipe_handle,
    115     MINIDUMP_TYPE dump_type,
    116     const CustomClientInfo* custom_info)
    117         : pipe_name_(),
    118           pipe_handle_(pipe_handle),
    119           dump_type_(dump_type),
    120           thread_id_(0),
    121           server_process_id_(0),
    122           crash_event_(NULL),
    123           crash_generated_(NULL),
    124           server_alive_(NULL),
    125           exception_pointers_(NULL),
    126           custom_info_() {
    127   memset(&assert_info_, 0, sizeof(assert_info_));
    128   if (custom_info) {
    129     custom_info_ = *custom_info;
    130   }
    131 }
    132 
    133 CrashGenerationClient::~CrashGenerationClient() {
    134   if (crash_event_) {
    135     CloseHandle(crash_event_);
    136   }
    137 
    138   if (crash_generated_) {
    139     CloseHandle(crash_generated_);
    140   }
    141 
    142   if (server_alive_) {
    143     CloseHandle(server_alive_);
    144   }
    145 }
    146 
    147 // Performs the registration step with the server process.
    148 // The registration step involves communicating with the server
    149 // via a named pipe. The client sends the following pieces of
    150 // data to the server:
    151 //
    152 // * Message tag indicating the client is requesting registration.
    153 // * Process id of the client process.
    154 // * Address of a DWORD variable in the client address space
    155 //   that will contain the thread id of the client thread that
    156 //   caused the crash.
    157 // * Address of a EXCEPTION_POINTERS* variable in the client
    158 //   address space that will point to an instance of EXCEPTION_POINTERS
    159 //   when the crash happens.
    160 // * Address of an instance of MDRawAssertionInfo that will contain
    161 //   relevant information in case of non-exception crashes like assertion
    162 //   failures and pure calls.
    163 //
    164 // In return the client expects the following information from the server:
    165 //
    166 // * Message tag indicating successful registration.
    167 // * Server process id.
    168 // * Handle to an object that client can signal to request dump
    169 //   generation from the server.
    170 // * Handle to an object that client can wait on after requesting
    171 //   dump generation for the server to finish dump generation.
    172 // * Handle to a mutex object that client can wait on to make sure
    173 //   server is still alive.
    174 //
    175 // If any step of the expected behavior mentioned above fails, the
    176 // registration step is not considered successful and hence out-of-process
    177 // dump generation service is not available.
    178 //
    179 // Returns true if the registration is successful; false otherwise.
    180 bool CrashGenerationClient::Register() {
    181   if (IsRegistered()) {
    182     return true;
    183   }
    184 
    185   HANDLE pipe = ConnectToServer();
    186   if (!pipe) {
    187     return false;
    188   }
    189 
    190   bool success = RegisterClient(pipe);
    191   CloseHandle(pipe);
    192   return success;
    193 }
    194 
    195 bool CrashGenerationClient::RequestUpload(DWORD crash_id) {
    196   HANDLE pipe = ConnectToServer();
    197   if (!pipe) {
    198     return false;
    199   }
    200 
    201   CustomClientInfo custom_info = {NULL, 0};
    202   ProtocolMessage msg(MESSAGE_TAG_UPLOAD_REQUEST, crash_id,
    203                       static_cast<MINIDUMP_TYPE>(NULL), NULL, NULL, NULL,
    204                       custom_info, NULL, NULL, NULL);
    205   DWORD bytes_count = 0;
    206   bool success = WriteFile(pipe, &msg, sizeof(msg), &bytes_count, NULL) != 0;
    207 
    208   CloseHandle(pipe);
    209   return success;
    210 }
    211 
    212 HANDLE CrashGenerationClient::ConnectToServer() {
    213   HANDLE pipe = ConnectToPipe(pipe_name_.c_str(),
    214                               kPipeDesiredAccess,
    215                               kPipeFlagsAndAttributes);
    216   if (!pipe) {
    217     return NULL;
    218   }
    219 
    220   DWORD mode = kPipeMode;
    221   if (!SetNamedPipeHandleState(pipe, &mode, NULL, NULL)) {
    222     CloseHandle(pipe);
    223     pipe = NULL;
    224   }
    225 
    226   return pipe;
    227 }
    228 
    229 bool CrashGenerationClient::RegisterClient(HANDLE pipe) {
    230   ProtocolMessage msg(MESSAGE_TAG_REGISTRATION_REQUEST,
    231                       GetCurrentProcessId(),
    232                       dump_type_,
    233                       &thread_id_,
    234                       &exception_pointers_,
    235                       &assert_info_,
    236                       custom_info_,
    237                       NULL,
    238                       NULL,
    239                       NULL);
    240   ProtocolMessage reply;
    241   DWORD bytes_count = 0;
    242   // The call to TransactNamedPipe below can be changed to a call
    243   // to TransactNamedPipeDebugHelper to help repro some scenarios.
    244   // For details see comments for TransactNamedPipeDebugHelper.
    245   if (!TransactNamedPipe(pipe,
    246                          &msg,
    247                          sizeof(msg),
    248                          &reply,
    249                          sizeof(ProtocolMessage),
    250                          &bytes_count,
    251                          NULL)) {
    252     return false;
    253   }
    254 
    255   if (!ValidateResponse(reply)) {
    256     return false;
    257   }
    258 
    259   ProtocolMessage ack_msg;
    260   ack_msg.tag = MESSAGE_TAG_REGISTRATION_ACK;
    261 
    262   if (!WriteFile(pipe, &ack_msg, sizeof(ack_msg), &bytes_count, NULL)) {
    263     return false;
    264   }
    265   crash_event_ = reply.dump_request_handle;
    266   crash_generated_ = reply.dump_generated_handle;
    267   server_alive_ = reply.server_alive_handle;
    268   server_process_id_ = reply.id;
    269 
    270   return true;
    271 }
    272 
    273 HANDLE CrashGenerationClient::ConnectToPipe(const wchar_t* pipe_name,
    274                                             DWORD pipe_access,
    275                                             DWORD flags_attrs) {
    276   if (pipe_handle_) {
    277     HANDLE t = pipe_handle_;
    278     pipe_handle_ = NULL;
    279     return t;
    280   }
    281 
    282   for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
    283     HANDLE pipe = CreateFile(pipe_name,
    284                              pipe_access,
    285                              0,
    286                              NULL,
    287                              OPEN_EXISTING,
    288                              flags_attrs,
    289                              NULL);
    290     if (pipe != INVALID_HANDLE_VALUE) {
    291       return pipe;
    292     }
    293 
    294     // Cannot continue retrying if error is something other than
    295     // ERROR_PIPE_BUSY.
    296     if (GetLastError() != ERROR_PIPE_BUSY) {
    297       break;
    298     }
    299 
    300     // Cannot continue retrying if wait on pipe fails.
    301     if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
    302       break;
    303     }
    304   }
    305 
    306   return NULL;
    307 }
    308 
    309 bool CrashGenerationClient::ValidateResponse(
    310     const ProtocolMessage& msg) const {
    311   return (msg.tag == MESSAGE_TAG_REGISTRATION_RESPONSE) &&
    312          (msg.id != 0) &&
    313          (msg.dump_request_handle != NULL) &&
    314          (msg.dump_generated_handle != NULL) &&
    315          (msg.server_alive_handle != NULL);
    316 }
    317 
    318 bool CrashGenerationClient::IsRegistered() const {
    319   return crash_event_ != NULL;
    320 }
    321 
    322 bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info,
    323                                         MDRawAssertionInfo* assert_info) {
    324   if (!IsRegistered()) {
    325     return false;
    326   }
    327 
    328   exception_pointers_ = ex_info;
    329   thread_id_ = GetCurrentThreadId();
    330 
    331   if (assert_info) {
    332     memcpy(&assert_info_, assert_info, sizeof(assert_info_));
    333   } else {
    334     memset(&assert_info_, 0, sizeof(assert_info_));
    335   }
    336 
    337   return SignalCrashEventAndWait();
    338 }
    339 
    340 bool CrashGenerationClient::RequestDump(EXCEPTION_POINTERS* ex_info) {
    341   return RequestDump(ex_info, NULL);
    342 }
    343 
    344 bool CrashGenerationClient::RequestDump(MDRawAssertionInfo* assert_info) {
    345   return RequestDump(NULL, assert_info);
    346 }
    347 
    348 bool CrashGenerationClient::SignalCrashEventAndWait() {
    349   assert(crash_event_);
    350   assert(crash_generated_);
    351   assert(server_alive_);
    352 
    353   // Reset the dump generated event before signaling the crash
    354   // event so that the server can set the dump generated event
    355   // once it is done generating the event.
    356   if (!ResetEvent(crash_generated_)) {
    357     return false;
    358   }
    359 
    360   if (!SetEvent(crash_event_)) {
    361     return false;
    362   }
    363 
    364   HANDLE wait_handles[kWaitEventCount] = {crash_generated_, server_alive_};
    365 
    366   DWORD result = WaitForMultipleObjects(kWaitEventCount,
    367                                         wait_handles,
    368                                         FALSE,
    369                                         kWaitForServerTimeoutMs);
    370 
    371   // Crash dump was successfully generated only if the server
    372   // signaled the crash generated event.
    373   return result == WAIT_OBJECT_0;
    374 }
    375 
    376 HANDLE CrashGenerationClient::DuplicatePipeToClientProcess(const wchar_t* pipe_name,
    377                                                            HANDLE hProcess) {
    378   for (int i = 0; i < kPipeConnectMaxAttempts; ++i) {
    379     HANDLE local_pipe = CreateFile(pipe_name, kPipeDesiredAccess,
    380                                    0, NULL, OPEN_EXISTING,
    381                                    kPipeFlagsAndAttributes, NULL);
    382     if (local_pipe != INVALID_HANDLE_VALUE) {
    383       HANDLE remotePipe = INVALID_HANDLE_VALUE;
    384       if (DuplicateHandle(GetCurrentProcess(), local_pipe,
    385                           hProcess, &remotePipe, 0, FALSE,
    386                           DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
    387         return remotePipe;
    388       } else {
    389         return INVALID_HANDLE_VALUE;
    390       }
    391     }
    392 
    393     // Cannot continue retrying if the error wasn't a busy pipe.
    394     if (GetLastError() != ERROR_PIPE_BUSY) {
    395       return INVALID_HANDLE_VALUE;
    396     }
    397 
    398     if (!WaitNamedPipe(pipe_name, kPipeBusyWaitTimeoutMs)) {
    399       return INVALID_HANDLE_VALUE;
    400     }
    401   }
    402   return INVALID_HANDLE_VALUE;
    403 }
    404 
    405 }  // namespace google_breakpad
    406