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