blob: fa989002e8a185f8fff42d9c467b82e825439075 [file] [log] [blame]
Minos Galanakis2c824b42025-03-20 09:28:45 +00001/* PSA firmware framework client API */
2
3/*
4 * Copyright The Mbed TLS Contributors
5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6 */
7
8#include <stdint.h>
9#include <stdlib.h>
10#include <stddef.h>
11#include <assert.h>
12#include <stdio.h>
13#include <string.h>
14#include <strings.h>
15#include <inttypes.h>
16#include <sys/types.h>
17#include <sys/ipc.h>
18#include <sys/msg.h>
19#include <psa/error.h>
20
21#include "common.h"
22
23typedef struct internal_handle {
24 int server_qid;
25 int client_qid;
26 int internal_server_qid;
27 int valid;
28} internal_handle_t;
29
30/* Access to this global is not thread safe */
31#define MAX_HANDLES 32
32static internal_handle_t handles[MAX_HANDLES] = { { 0 } };
33
34static int get_next_free_handle()
35{
36 /* Never return handle 0 as it's a special null handle */
37 for (int i = 1; i < MAX_HANDLES; i++) {
38 if (handles[i].valid == 0) {
39 return i;
40 }
41 }
42 return -1;
43}
44
45static int handle_is_valid(psa_handle_t handle)
46{
47 if (handle > 0 && handle < MAX_HANDLES) {
48 if (handles[handle].valid == 1) {
49 return 1;
50 }
51 }
52 PROGRAMMER_ERROR("ERROR: Invalid handle");
53 return 0;
54}
55
56static int get_queue_info(char *path, int *cqid, int *sqid)
57{
58
59 key_t server_queue_key;
60 int rx_qid, server_qid;
61
62 INFO("Attempting to contact a RoT service queue");
63
64 if ((rx_qid = msgget(IPC_PRIVATE, 0660)) == -1) {
65 INFO("msgget: rx_qid");
66 return -1;
67 }
68
69 if ((server_queue_key = ftok(path, PROJECT_ID)) == -1) {
70 INFO("ftok");
71 return -2;
72 }
73
74 if ((server_qid = msgget(server_queue_key, 0)) == -1) {
75 INFO("msgget: server_qid");
76 return -3;
77 }
78
79 *cqid = rx_qid;
80 *sqid = server_qid;
81
82 return 0;
83}
84
85static psa_status_t process_response(int rx_qid, vectors_t *vecs, int type,
86 int *internal_server_qid)
87{
88
89 struct message response, request;
90 psa_status_t ret = PSA_ERROR_CONNECTION_REFUSED;
91 size_t invec_seek[4] = { 0 };
92 size_t data_size;
93 psa_status_t invec, outvec; /* TODO: Should these be size_t ? */
94
95 assert(internal_server_qid > 0);
96
97 while (1) {
98 data_size = 0;
99 invec = 0;
100 outvec = 0;
101
102 // read response from server
103 if (msgrcv(rx_qid, &response, sizeof(struct message_text), 0, 0) == -1) {
104 puts(" msgrcv failed");
105 return ret;
106 }
107
108 // process return message from server
109 switch (response.message_type) {
110 case PSA_REPLY:
111 memcpy(&ret, response.message_text.buf, sizeof(psa_status_t));
112 printf(" Message received from server: %d\n", ret);
113 if (type == PSA_IPC_CONNECT && ret > 0) {
114 *internal_server_qid = ret;
115 INFO(" ASSSIGNED q ID %d", *internal_server_qid);
116 ret = PSA_SUCCESS;
117 }
118 return ret;
119 break;
120 case READ_REQUEST:
121 /* read data request */
122 request.message_type = READ_RESPONSE;
123
124 assert(vecs != 0);
125
126 memcpy(&invec, response.message_text.buf, sizeof(psa_status_t));
127 memcpy(&data_size, response.message_text.buf+sizeof(size_t), sizeof(size_t));
128 INFO(" Partition asked for %lu bytes from invec %d", data_size, invec);
129
130 /* need to add more checks here */
131 assert(invec >= 0 && invec < PSA_MAX_IOVEC);
132
133 if (data_size > MAX_FRAGMENT_SIZE) {
134 data_size = MAX_FRAGMENT_SIZE;
135 }
136
137 /* send response */
138 INFO(" invec_seek[invec] is %lu", invec_seek[invec]);
139 INFO(" Reading from offset %p", vecs->in_vec[invec].base + invec_seek[invec]);
140 memcpy(request.message_text.buf,
141 (vecs->in_vec[invec].base + invec_seek[invec]),
142 data_size);
143
144 /* update invec base TODO: check me */
145 invec_seek[invec] = invec_seek[invec] + data_size;
146
147 INFO(" Sending message of type %li", request.message_type);
148 INFO(" with content %s\n", request.message_text.buf);
149
150 if (msgsnd(*internal_server_qid, &request,
151 sizeof(int) + sizeof(uint32_t) + data_size, 0) == -1) {
152 INFO("Internal error: failed to respond to read request");
153 }
154 break;
155 case WRITE_REQUEST:
156 assert(vecs != 0);
157
158 request.message_type = WRITE_RESPONSE;
159
160 memcpy(&outvec, response.message_text.buf, sizeof(psa_status_t));
161 memcpy(&data_size, response.message_text.buf + sizeof(size_t), sizeof(size_t));
162 INFO(" Partition wants to write %lu bytes to outvec %d", data_size, outvec);
163
164 assert(outvec >= 0 && outvec < PSA_MAX_IOVEC);
165
166 /* copy memory into message and send back amount written */
167 size_t sofar = vecs->out_vec[outvec].len;
168 memcpy(vecs->out_vec[outvec].base + sofar,
169 response.message_text.buf+(sizeof(size_t)*2), data_size);
170 INFO(" Data size is %lu\n", data_size);
171 vecs->out_vec[outvec].len += data_size;
172
173 INFO(" Sending message of type %li\n", request.message_type);
174
175 /* send response */
176 if (msgsnd(*internal_server_qid, &request, sizeof(int) + data_size, 0) == -1) {
177 INFO("Internal error: failed to respond to write request");
178 }
179 break;
180 case SKIP_REQUEST:
181 memcpy(&invec, response.message_text.buf, sizeof(psa_status_t));
182 memcpy(&data_size, response.message_text.buf+sizeof(size_t), sizeof(size_t));
183 INFO(" Partition asked to skip %lu bytes in invec %d", data_size, invec);
184 assert(invec >= 0 && invec < PSA_MAX_IOVEC);
185 /* update invec base TODO: check me */
186 invec_seek[invec] = invec_seek[invec] + data_size;
187 break;
188
189 default:
190 FATAL(" ERROR: unknown internal message type: %ld\n",
191 response.message_type);
192 return ret;
193 }
194 }
195}
196
197static psa_status_t send(int rx_qid, int server_qid, int *internal_server_qid,
198 int32_t type, uint32_t minor_version, vectors_t *vecs)
199{
200 {
201 psa_status_t ret = PSA_ERROR_CONNECTION_REFUSED;
202 size_t request_msg_size = (sizeof(int) + sizeof(long)); /* msg type plus queue id */
203 struct message request;
204 request.message_type = 1; /* TODO: change this */
205 request.message_text.psa_type = type;
206 vector_sizes_t vec_sizes;
207
208 /* If the client is non-secure then set the NS bit */
209 if (__psa_ff_client_security_state != 0) {
210 request.message_type |= NON_SECURE;
211 }
212
213 assert(request.message_type >= 0);
214
215 INFO("SEND: Sending message of type %ld with psa_type %d", request.message_type, type);
216 INFO(" internal_server_qid = %i", *internal_server_qid);
217
218 request.message_text.qid = rx_qid;
219
220 if (type == PSA_IPC_CONNECT) {
221 memcpy(request.message_text.buf, &minor_version, sizeof(minor_version));
222 request_msg_size = request_msg_size + sizeof(minor_version);
223 INFO(" Request msg size is %lu", request_msg_size);
224 } else {
225 assert(internal_server_qid > 0);
226 }
227
228 if (vecs != NULL && type >= PSA_IPC_CALL) {
229
230 bzero(&vec_sizes, sizeof(vec_sizes));
231
232 /* Copy invec sizes */
233 for (size_t i = 0; i < (vecs->in_len); i++) {
234 vec_sizes.invec_sizes[i] = vecs->in_vec[i].len;
235 INFO(" Client sending vector %lu: %lu", i, vec_sizes.invec_sizes[i]);
236 }
237
238 /* Copy outvec sizes */
239 for (size_t i = 0; i < (vecs->out_len); i++) {
240 vec_sizes.outvec_sizes[i] = vecs->out_vec[i].len;
241
242 /* Reset to 0 since we need to eventually fill in with bytes written */
243 vecs->out_vec[i].len = 0;
244 }
245
246 memcpy(request.message_text.buf, &vec_sizes, sizeof(vec_sizes));
247 request_msg_size = request_msg_size + sizeof(vec_sizes);
248 }
249
250 INFO(" Sending and then waiting");
251
252 // send message to server
253 if (msgsnd(server_qid, &request, request_msg_size, 0) == -1) {
254 puts(" msgsnd failed");
255 return ret;
256 }
257
258 return process_response(rx_qid, vecs, type, internal_server_qid);
259 }
260}
261
262
263uint32_t psa_framework_version(void)
264{
265 return PSA_FRAMEWORK_VERSION;
266}
267
268psa_handle_t psa_connect(uint32_t sid, uint32_t minor_version)
269{
270
271 int idx;
272 psa_status_t ret;
273 char pathname[PATHNAMESIZE] = { 0 };
274
275 idx = get_next_free_handle();
276
277 /* if there's a free handle available */
278 if (idx >= 0) {
279 snprintf(pathname, PATHNAMESIZE - 1, "/tmp/psa_service_%u", sid);
280 INFO("Attempting to contact RoT service at %s", pathname);
281
282 /* if communication is possible */
283 if (get_queue_info(pathname, &handles[idx].client_qid, &handles[idx].server_qid) >= 0) {
284
285 ret = send(handles[idx].client_qid,
286 handles[idx].server_qid,
287 &handles[idx].internal_server_qid,
288 PSA_IPC_CONNECT,
289 minor_version,
290 NULL);
291
292 /* if connection accepted by RoT service */
293 if (ret >= 0) {
294 handles[idx].valid = 1;
295 return idx;
296 } else {
297 INFO("Server didn't like you");
298 }
299 } else {
300 INFO("Couldn't contact RoT service. Does it exist?");
301
302 if (__psa_ff_client_security_state == 0) {
303 PROGRAMMER_ERROR("Invalid SID");
304 }
305 }
306 }
307
308 INFO("Couldn't obtain a free handle");
309 return PSA_ERROR_CONNECTION_REFUSED;
310}
311
312uint32_t psa_version(uint32_t sid)
313{
314 int idx;
315 psa_status_t ret;
316 char pathname[PATHNAMESIZE] = { 0 };
317
318 idx = get_next_free_handle();
319
320 if (idx >= 0) {
321 snprintf(pathname, PATHNAMESIZE, "/tmp/psa_service_%u", sid);
322 if (get_queue_info(pathname, &handles[idx].client_qid, &handles[idx].server_qid) >= 0) {
323 ret = send(handles[idx].client_qid,
324 handles[idx].server_qid,
325 &handles[idx].internal_server_qid,
326 VERSION_REQUEST,
327 0,
328 NULL);
329 INFO("psa_version: Recieved from server %d\n", ret);
330 if (ret > 0) {
331 return ret;
332 }
333 }
334 }
335 INFO("psa_version failed: does the service exist?");
336 return PSA_VERSION_NONE;
337}
338
339psa_status_t psa_call(psa_handle_t handle,
340 int32_t type,
341 const psa_invec *in_vec,
342 size_t in_len,
343 psa_outvec *out_vec,
344 size_t out_len)
345{
346
347 handle_is_valid(handle);
348
349 if ((in_len + out_len) > PSA_MAX_IOVEC) {
350 PROGRAMMER_ERROR("Too many iovecs: %lu + %lu", in_len, out_len);
351 }
352
353 vectors_t vecs = { 0 };
354 vecs.in_vec = in_vec;
355 vecs.in_len = in_len;
356 vecs.out_vec = out_vec;
357 vecs.out_len = out_len;
358
359 return send(handles[handle].client_qid,
360 handles[handle].server_qid,
361 &handles[handle].internal_server_qid,
362 type,
363 0,
364 &vecs);
365}
366
367void psa_close(psa_handle_t handle)
368{
369 handle_is_valid(handle);
370 if (send(handles[handle].client_qid, handles[handle].server_qid,
371 &handles[handle].internal_server_qid, PSA_IPC_DISCONNECT, 0, NULL)) {
372 puts("ERROR: Couldn't send disconnect msg");
373 } else {
374 if (msgctl(handles[handle].client_qid, IPC_RMID, NULL) != 0) {
375 puts("ERROR: Failed to delete msg queue");
376 }
377 }
378 INFO("Closing handle %u", handle);
379 handles[handle].valid = 0;
380}