1 /*
2  * Copyright (C) 2015 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 <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <trusty_ipc.h>
22 #include <uapi/err.h>
23 
24 #include "gatekeeper_ipc.h"
25 #include "trusty_gatekeeper.h"
26 
27 using namespace gatekeeper;
28 TrustyGateKeeper* device;
29 
30 class SessionManager {
31 public:
SessionManager(long * err)32     SessionManager(long* err) { *err = device->OpenSession(); }
~SessionManager()33     ~SessionManager() { device->CloseSession(); }
34 };
35 
tipc_err_to_gatekeeper_err(long tipc_err)36 static gatekeeper_error_t tipc_err_to_gatekeeper_err(long tipc_err) {
37     switch (tipc_err) {
38     case NO_ERROR:
39         return ERROR_NONE;
40     case ERR_BAD_LEN:
41     case ERR_NOT_VALID:
42     case ERR_NOT_IMPLEMENTED:
43     case ERR_NOT_SUPPORTED:
44         return ERROR_INVALID;
45     default:
46         return ERROR_UNKNOWN;
47     }
48 }
49 
50 template <typename Request, typename Response>
exec_cmd(void (GateKeeper::* operation)(const Request &,Response *),uint8_t * in_buf,uint32_t in_size,UniquePtr<uint8_t[]> * out_buf,uint32_t * out_size)51 static gatekeeper_error_t exec_cmd(void (GateKeeper::*operation)(const Request&,
52                                                                  Response*),
53                                    uint8_t* in_buf,
54                                    uint32_t in_size,
55                                    UniquePtr<uint8_t[]>* out_buf,
56                                    uint32_t* out_size) {
57     long rc;
58     SessionManager sm(&rc);
59     if (rc != NO_ERROR)
60         return tipc_err_to_gatekeeper_err(rc);
61 
62     Request req;
63     gatekeeper_error_t err = req.Deserialize(in_buf, in_buf + in_size);
64     if (err != ERROR_NONE) {
65         TLOGE("error (%d) deserializing request\n", err);
66         return ERROR_INVALID;
67     }
68 
69     Response rsp;
70     (device->*operation)(req, &rsp);
71 
72     if (rsp.error == ERROR_NOT_IMPLEMENTED) {
73         return ERROR_NOT_IMPLEMENTED;
74     }
75 
76     *out_size = rsp.GetSerializedSize();
77     if (*out_size > GATEKEEPER_MAX_BUFFER_LENGTH) {
78         *out_size = 0;
79         TLOGE("response size too large (%d)\n", *out_size);
80         return ERROR_UNKNOWN;
81     }
82 
83     out_buf->reset(new uint8_t[*out_size]);
84     if (out_buf->get() == NULL) {
85         *out_size = 0;
86         return ERROR_UNKNOWN;
87     }
88 
89     if (rsp.Serialize(out_buf->get(), out_buf->get() + *out_size) !=
90         *out_size) {
91         TLOGE("error serializing response message\n");
92         return ERROR_UNKNOWN;
93     }
94 
95     return ERROR_NONE;
96 }
97 
handle_request(uint32_t cmd,uint8_t * in_buf,uint32_t in_buf_size,UniquePtr<uint8_t[]> * out_buf,uint32_t * out_buf_size)98 static gatekeeper_error_t handle_request(uint32_t cmd,
99                                          uint8_t* in_buf,
100                                          uint32_t in_buf_size,
101                                          UniquePtr<uint8_t[]>* out_buf,
102                                          uint32_t* out_buf_size) {
103     switch (cmd) {
104     case GK_ENROLL:
105         return exec_cmd(&GateKeeper::Enroll, in_buf, in_buf_size, out_buf,
106                         out_buf_size);
107     case GK_VERIFY:
108         return exec_cmd(&GateKeeper::Verify, in_buf, in_buf_size, out_buf,
109                         out_buf_size);
110     case GK_DELETE_USER:
111         return exec_cmd(&GateKeeper::DeleteUser, in_buf, in_buf_size, out_buf,
112                         out_buf_size);
113     case GK_DELETE_ALL_USERS:
114         return exec_cmd(&GateKeeper::DeleteAllUsers, in_buf, in_buf_size,
115                         out_buf, out_buf_size);
116     default:
117         return ERROR_INVALID;
118     }
119 }
120 
send_response(handle_t chan,uint32_t cmd,uint8_t * out_buf,uint32_t out_buf_size)121 static gatekeeper_error_t send_response(handle_t chan,
122                                         uint32_t cmd,
123                                         uint8_t* out_buf,
124                                         uint32_t out_buf_size) {
125     struct gatekeeper_message gk_msg = {cmd | GK_RESP_BIT, {}};
126     struct iovec iov[2] = {
127             {&gk_msg, sizeof(gk_msg)},
128             {out_buf, out_buf_size},
129     };
130     ipc_msg_t msg = {2, iov, 0, NULL};
131 
132     /* send message back to the caller */
133     long rc = send_msg(chan, &msg);
134 
135     // fatal error
136     if (rc < 0) {
137         TLOGE("failed (%ld) to send_msg for chan (%d)\n", rc, chan);
138         return tipc_err_to_gatekeeper_err(rc);
139     }
140 
141     return ERROR_NONE;
142 }
143 
send_error_response(handle_t chan,uint32_t cmd,gatekeeper_error_t err)144 static gatekeeper_error_t send_error_response(handle_t chan,
145                                               uint32_t cmd,
146                                               gatekeeper_error_t err) {
147     GateKeeperMessage msg(err);
148     size_t serialized_size = msg.GetSerializedSize();
149     uint8_t* out_buf = new uint8_t[serialized_size];
150     if (out_buf == NULL) {
151         return ERROR_UNKNOWN;
152     }
153 
154     msg.Serialize(out_buf, out_buf + serialized_size);
155     gatekeeper_error_t rc = send_response(chan, cmd, out_buf, serialized_size);
156 
157     delete[] out_buf;
158     return rc;
159 }
160 
handle_msg(handle_t chan)161 static gatekeeper_error_t handle_msg(handle_t chan) {
162     /* get message info */
163     ipc_msg_info_t msg_inf;
164 
165     long rc = get_msg(chan, &msg_inf);
166     if (rc == ERR_NO_MSG)
167         return ERROR_NONE; /* no new messages */
168 
169     // fatal error
170     if (rc != NO_ERROR) {
171         TLOGE("failed (%ld) to get_msg for chan (%d), closing connection\n", rc,
172               chan);
173         return tipc_err_to_gatekeeper_err(rc);
174     }
175 
176     /* TODO: handle heap allocation failure
177      * and retire the message on failure too
178      */
179     UniquePtr<uint8_t[]> msg_buf(new uint8_t[msg_inf.len]);
180 
181     /* read msg content */
182     struct iovec iov = {msg_buf.get(), msg_inf.len};
183     ipc_msg_t msg = {1, &iov, 0, NULL};
184 
185     rc = read_msg(chan, msg_inf.id, 0, &msg);
186 
187     // retire the message (note msg_inf.id becomes invalid after put_msg)
188     put_msg(chan, msg_inf.id);
189 
190     if (rc < 0) {
191         TLOGE("failed to read msg (%ld) for chan (%d)\n", rc, chan);
192         return tipc_err_to_gatekeeper_err(rc);
193     }
194 
195     if (((size_t)rc) < sizeof(gatekeeper_message)) {
196         TLOGE("invalid message of size (%zu) for chan (%d)\n", (size_t)rc,
197               chan);
198         return ERROR_INVALID;
199     }
200 
201     /* get request command */
202     gatekeeper_message* gk_msg =
203             reinterpret_cast<struct gatekeeper_message*>(msg_buf.get());
204 
205     UniquePtr<uint8_t[]> out_buf;
206     uint32_t out_buf_size = 0;
207     gatekeeper_error_t err = handle_request(
208             gk_msg->cmd, gk_msg->payload,
209             msg_inf.len - sizeof(gatekeeper_message), &out_buf, &out_buf_size);
210 
211     if (err != ERROR_NONE) {
212         TLOGE("unable (%ld) to handle request\n", rc);
213         return send_error_response(chan, gk_msg->cmd, err);
214     }
215 
216     err = send_response(chan, gk_msg->cmd, out_buf.get(), out_buf_size);
217 
218     if (err != ERROR_NONE) {
219         TLOGE("unable (%ld) to send response\n", rc);
220     }
221 
222     return err;
223 }
224 
gatekeeper_handle_port(uevent_t * ev)225 static void gatekeeper_handle_port(uevent_t* ev) {
226     if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
227         (ev->event & IPC_HANDLE_POLL_HUP) ||
228         (ev->event & IPC_HANDLE_POLL_MSG) ||
229         (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
230         /* should never happen with port handles */
231         TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle);
232         abort();
233     }
234 
235     uuid_t peer_uuid;
236     if (ev->event & IPC_HANDLE_POLL_READY) {
237         /* incoming connection: accept it */
238         int rc = accept(ev->handle, &peer_uuid);
239         if (rc < 0) {
240             TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
241             return;
242         }
243     }
244 }
245 
gatekeeper_handle_channel(uevent_t * ev)246 static void gatekeeper_handle_channel(uevent_t* ev) {
247     if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
248         (ev->event & IPC_HANDLE_POLL_READY)) {
249         /* close it as it is in an error state */
250         TLOGE("error event (0x%x) for chan (%d)\n", ev->event, ev->handle);
251         abort();
252     }
253 
254     handle_t chan = ev->handle;
255 
256     if (ev->event & IPC_HANDLE_POLL_MSG) {
257         gatekeeper_error_t rc = handle_msg(chan);
258         if (rc != ERROR_NONE) {
259             /* report an error and close channel */
260             TLOGE("failed (%u) to handle event on channel %d\n", rc,
261                   ev->handle);
262             close(chan);
263         }
264     }
265 
266     if (ev->event & IPC_HANDLE_POLL_HUP) {
267         /* closed by peer. */
268         close(chan);
269         return;
270     }
271 }
272 
gatekeeper_ipc_init(void)273 static long gatekeeper_ipc_init(void) {
274     int rc;
275 
276     /* Initialize service */
277     rc = port_create(GATEKEEPER_PORT, 1, GATEKEEPER_MAX_BUFFER_LENGTH,
278                      IPC_PORT_ALLOW_NS_CONNECT);
279     if (rc < 0) {
280         TLOGE("Failed (%d) to create port %s\n", rc, GATEKEEPER_PORT);
281     }
282 
283     return rc;
284 }
285 
main(void)286 int main(void) {
287     long rc;
288     uevent_t event;
289 
290     TLOGD("Initializing\n");
291 
292     device = new TrustyGateKeeper();
293 
294     rc = gatekeeper_ipc_init();
295     if (rc < 0) {
296         TLOGE("failed (%ld) to initialize gatekeeper", rc);
297         return rc;
298     }
299 
300     handle_t port = (handle_t)rc;
301 
302     /* enter main event loop */
303     while (true) {
304         event.handle = INVALID_IPC_HANDLE;
305         event.event = 0;
306         event.cookie = NULL;
307 
308         rc = wait_any(&event, INFINITE_TIME);
309         if (rc < 0) {
310             TLOGE("wait_any failed (%ld)\n", rc);
311             break;
312         }
313 
314         if (rc == NO_ERROR) { /* got an event */
315             if (event.handle == port) {
316                 gatekeeper_handle_port(&event);
317             } else {
318                 gatekeeper_handle_channel(&event);
319             }
320         }
321     }
322 
323     return 0;
324 }
325