OLD | NEW |
1 // Copyright 2015 The Crashpad Authors. All rights reserved. | 1 // Copyright 2015 The Crashpad Authors. All rights reserved. |
2 // | 2 // |
3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
4 // you may not use this file except in compliance with 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 | 5 // You may obtain a copy of the License at |
6 // | 6 // |
7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
8 // | 8 // |
9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 // See the License for the specific language governing permissions and | 12 // See the License for the specific language governing permissions and |
13 // limitations under the License. | 13 // limitations under the License. |
14 | 14 |
15 #include "util/win/registration_protocol_win.h" | 15 #include "util/win/registration_protocol_win.h" |
16 | 16 |
17 #include <windows.h> | 17 #include <windows.h> |
| 18 #include <sddl.h> |
18 | 19 |
19 #include "base/logging.h" | 20 #include "base/logging.h" |
| 21 #include "util/win/exception_handler_server.h" |
20 #include "util/win/scoped_handle.h" | 22 #include "util/win/scoped_handle.h" |
| 23 #include "util/win/scoped_local_alloc.h" |
21 | 24 |
22 namespace crashpad { | 25 namespace crashpad { |
23 | 26 |
24 bool SendToCrashHandlerServer(const base::string16& pipe_name, | 27 bool SendToCrashHandlerServer(const base::string16& pipe_name, |
25 const crashpad::ClientToServerMessage& message, | 28 const ClientToServerMessage& message, |
26 crashpad::ServerToClientMessage* response) { | 29 ServerToClientMessage* response) { |
27 // Retry CreateFile() in a loop. If the handler isn’t actively waiting in | 30 // Retry CreateFile() in a loop. If the handler isn’t actively waiting in |
28 // ConnectNamedPipe() on a pipe instance because it’s busy doing something | 31 // ConnectNamedPipe() on a pipe instance because it’s busy doing something |
29 // else, CreateFile() will fail with ERROR_PIPE_BUSY. WaitNamedPipe() waits | 32 // else, CreateFile() will fail with ERROR_PIPE_BUSY. WaitNamedPipe() waits |
30 // until a pipe instance is ready, but there’s no way to wait for this | 33 // until a pipe instance is ready, but there’s no way to wait for this |
31 // condition and atomically open the client side of the pipe in a single | 34 // condition and atomically open the client side of the pipe in a single |
32 // operation. CallNamedPipe() implements similar retry logic to this, also in | 35 // operation. CallNamedPipe() implements similar retry logic to this, also in |
33 // user-mode code. | 36 // user-mode code. |
34 // | 37 // |
35 // This loop is only intended to retry on ERROR_PIPE_BUSY. Notably, if the | 38 // This loop is only intended to retry on ERROR_PIPE_BUSY. Notably, if the |
36 // handler is so lazy that it hasn’t even called CreateNamedPipe() yet, | 39 // handler is so lazy that it hasn’t even called CreateNamedPipe() yet, |
37 // CreateFile() will fail with ERROR_FILE_NOT_FOUND, and this function is | 40 // CreateFile() will fail with ERROR_FILE_NOT_FOUND, and this function is |
38 // expected to fail without retrying anything. If the handler is started at | 41 // expected to fail without retrying anything. If the handler is started at |
39 // around the same time as its client, something external to this code must be | 42 // around the same time as its client, something external to this code must be |
40 // done to guarantee correct ordering. When the client starts the handler | 43 // done to guarantee correct ordering. When the client starts the handler |
41 // itself, CrashpadClient::StartHandler() provides this synchronization. | 44 // itself, CrashpadClient::StartHandler() provides this synchronization. |
42 for (int tries = 0;;) { | 45 for (;;) { |
43 ScopedFileHANDLE pipe( | 46 ScopedFileHANDLE pipe( |
44 CreateFile(pipe_name.c_str(), | 47 CreateFile(pipe_name.c_str(), |
45 GENERIC_READ | GENERIC_WRITE, | 48 GENERIC_READ | GENERIC_WRITE, |
46 0, | 49 0, |
47 nullptr, | 50 nullptr, |
48 OPEN_EXISTING, | 51 OPEN_EXISTING, |
49 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, | 52 SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, |
50 nullptr)); | 53 nullptr)); |
51 if (!pipe.is_valid()) { | 54 if (!pipe.is_valid()) { |
52 if (++tries == 5 || GetLastError() != ERROR_PIPE_BUSY) { | 55 if (GetLastError() != ERROR_PIPE_BUSY) { |
53 PLOG(ERROR) << "CreateFile"; | 56 PLOG(ERROR) << "CreateFile"; |
54 return false; | 57 return false; |
55 } | 58 } |
56 | 59 |
57 if (!WaitNamedPipe(pipe_name.c_str(), 1000) && | 60 if (!WaitNamedPipe(pipe_name.c_str(), NMPWAIT_WAIT_FOREVER)) { |
58 GetLastError() != ERROR_SEM_TIMEOUT) { | |
59 PLOG(ERROR) << "WaitNamedPipe"; | 61 PLOG(ERROR) << "WaitNamedPipe"; |
60 return false; | 62 return false; |
61 } | 63 } |
62 | 64 |
63 continue; | 65 continue; |
64 } | 66 } |
65 | 67 |
66 DWORD mode = PIPE_READMODE_MESSAGE; | 68 DWORD mode = PIPE_READMODE_MESSAGE; |
67 if (!SetNamedPipeHandleState(pipe.get(), &mode, nullptr, nullptr)) { | 69 if (!SetNamedPipeHandleState(pipe.get(), &mode, nullptr, nullptr)) { |
68 PLOG(ERROR) << "SetNamedPipeHandleState"; | 70 PLOG(ERROR) << "SetNamedPipeHandleState"; |
69 return false; | 71 return false; |
70 } | 72 } |
71 DWORD bytes_read = 0; | 73 DWORD bytes_read = 0; |
72 BOOL result = TransactNamedPipe( | 74 BOOL result = TransactNamedPipe( |
73 pipe.get(), | 75 pipe.get(), |
74 // This is [in], but is incorrectly declared non-const. | 76 // This is [in], but is incorrectly declared non-const. |
75 const_cast<crashpad::ClientToServerMessage*>(&message), | 77 const_cast<ClientToServerMessage*>(&message), |
76 sizeof(message), | 78 sizeof(message), |
77 response, | 79 response, |
78 sizeof(*response), | 80 sizeof(*response), |
79 &bytes_read, | 81 &bytes_read, |
80 nullptr); | 82 nullptr); |
81 if (!result) { | 83 if (!result) { |
82 PLOG(ERROR) << "TransactNamedPipe"; | 84 PLOG(ERROR) << "TransactNamedPipe"; |
83 return false; | 85 return false; |
84 } | 86 } |
85 if (bytes_read != sizeof(*response)) { | 87 if (bytes_read != sizeof(*response)) { |
86 LOG(ERROR) << "TransactNamedPipe: expected " << sizeof(*response) | 88 LOG(ERROR) << "TransactNamedPipe: expected " << sizeof(*response) |
87 << ", observed " << bytes_read; | 89 << ", observed " << bytes_read; |
88 return false; | 90 return false; |
89 } | 91 } |
90 return true; | 92 return true; |
91 } | 93 } |
92 } | 94 } |
93 | 95 |
| 96 HANDLE CreateNamedPipeInstance(const std::wstring& pipe_name, |
| 97 bool first_instance) { |
| 98 SECURITY_ATTRIBUTES security_attributes; |
| 99 SECURITY_ATTRIBUTES* security_attributes_pointer = nullptr; |
| 100 ScopedLocalAlloc scoped_sec_desc; |
| 101 |
| 102 if (first_instance) { |
| 103 // Pre-Vista does not have integrity levels. |
| 104 const DWORD version = GetVersion(); |
| 105 const DWORD major_version = LOBYTE(LOWORD(version)); |
| 106 const bool is_vista_or_later = major_version >= 6; |
| 107 if (is_vista_or_later) { |
| 108 // Mandatory Label, no ACE flags, no ObjectType, integrity level |
| 109 // untrusted. |
| 110 const wchar_t kSddl[] = L"S:(ML;;;;;S-1-16-0)"; |
| 111 |
| 112 PSECURITY_DESCRIPTOR sec_desc; |
| 113 PCHECK(ConvertStringSecurityDescriptorToSecurityDescriptor( |
| 114 kSddl, SDDL_REVISION_1, &sec_desc, nullptr)) |
| 115 << "ConvertStringSecurityDescriptorToSecurityDescriptor"; |
| 116 |
| 117 // Take ownership of the allocated SECURITY_DESCRIPTOR. |
| 118 scoped_sec_desc.reset(sec_desc); |
| 119 |
| 120 memset(&security_attributes, 0, sizeof(security_attributes)); |
| 121 security_attributes.nLength = sizeof(SECURITY_ATTRIBUTES); |
| 122 security_attributes.lpSecurityDescriptor = sec_desc; |
| 123 security_attributes.bInheritHandle = TRUE; |
| 124 security_attributes_pointer = &security_attributes; |
| 125 } |
| 126 } |
| 127 |
| 128 return CreateNamedPipe( |
| 129 pipe_name.c_str(), |
| 130 PIPE_ACCESS_DUPLEX | (first_instance ? FILE_FLAG_FIRST_PIPE_INSTANCE : 0), |
| 131 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, |
| 132 ExceptionHandlerServer::kPipeInstances, |
| 133 512, |
| 134 512, |
| 135 0, |
| 136 security_attributes_pointer); |
| 137 } |
| 138 |
94 } // namespace crashpad | 139 } // namespace crashpad |
OLD | NEW |