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 using gatekeeper::GatekeeperRawMessage;
33 
~GatekeeperWindowsChannel()34 GatekeeperWindowsChannel::~GatekeeperWindowsChannel() {
35   if (pipe_handle_) {
36     CloseHandle(pipe_handle_);
37   }
38 
39   if (pipe_overlapped_.hEvent) {
40     CloseHandle(pipe_overlapped_.hEvent);
41   }
42 }
43 
Create(HANDLE pipe_handle)44 std::unique_ptr<GatekeeperWindowsChannel> GatekeeperWindowsChannel::Create(
45     HANDLE pipe_handle) {
46   auto gatekeeper_channel =
47       std::unique_ptr<GatekeeperWindowsChannel>(new GatekeeperWindowsChannel());
48   if (!gatekeeper_channel->WaitForConnection(pipe_handle)) {
49     return nullptr;
50   }
51 
52   return gatekeeper_channel;
53 }
54 
WaitForConnection(HANDLE pipe_handle)55 bool GatekeeperWindowsChannel::WaitForConnection(HANDLE pipe_handle) {
56   assert(pipe_handle_ == NULL);
57   pipe_handle_ = pipe_handle;
58 
59   DWORD flags;
60   if (GetNamedPipeInfo(pipe_handle_,
61                        /*lpFlags= */ &flags,
62                        /*lpOutBufferSize= */ NULL,
63                        /* lpInBufferSize= */ NULL,
64                        /* lpMaxInstances= */ NULL) == 0) {
65     LOG(ERROR) << "Could not query Gatekeeper named pipe handle info. "
66                   "Got error code "
67                << GetLastError();
68     return false;
69   }
70 
71   if ((flags & PIPE_SERVER_END) == 0) {
72     LOG(ERROR) << "Gatekeeper handle is not the server end of a named pipe!";
73     return false;
74   }
75 
76   // Create the event object
77   HANDLE event_handle =
78       CreateEventA(/* lpEventAttributes= */ NULL, /* bManualReset= */ true,
79                    /* bInitialState= */ 0, /* lpName= */ NULL);
80   if (event_handle == NULL) {
81     LOG(ERROR)
82         << "Error: Could not create keymaster event object. Got error code "
83         << GetLastError();
84     return false;
85   }
86   pipe_overlapped_.hEvent = event_handle;
87 
88   // Wait for client to connect to the pipe
89   ConnectNamedPipe(pipe_handle_, &pipe_overlapped_);
90 
91   LOG(INFO) << "Listening to existing Gatekeeper pipe.";
92   if (WaitForSingleObject(pipe_overlapped_.hEvent, INFINITE) != WAIT_OBJECT_0) {
93     LOG(ERROR) << "Could not wait for Gatekeeper pipe's overlapped to be "
94                   "signalled. Got Windows error code "
95                << GetLastError();
96     return false;
97   }
98   if (!ResetEvent(pipe_overlapped_.hEvent)) {
99     LOG(ERROR) << "Could not reset Gatekeeper pipe's overlapped. Got Windows "
100                   "error code "
101                << GetLastError();
102     return false;
103   }
104   return true;
105 }
106 
SendRequest(uint32_t command,const gatekeeper::GateKeeperMessage & message)107 bool GatekeeperWindowsChannel::SendRequest(
108     uint32_t command, const gatekeeper::GateKeeperMessage& message) {
109   return SendMessage(command, false, message);
110 }
111 
SendResponse(uint32_t command,const gatekeeper::GateKeeperMessage & message)112 bool GatekeeperWindowsChannel::SendResponse(
113     uint32_t command, const gatekeeper::GateKeeperMessage& message) {
114   return SendMessage(command, true, message);
115 }
116 
117 // TODO(b/203538883): Remove non-vsock logic and enable vsock by default
SendMessage(uint32_t command,bool is_response,const gatekeeper::GateKeeperMessage & message)118 bool GatekeeperWindowsChannel::SendMessage(
119     uint32_t command, bool is_response,
120     const gatekeeper::GateKeeperMessage& message) {
121   auto payload_size = message.GetSerializedSize();
122 
123   if (payload_size > 1024 * 1024) {
124     LOG(WARNING) << "Sending large message with id: " << command
125                  << " and size: " << payload_size;
126   }
127 
128   auto to_send = CreateGatekeeperMessage(command, is_response, payload_size);
129   message.Serialize(to_send->payload, to_send->payload + payload_size);
130   auto write_size = payload_size + sizeof(GatekeeperRawMessage);
131   auto to_send_bytes = reinterpret_cast<const char*>(to_send.get());
132   if (!WriteFile(pipe_handle_, to_send_bytes, write_size, NULL,
133                  &pipe_overlapped_) &&
134       GetLastError() != ERROR_IO_PENDING) {
135     LOG(ERROR) << "Could not write Gatekeeper Message. Got Windows error code "
136                << GetLastError();
137     return false;
138   }
139 
140   // Vsock pipes are overlapped (asynchronous) and we need to wait for the
141   // overlapped event to be signaled.
142   // https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-waitforsingleobject#return-value
143   if (WaitForSingleObject(pipe_overlapped_.hEvent, INFINITE) != WAIT_OBJECT_0) {
144     LOG(ERROR) << "Could not wait for Gatekeeper pipe's overlapped to be "
145                   "signalled. Got Windows error code "
146                << GetLastError();
147     return false;
148   }
149   if (!ResetEvent(pipe_overlapped_.hEvent)) {
150     LOG(ERROR) << "Could not reset Gatekeeper pipe's overlapped. Got Windows "
151                   "error code "
152                << GetLastError();
153     return false;
154   }
155   return true;
156 }
157 
ReadFromPipe(LPVOID buffer,DWORD size)158 bool GatekeeperWindowsChannel::ReadFromPipe(LPVOID buffer, DWORD size) {
159   if (ReadFile(pipe_handle_, buffer, size, NULL, &pipe_overlapped_) == FALSE) {
160     if (GetLastError() == ERROR_BROKEN_PIPE) {
161       LOG(INFO) << "Gatekeeper pipe was closed.";
162       return false;
163     } else if (GetLastError() != ERROR_IO_PENDING) {
164       LOG(ERROR) << "Could not read Gatekeeper message. Got Windows error code "
165                  << GetLastError();
166       return false;
167     }
168 
169     // Wait for the asynchronous read to finish.
170     DWORD unused_bytes_read;
171     if (GetOverlappedResult(pipe_handle_, &pipe_overlapped_, &unused_bytes_read,
172                             /*bWait=*/TRUE) == FALSE) {
173       if (GetLastError() == ERROR_BROKEN_PIPE) {
174         LOG(INFO) << "Gatekeeper pipe was closed.";
175         return false;
176       }
177 
178       LOG(ERROR) << "Error receiving Gatekeeper data. Got Windows error code "
179                  << GetLastError();
180       return false;
181     }
182   }
183 
184   if (ResetEvent(pipe_overlapped_.hEvent) == 0) {
185     LOG(ERROR) << "Error calling ResetEvent for Gatekeeper data. Got "
186                   "Windows error code "
187                << GetLastError();
188 
189     return false;
190   }
191 
192   return true;
193 }
194 
ReceiveMessage()195 ManagedGatekeeperMessage GatekeeperWindowsChannel::ReceiveMessage() {
196   struct GatekeeperRawMessage message_header;
197 
198   if (!ReadFromPipe(&message_header, sizeof(message_header))) {
199     return {};
200   }
201 
202   if (message_header.payload_size > 1024 * 1024) {
203     LOG(WARNING) << "Received large message with id: " << message_header.cmd
204                  << " and size " << message_header.payload_size;
205   }
206 
207   auto message =
208       CreateGatekeeperMessage(message_header.cmd, message_header.is_response,
209                               message_header.payload_size);
210   auto message_bytes = reinterpret_cast<char*>(message->payload);
211   if (!ReadFromPipe(message_bytes, message->payload_size)) {
212     return {};
213   }
214 
215   return message;
216 }
217 
218 }  // namespace cuttlefish