1 /*
2 * Copyright (C) 2023 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 #define TLOG_TAG "coverage-client-srv"
18
19 #include "coverage.h"
20
21 #include <interface/line-coverage/client.h>
22 #include <lib/coverage/common/ipc.h>
23 #include <lib/coverage/common/cov_shm.h>
24 #include <lib/tipc/tipc_srv.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <trusty_log.h>
29 #include <uapi/err.h>
30 #include <lk/list.h>
31
32 struct chan_ctx {
33 struct coverage_record* record;
34 struct list_node* last_sent_node;
35 };
36
signal_event(struct cov_shm * mailbox,size_t ta_idx,int event)37 static void signal_event(struct cov_shm* mailbox, size_t ta_idx, int event) {
38 int* app_mailbox = (int*)(mailbox->base) + ta_idx;
39 WRITE_ONCE(*app_mailbox, event);
40 }
41
handle_send_list(handle_t chan,struct line_coverage_client_req * req,struct list_node * coverage_record_list,struct chan_ctx * ctx)42 static int handle_send_list(handle_t chan,
43 struct line_coverage_client_req* req,
44 struct list_node* coverage_record_list,
45 struct chan_ctx* ctx) {
46 int rc;
47 uevent_t evt;
48 handle_t memref;
49 struct line_coverage_client_resp resp;
50 struct coverage_record* cur_record;
51 memset(&resp, 0, sizeof(struct line_coverage_client_resp));
52 struct uuid zero_uuid = {0, 0, 0, { 0 }};
53 struct list_node* cur_node = list_next(coverage_record_list, ctx->last_sent_node);
54
55 while(cur_node != NULL) {
56 resp.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
57 cur_record = containerof(cur_node, struct coverage_record, node);
58 resp.send_list_args.uuid = cur_record->uuid;
59
60 rc = coverage_send(chan, &resp, sizeof(resp), NULL);
61 if (rc != NO_ERROR) {
62 TLOGE("failed (%d) to send to list elements\n", rc);
63 return rc;
64 }
65
66 rc = wait(chan, &evt, INFINITE_TIME);
67 rc = coverage_recv(chan, &req, sizeof(req), &memref);
68 if (rc != NO_ERROR) {
69 TLOGE("failed (%d) to receive response\n", rc);
70 return rc;
71 }
72 ctx->last_sent_node = cur_node;
73 cur_node = list_next(coverage_record_list, cur_node);
74 }
75
76 resp.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
77 resp.send_list_args.uuid = zero_uuid;
78 rc = coverage_send(chan, &resp, sizeof(resp), NULL);
79 if (rc != NO_ERROR) {
80 TLOGE("failed (%d) to send end of list\n", rc);
81 return rc;
82 }
83 return NO_ERROR;
84 }
85
handle_open(handle_t chan,struct line_coverage_client_req * req,struct list_node * coverage_record_list,struct chan_ctx * ctx)86 static int handle_open(handle_t chan,
87 struct line_coverage_client_req* req,
88 struct list_node* coverage_record_list,
89 struct chan_ctx* ctx) {
90 int rc;
91 struct line_coverage_client_resp resp;
92 struct coverage_record* record;
93 char uuid_str[UUID_STR_SIZE];
94
95 uuid_to_str(&req->open_args.uuid, uuid_str);
96
97 record = find_coverage_record(coverage_record_list, &req->open_args.uuid);
98 if (!record) {
99 TLOGE("coverage record not found for uuid: %s\n", uuid_str);
100 return ERR_NOT_FOUND;
101 }
102
103 memset(&resp, 0, sizeof(struct line_coverage_client_resp));
104 resp.hdr.cmd = req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
105 resp.open_args.record_len = record->record_len;
106 rc = coverage_send(chan, &resp, sizeof(resp), NULL);
107 if (rc != NO_ERROR) {
108 TLOGE("failed (%d) to reply to open request\n", rc);
109 return rc;
110 }
111
112 ctx->record = record;
113 return NO_ERROR;
114 }
115
handle_share_record(handle_t chan,struct line_coverage_client_req * req,struct coverage_record * record,handle_t memref,struct cov_shm * mailbox)116 static int handle_share_record(handle_t chan,
117 struct line_coverage_client_req* req,
118 struct coverage_record* record,
119 handle_t memref,
120 struct cov_shm* mailbox) {
121 int rc;
122 struct line_coverage_client_resp resp;
123
124 if (memref == INVALID_IPC_HANDLE) {
125 TLOGE("invalid memref");
126 return ERR_BAD_LEN;
127 }
128 memset(&resp, 0, sizeof(struct line_coverage_client_resp));
129 resp.hdr.cmd = req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT;
130 rc = coverage_send(chan, &resp, sizeof(resp), NULL);
131 if (rc != NO_ERROR) {
132 TLOGE("failed (%d) to reply to share record request\n", rc);
133 return rc;
134 }
135
136 cov_shm_init(&record->data, memref, NULL, req->share_record_args.shm_len);
137
138 signal_event(mailbox, record->ta_idx, COVERAGE_MAILBOX_RECORD_READY);
139
140 return NO_ERROR;
141 }
142
on_connect(const struct tipc_port * port,handle_t chan,const struct uuid * peer,void ** ctx_p)143 static int on_connect(const struct tipc_port* port,
144 handle_t chan,
145 const struct uuid* peer,
146 void** ctx_p) {
147 struct chan_ctx* ctx = calloc(1, sizeof(*ctx));
148 if (!ctx) {
149 TLOGE("failed to allocate channel context\n");
150 return ERR_NO_MEMORY;
151 }
152
153 struct srv_state* state = get_srv_state(port);
154 ctx->record = NULL;
155 ctx->last_sent_node = &state->coverage_record_list;
156 *ctx_p = ctx;
157 return NO_ERROR;
158 }
159
on_message(const struct tipc_port * port,handle_t chan,void * _ctx)160 static int on_message(const struct tipc_port* port, handle_t chan, void* _ctx) {
161 int rc;
162 handle_t memref;
163 struct line_coverage_client_req req;
164 struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
165 struct srv_state* state = get_srv_state(port);
166
167 rc = coverage_recv(chan, &req, sizeof(req), &memref);
168 if (rc != NO_ERROR) {
169 TLOGE("failed (%d) to receive coverage client request\n", rc);
170 return rc;
171 }
172
173 switch (req.hdr.cmd) {
174 case LINE_COVERAGE_CLIENT_CMD_SEND_LIST:
175 return handle_send_list(chan, &req, &state->coverage_record_list, ctx);
176
177 case LINE_COVERAGE_CLIENT_CMD_OPEN:
178 return handle_open(chan, &req, &state->coverage_record_list, ctx);
179
180 case LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD:
181 return handle_share_record(chan, &req, ctx->record, memref,
182 &state->mailbox);
183
184 default:
185 TLOGE("command 0x%x: unknown command\n", req.hdr.cmd);
186 return ERR_CMD_UNKNOWN;
187 }
188 }
189
on_channel_cleanup(void * _ctx)190 static void on_channel_cleanup(void* _ctx) {
191 struct chan_ctx* ctx = (struct chan_ctx*)_ctx;
192 free(ctx);
193 }
194
coverage_client_init(struct srv_state * state)195 int coverage_client_init(struct srv_state* state) {
196 static struct tipc_port_acl port_acl = {
197 .flags = IPC_PORT_ALLOW_TA_CONNECT | IPC_PORT_ALLOW_NS_CONNECT,
198 };
199 static struct tipc_port port = {
200 .name = LINE_COVERAGE_CLIENT_PORT,
201 .msg_max_size = MAX(sizeof(struct line_coverage_client_req),
202 sizeof(struct line_coverage_client_resp)),
203 .msg_queue_len = 1,
204 .acl = &port_acl,
205 };
206 static struct tipc_srv_ops ops = {
207 .on_connect = on_connect,
208 .on_message = on_message,
209 .on_channel_cleanup = on_channel_cleanup,
210 };
211 set_srv_state(&port, state);
212
213 return tipc_add_service(state->hset, &port, 1, 1, &ops);
214 }
215