1 /*
2 * Copyright 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "common/libs/security/gatekeeper_channel_windows.h"
18
19 #include <windows.h>
20
21 #include <errhandlingapi.h>
22 #include <fileapi.h>
23 #include <handleapi.h>
24 #include <namedpipeapi.h>
25 #include <chrono>
26 #include <cstdlib>
27 #include <thread>
28
29 #include <android-base/logging.h>
30
31 namespace cuttlefish {
32
~GatekeeperWindowsChannel()33 GatekeeperWindowsChannel::~GatekeeperWindowsChannel() {
34 if (pipe_handle_) {
35 CloseHandle(pipe_handle_);
36 }
37
38 if (pipe_overlapped_.hEvent) {
39 CloseHandle(pipe_overlapped_.hEvent);
40 }
41 }
42
Create(HANDLE pipe_handle)43 std::unique_ptr<GatekeeperWindowsChannel> GatekeeperWindowsChannel::Create(
44 HANDLE pipe_handle) {
45 auto gatekeeper_channel =
46 std::unique_ptr<GatekeeperWindowsChannel>(new GatekeeperWindowsChannel());
47 if (!gatekeeper_channel->WaitForConnection(pipe_handle)) {
48 return nullptr;
49 }
50
51 return gatekeeper_channel;
52 }
53
WaitForConnection(HANDLE pipe_handle)54 bool GatekeeperWindowsChannel::WaitForConnection(HANDLE pipe_handle) {
55 assert(pipe_handle_ == NULL);
56 pipe_handle_ = pipe_handle;
57
58 DWORD flags;
59 if (GetNamedPipeInfo(pipe_handle_,
60 /*lpFlags= */ &flags,
61 /*lpOutBufferSize= */ NULL,
62 /* lpInBufferSize= */ NULL,
63 /* lpMaxInstances= */ NULL) == 0) {
64 LOG(ERROR) << "Could not query Gatekeeper named pipe handle info. "
65 "Got error code "
66 << GetLastError();
67 return false;
68 }
69
70 if ((flags & PIPE_SERVER_END) == 0) {
71 LOG(ERROR) << "Gatekeeper handle is not the server end of a named pipe!";
72 return false;
73 }
74
75 // Create the event object
76 HANDLE event_handle =
77 CreateEventA(/* lpEventAttributes= */ NULL, /* bManualReset= */ true,
78 /* bInitialState= */ 0, /* lpName= */ NULL);
79 if (event_handle == NULL) {
80 LOG(ERROR)
81 << "Error: Could not create keymaster event object. Got error code "
82 << GetLastError();
83 return false;
84 }
85 pipe_overlapped_.hEvent = event_handle;
86
87 // Wait for client to connect to the pipe
88 ConnectNamedPipe(pipe_handle_, &pipe_overlapped_);
89
90 LOG(INFO) << "Listening to existing Gatekeeper pipe.";
91 if (WaitForSingleObject(pipe_overlapped_.hEvent, INFINITE) != WAIT_OBJECT_0) {
92 LOG(ERROR) << "Could not wait for Gatekeeper pipe's overlapped to be "
93 "signalled. Got Windows error code "
94 << GetLastError();
95 return false;
96 }
97 if (!ResetEvent(pipe_overlapped_.hEvent)) {
98 LOG(ERROR) << "Could not reset Gatekeeper pipe's overlapped. Got Windows "
99 "error code "
100 << GetLastError();
101 return false;
102 }
103 return true;
104 }
105
SendRequest(uint32_t command,const gatekeeper::GateKeeperMessage & message)106 bool GatekeeperWindowsChannel::SendRequest(
107 uint32_t command, const gatekeeper::GateKeeperMessage& message) {
108 return SendMessage(command, false, message);
109 }
110
SendResponse(uint32_t command,const gatekeeper::GateKeeperMessage & message)111 bool GatekeeperWindowsChannel::SendResponse(
112 uint32_t command, const gatekeeper::GateKeeperMessage& message) {
113 return SendMessage(command, true, message);
114 }
115
116 // TODO(b/203538883): Remove non-vsock logic and enable vsock by default
SendMessage(uint32_t command,bool is_response,const gatekeeper::GateKeeperMessage & message)117 bool GatekeeperWindowsChannel::SendMessage(
118 uint32_t command, bool is_response,
119 const gatekeeper::GateKeeperMessage& message) {
120 auto payload_size = message.GetSerializedSize();
121
122 if (payload_size > 1024 * 1024) {
123 LOG(WARNING) << "Sending large message with id: " << command
124 << " and size: " << payload_size;
125 }
126
127 auto to_send_result = transport::CreateMessage(command, is_response, payload_size);
128 if (!to_send_result.ok()) {
129 LOG(ERROR) << "Could not allocate Gatekeeper Message: "
130 << to_send_result.error().FormatForEnv();
131 return false;
132 }
133 auto to_send = std::move(to_send_result.value());
134 message.Serialize(to_send->payload, to_send->payload + payload_size);
135 auto write_size = payload_size + sizeof(transport::RawMessage);
136 auto to_send_bytes = reinterpret_cast<const char*>(to_send.get());
137 if (!WriteFile(pipe_handle_, to_send_bytes, write_size, NULL,
138 &pipe_overlapped_) &&
139 GetLastError() != ERROR_IO_PENDING) {
140 LOG(ERROR) << "Could not write Gatekeeper Message. Got Windows error code "
141 << GetLastError();
142 return false;
143 }
144
145 // Vsock pipes are overlapped (asynchronous) and we need to wait for the
146 // overlapped event to be signaled.
147 // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject#return-value
148 if (WaitForSingleObject(pipe_overlapped_.hEvent, INFINITE) != WAIT_OBJECT_0) {
149 LOG(ERROR) << "Could not wait for Gatekeeper pipe's overlapped to be "
150 "signalled. Got Windows error code "
151 << GetLastError();
152 return false;
153 }
154 if (!ResetEvent(pipe_overlapped_.hEvent)) {
155 LOG(ERROR) << "Could not reset Gatekeeper pipe's overlapped. Got Windows "
156 "error code "
157 << GetLastError();
158 return false;
159 }
160 return true;
161 }
162
ReadFromPipe(LPVOID buffer,DWORD size)163 bool GatekeeperWindowsChannel::ReadFromPipe(LPVOID buffer, DWORD size) {
164 if (ReadFile(pipe_handle_, buffer, size, NULL, &pipe_overlapped_) == FALSE) {
165 if (GetLastError() == ERROR_BROKEN_PIPE) {
166 LOG(INFO) << "Gatekeeper pipe was closed.";
167 return false;
168 } else if (GetLastError() != ERROR_IO_PENDING) {
169 LOG(ERROR) << "Could not read Gatekeeper message. Got Windows error code "
170 << GetLastError();
171 return false;
172 }
173
174 // Wait for the asynchronous read to finish.
175 DWORD unused_bytes_read;
176 if (GetOverlappedResult(pipe_handle_, &pipe_overlapped_, &unused_bytes_read,
177 /*bWait=*/TRUE) == FALSE) {
178 if (GetLastError() == ERROR_BROKEN_PIPE) {
179 LOG(INFO) << "Gatekeeper pipe was closed.";
180 return false;
181 }
182
183 LOG(ERROR) << "Error receiving Gatekeeper data. Got Windows error code "
184 << GetLastError();
185 return false;
186 }
187 }
188
189 if (ResetEvent(pipe_overlapped_.hEvent) == 0) {
190 LOG(ERROR) << "Error calling ResetEvent for Gatekeeper data. Got "
191 "Windows error code "
192 << GetLastError();
193
194 return false;
195 }
196
197 return true;
198 }
199
ReceiveMessage()200 transport::ManagedMessage GatekeeperWindowsChannel::ReceiveMessage() {
201 struct transport::RawMessage message_header;
202
203 if (!ReadFromPipe(&message_header, sizeof(message_header))) {
204 return {};
205 }
206
207 if (message_header.payload_size > 1024 * 1024) {
208 LOG(WARNING) << "Received large message with id: " << message_header.command
209 << " and size " << message_header.payload_size;
210 }
211
212 auto message_result = transport::CreateMessage(message_header.command,
213 message_header.is_response,
214 message_header.payload_size);
215 if (!message_result.ok()) {
216 return {};
217 }
218 auto message = std::move(message_result.value());
219 auto message_bytes = reinterpret_cast<char*>(message->payload);
220 if (!ReadFromPipe(message_bytes, message->payload_size)) {
221 return {};
222 }
223
224 return message;
225 }
226
227 } // namespace cuttlefish
228