Home | History | Annotate | Download | only in tee_client_api
      1 /**
      2  * Copyright(c) 2011 Trusted Logic.   All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *  * Neither the name Trusted Logic nor the names of its
     15  *    contributors may be used to endorse or promote products derived
     16  *    from this software without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     29  */
     30 
     31 #include "tee_client_api.h"
     32 #include "schannel6_protocol.h"
     33 #include "s_error.h"
     34 #include "s_version.h"
     35 
     36 #include <stdlib.h>
     37 #include <stdio.h>
     38 #include <ctype.h>
     39 #include <string.h>
     40 #include <stdarg.h>
     41 #include <assert.h>
     42 
     43 #include <sys/ioctl.h>
     44 #include <sys/types.h>
     45 #include <sys/stat.h>
     46 #include <sys/mman.h>
     47 #include <unistd.h>
     48 #include <fcntl.h>
     49 #include <errno.h>
     50 #include <unistd.h>
     51 #include <linux/limits.h>
     52 #include <time.h>
     53 #include <sys/time.h>
     54 
     55 /*
     56  * SCX_VERSION_INFORMATION_BUFFER structure description
     57  * Description of the sVersionBuffer handed over from user space to kernel space
     58  * This field is filled after an IOCTL call and handed back to user space
     59  */
     60 typedef struct
     61 {
     62    uint8_t sDriverDescription[65];
     63    uint8_t sSecureWorldDescription[65];
     64 } SCX_VERSION_INFORMATION_BUFFER;
     65 
     66 
     67 /* The IOCTLs to the driver */
     68 #define IOCTL_SCX_GET_VERSION \
     69          _IO('z', 0)
     70 
     71 #define IOCTL_SCX_EXCHANGE \
     72          _IOWR('z', 1, SCHANNEL6_COMMAND)
     73 
     74 #define IOCTL_SCX_GET_DESCRIPTION \
     75          _IOR('z', 2, SCX_VERSION_INFORMATION_BUFFER)
     76 
     77 
     78 /* Expected driver interface version. */
     79 #define SM_DRIVER_VERSION 0x04000000
     80 
     81 #define SCX_DEFAULT_DEVICE_NAME "tf_driver"
     82 
     83 #define SCX_PARAM_TYPE_GET(nParamTypes, i) (((nParamTypes) >> (4*i)) & 0xF)
     84 
     85 #define VAR_NOT_USED(variable)  do{(void)(variable);}while(0);
     86 
     87 #define SIZE_4KB  0x1000
     88 #define SIZE_1MB  0x100000
     89 
     90 /* ------------------------------------------------------------------------ */
     91 /*    UTILS                                                                 */
     92 /* ------------------------------------------------------------------------ */
     93 #ifdef NDEBUG
     94 /* Compile-out the traces */
     95 #define TRACE_ERROR(...)
     96 #define TRACE_WARNING(...)
     97 #define TRACE_INFO(...)
     98 #else
     99 static void TRACE_ERROR(const char* format, ...)
    100 {
    101    va_list ap;
    102    va_start(ap, format);
    103    fprintf(stderr, "TRACE: ERROR: ");
    104    vfprintf(stderr, format, ap);
    105    fprintf(stderr, "\n");
    106    va_end(ap);
    107 }
    108 
    109 static void TRACE_WARNING(const char* format, ...)
    110 {
    111    va_list ap;
    112    va_start(ap, format);
    113    fprintf(stderr, "TRACE: WARNING: ");
    114    vfprintf(stderr, format, ap);
    115    fprintf(stderr, "\n");
    116    va_end(ap);
    117 }
    118 
    119 static void TRACE_INFO(const char* format, ...)
    120 {
    121    va_list ap;
    122    va_start(ap, format);
    123    fprintf(stderr, "TRACE: ");
    124    vfprintf(stderr, format, ap);
    125    fprintf(stderr, "\n");
    126    va_end(ap);
    127 }
    128 #endif /* NDEBUG */
    129 
    130 
    131 /*
    132  * ====================================================
    133  *                 Internal functions
    134  * =====================================================
    135 */
    136 
    137 static void scxYield(void)
    138 {
    139    sleep(0);
    140 }
    141 
    142 /* ------------------------------------------------------------------------ */
    143 
    144 
    145 /*
    146  * Exchange a message with the Secure World
    147  * by calling the ioctl command of the linux driver
    148  *
    149  * @param pContext
    150  * @param pCommand a SChannel command message that must have been filled except for the operation parameters
    151  * @param pAnswer  a placeholder for the SChannel answer
    152  * @param pOperation a TEEC_Operation structure that contains the operation parameters (and types)
    153  *                   and is updated with the SChannel answer data as appropriate. This parameter is
    154  *                   used only for the open and invoke operations
    155  */
    156 static TEEC_Result scxExchangeMessage(
    157    IN  TEEC_Context*     pContext,
    158    IN  SCHANNEL6_COMMAND* pCommand,
    159    OUT SCHANNEL6_ANSWER*  pAnswer,
    160    IN TEEC_Operation* pOperation)
    161 {
    162    TEEC_Result nResult = TEEC_SUCCESS;
    163 
    164    TRACE_INFO("scxExchangeMessage[0x%X]\n",pContext);
    165 
    166    if (pOperation != NULL)
    167    {
    168       /* Determine message parameters from operation parameters */
    169       uint32_t i;
    170       SCHANNEL6_COMMAND_PARAM* pSCXParams;
    171 
    172       /* Note that nParamType is at the same position in an open and an invoke message */
    173       pCommand->sHeader.nMessageInfo = pOperation->paramTypes;
    174 
    175       if (pCommand->sHeader.nMessageType == SCX_OPEN_CLIENT_SESSION)
    176       {
    177          pSCXParams = pCommand->sOpenClientSession.sParams;
    178       }
    179       else
    180       {
    181          /* An invoke-command */
    182          pSCXParams = pCommand->sInvokeClientCommand.sParams;
    183       }
    184 
    185       for (i = 0; i < 4; i++)
    186       {
    187          uint32_t nTEECParamType = SCX_PARAM_TYPE_GET(pOperation->paramTypes, i);
    188          TEEC_Parameter*  pTEECParam = &pOperation->params[i];
    189          SCHANNEL6_COMMAND_PARAM* pSCXParam = &pSCXParams[i];
    190 
    191          if (nTEECParamType & SCX_PARAM_TYPE_MEMREF_FLAG)
    192          {
    193             if (nTEECParamType & SCX_PARAM_TYPE_REGISTERED_MEMREF_FLAG)
    194             {
    195                /* A registered memref */
    196                pSCXParam->sMemref.hBlock  = pTEECParam->memref.parent->imp._hBlock;
    197                if (nTEECParamType == TEEC_MEMREF_WHOLE)
    198                {
    199                   /* A memref on the whole shared memory */
    200                   /* Set the direction from the shared memory flags */
    201                   pCommand->sInvokeClientCommand.nParamTypes |=
    202                      (pTEECParam->memref.parent->flags & (SCX_PARAM_TYPE_INPUT_FLAG | SCX_PARAM_TYPE_OUTPUT_FLAG))
    203                      << (4*i);
    204                   pSCXParam->sMemref.nSize   = pTEECParam->memref.parent->size;
    205                   pSCXParam->sMemref.nOffset = 0;
    206                }
    207                else
    208                {
    209                   /* A partial memref */
    210                   pSCXParam->sMemref.nSize   = pTEECParam->memref.size;
    211                   pSCXParam->sMemref.nOffset = pTEECParam->memref.offset;
    212                }
    213             }
    214             else
    215             {
    216                /* A temporary memref */
    217                /* Set nOffset to the address in the client. This allows the server
    218                  to allocate a block with the same alignment and also to
    219                  detect a NULL tmpref.
    220                */
    221                pSCXParam->sTempMemref.nOffset = (uint32_t)pTEECParam->tmpref.buffer;
    222                pSCXParam->sTempMemref.nDescriptor = (uint32_t)pTEECParam->tmpref.buffer;
    223                pSCXParam->sTempMemref.nSize = pTEECParam->tmpref.size;
    224             }
    225          }
    226          else if (nTEECParamType & SCX_PARAM_TYPE_INPUT_FLAG)
    227          {
    228             /* An input value */
    229             pSCXParam->sValue.a = pTEECParam->value.a;
    230             pSCXParam->sValue.b = pTEECParam->value.b;
    231          }
    232       }
    233    }
    234 
    235    pCommand->sHeader.nOperationID = (uint32_t)pAnswer;
    236 
    237    nResult = ioctl((S_HANDLE)pContext->imp._hConnection, IOCTL_SCX_EXCHANGE, pCommand);
    238    if (nResult != S_SUCCESS)
    239    {
    240       TRACE_INFO("scxExchangeMessage[0x%X]: Ioctl returned error: 0x%x (0x%x - %d)\n",pContext,nResult,errno,errno);
    241       switch(errno)
    242       {
    243          case ENOMEM:
    244             nResult=TEEC_ERROR_OUT_OF_MEMORY;
    245             break;
    246          case EACCES:
    247             nResult=TEEC_ERROR_ACCESS_DENIED;
    248             break;
    249          default:
    250             nResult=TEEC_ERROR_COMMUNICATION;
    251             break;
    252       }
    253    }
    254 
    255    if (pOperation != NULL)
    256    {
    257       /* Update the operation parameters from the answer message */
    258       uint32_t   i;
    259       SCHANNEL6_ANSWER_PARAM *  pSCXAnswers;
    260       if (pAnswer->sHeader.nMessageType == SCX_OPEN_CLIENT_SESSION)
    261       {
    262          /* Open session */
    263          pSCXAnswers = pAnswer->sOpenClientSession.sAnswers;
    264       }
    265       else
    266       {
    267          /* Invoke case */
    268          pSCXAnswers = pAnswer->sInvokeClientCommand.sAnswers;
    269       }
    270 
    271       for (i = 0; i < 4; i++)
    272       {
    273          uint32_t   nSCXParamType;
    274          nSCXParamType = SCX_GET_PARAM_TYPE(pCommand->sHeader.nMessageInfo, i);
    275          if (nSCXParamType & SCX_PARAM_TYPE_OUTPUT_FLAG)
    276          {
    277             if (nSCXParamType & SCX_PARAM_TYPE_MEMREF_FLAG)
    278             {
    279                /* Trick: the size field is at the same position in a memref or a tmpref */
    280                pOperation->params[i].memref.size = pSCXAnswers[i].sSize.nSize;
    281             }
    282             else
    283             {
    284                /* An output value */
    285                pOperation->params[i].value.a = pSCXAnswers[i].sValue.a;
    286                pOperation->params[i].value.b = pSCXAnswers[i].sValue.b;
    287             }
    288          }
    289       }
    290    }
    291 
    292    return nResult;
    293 }
    294 
    295 /* ------------------------------------------------------------------------ */
    296 
    297 static void* scxAllocateSharedMemory(
    298    IN uint32_t nLength)
    299 {
    300    if (nLength == 0)
    301    {
    302       /* This is valid, although we don't want to call mmap.
    303          Just return a dummy non-NULL pointer */
    304       return (void*)0x10;
    305    }
    306    else
    307    {
    308       return mmap(
    309          0,nLength,
    310          PROT_READ | PROT_WRITE,
    311          MAP_SHARED | MAP_ANONYMOUS,
    312          0,0);
    313    }
    314 }
    315 
    316 /* ------------------------------------------------------------------------ */
    317 
    318 static void scxReleaseSharedMemory(IN void* pBuffer,
    319                                    IN uint32_t nLength)
    320 {
    321    if (nLength == 0)
    322    {
    323       return;
    324    }
    325    if (munmap(pBuffer, nLength)!= 0)
    326    {
    327        TRACE_WARNING("scxReleaseSharedMemory returned 0x%x \n",errno);
    328    }
    329 }
    330 /* ------------------------------------------------------------------------ */
    331 
    332 uint64_t scxGetCurrentTime(void)
    333 {
    334    uint64_t currentTime = 0;
    335    struct timeval now;
    336 
    337    gettimeofday(&now,NULL);
    338    currentTime = now.tv_sec;
    339    currentTime = (currentTime * 1000) + (now.tv_usec / 1000);
    340 
    341    return currentTime;
    342 }
    343 /* ------------------------------------------------------------------------ */
    344 
    345 /*
    346  * ====================================================
    347  *                TEE Client API
    348  * =====================================================
    349 */
    350 
    351 /**
    352  * Get a time-limit equal to now + relative timeout expressed in milliseconds.
    353  **/
    354 void TEEC_GetTimeLimit(
    355     TEEC_Context*    sContext,
    356     uint32_t         nTimeout,
    357     TEEC_TimeLimit*  sTimeLimit)
    358 {
    359    uint64_t nTimeLimit = 0;
    360    VAR_NOT_USED(sContext);
    361 
    362    TRACE_INFO("TEEC_GetTimeLimit(0x%X, %u ms)", sContext, nTimeout);
    363 
    364    if (nTimeout == 0xFFFFFFFF )
    365    {
    366       /* Infinite timeout */
    367       nTimeLimit = SCTIME_INFINITE;
    368    }
    369    else
    370    {
    371        nTimeLimit = scxGetCurrentTime() + nTimeout;
    372    }
    373    TRACE_INFO("GetTimeLimit %ld\n",nTimeLimit);
    374    memcpy(sTimeLimit, &nTimeLimit, sizeof(TEEC_TimeLimit));
    375 }
    376 
    377 //-----------------------------------------------------------------------------------------------------
    378 TEEC_Result TEEC_InitializeContext(
    379     const char*   pDeviceName,
    380     TEEC_Context* pContext)
    381 {
    382 
    383   TEEC_Result nError = TEEC_SUCCESS;
    384    S_HANDLE hDriver   = S_HANDLE_NULL;
    385    char sFullDeviceName[PATH_MAX];
    386    uint32_t nVersion;
    387 
    388    if(pDeviceName == NULL)
    389    {
    390       pDeviceName = SCX_DEFAULT_DEVICE_NAME;
    391    }
    392    strcpy(sFullDeviceName, "/dev/");
    393    strcat(sFullDeviceName, pDeviceName);
    394 
    395    hDriver = open(sFullDeviceName, O_RDWR, 0);
    396 
    397    if (hDriver == (uint32_t)-1)
    398    {
    399       TRACE_ERROR("scxOpen: open() failed 0x%x\n", errno);
    400       switch(errno)
    401       {
    402          case ENOMEM:
    403             nError = TEEC_ERROR_OUT_OF_MEMORY;
    404             goto error;
    405          case EINTR:
    406              break;
    407          default:
    408             nError = TEEC_ERROR_COMMUNICATION;
    409             goto error;
    410       }
    411    }
    412    fcntl(hDriver, F_SETFD, FD_CLOEXEC);
    413    nVersion = ioctl(hDriver, IOCTL_SCX_GET_VERSION);
    414    if (nVersion != SM_DRIVER_VERSION)
    415    {
    416       TRACE_ERROR("scxOpen: Not expected driver version: 0x%x instead of 0x%x\n", nVersion,SM_DRIVER_VERSION);
    417       switch(errno)
    418       {
    419          case ENOMEM:
    420             nError=TEEC_ERROR_OUT_OF_MEMORY;
    421             break;
    422          default:
    423             nError=TEEC_ERROR_COMMUNICATION;
    424             break;
    425       }
    426       close(hDriver);
    427    }
    428 error:
    429    if(nError == TEEC_SUCCESS)
    430    {
    431        pContext->imp._hConnection = hDriver;
    432    }
    433    else
    434    {
    435       TRACE_ERROR("scxOpen failed 0x%x\n", nError);
    436       pContext->imp._hConnection = 0;
    437    }
    438 
    439    return nError;
    440 }
    441 
    442 //-----------------------------------------------------------------------------------------------------
    443 void TEEC_FinalizeContext(TEEC_Context* pContext)
    444 {
    445    TRACE_INFO("TEEC_FinalizeContext[0x%X]", pContext);
    446 
    447    if (pContext == NULL) return;
    448 
    449    close(pContext->imp._hConnection);
    450    pContext->imp._hConnection = 0;
    451 }
    452 
    453 //-----------------------------------------------------------------------------------------------------
    454 TEEC_Result TEEC_OpenSession (
    455     TEEC_Context*    context,
    456     TEEC_Session*    session,      /* OUT */
    457     const TEEC_UUID* destination,  /* The trusted application UUID we want to open the session with */
    458     uint32_t         connectionMethod, /* LoginType*/
    459     void*            connectionData,  /* LoginData */
    460     TEEC_Operation*  operation,    /* payload. If operation is NULL then no data buffers are exchanged with the Trusted Application, and the operation cannot be cancelled by the Client Application */
    461     uint32_t*        errorOrigin)
    462 {
    463   return TEEC_OpenSessionEx(context,
    464                             session,
    465                             NULL,
    466                             destination,
    467                             connectionMethod,
    468                             connectionData,
    469                             operation,
    470                             errorOrigin);
    471 }
    472 
    473 //-----------------------------------------------------------------------------------------------------
    474 void TEEC_CloseSession (TEEC_Session* session)
    475 {
    476    TEEC_Context*     context;
    477    SCHANNEL6_ANSWER  sAnswer;
    478    SCHANNEL6_COMMAND sCommand;
    479    if (session == NULL) return;
    480    context = session->imp._pContext;
    481    memset(&sCommand,0,sizeof(sCommand));
    482    sCommand.sHeader.nMessageType = SCX_CLOSE_CLIENT_SESSION;
    483    sCommand.sHeader.nMessageSize = (sizeof(SCHANNEL6_CLOSE_CLIENT_SESSION_COMMAND)
    484                                          - sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t);
    485    sCommand.sCloseClientSession.hClientSession = session->imp._hClientSession;
    486    scxExchangeMessage(context, &sCommand, &sAnswer, NULL);
    487    /* we ignore the error code of scxExchangeMessage */
    488    session->imp._hClientSession = S_HANDLE_NULL;
    489    session->imp._pContext = NULL;
    490 }
    491 
    492 //-----------------------------------------------------------------------------------------------------
    493 TEEC_Result TEEC_InvokeCommand(
    494     TEEC_Session*     session,
    495     uint32_t          commandID,
    496     TEEC_Operation*   operation,
    497     uint32_t*         errorOrigin)
    498 {
    499     return TEEC_InvokeCommandEx(session,
    500                             NULL,
    501                             commandID,
    502                             operation,
    503                             errorOrigin);
    504 }
    505 
    506 
    507 //-----------------------------------------------------------------------------------------------------
    508 /* Used to implement both register and allocate */
    509 static TEEC_Result TEEC_RegisterSharedMemory0(
    510     TEEC_Context*      context,
    511     TEEC_SharedMemory* sharedMem)
    512 {
    513    TEEC_Result nResult;
    514    SCHANNEL6_COMMAND sCommand;
    515    SCHANNEL6_ANSWER  sAnswer;
    516 
    517    TRACE_INFO("TEEC_RegisterSharedMemory0 (%p, %p)",context, sharedMem);
    518    memset(&sCommand, 0, sizeof(sCommand));
    519 
    520    sCommand.sRegisterSharedMemory.nMessageSize = (sizeof(SCHANNEL6_REGISTER_SHARED_MEMORY_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/4;
    521    sCommand.sRegisterSharedMemory.nMessageType             = SCX_REGISTER_SHARED_MEMORY;
    522    sCommand.sRegisterSharedMemory.nMemoryFlags             = sharedMem->flags;
    523    sCommand.sRegisterSharedMemory.nSharedMemSize           = sharedMem->size;
    524    sCommand.sRegisterSharedMemory.nSharedMemStartOffset    = 0;
    525    sCommand.sRegisterSharedMemory.nSharedMemDescriptors[0] = (uint32_t)sharedMem->buffer;
    526    nResult = scxExchangeMessage(context,
    527                 &sCommand,
    528                 &sAnswer,
    529                 NULL);
    530    if (nResult == TEEC_SUCCESS)
    531    {
    532        nResult = sAnswer.sRegisterSharedMemory.nErrorCode;
    533    }
    534    if (nResult == TEEC_SUCCESS)
    535    {
    536       sharedMem->imp._pContext = context;
    537       sharedMem->imp._hBlock = sAnswer.sRegisterSharedMemory.hBlock;
    538    }
    539    return nResult;
    540 }
    541 
    542 
    543 //-----------------------------------------------------------------------------------------------------
    544 TEEC_Result TEEC_RegisterSharedMemory(
    545     TEEC_Context*      context,
    546     TEEC_SharedMemory* sharedMem)
    547 {
    548    TRACE_INFO("TEEC_RegisterSharedMemory (%p)",context);
    549    sharedMem->imp._pContext = NULL;
    550    sharedMem->imp._hBlock = S_HANDLE_NULL;
    551    sharedMem->imp._bAllocated = false;
    552    return TEEC_RegisterSharedMemory0(context, sharedMem);
    553 }
    554 
    555 //-----------------------------------------------------------------------------------------------------
    556 TEEC_Result TEEC_AllocateSharedMemory(
    557     TEEC_Context*      context,
    558     TEEC_SharedMemory* sharedMem)
    559 {
    560    TEEC_Result nResult;
    561    TRACE_INFO("TEEC_AllocateSharedMemory (%p)",context);
    562 
    563    sharedMem->imp._pContext = NULL;
    564    sharedMem->imp._hBlock = S_HANDLE_NULL;
    565    sharedMem->buffer = scxAllocateSharedMemory(sharedMem->size);
    566    if (sharedMem->buffer == NULL)
    567    {
    568       return TEEC_ERROR_OUT_OF_MEMORY;
    569    }
    570    sharedMem->imp._bAllocated = true;
    571    nResult = TEEC_RegisterSharedMemory0(context, sharedMem);
    572    if (nResult != TEEC_SUCCESS)
    573    {
    574       scxReleaseSharedMemory(sharedMem->buffer,sharedMem->size);
    575       sharedMem->buffer = NULL;
    576    }
    577    return nResult;
    578 }
    579 
    580 //-----------------------------------------------------------------------------------------------------
    581 void TEEC_ReleaseSharedMemory (
    582     TEEC_SharedMemory* sharedMem)
    583 {
    584    SCHANNEL6_ANSWER  sAnswer;
    585    SCHANNEL6_COMMAND sMessage;
    586    TEEC_Context* context;
    587 
    588    context = (TEEC_Context *)sharedMem->imp._pContext;
    589    memset(&sMessage, 0, sizeof(SCHANNEL6_COMMAND));
    590    sMessage.sReleaseSharedMemory.nMessageType = SCX_RELEASE_SHARED_MEMORY;
    591    sMessage.sReleaseSharedMemory.nMessageSize = (sizeof(SCHANNEL6_RELEASE_SHARED_MEMORY_COMMAND)
    592                                     - sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t);
    593    sMessage.sReleaseSharedMemory.hBlock = sharedMem->imp._hBlock;
    594    scxExchangeMessage(context,&sMessage, &sAnswer, NULL);
    595    if (sharedMem->imp._bAllocated)
    596    {
    597        scxReleaseSharedMemory(sharedMem->buffer,sharedMem->size);
    598        /* Update parameters:
    599        * In this case the Implementation MUST set the buffer and size fields of the sharedMem structure
    600        * to NULL and 0 respectively before returning.
    601        */
    602        sharedMem->buffer = NULL;
    603        sharedMem->size = 0;
    604    }
    605    sharedMem->imp._pContext = NULL;
    606    sharedMem->imp._hBlock = S_HANDLE_NULL;
    607 }
    608 
    609 //-----------------------------------------------------------------------------------------------------
    610 void TEEC_RequestCancellation(TEEC_Operation* operation)
    611 {
    612    uint32_t nOperationState;
    613    TEEC_Result       nResult;
    614 
    615    if (operation == NULL) return;
    616 
    617 retry:
    618    nOperationState = operation->started;
    619    if (nOperationState == 2)
    620     {
    621       /* Operation already finished. Return immediately */
    622       return;
    623    }
    624    else if (nOperationState == 1)
    625    {
    626        /* Operation is in progress */
    627        TEEC_Context*     context;
    628        SCHANNEL6_ANSWER  sAnswer;
    629        SCHANNEL6_COMMAND sMessage;
    630 
    631        context = operation->imp._pContext;
    632 
    633        memset(&sMessage,0,sizeof(sMessage));
    634        sMessage.sHeader.nMessageType = SCX_CANCEL_CLIENT_OPERATION;
    635        sMessage.sHeader.nMessageSize = (sizeof(SCHANNEL6_CANCEL_CLIENT_OPERATION_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/4;
    636        sMessage.sCancelClientOperation.hClientSession = operation->imp._hSession;
    637        sMessage.sCancelClientOperation.nCancellationID = (uint32_t)operation;
    638        nResult = scxExchangeMessage(context,&sMessage, &sAnswer, NULL);
    639 
    640        if (nResult != TEEC_SUCCESS)
    641        {
    642            /* Communication failure. Ignore the error: the operation is already cancelled anyway */
    643            return;
    644        }
    645        if (sAnswer.sCancelClientOperation.nErrorCode == S_SUCCESS)
    646        {
    647            /* Command was successfully cancelled */
    648            return;
    649        }
    650        /* Otherwise, the command has not yet reached the secure world or has already finished and we must retry */
    651    }
    652    /* This applies as well when nOperationState == 0. In this case, the operation has not yet
    653       started yet and we don't even have a pointer to the context */
    654    scxYield();
    655    goto retry;
    656 }
    657 
    658 
    659 //-----------------------------------------------------------------------------------------------------
    660 TEEC_Result TEEC_ReadSignatureFile(
    661                                    void**    ppSignatureFile,
    662                                    uint32_t* pnSignatureFileLength)
    663 {
    664    TEEC_Result nErrorCode = TEEC_SUCCESS;
    665 
    666    uint32_t      nBytesRead;
    667    uint32_t      nSignatureSize = 0;
    668    uint8_t*     pSignature = NULL;
    669    FILE*    pSignatureFile = NULL;
    670    char     sFileName[PATH_MAX + 1 + 5];  /* Allocate room for the signature extension */
    671    long     nFileSize;
    672 
    673    *pnSignatureFileLength = 0;
    674    *ppSignatureFile = NULL;
    675 
    676    if (realpath("/proc/self/exe", sFileName) == NULL)
    677    {
    678       TRACE_ERROR("TEEC_ReadSignatureFile: realpath failed [%d]", errno);
    679       return TEEC_ERROR_OS;
    680    }
    681 
    682    /* Work out the signature file name */
    683    strcat(sFileName, ".ssig");
    684 
    685    pSignatureFile = fopen(sFileName, "rb");
    686    if (pSignatureFile == NULL)
    687    {
    688       /* Signature doesn't exist */
    689        return TEEC_ERROR_ITEM_NOT_FOUND;
    690    }
    691 
    692    if (fseek(pSignatureFile, 0, SEEK_END) != 0)
    693    {
    694       TRACE_ERROR("TEEC_ReadSignatureFile: fseek(%s) failed [%d]",
    695                      sFileName, errno);
    696       nErrorCode = TEEC_ERROR_OS;
    697       goto error;
    698    }
    699 
    700    nFileSize = ftell(pSignatureFile);
    701    if (nFileSize < 0)
    702    {
    703       TRACE_ERROR("TEEC_ReadSignatureFile: ftell(%s) failed [%d]",
    704                      sFileName, errno);
    705       nErrorCode = TEEC_ERROR_OS;
    706       goto error;
    707    }
    708 
    709    nSignatureSize = (uint32_t)nFileSize;
    710 
    711    if (nSignatureSize != 0)
    712    {
    713       pSignature = malloc(nSignatureSize);
    714       if (pSignature == NULL)
    715       {
    716          TRACE_ERROR("TEEC_ReadSignatureFile: Heap - Out of memory for %u bytes",
    717                         nSignatureSize);
    718          nErrorCode = TEEC_ERROR_OUT_OF_MEMORY;
    719          goto error;
    720       }
    721 
    722       rewind(pSignatureFile);
    723 
    724       nBytesRead = fread(pSignature, 1, nSignatureSize, pSignatureFile);
    725       if (nBytesRead < nSignatureSize)
    726       {
    727          TRACE_ERROR("TEEC_ReadSignatureFile: fread failed [%d]", errno);
    728          nErrorCode = TEEC_ERROR_OS;
    729          goto error;
    730       }
    731    }
    732 
    733    fclose(pSignatureFile);
    734 
    735    *pnSignatureFileLength = nSignatureSize;
    736    *ppSignatureFile = pSignature;
    737 
    738    return S_SUCCESS;
    739 
    740 error:
    741    fclose(pSignatureFile);
    742    free(pSignature);
    743 
    744    return nErrorCode;
    745 }
    746 
    747 //-----------------------------------------------------------------------------------------------------
    748 TEEC_Result TEEC_OpenSessionEx (
    749     TEEC_Context*         context,
    750     TEEC_Session*         session,      /* OUT */
    751     const TEEC_TimeLimit* timeLimit,
    752     const TEEC_UUID*      destination,  /* The trusted application UUID we want to open the session with */
    753     uint32_t              connectionMethod, /* LoginType*/
    754     void*                 connectionData,  /* LoginData */
    755     TEEC_Operation*       operation,    /* payload. If operation is NULL then no data buffers are exchanged with the Trusted Application, and the operation cannot be cancelled by the Client Application */
    756     uint32_t*             returnOrigin)
    757 {
    758    TEEC_Result nError;
    759    uint32_t nReturnOrigin;
    760    SCHANNEL6_ANSWER  sAnswer;
    761    SCHANNEL6_COMMAND sCommand;
    762 
    763    memset(&sCommand, 0, sizeof(SCHANNEL6_COMMAND));
    764 
    765    sCommand.sHeader.nMessageType = SCX_OPEN_CLIENT_SESSION;
    766    sCommand.sHeader.nMessageSize = (sizeof(SCHANNEL6_OPEN_CLIENT_SESSION_COMMAND) - 20 -sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t);
    767    if (timeLimit == NULL)
    768    {
    769       sCommand.sOpenClientSession.sTimeout = SCTIME_INFINITE;
    770    }
    771    else
    772    {
    773       sCommand.sOpenClientSession.sTimeout = *(uint64_t*)timeLimit;
    774    }
    775    sCommand.sOpenClientSession.sDestinationUUID   = *((S_UUID*)destination);
    776    sCommand.sOpenClientSession.nLoginType         = connectionMethod;
    777    if ((connectionMethod == TEEC_LOGIN_GROUP)||(connectionMethod == TEEC_LOGIN_GROUP_APPLICATION))
    778    {
    779        /* connectionData MUST point to a uint32_t which contains the group
    780        * which this Client Application wants to connect as. The Linux Driver
    781        * is responsible for securely ensuring that the Client Application
    782        * instance is actually a member of this group.
    783        */
    784        if (connectionData != NULL)
    785        {
    786            *(uint32_t*)sCommand.sOpenClientSession.sLoginData = *(uint32_t*)connectionData;
    787            sCommand.sHeader.nMessageSize += sizeof(uint32_t);
    788        }
    789    }
    790    sCommand.sOpenClientSession.nCancellationID    = (uint32_t)operation; // used for TEEC_RequestCancellation
    791 
    792    if (operation != NULL)
    793    {
    794        operation->imp._pContext = context;
    795        operation->imp._hSession = S_HANDLE_NULL;
    796        operation->started = 1;
    797    }
    798 
    799    nError = scxExchangeMessage(context, &sCommand, &sAnswer, operation);
    800 
    801    if (operation != NULL) operation->started = 2;
    802 
    803    if (nError != TEEC_SUCCESS)
    804    {
    805        nReturnOrigin = TEEC_ORIGIN_COMMS;
    806    }
    807    else
    808    {
    809        nError = sAnswer.sOpenClientSession.nErrorCode;
    810        nReturnOrigin = sAnswer.sOpenClientSession.nReturnOrigin;
    811    }
    812 
    813    if (returnOrigin != NULL) *returnOrigin = nReturnOrigin;
    814 
    815    if (nError == S_SUCCESS)
    816    {
    817        session->imp._hClientSession = sAnswer.sOpenClientSession.hClientSession;
    818        session->imp._pContext       = context;
    819    }
    820 
    821    return nError;
    822 }
    823 
    824 //-----------------------------------------------------------------------------------------------------
    825 TEEC_Result TEEC_InvokeCommandEx(
    826     TEEC_Session*         session,
    827     const TEEC_TimeLimit* timeLimit,
    828     uint32_t              commandID,
    829     TEEC_Operation*       operation,
    830     uint32_t*             returnOrigin)
    831 {
    832    TEEC_Result nError;
    833    SCHANNEL6_ANSWER  sAnswer;
    834    SCHANNEL6_COMMAND sCommand;
    835    uint32_t    nReturnOrigin;
    836    TEEC_Context * context;
    837 
    838    context = (TEEC_Context *)session->imp._pContext;
    839    memset(&sCommand, 0, sizeof(SCHANNEL6_COMMAND));
    840 
    841    sCommand.sHeader.nMessageType = SCX_INVOKE_CLIENT_COMMAND;
    842    sCommand.sHeader.nMessageSize = (sizeof(SCHANNEL6_INVOKE_CLIENT_COMMAND_COMMAND) - sizeof(SCHANNEL6_COMMAND_HEADER))/sizeof(uint32_t);
    843    sCommand.sInvokeClientCommand.nClientCommandIdentifier = commandID;
    844     if (timeLimit == NULL)
    845    {
    846       sCommand.sInvokeClientCommand.sTimeout = SCTIME_INFINITE;
    847    }
    848    else
    849    {
    850       sCommand.sInvokeClientCommand.sTimeout = *(uint64_t*)timeLimit;
    851    }
    852    sCommand.sInvokeClientCommand.hClientSession     = session->imp._hClientSession;
    853    sCommand.sInvokeClientCommand.nCancellationID = (uint32_t)operation; // used for TEEC_RequestCancellation
    854 
    855    if (operation != NULL)
    856    {
    857       operation->imp._pContext = session->imp._pContext;
    858       operation->imp._hSession = session->imp._hClientSession;
    859       operation->started = 1;
    860    }
    861 
    862    nError = scxExchangeMessage(context, &sCommand, &sAnswer, operation);
    863 
    864    if (operation != NULL)
    865    {
    866       operation->started = 2;
    867       operation->imp._hSession = S_HANDLE_NULL;
    868       operation->imp._pContext = NULL;
    869    }
    870 
    871    if (nError != TEEC_SUCCESS)
    872    {
    873       nReturnOrigin = TEEC_ORIGIN_COMMS;
    874    }
    875    else
    876    {
    877        nError = sAnswer.sInvokeClientCommand.nErrorCode;
    878        nReturnOrigin = sAnswer.sInvokeClientCommand.nReturnOrigin;
    879     }
    880 
    881    if (returnOrigin != NULL) *returnOrigin = nReturnOrigin;
    882 
    883    return nError;
    884 
    885 }
    886 
    887 //-----------------------------------------------------------------------------------------------------
    888 /*
    889  * Retrieves information about the implementation
    890  */
    891 void TEEC_GetImplementationInfo(
    892                                 TEEC_Context*            context,
    893                                 TEEC_ImplementationInfo* description)
    894 {
    895    TRACE_INFO("TEEC_GetImplementationInfo");
    896 
    897    memset(description, 0, sizeof(TEEC_ImplementationInfo));
    898 
    899    strcpy(description->apiDescription, S_VERSION_STRING);
    900 
    901    if (context != NULL)
    902    {
    903       SCX_VERSION_INFORMATION_BUFFER sInfoBuffer;
    904       uint32_t nResult;
    905 
    906       nResult = ioctl((S_HANDLE)context->imp._hConnection, IOCTL_SCX_GET_DESCRIPTION, &sInfoBuffer);
    907       if (nResult != S_SUCCESS)
    908       {
    909          TRACE_ERROR("TEEC_GetImplementationInfo[0x%X]: ioctl returned error: 0x%x ( %d)\n",context, nResult, errno);
    910          return;
    911       }
    912 
    913       memcpy(description->commsDescription, sInfoBuffer.sDriverDescription, 64);
    914       description->commsDescription[64] = 0;
    915       memcpy(description->TEEDescription, sInfoBuffer.sSecureWorldDescription, 64);
    916       description->TEEDescription[64] = 0;
    917    }
    918 }
    919 
    920 void TEEC_GetImplementationLimits(
    921    TEEC_ImplementationLimits* limits)
    922 {
    923    memset(limits, 0, sizeof(TEEC_ImplementationLimits));
    924 
    925    /* A temp mem ref can not be mapped on more than 1Mb */
    926    limits->pageSize = SIZE_4KB;
    927    limits->tmprefMaxSize = SIZE_1MB;
    928    limits->sharedMemMaxSize = SIZE_1MB * 8;
    929  }
    930