• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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