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