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