Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Unified Diff: handler/win/registration_pipe_state.cc

Issue 1126783004: Introduce RegistrationServer. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: One extra comment. Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « handler/win/registration_pipe_state.h ('k') | handler/win/registration_pipe_state_test.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: handler/win/registration_pipe_state.cc
diff --git a/handler/win/registration_pipe_state.cc b/handler/win/registration_pipe_state.cc
new file mode 100644
index 0000000000000000000000000000000000000000..08d265f1ce871ff444bc1dfab645788375f13af5
--- /dev/null
+++ b/handler/win/registration_pipe_state.cc
@@ -0,0 +1,289 @@
+// Copyright 2015 The Crashpad Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include "handler/win/registration_pipe_state.h"
+
+#include <string.h>
+
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "util/stdlib/pointer_container.h"
+
+namespace crashpad {
+
+RegistrationPipeState::RegistrationPipeState(
+ ScopedFileHANDLE pipe,
+ RegistrationServer::Delegate* delegate)
+ : request_(),
+ response_(),
+ completion_handler_(nullptr),
+ overlapped_(),
+ event_(),
+ pipe_(pipe.Pass()),
+ waiting_for_close_(false),
+ delegate_(delegate),
+ get_named_pipe_client_process_id_proc_(nullptr) {
+ HMODULE kernel_dll = GetModuleHandle(L"kernel32.dll");
+ if (kernel_dll) {
+ get_named_pipe_client_process_id_proc_ =
+ reinterpret_cast<decltype(GetNamedPipeClientProcessId)*>(
+ GetProcAddress(kernel_dll, "GetNamedPipeClientProcessId"));
+ }
+}
+
+RegistrationPipeState::~RegistrationPipeState() {
+}
+
+bool RegistrationPipeState::Initialize() {
+ DCHECK(!event_.is_valid());
+ DCHECK(pipe_.is_valid());
+
+ event_.reset(CreateEvent(nullptr, true, false, nullptr));
+
+ if (!event_.is_valid()) {
+ PLOG(ERROR) << "CreateEvent";
+ } else {
+ overlapped_.hEvent = event_.get();
+ if (IssueConnect())
+ return true;
+ }
+
+ overlapped_.hEvent = nullptr;
+ event_.reset();
+ pipe_.reset();
+ completion_handler_ = nullptr;
+
+ return false;
+}
+
+void RegistrationPipeState::Stop() {
+ DCHECK(pipe_.is_valid());
+ if (!CancelIo(pipe_.get()))
+ PLOG(FATAL) << "CancelIo";
+}
+
+bool RegistrationPipeState::OnCompletion() {
+ AsyncCompletionHandler completion_handler = completion_handler_;
+ completion_handler_ = nullptr;
+
+ DWORD bytes_transferred = 0;
+ BOOL success = GetOverlappedResult(pipe_.get(),
+ &overlapped_,
+ &bytes_transferred,
+ false); // Do not wait.
+ if (!success) {
+ // ERROR_BROKEN_PIPE is expected when we are waiting for the client to close
+ // the pipe (signaling that they are done reading the response).
+ if (!waiting_for_close_ || GetLastError() != ERROR_BROKEN_PIPE)
+ PLOG(ERROR) << "GetOverlappedResult";
+ }
+
+ bool still_running = false;
+ if (!ResetEvent(event_.get())) {
+ PLOG(ERROR) << "ResetEvent";
+ } else if (!completion_handler) {
+ NOTREACHED();
+ still_running = ResetConnection();
+ } else if (!success) {
+ still_running = ResetConnection();
+ } else {
+ still_running = (this->*completion_handler)(bytes_transferred);
+ }
+
+ if (!still_running) {
+ overlapped_.hEvent = nullptr;
+ event_.reset();
+ pipe_.reset();
+ completion_handler_ = nullptr;
+ } else {
+ DCHECK(completion_handler_);
+ }
+
+ return still_running;
+}
+
+bool RegistrationPipeState::OnConnectComplete(DWORD /* bytes_transferred */) {
+ return IssueRead();
+}
+
+bool RegistrationPipeState::OnReadComplete(DWORD bytes_transferred) {
+ if (bytes_transferred != sizeof(request_)) {
+ LOG(ERROR) << "Invalid message size: " << bytes_transferred;
+ return ResetConnection();
+ } else {
+ return HandleRequest();
+ }
+}
+
+bool RegistrationPipeState::OnWriteComplete(DWORD bytes_transferred) {
+ if (bytes_transferred != sizeof(response_)) {
+ LOG(ERROR) << "Incomplete write operation. Bytes written: "
+ << bytes_transferred;
+ }
+
+ return IssueWaitForClientClose();
+}
+
+bool RegistrationPipeState::OnWaitForClientCloseComplete(
+ DWORD bytes_transferred) {
+ LOG(ERROR) << "Unexpected extra data (" << bytes_transferred
+ << " bytes) received from client.";
+ return ResetConnection();
+}
+
+bool RegistrationPipeState::IssueConnect() {
+ if (ConnectNamedPipe(pipe_.get(), &overlapped_)) {
+ return OnConnectComplete(0); // bytes_transferred (ignored)
+ } else {
+ DWORD result = GetLastError();
+ if (result == ERROR_PIPE_CONNECTED) {
+ return OnConnectComplete(0); // bytes_transferred (ignored)
+ } else if (result == ERROR_IO_PENDING) {
+ completion_handler_ = &RegistrationPipeState::OnConnectComplete;
+ return true;
+ } else {
+ PLOG(ERROR) << "ConnectNamedPipe";
+ return false;
+ }
+ }
+}
+
+bool RegistrationPipeState::IssueRead() {
+ DWORD bytes_read = 0;
+ if (ReadFile(pipe_.get(),
+ &request_,
+ sizeof(request_),
+ &bytes_read,
+ &overlapped_)) {
+ return OnReadComplete(bytes_read);
+ } else if (GetLastError() == ERROR_IO_PENDING) {
+ completion_handler_ = &RegistrationPipeState::OnReadComplete;
+ return true;
+ } else {
+ PLOG(ERROR) << "ReadFile";
+ return ResetConnection();
+ }
+}
+
+bool RegistrationPipeState::IssueWrite() {
+ DWORD bytes_written = 0;
+ if (WriteFile(pipe_.get(),
+ &response_,
+ sizeof(response_),
+ &bytes_written,
+ &overlapped_)) {
+ return OnWriteComplete(bytes_written);
+ } else if (GetLastError() == ERROR_IO_PENDING) {
+ completion_handler_ = &RegistrationPipeState::OnWriteComplete;
+ return true;
+ } else {
+ PLOG(ERROR) << "WriteFile";
+ return ResetConnection();
+ }
+}
+
+bool RegistrationPipeState::IssueWaitForClientClose() {
+ // If we invoke DisconnectNamedPipe before the client has read the response
+ // the response will never be delivered. Therefore we issue an extra ReadFile
+ // operation after writing the response. No data is expected - the operation
+ // will be 'completed' when the client closes the pipe.
+ waiting_for_close_ = true;
+ DWORD bytes_read = 0;
+ if (ReadFile(pipe_.get(),
+ &request_,
+ sizeof(request_),
+ &bytes_read,
+ &overlapped_)) {
+ return OnWaitForClientCloseComplete(bytes_read);
+ } else if (GetLastError() == ERROR_IO_PENDING) {
+ completion_handler_ = &RegistrationPipeState::OnWaitForClientCloseComplete;
+ return true;
+ } else {
+ PLOG(ERROR) << "ReadFile";
+ return ResetConnection();
+ }
+}
+
+bool RegistrationPipeState::HandleRequest() {
+ if (get_named_pipe_client_process_id_proc_) {
+ // On Vista+ we can verify that the client is who they claim to be, thus
+ // preventing arbitrary processes from having us duplicate handles into
+ // other processes.
+ DWORD real_client_process_id = 0;
+ if (!get_named_pipe_client_process_id_proc_(pipe_.get(),
+ &real_client_process_id)) {
+ PLOG(ERROR) << "GetNamedPipeClientProcessId";
+ } else if (real_client_process_id != request_.client_process_id) {
+ LOG(ERROR) << "Client process ID from request ("
+ << request_.client_process_id
+ << ") does not match pipe client process ID ("
+ << real_client_process_id << ").";
+ return ResetConnection();
+ }
+ }
+
+ ScopedKernelHANDLE client_process(
+ OpenProcess(PROCESS_ALL_ACCESS, false, request_.client_process_id));
+ if (!client_process.is_valid()) {
+ if (ImpersonateNamedPipeClient(pipe_.get())) {
+ client_process.reset(
+ OpenProcess(PROCESS_ALL_ACCESS, false, request_.client_process_id));
+ RevertToSelf();
+ }
+ }
+
+ if (!client_process.is_valid()) {
+ LOG(ERROR) << "Failed to open client process.";
+ return ResetConnection();
+ }
+
+ memset(&response_, 0, sizeof(response_));
+
+ HANDLE request_report_event = nullptr;
+ HANDLE report_complete_event = nullptr;
+
+ if (!delegate_->RegisterClient(client_process.Pass(),
+ request_.crashpad_info_address,
+ &request_report_event,
+ &report_complete_event)) {
+ return ResetConnection();
+ }
+
+ // A handle has at most 32 significant bits, though its type is void*. Thus we
+ // truncate it here. An interesting exception is INVALID_HANDLE_VALUE, which
+ // is '-1'. It is still safe to truncate it from 0xFFFFFFFFFFFFFFFF to
+ // 0xFFFFFFFF, but a 64-bit client receiving that value must correctly sign
+ // extend it.
+ response_.request_report_event =
+ reinterpret_cast<uint32_t>(request_report_event);
+ response_.report_complete_event =
+ reinterpret_cast<uint32_t>(report_complete_event);
+ return IssueWrite();
+}
+
+bool RegistrationPipeState::ResetConnection() {
+ memset(&request_, 0, sizeof(request_));
+ waiting_for_close_ = false;
+
+ if (!DisconnectNamedPipe(pipe_.get())) {
+ PLOG(ERROR) << "DisconnectNamedPipe";
+ return false;
+ } else {
+ return IssueConnect();
+ }
+}
+
+} // namespace crashpad
« no previous file with comments | « handler/win/registration_pipe_state.h ('k') | handler/win/registration_pipe_state_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698