• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
TRACE_ERROR(const char * format,...)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 
TRACE_WARNING(const char * format,...)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 
TRACE_INFO(const char * format,...)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 
scxYield(void)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  */
scxExchangeMessage(IN TEEC_Context * pContext,IN SCHANNEL6_COMMAND * pCommand,OUT SCHANNEL6_ANSWER * pAnswer,IN TEEC_Operation * pOperation)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 
scxAllocateSharedMemory(IN uint32_t nLength)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 
scxReleaseSharedMemory(IN void * pBuffer,IN uint32_t nLength)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 
scxGetCurrentTime(void)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  **/
TEEC_GetTimeLimit(TEEC_Context * sContext,uint32_t nTimeout,TEEC_TimeLimit * sTimeLimit)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 //-----------------------------------------------------------------------------------------------------
TEEC_InitializeContext(const char * pDeviceName,TEEC_Context * pContext)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 //-----------------------------------------------------------------------------------------------------
TEEC_FinalizeContext(TEEC_Context * pContext)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 //-----------------------------------------------------------------------------------------------------
TEEC_OpenSession(TEEC_Context * context,TEEC_Session * session,const TEEC_UUID * destination,uint32_t connectionMethod,void * connectionData,TEEC_Operation * operation,uint32_t * errorOrigin)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 //-----------------------------------------------------------------------------------------------------
TEEC_CloseSession(TEEC_Session * session)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 //-----------------------------------------------------------------------------------------------------
TEEC_InvokeCommand(TEEC_Session * session,uint32_t commandID,TEEC_Operation * operation,uint32_t * errorOrigin)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 */
TEEC_RegisterSharedMemory0(TEEC_Context * context,TEEC_SharedMemory * sharedMem)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 //-----------------------------------------------------------------------------------------------------
TEEC_RegisterSharedMemory(TEEC_Context * context,TEEC_SharedMemory * sharedMem)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 //-----------------------------------------------------------------------------------------------------
TEEC_AllocateSharedMemory(TEEC_Context * context,TEEC_SharedMemory * sharedMem)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 //-----------------------------------------------------------------------------------------------------
TEEC_ReleaseSharedMemory(TEEC_SharedMemory * sharedMem)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 //-----------------------------------------------------------------------------------------------------
TEEC_RequestCancellation(TEEC_Operation * operation)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 //-----------------------------------------------------------------------------------------------------
TEEC_ReadSignatureFile(void ** ppSignatureFile,uint32_t * pnSignatureFileLength)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 //-----------------------------------------------------------------------------------------------------
TEEC_OpenSessionEx(TEEC_Context * context,TEEC_Session * session,const TEEC_TimeLimit * timeLimit,const TEEC_UUID * destination,uint32_t connectionMethod,void * connectionData,TEEC_Operation * operation,uint32_t * returnOrigin)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 //-----------------------------------------------------------------------------------------------------
TEEC_InvokeCommandEx(TEEC_Session * session,const TEEC_TimeLimit * timeLimit,uint32_t commandID,TEEC_Operation * operation,uint32_t * returnOrigin)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  */
TEEC_GetImplementationInfo(TEEC_Context * context,TEEC_ImplementationInfo * description)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 
TEEC_GetImplementationLimits(TEEC_ImplementationLimits * limits)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