1 /*
2 * Copyright (c) 2020, Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23 #include <lib/ktipc/ktipc.h>
24
25 #include <assert.h>
26 #include <err.h>
27 #include <inttypes.h>
28 #include <kernel/thread.h>
29 #include <lib/trusty/handle_set.h>
30 #include <lib/trusty/ipc.h>
31 #include <lib/trusty/ipc_msg.h>
32 #include <lk/init.h>
33 #include <lk/list.h>
34 #include <string.h>
35 #include <trace.h>
36
37 #define LOCAL_TRACE 0
38
39 struct ksrv_event_handler {
40 void (*handler)(struct ktipc_server* ksrv,
41 struct ksrv_event_handler* evth,
42 uint32_t event);
43 };
44
45 struct ksrv_port {
46 struct handle_ref href;
47 struct ksrv_event_handler evth;
48 const struct ktipc_srv_ops* ops;
49 const struct ktipc_port* port;
50 };
51
52 struct ksrv_chan {
53 struct handle_ref href;
54 struct ksrv_event_handler evth;
55 const struct ktipc_srv_ops* ops;
56 const struct ktipc_port* port;
57 void* user_ctx;
58 };
59
60 /*
61 * Helper to close channel
62 */
ktipc_chan_close(struct ksrv_chan * kchan)63 static void ktipc_chan_close(struct ksrv_chan* kchan) {
64 void* user_ctx = kchan->user_ctx;
65 const struct ktipc_srv_ops* ops = kchan->ops;
66
67 /* detach handle_ref */
68 handle_set_detach_ref(&kchan->href);
69
70 /* close channel */
71 handle_decref(kchan->href.handle);
72
73 /* free memory */
74 free(kchan);
75
76 /* cleanup user allocated state if any */
77 if (user_ctx) {
78 ops->on_channel_cleanup(user_ctx);
79 }
80 }
81
chan_event_handler(struct ktipc_server * ksrv,struct ksrv_event_handler * evth,uint32_t event)82 static void chan_event_handler(struct ktipc_server* ksrv,
83 struct ksrv_event_handler* evth,
84 uint32_t event) {
85 int rc;
86
87 struct ksrv_chan* kchan = containerof(evth, struct ksrv_chan, evth);
88
89 if ((event & IPC_HANDLE_POLL_ERROR) || (event & IPC_HANDLE_POLL_READY)) {
90 /* should never happen for channel handles */
91 TRACEF("error event (0x%" PRIx32 ")\n", event);
92 ktipc_chan_close(kchan);
93 return;
94 }
95
96 if (event & IPC_HANDLE_POLL_MSG) {
97 LTRACEF("got message\n");
98
99 rc = kchan->ops->on_message(kchan->port, kchan->href.handle,
100 kchan->user_ctx);
101 if (rc < 0) {
102 /* report an error and close channel */
103 TRACEF("failed (%d) to handle event on channel %p\n", rc,
104 kchan->href.handle);
105 ktipc_chan_close(kchan);
106 return;
107 }
108 }
109
110 if (event & IPC_HANDLE_POLL_HUP) {
111 LTRACEF("connection closed by peer\n");
112
113 /* closed by peer. */
114 if (kchan->ops->on_disconnect) {
115 kchan->ops->on_disconnect(kchan->port, kchan->href.handle,
116 kchan->user_ctx);
117 }
118 ktipc_chan_close(kchan);
119 return;
120 }
121
122 if (event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
123 LTRACEF("unblocked for sending\n");
124
125 if (kchan->ops->on_send_unblocked) {
126 rc = kchan->ops->on_send_unblocked(kchan->port, kchan->href.handle,
127 kchan->user_ctx);
128 if (rc < 0) {
129 /* report an error and close channel */
130 TRACEF("failed (%d) to handle event on channel %p\n", rc,
131 kchan->href.handle);
132 ktipc_chan_close(kchan);
133 return;
134 }
135 } else {
136 LTRACEF("send-unblocking not handled for channel %p\n",
137 kchan->href.handle);
138 ktipc_chan_close(kchan);
139 return;
140 }
141 }
142 }
143
144 /*
145 * Check if client is allowed to connect on specified port
146 */
client_is_allowed(const struct ktipc_port_acl * acl,const struct uuid * peer)147 static bool client_is_allowed(const struct ktipc_port_acl* acl,
148 const struct uuid* peer) {
149 uint32_t i;
150
151 if (!acl->uuid_num)
152 return true;
153
154 for (i = 0; i < acl->uuid_num; i++) {
155 if (memcmp(peer, acl->uuids[i], sizeof(*peer)) == 0) {
156 /* match */
157 return true;
158 }
159 }
160
161 return false;
162 }
163
164 /*
165 * Handle incoming connection
166 */
handle_connect(struct ktipc_server * ksrv,struct ksrv_port * kport)167 static void handle_connect(struct ktipc_server* ksrv, struct ksrv_port* kport) {
168 int rc;
169 struct handle* hchan;
170 const struct uuid* peer;
171 void* user_ctx = NULL;
172 struct ksrv_chan* kchan;
173
174 /* incoming connection: accept it */
175 rc = ipc_port_accept(kport->href.handle, &hchan, &peer);
176 if (rc < 0) {
177 TRACEF("failed (%d) to accept on port %s\n", rc, kport->port->name);
178 return;
179 }
180
181 /* do access control */
182 if (!client_is_allowed(kport->port->acl, peer)) {
183 TRACEF("access denied on port %s\n", kport->port->name);
184 goto err_access;
185 }
186
187 kchan = calloc(1, sizeof(*kchan));
188 if (!kchan) {
189 TRACEF("oom handling connect on port %s\n", kport->port->name);
190 goto err_oom;
191 }
192
193 /* setup channel structure */
194 kchan->evth.handler = chan_event_handler;
195 kchan->port = kport->port;
196 kchan->ops = kport->ops;
197
198 /* add new channel to handle set */
199 kchan->href.emask = ~0U;
200 kchan->href.cookie = &kchan->evth;
201 kchan->href.handle = hchan;
202
203 rc = handle_set_attach(ksrv->hset, &kchan->href);
204 if (rc != NO_ERROR) {
205 TRACEF("failed (%d) to add chan to hset\n", rc);
206 goto err_hset_add;
207 }
208
209 /* invoke on_connect handler if any */
210 if (kport->ops->on_connect) {
211 rc = kport->ops->on_connect(kport->port, hchan, peer, &user_ctx);
212 if (rc < 0) {
213 TRACEF("on_connect failed (%d) on port %s\n", rc,
214 kport->port->name);
215 goto err_on_connect;
216 }
217 }
218
219 /* attach context provided by caller */
220 kchan->user_ctx = user_ctx;
221
222 return;
223
224 err_on_connect:
225 handle_set_detach_ref(&kchan->href);
226 err_hset_add:
227 free(kchan);
228 err_oom:
229 err_access:
230 handle_decref(hchan);
231 }
232
port_event_handler(struct ktipc_server * ksrv,struct ksrv_event_handler * evth,uint32_t event)233 static void port_event_handler(struct ktipc_server* ksrv,
234 struct ksrv_event_handler* evth,
235 uint32_t event) {
236 struct ksrv_port* kport = containerof(evth, struct ksrv_port, evth);
237
238 if ((event & IPC_HANDLE_POLL_ERROR) || (event & IPC_HANDLE_POLL_HUP) ||
239 (event & IPC_HANDLE_POLL_MSG) ||
240 (event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
241 /* should never happen with port handles */
242 LTRACEF("error event (0x%" PRIx32 ") for port\n", event);
243 return;
244 }
245
246 if (event & IPC_HANDLE_POLL_READY) {
247 handle_connect(ksrv, kport);
248 }
249 }
250
ktipc_server_add_port(struct ktipc_server * ksrv,const struct ktipc_port * port,const struct ktipc_srv_ops * ops)251 int ktipc_server_add_port(struct ktipc_server* ksrv,
252 const struct ktipc_port* port,
253 const struct ktipc_srv_ops* ops) {
254 int rc;
255 struct ksrv_port* kport;
256
257 if (!ksrv) {
258 rc = ERR_INVALID_ARGS;
259 goto err_null_ksrv;
260 }
261
262 /* validate ops structure */
263 if (!ops) {
264 TRACEF("ktipc_srv_ops structure is NULL\n");
265 rc = ERR_INVALID_ARGS;
266 goto err_null_ops;
267 }
268 if (!ops->on_message) {
269 TRACEF("on_message handler is NULL\n");
270 rc = ERR_INVALID_ARGS;
271 goto err_null_on_message;
272 }
273 /* on_channel_cleanup is required if on_connect is present */
274 if (ops->on_connect && !ops->on_channel_cleanup) {
275 TRACEF("on_connect handler without on_channel_cleanup\n");
276 rc = ERR_INVALID_ARGS;
277 goto err_null_on_channel_cleanup;
278 }
279
280 /* allocate port tracking structure */
281 kport = calloc(1, sizeof(*kport));
282 if (!kport) {
283 TRACEF("failed to allocate port\n");
284 rc = ERR_NO_MEMORY;
285 goto err_oom;
286 }
287
288 /* create port */
289 rc = ipc_port_create(port->uuid, port->name, port->msg_queue_len,
290 port->msg_max_size, port->acl->flags,
291 &kport->href.handle);
292 if (rc) {
293 TRACEF("failed (%d) to create port %s\n", rc, port->name);
294 goto err_port_create;
295 }
296
297 /* and publish it */
298 rc = ipc_port_publish(kport->href.handle);
299 if (rc) {
300 TRACEF("failed (%d) to publish port %s\n", rc, port->name);
301 goto err_port_publish;
302 }
303
304 /* configure port event handler */
305 kport->evth.handler = port_event_handler;
306 kport->port = port;
307 kport->ops = ops;
308
309 /* attach it to handle set */
310 kport->href.emask = ~0U;
311 kport->href.cookie = &kport->evth;
312
313 rc = handle_set_attach(ksrv->hset, &kport->href);
314 if (rc < 0) {
315 TRACEF("failed (%d) to attach handle for port %s\n", rc, port->name);
316 goto err_hset_add_port;
317 }
318
319 /* kick have handles event */
320 event_signal(&ksrv->have_handles_evt, false);
321
322 return 0;
323
324 err_hset_add_port:
325 err_port_publish:
326 handle_decref(kport->href.handle);
327 err_port_create:
328 free(kport);
329 err_oom:
330 err_null_on_channel_cleanup:
331 err_null_on_message:
332 err_null_ops:
333 err_null_ksrv:
334 return rc;
335 }
336
ksrv_event_loop(struct ktipc_server * ksrv)337 static void ksrv_event_loop(struct ktipc_server* ksrv) {
338 int rc;
339 struct handle_ref evt_ref;
340
341 while (true) {
342 /* wait here until we have handles */
343 event_wait(&ksrv->have_handles_evt);
344 while (true) {
345 rc = handle_set_wait(ksrv->hset, &evt_ref, INFINITE_TIME);
346 if (rc != NO_ERROR) {
347 panic("handle_set_wait failed: %d\n", rc);
348 }
349
350 /* get handler and invoke it */
351 struct ksrv_event_handler* evth = evt_ref.cookie;
352 DEBUG_ASSERT(evth && evth->handler);
353 evth->handler(ksrv, evth, evt_ref.emask);
354
355 /* decrement ref obtained by handle_set_wait */
356 handle_decref(evt_ref.handle);
357 }
358 }
359 }
360
ksrv_thread(void * args)361 static int ksrv_thread(void* args) {
362 struct ktipc_server* ksrv = args;
363
364 LTRACEF("starting ktipc service: %s\n", ksrv->name);
365
366 ksrv->hset = handle_set_create();
367 if (!ksrv->hset) {
368 TRACEF("failed to create handle set\n");
369 return ERR_NO_MEMORY;
370 }
371
372 /* enter event loop */
373 ksrv_event_loop(ksrv);
374 LTRACEF("event loop returned\n");
375
376 /* kill handle set */
377 handle_decref(ksrv->hset);
378 return 0;
379 }
380
ktipc_server_start(struct ktipc_server * ksrv)381 int ktipc_server_start(struct ktipc_server* ksrv) {
382 DEBUG_ASSERT(ksrv);
383 DEBUG_ASSERT(!ksrv->thread);
384
385 ksrv->thread = thread_create(ksrv->name, ksrv_thread, ksrv,
386 DEFAULT_PRIORITY, DEFAULT_STACK_SIZE);
387 if (!ksrv->thread) {
388 TRACEF("failed to create %s thread\n", ksrv->name);
389 return ERR_NO_MEMORY;
390 }
391 thread_resume(ksrv->thread);
392 return 0;
393 }
394
ktipc_recv_iov(struct handle * chan,size_t min_sz,struct iovec_kern * iov,uint32_t num_iov,struct handle ** handles,uint32_t num_handles)395 int ktipc_recv_iov(struct handle* chan,
396 size_t min_sz,
397 struct iovec_kern* iov,
398 uint32_t num_iov,
399 struct handle** handles,
400 uint32_t num_handles) {
401 int rc;
402 struct ipc_msg_info msg_inf;
403 size_t max_sz = 0;
404
405 rc = ipc_get_msg(chan, &msg_inf);
406 if (rc) {
407 return rc;
408 }
409
410 for (uint32_t i = 0; i < num_iov; i++) {
411 max_sz += iov[i].iov_len;
412 }
413
414 if (msg_inf.len < min_sz || msg_inf.len > max_sz) {
415 /* unexpected msg size: buffer too small or too big */
416 rc = ERR_BAD_LEN;
417 } else {
418 struct ipc_msg_kern msg = {
419 .iov = iov,
420 .num_iov = num_iov,
421 .handles = handles,
422 .num_handles = num_handles,
423 };
424 rc = ipc_read_msg(chan, msg_inf.id, 0, &msg);
425 }
426
427 ipc_put_msg(chan, msg_inf.id);
428 return rc;
429 }
430