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