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 <assert.h>
18 #include <stdlib.h>
19 
20 #include <lib/tipc/tipc.h>
21 #include <lk/list.h>
22 #include <trusty_ipc.h>
23 #include <trusty_log.h>
24 #include <uapi/err.h>
25 
26 #include "ipc.h"
27 
28 #define MSG_BUF_MAX_SIZE 4096
29 
30 #define TLOG_TAG "ss-ipc"
31 
32 /* Start logging response waits after this many milliseconds. */
33 #define RESPONSE_TIMEOUT 1000
34 
35 /*
36  * Don't wait more than this many ms between logging statements (currently
37  * 1000s)
38  */
39 #define RESPONSE_TIMEOUT_MAX (RESPONSE_TIMEOUT * 1000 * 1000)
40 
41 static void* msg_buf;
42 static size_t msg_buf_size;
43 
44 static void handle_channel(const uevent_t* ev, void* self);
45 static void handle_port(const uevent_t* ev, void* self);
46 
maybe_grow_msg_buf(size_t new_max_size)47 static int maybe_grow_msg_buf(size_t new_max_size) {
48     if (new_max_size > msg_buf_size) {
49         uint8_t* tmp = realloc(msg_buf, new_max_size);
50         if (tmp == NULL) {
51             return ERR_NO_MEMORY;
52         }
53         msg_buf = tmp;
54         msg_buf_size = new_max_size;
55     }
56     return NO_ERROR;
57 }
58 
handle_port_errors(const uevent_t * ev)59 static inline void handle_port_errors(const uevent_t* ev) {
60     if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
61         (ev->event & IPC_HANDLE_POLL_HUP) ||
62         (ev->event & IPC_HANDLE_POLL_MSG) ||
63         (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) {
64         /* should never happen with port handles */
65         TLOGE("error event (0x%x) for port (%d)\n", ev->event, ev->handle);
66         abort();
67     }
68 }
69 
handle_chan_errors(const uevent_t * ev)70 static inline void handle_chan_errors(const uevent_t* ev) {
71     if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
72         (ev->event & IPC_HANDLE_POLL_READY)) {
73         TLOGE("error event (0x%x) for chan (%d)\n", ev->event, ev->handle);
74         abort();
75     }
76 }
77 
is_valid_port_ops(struct ipc_port_ops * ops)78 static int is_valid_port_ops(struct ipc_port_ops* ops) {
79     return (ops->on_connect != NULL);
80 }
81 
is_valid_chan_ops(struct ipc_channel_ops * ops)82 static bool is_valid_chan_ops(struct ipc_channel_ops* ops) {
83     return (ops->on_disconnect != NULL);
84 }
85 
do_connect(struct ipc_port_context * ctx,const uevent_t * ev)86 static int do_connect(struct ipc_port_context* ctx, const uevent_t* ev) {
87     int rc;
88     handle_t chan_handle;
89     struct ipc_channel_context* chan_ctx;
90 
91     struct tipc_hset* hset = ctx->common.hset;
92 
93     if (ev->event & IPC_HANDLE_POLL_READY) {
94         /* incoming connection: accept it */
95         uuid_t peer_uuid;
96         rc = accept(ev->handle, &peer_uuid);
97         if (rc < 0) {
98             TLOGE("failed (%d) to accept on port %d\n", rc, ev->handle);
99             return rc;
100         }
101 
102         chan_handle = (handle_t)rc;
103         chan_ctx = ctx->ops.on_connect(ctx, &peer_uuid, chan_handle);
104         if (chan_ctx == NULL) {
105             TLOGE("%s: failure initializing channel state (%d)\n", __func__,
106                   rc);
107             rc = ERR_GENERIC;
108             goto err_on_connect;
109         }
110 
111         assert(is_valid_chan_ops(&chan_ctx->ops));
112 
113         chan_ctx->common = (struct ipc_context){
114                 .evt_handler = {.proc = handle_channel, .priv = chan_ctx},
115                 .hset = hset,
116                 .handle = chan_handle,
117         };
118         rc = tipc_hset_add_entry(hset, chan_handle, ~0u,
119                                  &chan_ctx->common.evt_handler);
120         if (rc < 0) {
121             TLOGE("failed (%d) to set_cookie on chan %d\n", rc, chan_handle);
122             goto err_add_entry;
123         }
124         list_add_tail(&ctx->channels, &chan_ctx->node);
125     }
126 
127     return NO_ERROR;
128 
129 err_add_entry:
130     chan_ctx->ops.on_disconnect(chan_ctx);
131 err_on_connect:
132     close(chan_handle);
133     return rc;
134 }
135 
do_handle_msg(struct ipc_channel_context * ctx,const uevent_t * ev)136 static int do_handle_msg(struct ipc_channel_context* ctx, const uevent_t* ev) {
137     handle_t chan = ev->handle;
138 
139     /* get message info */
140     ipc_msg_info_t msg_inf;
141     int rc = get_msg(chan, &msg_inf);
142     if (rc == ERR_NO_MSG)
143         return NO_ERROR; /* no new messages */
144 
145     if (rc != NO_ERROR) {
146         TLOGE("failed (%d) to get_msg for chan (%d), closing connection\n", rc,
147               chan);
148         return rc;
149     }
150 
151     if (msg_inf.len > MSG_BUF_MAX_SIZE) {
152         TLOGE("%s: message too large %zu\n", __func__, msg_inf.len);
153         put_msg(chan, msg_inf.id);
154         return ERR_NOT_ENOUGH_BUFFER;
155     }
156 
157     /* read msg content */
158     struct iovec iov = {
159             .iov_base = msg_buf,
160             .iov_len = msg_inf.len,
161     };
162     ipc_msg_t msg = {
163             .iov = &iov,
164             .num_iov = 1,
165     };
166 
167     rc = read_msg(chan, msg_inf.id, 0, &msg);
168     put_msg(chan, msg_inf.id);
169     if (rc < 0) {
170         TLOGE("failed to read msg (%d, %d)\n", rc, chan);
171         return rc;
172     }
173 
174     if (((size_t)rc) < msg_inf.len) {
175         TLOGE("invalid message of size (%d, %d)\n", rc, chan);
176         return ERR_NOT_VALID;
177     }
178 
179     rc = ctx->ops.on_handle_msg(ctx, msg_buf, msg_inf.len);
180 
181 err_handle_msg:
182 err_read_msg:
183     return rc;
184 }
185 
do_disconnect(struct ipc_channel_context * context,const uevent_t * ev)186 static void do_disconnect(struct ipc_channel_context* context,
187                           const uevent_t* ev) {
188     list_delete(&context->node);
189     tipc_hset_remove_entry(context->common.hset, ev->handle);
190     context->ops.on_disconnect(context);
191     close(ev->handle);
192 }
193 
handle_port(const struct uevent * ev,void * self)194 static void handle_port(const struct uevent* ev, void* self) {
195     struct ipc_port_context* port_ctx = self;
196     assert(is_valid_port_ops(&port_ctx->ops));
197 
198     handle_port_errors(ev);
199 
200     do_connect(port_ctx, ev);
201 }
202 
handle_channel(const struct uevent * ev,void * self)203 static void handle_channel(const struct uevent* ev, void* self) {
204     struct ipc_channel_context* channel_ctx = self;
205     assert(is_valid_chan_ops(&channel_ctx->ops));
206 
207     handle_chan_errors(ev);
208 
209     if (ev->event & IPC_HANDLE_POLL_MSG) {
210         if (channel_ctx->ops.on_handle_msg != NULL) {
211             int rc = do_handle_msg(channel_ctx, ev);
212             if (rc < 0) {
213                 TLOGE("error (%d) in channel, disconnecting "
214                       "peer\n",
215                       rc);
216                 do_disconnect(channel_ctx, ev);
217                 return;
218             }
219         } else {
220             TLOGE("error: unexpected message in channel (%d). closing...\n",
221                   ev->handle);
222             do_disconnect(channel_ctx, ev);
223             return;
224         }
225     }
226 
227     if (ev->event & IPC_HANDLE_POLL_HUP) {
228         do_disconnect(channel_ctx, ev);
229     }
230 }
231 
read_response(handle_t session,uint32_t msg_id,struct iovec * iovecs,size_t iovec_count)232 static int read_response(handle_t session,
233                          uint32_t msg_id,
234                          struct iovec* iovecs,
235                          size_t iovec_count) {
236     struct ipc_msg rx_msg = {
237             .iov = iovecs,
238             .num_iov = iovec_count,
239     };
240 
241     long rc = read_msg(session, msg_id, 0, &rx_msg);
242     put_msg(session, msg_id);
243     if (rc < 0) {
244         TLOGE("%s: failed to read msg (%ld)\n", __func__, rc);
245         return rc;
246     }
247 
248     size_t read_size = (size_t)rc;
249     return read_size;
250 }
251 
await_response(handle_t session,struct ipc_msg_info * inf)252 static int await_response(handle_t session, struct ipc_msg_info* inf) {
253     uevent_t uevt;
254     unsigned long wait_timeout = RESPONSE_TIMEOUT;
255     long rc;
256     while (true) {
257         rc = wait(session, &uevt, wait_timeout);
258         if (rc != ERR_TIMED_OUT) {
259             break;
260         }
261         TLOGE("%s: storage response wait timed out after %ldx ms\n", __func__,
262               wait_timeout);
263         wait_timeout *= 2;
264         if (wait_timeout > RESPONSE_TIMEOUT_MAX) {
265             wait_timeout = RESPONSE_TIMEOUT_MAX;
266         }
267     }
268     if (rc != NO_ERROR) {
269         TLOGE("%s: error while waiting for response (%ld)\n", __func__, rc);
270         return rc;
271     }
272 
273     rc = get_msg(session, inf);
274     if (rc != NO_ERROR) {
275         TLOGE("%s: failed to get_msg (%ld)\n", __func__, rc);
276     }
277 
278     return rc;
279 }
280 
wait_to_send(handle_t session,struct ipc_msg * msg)281 static int wait_to_send(handle_t session, struct ipc_msg* msg) {
282     int rc;
283     struct uevent ev = UEVENT_INITIAL_VALUE(ev);
284 
285     rc = wait(session, &ev, INFINITE_TIME);
286     if (rc < 0) {
287         TLOGE("failed to wait for outgoing queue to free up\n");
288         return rc;
289     }
290 
291     if (ev.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
292         return send_msg(session, msg);
293     }
294 
295     if (ev.event & IPC_HANDLE_POLL_MSG) {
296         return ERR_BUSY;
297     }
298 
299     if (ev.event & IPC_HANDLE_POLL_HUP) {
300         return ERR_CHANNEL_CLOSED;
301     }
302 
303     return rc;
304 }
305 
sync_ipc_send_msg(handle_t session,struct iovec * tx_iovecs,unsigned int tx_iovec_count,struct iovec * rx_iovecs,unsigned int rx_iovec_count)306 int sync_ipc_send_msg(handle_t session,
307                       struct iovec* tx_iovecs,
308                       unsigned int tx_iovec_count,
309                       struct iovec* rx_iovecs,
310                       unsigned int rx_iovec_count) {
311     struct ipc_msg tx_msg = {
312             .iov = tx_iovecs,
313             .num_iov = tx_iovec_count,
314     };
315 
316     long rc = send_msg(session, &tx_msg);
317     if (rc == ERR_NOT_ENOUGH_BUFFER) {
318         rc = wait_to_send(session, &tx_msg);
319     }
320 
321     if (rc < 0) {
322         TLOGE("%s: failed (%ld) to send_msg\n", __func__, rc);
323         return rc;
324     }
325 
326     if (rx_iovecs == NULL || rx_iovec_count == 0) {
327         assert(rx_iovec_count == 0);
328         assert(rx_iovecs == NULL);
329         return NO_ERROR;
330     }
331 
332     struct ipc_msg_info inf;
333     rc = await_response(session, &inf);
334     if (rc < 0) {
335         TLOGE("%s: failed (%ld) to await response\n", __func__, rc);
336         return rc;
337     }
338 
339     size_t min_len = rx_iovecs[0].iov_len;
340     if (inf.len < min_len) {
341         TLOGE("%s: invalid response length (%zu)\n", __func__, inf.len);
342         put_msg(session, inf.id);
343         return ERR_NOT_VALID;
344     }
345 
346     /* calculate total message size */
347     size_t resp_size = 0;
348     for (size_t i = 0; i < rx_iovec_count; ++i) {
349         resp_size += rx_iovecs[i].iov_len;
350     }
351 
352     if (resp_size < inf.len) {
353         TLOGE("%s: response buffer too short (%zu < %zu) \n", __func__,
354               resp_size, inf.len);
355         put_msg(session, inf.id);
356         return ERR_BAD_LEN;
357     }
358 
359     rc = read_response(session, inf.id, rx_iovecs, rx_iovec_count);
360     put_msg(session, inf.id);
361     if (rc < 0) {
362         TLOGE("%s: response has error (%ld)\n", __func__, rc);
363         return rc;
364     }
365 
366     size_t read_len = (size_t)rc;
367     if (read_len != inf.len) {
368         // data read in does not match message length
369         TLOGE("%s: invalid response length (%zu)\n", __func__, read_len);
370         return ERR_IO;
371     }
372 
373     return read_len;
374 }
375 
ipc_port_create(struct tipc_hset * hset,struct ipc_port_context * ctxp,const char * port_name,size_t queue_size,size_t max_buffer_size,uint32_t flags)376 int ipc_port_create(struct tipc_hset* hset,
377                     struct ipc_port_context* ctxp,
378                     const char* port_name,
379                     size_t queue_size,
380                     size_t max_buffer_size,
381                     uint32_t flags) {
382     int rc;
383     assert(ctxp);
384     assert(is_valid_port_ops(&ctxp->ops));
385 
386     rc = port_create(port_name, queue_size, max_buffer_size, flags);
387 
388     if (rc < 0) {
389         TLOGE("Failed to create port %s %d\n", port_name, rc);
390         return rc;
391     }
392 
393     handle_t port_handle = (handle_t)rc;
394     ctxp->common = (struct ipc_context){
395             .evt_handler = {.proc = handle_port, .priv = ctxp},
396             .hset = hset,
397             .handle = port_handle,
398     };
399     rc = tipc_hset_add_entry(hset, port_handle, ~0u, &ctxp->common.evt_handler);
400     if (rc < 0) {
401         TLOGE("Failed to add handle on port %s (%d)\n", port_name, rc);
402         goto err_add_entry;
403     }
404 
405     rc = maybe_grow_msg_buf(max_buffer_size);
406     if (rc < 0) {
407         TLOGE("Failed to create msg buffer of size %zu (%d)\n", max_buffer_size,
408               rc);
409         goto err_grow_msg;
410     }
411 
412     list_initialize(&ctxp->channels);
413     return NO_ERROR;
414 
415 err_add_entry:
416 err_grow_msg:
417     close(port_handle);
418     return rc;
419 }
420 
ipc_port_destroy(struct ipc_port_context * ctx)421 int ipc_port_destroy(struct ipc_port_context* ctx) {
422     tipc_hset_remove_entry(ctx->common.hset, ctx->common.handle);
423     close(ctx->common.handle);
424     while (!list_is_empty(&ctx->channels)) {
425         struct ipc_channel_context* chan_ctx = list_remove_head_type(
426                 &ctx->channels, struct ipc_channel_context, node);
427         assert(chan_ctx);
428         handle_t chan_handle = chan_ctx->common.handle;
429         TLOGE("client still connected, handle %d\n", chan_handle);
430         tipc_hset_remove_entry(chan_ctx->common.hset, chan_ctx->common.handle);
431         chan_ctx->ops.on_disconnect(chan_ctx);
432         close(chan_handle);
433     }
434     return NO_ERROR;
435 }
436