1 /*
2 * Copyright (C) 2019 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 <lib/coverage/common/cov_shm.h>
18 #include <interface/line-coverage/aggregator.h>
19 #include <lib/line-coverage/shm.h>
20 #include <lib/coverage/common/ipc.h>
21 #include <assert.h>
22 #include <lk/err_ptr.h>
23 #include <lk/list.h>
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <uapi/err.h>
29 #include <uapi/mm.h>
30
31 #define TLOG_TAG "tipc-srv"
32 #include <lib/tipc/tipc_srv.h>
33 #include <trusty_log.h>
34
35 #include "tipc_priv.h"
36
37 static void port_event_handler_proc(const struct uevent* ev, void* port_ctx);
38 static void chan_event_handler_proc(const struct uevent* ev, void* chan_ctx);
39
40 struct port_ctx {
41 struct tipc_event_handler event_handler;
42 const struct tipc_port* cfg;
43 struct tipc_srv* srv;
44 handle_t handle;
45 };
46
47 struct chan_ctx {
48 struct list_node chan_list_node;
49 struct tipc_event_handler event_handler;
50 struct port_ctx* port;
51 handle_t handle;
52 void* user_ctx;
53 };
54
55 struct tipc_srv {
56 struct list_node chan_list;
57 const struct tipc_srv_ops* ops;
58 struct tipc_hset* hset;
59 uint32_t chan_cnt;
60 uint32_t max_chan_cnt;
61 uint32_t port_cnt;
62 struct port_ctx ports[0];
63 };
64
65 /*
66 * Helper to mask/unmask events for all ports
67 */
set_ports_event_mask(struct tipc_srv * srv,uint32_t mask)68 static void set_ports_event_mask(struct tipc_srv* srv, uint32_t mask) {
69 uint32_t i;
70 struct port_ctx* p;
71
72 /* unmask ports here */
73 for (i = 0, p = srv->ports; i < srv->port_cnt; i++, p++) {
74 (void)tipc_hset_mod_entry(srv->hset, p->handle, mask,
75 &p->event_handler);
76 }
77 }
78
server_at_max_chan_cnt(struct tipc_srv * srv)79 static bool server_at_max_chan_cnt(struct tipc_srv* srv) {
80 return (srv->max_chan_cnt && (srv->chan_cnt == srv->max_chan_cnt));
81 }
82
83 /*
84 * Helper to close channel
85 */
tipc_chan_close(struct chan_ctx * chan)86 static void tipc_chan_close(struct chan_ctx* chan) {
87 int rc;
88 struct tipc_srv* srv = chan->port->srv;
89 void* user_ctx = chan->user_ctx;
90
91 /* remove it from handle set */
92 rc = tipc_hset_remove_entry(srv->hset, chan->handle);
93 if (rc != NO_ERROR) {
94 /* the only reason for this to fail if any handle is somehow
95 * becomes invalid. There is no reasonable way to recover
96 * from this.
97 */
98 TLOGE("hset_remove_entry failed (%d)\n", rc);
99 abort();
100 }
101
102 /* remove it from list */
103 list_delete(&chan->chan_list_node);
104
105 /*
106 * if we had a maximum number of channels we will now be below maximum.
107 * Unmask ports for this service so we can create channels.
108 */
109 if (server_at_max_chan_cnt(srv)) {
110 set_ports_event_mask(srv, ~0u);
111 }
112
113 /* decrement channel count */
114 srv->chan_cnt--;
115
116 /* close channel */
117 close(chan->handle);
118
119 /* free memory */
120 free(chan);
121
122 /* cleanup user allocated state if any */
123 if (srv->ops->on_channel_cleanup && user_ctx) {
124 srv->ops->on_channel_cleanup(user_ctx);
125 }
126 }
127
128 /*
129 * channel event handler
130 */
chan_event_handler_proc(const struct uevent * ev,void * chan_ctx)131 static void chan_event_handler_proc(const struct uevent* ev, void* chan_ctx) {
132 int rc;
133 struct chan_ctx* chan = chan_ctx;
134 struct tipc_srv* srv = chan->port->srv;
135
136 assert(ev->handle == chan->handle);
137
138 tipc_handle_chan_errors(ev);
139
140 setup_shm();
141
142 if (ev->event & IPC_HANDLE_POLL_MSG) {
143 rc = srv->ops->on_message(chan->port->cfg, chan->handle,
144 chan->user_ctx);
145 if (rc < 0) {
146 /* report an error and close channel */
147 TLOGE("failed (%d) to handle event on channel %d\n", rc,
148 ev->handle);
149 tipc_chan_close(chan);
150 dump_shm();
151 return;
152 }
153 }
154
155 if (ev->event & IPC_HANDLE_POLL_HUP) {
156 /* closed by peer. */
157 TLOGD("close connection\n");
158 dump_shm();
159 if (srv->ops->on_disconnect) {
160 srv->ops->on_disconnect(chan->port->cfg, chan->handle,
161 chan->user_ctx);
162 }
163
164 tipc_chan_close(chan);
165 return;
166 }
167
168 if (ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED) {
169 if (srv->ops->on_send_unblocked) {
170 rc = srv->ops->on_send_unblocked(chan->port->cfg, chan->handle,
171 chan->user_ctx);
172 if (rc < 0) {
173 /* report an error and close channel */
174 TLOGE("failed (%d) to handle event on channel %d\n", rc,
175 ev->handle);
176 tipc_chan_close(chan);
177 return;
178 }
179 } else {
180 TLOGE("send-unblocking not handled for channel %d\n", ev->handle);
181 tipc_chan_close(chan);
182 return;
183 }
184 }
185 }
186
187 /*
188 * Check if client is allowed to connect on specified port
189 */
client_is_allowed(const struct tipc_port_acl * acl,const struct uuid * peer)190 static bool client_is_allowed(const struct tipc_port_acl* acl,
191 const struct uuid* peer) {
192 uint32_t i;
193
194 if (!acl->uuid_num)
195 return true;
196
197 for (i = 0; i < acl->uuid_num; i++) {
198 if (memcmp(peer, acl->uuids[i], sizeof(*peer)) == 0) {
199 /* match */
200 return true;
201 }
202 }
203
204 return false;
205 }
206
207 /*
208 * Handle incoming connection
209 */
handle_connect(struct port_ctx * port)210 static void handle_connect(struct port_ctx* port) {
211 int rc;
212 handle_t hchan;
213 struct uuid peer;
214 void* user_ctx = NULL;
215 struct chan_ctx* chan;
216 struct tipc_srv* srv = port->srv;
217
218 TLOGD("Incoming connection on %s\n", port->cfg->name);
219
220 /* incoming connection: accept it */
221 rc = accept(port->handle, &peer);
222 if (rc < 0) {
223 TLOGE("failed (%d) to accept on port %s\n", rc, port->cfg->name);
224 return;
225 }
226 hchan = (handle_t)rc;
227
228 if (server_at_max_chan_cnt(srv)) {
229 /* we should not ever get here after we implement port mask */
230 TLOGE("too many channels for port %s\n", port->cfg->name);
231 goto err_too_many_chan;
232 }
233
234 /* do access control */
235 if (!client_is_allowed(port->cfg->acl, &peer)) {
236 TLOGE("access denied on port %s\n", port->cfg->name);
237 goto err_access;
238 }
239
240 chan = calloc(1, sizeof(*chan));
241 if (!chan) {
242 TLOGE("oom while handling port %s\n", port->cfg->name);
243 goto err_oom;
244 }
245
246 /* fill channel structure */
247 chan->event_handler.proc = chan_event_handler_proc;
248 chan->event_handler.priv = chan;
249 chan->port = port;
250 chan->handle = hchan;
251
252 /* add new channel to handle set */
253 rc = tipc_hset_add_entry(srv->hset, hchan, ~0u, &chan->event_handler);
254 if (rc != NO_ERROR) {
255 TLOGE("failed (%d) to add chan to hset\n", rc);
256 goto err_hset_add;
257 }
258
259 /* invoke on_connect handler if any */
260 if (srv->ops->on_connect) {
261 rc = srv->ops->on_connect(port->cfg, chan->handle, &peer, &user_ctx);
262 if (rc < 0) {
263 TLOGE("on_connect failed (%d) on port %s\n", rc, port->cfg->name);
264 goto err_on_connect;
265 }
266 }
267
268 /* attach context provided by caller */
269 chan->user_ctx = user_ctx;
270
271 /* add it to the list */
272 list_add_tail(&srv->chan_list, &chan->chan_list_node);
273 srv->chan_cnt++;
274
275 /* mask all ports if max number of connections has been reached */
276 if (server_at_max_chan_cnt(srv)) {
277 set_ports_event_mask(srv, 0u);
278 }
279
280 TLOGD("got connection on %s\n", port->cfg->name);
281 return;
282
283 err_on_connect:
284 err_hset_add:
285 free(chan);
286 err_oom:
287 err_too_many_chan:
288 err_access:
289 close(hchan);
290 }
291
292 /*
293 * Port event handler
294 */
port_event_handler_proc(const struct uevent * ev,void * ctx)295 static void port_event_handler_proc(const struct uevent* ev, void* ctx) {
296 tipc_handle_port_errors(ev);
297
298 if (ev->event & IPC_HANDLE_POLL_READY) {
299 struct port_ctx* port = ctx;
300 assert(port->handle == ev->handle);
301 handle_connect(port);
302 }
303 }
304
305 /*
306 * Add new TIPC service to handle set
307 */
tipc_add_service(struct tipc_hset * hset,const struct tipc_port * ports,uint32_t num_ports,uint32_t max_chan_cnt,const struct tipc_srv_ops * ops)308 int tipc_add_service(struct tipc_hset* hset,
309 const struct tipc_port* ports,
310 uint32_t num_ports,
311 uint32_t max_chan_cnt,
312 const struct tipc_srv_ops* ops) {
313 int rc;
314 uint32_t i;
315 struct tipc_srv* srv;
316 struct port_ctx* port;
317
318 if (IS_ERR(hset)) {
319 TLOGE("invalid handle set (%d)\n", PTR_ERR(hset));
320 return ERR_INVALID_ARGS;
321 }
322
323 if (!hset || !ports || !num_ports || !ops) {
324 TLOGE("required parameter is missing\n");
325 return ERR_INVALID_ARGS;
326 }
327
328 /* allocate new service */
329 srv = calloc(1,
330 sizeof(struct tipc_srv) + sizeof(struct port_ctx) * num_ports);
331 if (!srv) {
332 return ERR_NO_MEMORY;
333 }
334
335 /* and initialize it */
336 srv->hset = hset;
337 srv->port_cnt = num_ports;
338 srv->max_chan_cnt = max_chan_cnt;
339
340 list_initialize(&srv->chan_list);
341
342 srv->ops = ops;
343 for (i = 0; i < num_ports; i++) {
344 srv->ports[i].handle = INVALID_IPC_HANDLE;
345 }
346
347 /* for each port */
348 for (i = 0; i < num_ports; i++) {
349 TLOGD("Initialize port: %s\n", ports[i].name);
350
351 port = &srv->ports[i];
352
353 if (!ports[i].acl) {
354 TLOGE("ACL is required to create port\n");
355 rc = ERR_INVALID_ARGS;
356 goto err_no_acl;
357 }
358
359 /* create port */
360 rc = port_create(ports[i].name, ports[i].msg_queue_len,
361 ports[i].msg_max_size, ports[i].acl->flags);
362 if (rc < 0) {
363 TLOGE("failed (%d) to create port\n", rc);
364 goto err_port_create;
365 }
366 port->handle = (handle_t)rc;
367
368 /* init event handler and other pointers */
369 port->cfg = &ports[i];
370 port->event_handler.proc = port_event_handler_proc;
371 port->event_handler.priv = port;
372 port->srv = srv;
373
374 /* and add it to the handle set */
375 rc = tipc_hset_add_entry(hset, port->handle, ~0u, &port->event_handler);
376 if (rc < 0) {
377 TLOGE("failed (%d) to register port\n", rc);
378 goto err_hset_add;
379 }
380 }
381 setup_mailbox(ports, num_ports);
382 return 0;
383
384 err_hset_add:
385 err_port_create:
386 err_no_acl:
387 /* kill all ports we have created so far */
388 for (i = 0; i < num_ports; i++) {
389 if (srv->ports[i].handle != INVALID_IPC_HANDLE) {
390 /* Note: closing handle also removes it from all handle sets */
391 rc = close(srv->ports[i].handle);
392 assert(rc == 0);
393 }
394 }
395 /* then free service */
396 free(srv);
397
398 return rc;
399 }
400