client.c (12271B)
1 /* 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 23 typedef 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 32 static internal_handle_t handles[MAX_HANDLES] = { { 0 } }; 33 34 static 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 45 static 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 56 static 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 85 static 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 197 static 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 263 uint32_t psa_framework_version(void) 264 { 265 return PSA_FRAMEWORK_VERSION; 266 } 267 268 psa_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 312 uint32_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 339 psa_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 367 void 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 }