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

Side by Side Diff: handler/win/registration_pipe_state.cc

Issue 1126783004: Introduce RegistrationServer. (Closed) Base URL: https://chromium.googlesource.com/crashpad/crashpad@master
Patch Set: Add comments, tidy. Created 5 years, 6 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 unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2015 The Crashpad Authors. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "handler/win/registration_pipe_state.h"
16
17 #include <string.h>
18 #include <vector>
scottmg 2015/05/25 18:41:54 split C and C++ headers by a newline
erikwright (departed) 2015/05/25 19:42:12 Done.
19
20 #include "base/logging.h"
21 #include "base/memory/scoped_ptr.h"
22 #include "util/stdlib/pointer_container.h"
23
24 namespace crashpad {
25
26 RegistrationPipeState::RegistrationPipeState(
27 ScopedFileHANDLE pipe,
28 RegistrationServer::Delegate* delegate)
29 : request_(),
30 response_(),
31 completion_handler_(nullptr),
32 overlapped_(),
33 event_(),
34 pipe_(pipe.Pass()),
35 waiting_for_close_(false),
36 delegate_(delegate),
37 get_named_pipe_client_process_id_proc_(nullptr) {
38 HMODULE kernel_dll = GetModuleHandle(L"kernel32.dll");
39 if (kernel_dll) {
40 get_named_pipe_client_process_id_proc_ =
41 reinterpret_cast<decltype(GetNamedPipeClientProcessId)*>(
42 GetProcAddress(kernel_dll, "GetNamedPipeClientProcessId"));
43 }
44 }
45
46 RegistrationPipeState::~RegistrationPipeState() {
47 }
48
49 bool RegistrationPipeState::Initialize() {
50 DCHECK(!event_.is_valid());
51 DCHECK(pipe_.is_valid());
52
53 event_.reset(CreateEvent(nullptr, true, false, nullptr));
54
55 if (!event_.is_valid()) {
56 PLOG(ERROR) << "CreateEvent";
57 } else {
58 overlapped_.hEvent = event_.get();
59 if (IssueConnect())
60 return true;
61 }
62
63 overlapped_.hEvent = nullptr;
64 event_.reset();
65 pipe_.reset();
66 completion_handler_ = nullptr;
67
68 return false;
69 }
70
71 void RegistrationPipeState::Stop() {
72 DCHECK(pipe_.is_valid());
73 if (!CancelIo(pipe_.get()))
74 PLOG(FATAL) << "CancelIo";
75 }
76
77 bool RegistrationPipeState::OnCompletion() {
78 AsyncCompletionHandler completion_handler = completion_handler_;
79 completion_handler_ = nullptr;
80
81 DWORD bytes_transferred = 0;
82 BOOL success = GetOverlappedResult(pipe_.get(),
83 &overlapped_,
84 &bytes_transferred,
85 false); // Do not wait.
86 if (!success) {
87 // ERROR_BROKEN_PIPE is expected when we are waiting for the client to close
88 // the pipe (signaling that they are done reading the response).
89 if (!waiting_for_close_ || GetLastError() != ERROR_BROKEN_PIPE)
90 PLOG(ERROR) << "GetOverlappedResult";
91 }
92
93 bool still_running = false;
94 if (!ResetEvent(event_.get())) {
95 PLOG(ERROR) << "ResetEvent";
96 } else if (!completion_handler) {
97 NOTREACHED();
98 still_running = ResetConnection();
99 } else if (!success) {
100 still_running = ResetConnection();
101 } else {
102 still_running = (this->*completion_handler)(bytes_transferred);
103 }
104
105 if (!still_running) {
106 overlapped_.hEvent = nullptr;
107 event_.reset();
108 pipe_.reset();
109 completion_handler_ = nullptr;
110 } else {
111 DCHECK(completion_handler_);
112 }
113
114 return still_running;
115 }
116
117 bool RegistrationPipeState::OnConnectComplete(DWORD /* bytes_transferred */) {
118 return IssueRead();
119 }
120
121 bool RegistrationPipeState::OnReadComplete(DWORD bytes_transferred) {
122 if (bytes_transferred != sizeof(request_)) {
123 LOG(ERROR) << "Invalid message size: " << bytes_transferred;
124 return ResetConnection();
125 } else {
126 return HandleRequest();
127 }
128 }
129
130 bool RegistrationPipeState::OnWriteComplete(DWORD bytes_transferred) {
131 if (bytes_transferred != sizeof(response_)) {
132 LOG(ERROR) << "Incomplete write operation. Bytes written: "
133 << bytes_transferred;
134 }
135
136 return IssueWaitForClientClose();
137 }
138
139 bool RegistrationPipeState::OnWaitForClientCloseComplete(
140 DWORD bytes_transferred) {
141 LOG(ERROR) << "Unexpected extra data (" << bytes_transferred
142 << " bytes) received from client.";
143 return ResetConnection();
144 }
145
146 bool RegistrationPipeState::IssueConnect() {
147 if (ConnectNamedPipe(pipe_.get(), &overlapped_)) {
148 return OnConnectComplete(0); // bytes_transferred (ignored)
149 } else {
150 DWORD result = GetLastError();
151 if (result == ERROR_PIPE_CONNECTED) {
152 return OnConnectComplete(0); // bytes_transferred (ignored)
153 } else if (result == ERROR_IO_PENDING) {
154 completion_handler_ = &RegistrationPipeState::OnConnectComplete;
155 return true;
156 } else {
157 PLOG(ERROR) << "ConnectNamedPipe";
158 return false;
159 }
160 }
161 }
162
163 bool RegistrationPipeState::IssueRead() {
164 DWORD bytes_read = 0;
165 if (ReadFile(pipe_.get(),
166 &request_,
167 sizeof(request_),
168 &bytes_read,
169 &overlapped_)) {
170 return OnReadComplete(bytes_read);
171 } else if (GetLastError() == ERROR_IO_PENDING) {
172 completion_handler_ = &RegistrationPipeState::OnReadComplete;
173 return true;
174 } else {
175 PLOG(ERROR) << "ReadFile";
176 return ResetConnection();
177 }
178 }
179
180 bool RegistrationPipeState::IssueWrite() {
181 DWORD bytes_written = 0;
182 if (WriteFile(pipe_.get(),
183 &response_,
184 sizeof(response_),
185 &bytes_written,
186 &overlapped_)) {
187 return OnWriteComplete(bytes_written);
188 } else if (GetLastError() == ERROR_IO_PENDING) {
189 completion_handler_ = &RegistrationPipeState::OnWriteComplete;
190 return true;
191 } else {
192 PLOG(ERROR) << "WriteFile";
193 return ResetConnection();
194 }
195 }
196
197 bool RegistrationPipeState::IssueWaitForClientClose() {
198 waiting_for_close_ = true;
199 DWORD bytes_read = 0;
200 if (ReadFile(pipe_.get(),
201 &request_,
202 sizeof(request_),
203 &bytes_read,
204 &overlapped_)) {
205 return OnWaitForClientCloseComplete(bytes_read);
206 } else if (GetLastError() == ERROR_IO_PENDING) {
207 completion_handler_ = &RegistrationPipeState::OnWaitForClientCloseComplete;
208 return true;
209 } else {
210 PLOG(ERROR) << "ReadFile";
211 return ResetConnection();
212 }
213 }
214
215 bool RegistrationPipeState::HandleRequest() {
216 if (get_named_pipe_client_process_id_proc_) {
217 // On Vista+ we can verify that the client is who they claim to be, thus
218 // preventing arbitrary processes from having us duplicate handles into
219 // other processes.
220 DWORD real_client_process_id = 0;
221 if (!get_named_pipe_client_process_id_proc_(pipe_.get(),
222 &real_client_process_id)) {
223 PLOG(ERROR) << "GetNamedPipeClientProcessId";
224 } else if (real_client_process_id != request_.client_process_id) {
225 LOG(ERROR) << "Client process ID from request ("
226 << request_.client_process_id
227 << ") does not match pipe client process ID ("
228 << real_client_process_id << ").";
229 return ResetConnection();
230 }
231 }
232
233 ScopedKernelHANDLE client_process(
234 OpenProcess(PROCESS_ALL_ACCESS, false, request_.client_process_id));
235 if (!client_process.is_valid()) {
236 if (ImpersonateNamedPipeClient(pipe_.get())) {
237 client_process.reset(
238 OpenProcess(PROCESS_ALL_ACCESS, false, request_.client_process_id));
239 RevertToSelf();
240 }
241 }
242
243 if (!client_process.is_valid()) {
244 LOG(ERROR) << "Failed to open client process.";
245 return ResetConnection();
246 }
247
248 memset(&response_, 0, sizeof(response_));
249
250 HANDLE request_report_event = nullptr;
251 HANDLE report_complete_event = nullptr;
252
253 if (!delegate_->RegisterClient(client_process.Pass(),
254 request_.crashpad_info_address,
255 &request_report_event,
256 &report_complete_event)) {
257 return ResetConnection();
258 }
259
260 // A handle has at most 32 significant bits, though its type is void*. Thus we
261 // truncate it here. An interesting exception is INVALID_HANDLE_VALUE, which
262 // is '-1'. It is still safe to truncate it from 0xFFFFFFFFFFFFFFFF to
263 // 0xFFFFFFFF, but a 64-bit client receiving that value must correctly sign
264 // extend it.
265 response_.request_report_event =
266 reinterpret_cast<uint32_t>(request_report_event);
267 response_.report_complete_event =
268 reinterpret_cast<uint32_t>(report_complete_event);
269 return IssueWrite();
270 }
271
272 bool RegistrationPipeState::ResetConnection() {
273 memset(&request_, 0, sizeof(request_));
274 waiting_for_close_ = false;
275
276 if (!DisconnectNamedPipe(pipe_.get())) {
277 PLOG(ERROR) << "DisconnectNamedPipe";
278 return false;
279 } else {
280 return IssueConnect();
281 }
282 }
283
284 } // namespace crashpad
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698