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