quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

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 }