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