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 #if defined(ANDROID) 32 #include <stddef.h> 33 #endif 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 38 /* 39 * When porting to a new OS, insert here the appropriate include files 40 */ 41 #include <sys/stat.h> 42 #include <errno.h> 43 #include <sys/types.h> 44 #include <fcntl.h> 45 46 #if defined(LINUX) || defined(ANDROID) 47 #include <unistd.h> 48 #include <sys/resource.h> 49 50 51 #if defined(ANDROID) 52 /* fdatasync does not exist on Android */ 53 #define fdatasync fsync 54 #else 55 /* 56 * http://linux.die.net/man/2/fsync 57 * The function fdatasync seems to be absent of the header file 58 * in some distributions 59 */ 60 int fdatasync(int fd); 61 #endif /* ANDROID */ 62 #include <syslog.h> 63 #include <sys/types.h> 64 #include <sys/stat.h> 65 #include <pthread.h> 66 #include <semaphore.h> 67 #define PATH_SEPARATOR '/' 68 #endif /* LINUX || ANDROID */ 69 70 #ifdef WIN32 71 #include <windows.h> 72 #include <io.h> 73 #define PATH_SEPARATOR '\\' 74 #endif 75 76 #ifdef __SYMBIAN32__ 77 #include <unistd.h> 78 #include "os_symbian.h" 79 #define PATH_SEPARATOR '\\' 80 #endif 81 82 #include <stdarg.h> 83 #include <assert.h> 84 85 #include "service_delegation_protocol.h" 86 87 #include "s_version.h" 88 #include "s_error.h" 89 #include "tee_client_api.h" 90 91 /* You can define the preprocessor constant SUPPORT_DELEGATION_EXTENSION 92 if you want to pass extended options in a configuration file (option '-c'). 93 It is up to you to define the format of this configuration file and the 94 extended option in the source file delegation_client_extension.c. You can 95 use extended options, e.g., to control the name of each partition file. */ 96 #ifdef SUPPORT_DELEGATION_EXTENSION 97 #include "delegation_client_extension.h" 98 #endif 99 100 #ifdef TFSW_FDM_ANDROID 101 #include <android/log.h> 102 #endif 103 104 /*---------------------------------------------------------------------------- 105 * Design notes 106 * ============ 107 * 108 * This implementation of the delegation daemon supports the protocol 109 * specified in the Product Reference Manual ("Built-in Services Protocols Specification") 110 * 111 *----------------------------------------------------------------------------*/ 112 113 /*---------------------------------------------------------------------------- 114 * Defines and structures 115 *----------------------------------------------------------------------------*/ 116 #define ECHANGE_BUFFER_INSTRUCTIONS_NB 1000 117 118 #define DEFAULT_WORKSPACE_SIZE (128*1024) 119 120 /* A single shared memory block is used to contain the administrative data, the 121 instruction buffer and the workspace. The size of the instruction buffer is 122 fixed, but the size of workspace can be configured using the "-workspaceSize" 123 command-line option. */ 124 typedef struct 125 { 126 DELEGATION_ADMINISTRATIVE_DATA sAdministrativeData; 127 uint32_t sInstructions[ECHANGE_BUFFER_INSTRUCTIONS_NB]; 128 uint8_t sWorkspace[1/*g_nWorkspaceSize*/]; 129 } DELEGATION_EXCHANGE_BUFFER; 130 131 #ifdef SUPPORT_RPMB_PARTITION 132 typedef struct 133 { 134 uint8_t pDummy[196]; 135 uint8_t pMAC[32]; 136 uint8_t pData[256]; 137 uint8_t pNonce[16]; 138 uint32_t nMC; 139 uint16_t nAddr; 140 uint16_t nBlockCount; 141 uint16_t nResult; 142 uint16_t nReqOrResp; 143 } DELEGATION_RPMB_MESSAGE; 144 #endif 145 146 #define MD_VAR_NOT_USED(variable) do{(void)(variable);}while(0); 147 148 #define MD_INLINE __inline 149 150 /* ---------------------------------------------- 151 Traces and logs 152 153 On Linux, traces and logs go either to the console (stderr) or to the syslog. 154 When the daemon is started, the logs go to the console. Once and if the daemon 155 is detached, the logs go to syslog. 156 157 On other systems, traces and logs go systematically to stderr 158 159 The difference between traces and logs is that traces are compiled out 160 in release builds whereas logs are visible to the customer. 161 162 -----------------------------------------------*/ 163 #if defined(LINUX) || (defined ANDROID) 164 165 static bool bDetached = false; 166 167 static MD_INLINE void LogError(const char* format, ...) 168 { 169 va_list ap; 170 va_start(ap, format); 171 if (bDetached) 172 { 173 vsyslog(LOG_ERR, format, ap); 174 } 175 else 176 { 177 #ifdef TFSW_FDM_ANDROID 178 __android_log_vprint(ANDROID_LOG_ERROR , "TF Daemon", format, ap); 179 #else 180 fprintf(stderr, "ERROR: "); 181 vfprintf(stderr, format, ap); 182 fprintf(stderr, "\n"); 183 #endif 184 } 185 va_end(ap); 186 } 187 188 static MD_INLINE void LogWarning(const char* format, ...) 189 { 190 va_list ap; 191 va_start(ap, format); 192 if (bDetached) 193 { 194 vsyslog(LOG_WARNING, format, ap); 195 } 196 else 197 { 198 #ifdef TFSW_FDM_ANDROID 199 __android_log_vprint(ANDROID_LOG_WARN , "TF Daemon", format, ap); 200 #else 201 fprintf(stderr, "WARNING: "); 202 vfprintf(stderr, format, ap); 203 fprintf(stderr, "\n"); 204 #endif 205 } 206 va_end(ap); 207 } 208 static MD_INLINE void LogInfo(const char* format, ...) 209 { 210 va_list ap; 211 va_start(ap, format); 212 if (bDetached) 213 { 214 vsyslog(LOG_INFO, format, ap); 215 } 216 else 217 { 218 #ifdef TFSW_FDM_ANDROID 219 __android_log_vprint(ANDROID_LOG_INFO , "TF Daemon", format, ap); 220 #else 221 vfprintf(stderr, format, ap); 222 fprintf(stderr, "\n"); 223 #endif 224 } 225 va_end(ap); 226 } 227 228 static MD_INLINE void TRACE_ERROR(const char* format, ...) 229 { 230 #ifndef NDEBUG 231 va_list ap; 232 va_start(ap, format); 233 if (bDetached) 234 { 235 vsyslog(LOG_ERR, format, ap); 236 } 237 else 238 { 239 #ifdef TFSW_FDM_ANDROID 240 __android_log_vprint(ANDROID_LOG_ERROR , "TF Daemon", format, ap); 241 #else 242 fprintf(stderr, "TRACE: ERROR: "); 243 vfprintf(stderr, format, ap); 244 fprintf(stderr, "\n"); 245 #endif 246 } 247 va_end(ap); 248 #else 249 MD_VAR_NOT_USED(format); 250 #endif /* NDEBUG */ 251 } 252 253 static MD_INLINE void TRACE_WARNING(const char* format, ...) 254 { 255 #ifndef NDEBUG 256 va_list ap; 257 va_start(ap, format); 258 if (bDetached) 259 { 260 vsyslog(LOG_WARNING, format, ap); 261 } 262 else 263 { 264 #ifdef TFSW_FDM_ANDROID 265 __android_log_vprint(ANDROID_LOG_WARN , "TF Daemon", format, ap); 266 #else 267 fprintf(stderr, "TRACE: WARNING: "); 268 vfprintf(stderr, format, ap); 269 fprintf(stderr, "\n"); 270 #endif 271 } 272 va_end(ap); 273 #else 274 MD_VAR_NOT_USED(format); 275 #endif /* NDEBUG */ 276 } 277 278 static MD_INLINE void TRACE_INFO(const char* format, ...) 279 { 280 #ifndef NDEBUG 281 va_list ap; 282 va_start(ap, format); 283 if (bDetached) 284 { 285 vsyslog(LOG_DEBUG, format, ap); 286 } 287 else 288 { 289 #ifdef TFSW_FDM_ANDROID 290 __android_log_vprint(ANDROID_LOG_INFO , "TF Daemon", format, ap); 291 #else 292 fprintf(stderr, "TRACE: "); 293 vfprintf(stderr, format, ap); 294 fprintf(stderr, "\n"); 295 #endif 296 } 297 va_end(ap); 298 #else 299 MD_VAR_NOT_USED(format); 300 #endif /* NDEBUG */ 301 } 302 #elif defined __SYMBIAN32__ 303 /* defined in os_symbian.h */ 304 305 #elif defined NO_LOG_NO_TRACE 306 static MD_INLINE void LogError(const char* format, ...) 307 { 308 MD_VAR_NOT_USED(format); 309 } 310 static MD_INLINE void LogWarning(const char* format, ...) 311 { 312 MD_VAR_NOT_USED(format); 313 } 314 static MD_INLINE void LogInfo(const char* format, ...) 315 { 316 MD_VAR_NOT_USED(format); 317 } 318 319 static MD_INLINE void TRACE_ERROR(const char* format, ...) 320 { 321 MD_VAR_NOT_USED(format); 322 } 323 324 static MD_INLINE void TRACE_WARNING(const char* format, ...) 325 { 326 MD_VAR_NOT_USED(format); 327 } 328 329 static MD_INLINE void TRACE_INFO(const char* format, ...) 330 { 331 MD_VAR_NOT_USED(format); 332 } 333 334 #else 335 /* !defined(LINUX) || !defined(ANDROID) */ 336 337 static MD_INLINE void LogError(const char* format, ...) 338 { 339 va_list ap; 340 va_start(ap, format); 341 fprintf(stderr, "ERROR: "); 342 vfprintf(stderr, format, ap); 343 fprintf(stderr, "\n"); 344 va_end(ap); 345 } 346 static MD_INLINE void LogWarning(const char* format, ...) 347 { 348 va_list ap; 349 va_start(ap, format); 350 fprintf(stderr, "WARNING: "); 351 vfprintf(stderr, format, ap); 352 fprintf(stderr, "\n"); 353 va_end(ap); 354 } 355 static MD_INLINE void LogInfo(const char* format, ...) 356 { 357 va_list ap; 358 va_start(ap, format); 359 vfprintf(stderr, format, ap); 360 fprintf(stderr, "\n"); 361 va_end(ap); 362 } 363 364 static MD_INLINE void TRACE_ERROR(const char* format, ...) 365 { 366 #ifndef NDEBUG 367 va_list ap; 368 va_start(ap, format); 369 fprintf(stderr, "TRACE: ERROR: "); 370 vfprintf(stderr, format, ap); 371 fprintf(stderr, "\n"); 372 va_end(ap); 373 #else 374 MD_VAR_NOT_USED(format); 375 #endif /* NDEBUG */ 376 } 377 378 static MD_INLINE void TRACE_WARNING(const char* format, ...) 379 { 380 #ifndef NDEBUG 381 va_list ap; 382 va_start(ap, format); 383 fprintf(stderr, "TRACE: WARNING: "); 384 vfprintf(stderr, format, ap); 385 fprintf(stderr, "\n"); 386 va_end(ap); 387 #else 388 MD_VAR_NOT_USED(format); 389 #endif /* NDEBUG */ 390 } 391 392 static MD_INLINE void TRACE_INFO(const char* format, ...) 393 { 394 #ifndef NDEBUG 395 va_list ap; 396 va_start(ap, format); 397 fprintf(stderr, "TRACE: "); 398 vfprintf(stderr, format, ap); 399 fprintf(stderr, "\n"); 400 va_end(ap); 401 #else 402 MD_VAR_NOT_USED(format); 403 #endif /* NDEBUG */ 404 } 405 #endif /* defined(LINUX) || defined(ANDROID) */ 406 407 /*---------------------------------------------------------------------------- 408 * Globals 409 *----------------------------------------------------------------------------*/ 410 /* The sector size */ 411 static uint32_t g_nSectorSize; 412 413 /* The workspace size */ 414 static uint32_t g_nWorkspaceSize = DEFAULT_WORKSPACE_SIZE; 415 416 /* UUID of the delegation service */ 417 static const TEEC_UUID g_sServiceId = SERVICE_DELEGATION_UUID; 418 419 /* pWorkspaceBuffer points to the workspace buffer shared with the secure 420 world to transfer the sectors in the READ and WRITE instructions */ 421 static uint8_t* g_pWorkspaceBuffer; 422 static DELEGATION_EXCHANGE_BUFFER * g_pExchangeBuffer; 423 TEEC_SharedMemory sExchangeSharedMem; 424 /* 425 The absolute path name for each of the 16 possible partitions. 426 */ 427 static char* g_pPartitionNames[16]; 428 429 /* The file context for each of the 16 possible partitions. An entry 430 in this array is NULL if the corresponding partition is currently not opened 431 */ 432 static FILE* g_pPartitionFiles[16]; 433 434 /*---------------------------------------------------------------------------- 435 * Utilities functions 436 *----------------------------------------------------------------------------*/ 437 static void printUsage(void) 438 { 439 LogInfo("usage : tf_daemon [options]"); 440 LogInfo("where [options] are:"); 441 LogInfo("-h --help Display help."); 442 #ifdef SUPPORT_DELEGATION_EXTENSION 443 LogInfo("-c <conf> Configuration file path."); 444 #else 445 /* If the compilation parameter SUPPORT_DELEGATION_EXTENSION is not set, each 446 partition is stored as a file within the base dir */ 447 LogInfo("-storageDir <baseDir> Set the directory where the data will be stored; this directory"); 448 LogInfo(" must be writable and executable (this parameter is mandatory)"); 449 #endif 450 LogInfo("-d Turns on debug mode. If not specified, the daemon will fork itself"); 451 LogInfo(" and get detached from the console."); 452 #ifndef SUPPORT_DELEGATION_EXTENSION 453 LogInfo("-workspaceSize <integer> Set the size in bytes of the workspace. Must be greater or equal to 8 sectors."); 454 LogInfo(" (default is 128KB)"); 455 #endif 456 } 457 458 static TEEC_Result errno2serror(void) 459 { 460 switch (errno) 461 { 462 case EINVAL: 463 return S_ERROR_BAD_PARAMETERS; 464 case EMFILE: 465 return S_ERROR_NO_MORE_HANDLES; 466 case ENOENT: 467 return S_ERROR_ITEM_NOT_FOUND; 468 case EEXIST: 469 return S_ERROR_ITEM_EXISTS; 470 case ENOSPC: 471 return S_ERROR_STORAGE_NO_SPACE; 472 case ENOMEM: 473 return S_ERROR_OUT_OF_MEMORY; 474 case EBADF: 475 case EACCES: 476 default: 477 return S_ERROR_STORAGE_UNREACHABLE; 478 } 479 } 480 481 /* 482 * Check if the directory in parameter exists with Read/Write access 483 * Return 0 in case of success and 1 otherwise. 484 */ 485 int static_checkStorageDirAndAccessRights(char * directoryName) 486 { 487 #ifdef __SYMBIAN32__ 488 /* it looks like stat is not working properly on Symbian 489 Create and remove dummy file to check access rights */ 490 FILE *stream; 491 char *checkAccess = NULL; 492 493 if (directoryName == NULL) 494 { 495 LogError("Directory Name is NULL"); 496 return 1; 497 } 498 499 checkAccess = malloc(strlen(directoryName)+1/* \ */ +1 /* a */ + 1 /* 0 */); 500 if (!checkAccess) 501 { 502 LogError("storageDir '%s' allocation error", directoryName); 503 return 1; 504 } 505 sprintf(checkAccess,"%s\\a",directoryName); 506 stream = fopen(checkAccess, "w+b"); 507 if (!stream) 508 { 509 LogError("storageDir '%s' is incorrect or cannot be reached", directoryName); 510 return 1; 511 } 512 fclose(stream); 513 unlink(checkAccess); 514 #else 515 /* Non-Symbian OS: use stat */ 516 struct stat buf; 517 int result = 0; 518 519 if (directoryName == NULL) 520 { 521 LogError("Directory Name is NULL"); 522 return 1; 523 } 524 525 result = stat(directoryName, &buf); 526 if (result == 0) 527 { 528 /* Storage dir exists. Check access rights */ 529 #if defined(LINUX) || (defined ANDROID) 530 if ((buf.st_mode & (S_IXUSR | S_IWUSR)) != (S_IXUSR | S_IWUSR)) 531 { 532 LogError("storageDir '%s' does not have read-write access", directoryName); 533 return 1; 534 } 535 #endif 536 } 537 else if (errno == ENOENT) 538 { 539 LogError("storageDir '%s' does not exist", directoryName); 540 return 1; 541 } 542 else 543 { 544 /* Another error */ 545 LogError("storageDir '%s' is incorrect or cannot be reached", directoryName); 546 return 1; 547 } 548 #endif 549 return 0; 550 } 551 552 553 554 /*---------------------------------------------------------------------------- 555 * Instructions 556 *----------------------------------------------------------------------------*/ 557 558 /** 559 * This function executes the DESTROY_PARTITION instruction 560 * 561 * @param nPartitionID: the partition identifier 562 **/ 563 static TEEC_Result partitionDestroy(uint32_t nPartitionID) 564 { 565 TEEC_Result nError = S_SUCCESS; 566 567 if (g_pPartitionFiles[nPartitionID] != NULL) 568 { 569 /* The partition must not be currently opened */ 570 LogError("g_pPartitionFiles not NULL"); 571 return S_ERROR_BAD_STATE; 572 } 573 574 /* Try to erase the file */ 575 #if defined(LINUX) || (defined ANDROID) || defined (__SYMBIAN32__) 576 if (unlink(g_pPartitionNames[nPartitionID]) != 0) 577 #endif 578 #ifdef WIN32 579 if (_unlink(g_pPartitionNames[nPartitionID]) != 0) 580 #endif 581 { 582 /* File in use or OS didn't allow the operation */ 583 nError = errno2serror(); 584 } 585 586 return nError; 587 } 588 589 /** 590 * This function executes the CREATE_PARTITION instruction. When successful, 591 * it fills the g_pPartitionFiles[nPartitionID] slot. 592 * 593 * @param nPartitionID: the partition identifier 594 **/ 595 static TEEC_Result partitionCreate(uint32_t nPartitionID) 596 { 597 uint32_t nError = S_SUCCESS; 598 599 if (g_pPartitionFiles[nPartitionID] != NULL) 600 { 601 /* The partition is already opened */ 602 LogError("g_pPartitionFiles not NULL"); 603 return S_ERROR_BAD_STATE; 604 } 605 606 /* Create the file unconditionnally */ 607 LogInfo("Create storage file \"%s\"", g_pPartitionNames[nPartitionID]); 608 g_pPartitionFiles[nPartitionID] = fopen(g_pPartitionNames[nPartitionID], "w+b"); 609 610 if (g_pPartitionFiles[nPartitionID] == NULL) 611 { 612 LogError("Cannot create storage file \"%s\"", g_pPartitionNames[nPartitionID]); 613 nError = errno2serror(); 614 return nError; 615 } 616 617 return nError; 618 } 619 620 /** 621 * This function executes the OPEN_PARTITION instruction. When successful, 622 * it fills the g_pPartitionFiles[nPartitionID] slot and writes the partition 623 * size in hResultEncoder 624 * 625 * @param nPartitionID: the partition identifier 626 * @param pnPartitionSize: filled with the number of sectors in the partition 627 **/ 628 static TEEC_Result partitionOpen(uint32_t nPartitionID, uint32_t* pnPartitionSize) 629 { 630 uint32_t nError = S_SUCCESS; 631 632 if (g_pPartitionFiles[nPartitionID] != NULL) 633 { 634 /* No partition must be currently opened in the session */ 635 LogError("g_pPartitionFiles not NULL"); 636 return S_ERROR_BAD_STATE; 637 } 638 639 /* Open the file */ 640 g_pPartitionFiles[nPartitionID] = fopen(g_pPartitionNames[nPartitionID], "r+b"); 641 if (g_pPartitionFiles[nPartitionID] == NULL) 642 { 643 if (errno == ENOENT) 644 { 645 /* File does not exist */ 646 LogError("Storage file \"%s\" does not exist", g_pPartitionNames[nPartitionID]); 647 nError = S_ERROR_ITEM_NOT_FOUND; 648 return nError; 649 } 650 else 651 { 652 LogError("cannot open storage file \"%s\"", g_pPartitionNames[nPartitionID]); 653 nError = errno2serror(); 654 return nError; 655 } 656 } 657 /* Determine the current number of sectors */ 658 fseek(g_pPartitionFiles[nPartitionID], 0L, SEEK_END); 659 *pnPartitionSize = ftell(g_pPartitionFiles[nPartitionID]) / g_nSectorSize; 660 661 LogInfo("storage file \"%s\" successfully opened (size = %d KB (%d bytes))", 662 g_pPartitionNames[nPartitionID], 663 ((*pnPartitionSize) * g_nSectorSize) / 1024, 664 ((*pnPartitionSize) * g_nSectorSize)); 665 666 return nError; 667 } 668 669 670 /** 671 * This function executes the CLOSE_PARTITION instruction. 672 * It closes the partition file. 673 * 674 * @param nPartitionID: the partition identifier 675 **/ 676 static TEEC_Result partitionClose(uint32_t nPartitionID) 677 { 678 if (g_pPartitionFiles[nPartitionID] == NULL) 679 { 680 /* The partition is currently not opened */ 681 return S_ERROR_BAD_STATE; 682 } 683 fclose(g_pPartitionFiles[nPartitionID]); 684 g_pPartitionFiles[nPartitionID] = NULL; 685 return S_SUCCESS; 686 } 687 688 /** 689 * This function executes the READ instruction. 690 * 691 * @param nPartitionID: the partition identifier 692 * @param nSectorIndex: the index of the sector to read 693 * @param nWorkspaceOffset: the offset in the workspace where the sector must be written 694 **/ 695 static TEEC_Result partitionRead(uint32_t nPartitionID, uint32_t nSectorIndex, uint32_t nWorkspaceOffset) 696 { 697 FILE* pFile; 698 699 TRACE_INFO(">Partition %1X: read sector 0x%08X into workspace at offset 0x%08X", 700 nPartitionID, nSectorIndex, nWorkspaceOffset); 701 702 pFile = g_pPartitionFiles[nPartitionID]; 703 704 if (pFile == NULL) 705 { 706 /* The partition is not opened */ 707 return S_ERROR_BAD_STATE; 708 } 709 710 if (fseek(pFile, nSectorIndex*g_nSectorSize, SEEK_SET) != 0) 711 { 712 LogError("fseek error: %s", strerror(errno)); 713 return errno2serror(); 714 } 715 716 if (fread(g_pWorkspaceBuffer + nWorkspaceOffset, 717 g_nSectorSize, 1, 718 pFile) != 1) 719 { 720 if (feof(pFile)) 721 { 722 LogError("fread error: End-Of-File detected"); 723 return S_ERROR_ITEM_NOT_FOUND; 724 } 725 LogError("fread error: %s", strerror(errno)); 726 return errno2serror(); 727 } 728 729 return S_SUCCESS; 730 } 731 732 #ifdef SUPPORT_RPMB_PARTITION 733 static TEEC_Result rpmbRead(DELEGATION_RPMB_INSTRUCTION *pInstruction) 734 { 735 DELEGATION_RPMB_MESSAGE* pMessages; 736 uint32_t nNbMsg, nIndex; 737 738 nNbMsg = g_nSectorSize >> 8; 739 pMessages = (DELEGATION_RPMB_MESSAGE*)malloc(nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE)); 740 if (pMessages == NULL) 741 { 742 return S_ERROR_OUT_OF_MEMORY; 743 } 744 memset(pMessages,0,nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE)); 745 746 for (nIndex=0;nIndex<nNbMsg;nIndex++) 747 { 748 memcpy(pMessages[nIndex].pNonce , pInstruction->pNonce, 16); 749 pMessages[nIndex].nAddr = pInstruction->nAddr; 750 pMessages[nIndex].nBlockCount = pInstruction->nBlockCount; 751 pMessages[nIndex].nReqOrResp = 0x0004; 752 } 753 memcpy(pMessages[nNbMsg-1].pMAC,pInstruction->nMAC,32); 754 755 /* TODO: send to the RPMB driver */ 756 757 memcpy(pInstruction->pNonce,pMessages[0].pNonce , 16); 758 pInstruction->nAddr = pMessages[0].nAddr; 759 pInstruction->nBlockCount = pMessages[0].nBlockCount; 760 for (nIndex=0;nIndex<nNbMsg;nIndex++) 761 { 762 memcpy(g_pWorkspaceBuffer + pInstruction->nWorkspaceOffset[nIndex],pMessages[nIndex].pData,256); 763 } 764 memcpy(pInstruction->nMAC, pMessages[nNbMsg-1].pMAC,32); 765 pInstruction->nResult=pMessages[nNbMsg-1].nResult; 766 767 free(pMessages); 768 769 return S_SUCCESS; 770 } 771 #endif 772 /** 773 * This function executes the WRITE instruction. 774 * 775 * @param nPartitionID: the partition identifier 776 * @param nSectorIndex: the index of the sector to read 777 * @param nWorkspaceOffset: the offset in the workspace where the sector must be read 778 **/ 779 static TEEC_Result partitionWrite(uint32_t nPartitionID, uint32_t nSectorIndex, uint32_t nWorkspaceOffset) 780 { 781 FILE* pFile; 782 783 TRACE_INFO(">Partition %1X: write sector 0x%X from workspace at offset 0x%X", 784 nPartitionID, nSectorIndex, nWorkspaceOffset); 785 786 pFile = g_pPartitionFiles[nPartitionID]; 787 788 if (pFile == NULL) 789 { 790 /* The partition is not opened */ 791 return S_ERROR_BAD_STATE; 792 } 793 794 if (fseek(pFile, nSectorIndex*g_nSectorSize, SEEK_SET) != 0) 795 { 796 LogError("fseek error: %s", strerror(errno)); 797 return errno2serror(); 798 } 799 800 if (fwrite(g_pWorkspaceBuffer + nWorkspaceOffset, 801 g_nSectorSize, 1, 802 pFile) != 1) 803 { 804 LogError("fread error: %s", strerror(errno)); 805 return errno2serror(); 806 } 807 return S_SUCCESS; 808 } 809 810 #ifdef SUPPORT_RPMB_PARTITION 811 static TEEC_Result rpmbWrite(DELEGATION_RPMB_INSTRUCTION *pInstruction) 812 { 813 DELEGATION_RPMB_MESSAGE* pMessages; 814 uint32_t nNbMsg, nIndex; 815 816 nNbMsg = g_nSectorSize >> 8; 817 pMessages = (DELEGATION_RPMB_MESSAGE*)malloc(nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE)); 818 if (pMessages == NULL) 819 { 820 return S_ERROR_OUT_OF_MEMORY; 821 } 822 memset(pMessages,0,nNbMsg * sizeof(DELEGATION_RPMB_MESSAGE)); 823 824 for (nIndex=0;nIndex<nNbMsg;nIndex++) 825 { 826 memcpy(pMessages[nIndex].pData,g_pWorkspaceBuffer + pInstruction->nWorkspaceOffset[nIndex],256); 827 pMessages[nIndex].nMC = pInstruction->nMC; 828 pMessages[nIndex].nAddr = pInstruction->nAddr; 829 pMessages[nIndex].nBlockCount = pInstruction->nBlockCount; 830 pMessages[nIndex].nReqOrResp = 0x0003; 831 } 832 memcpy(pMessages[nNbMsg-1].pMAC,pInstruction->nMAC,32); 833 834 /* TODO: send to the RPMB driver */ 835 836 pInstruction->nAddr = pMessages[0].nAddr; 837 pInstruction->nMC = pMessages[0].nMC; 838 memcpy(pInstruction->nMAC, pMessages[nNbMsg-1].pMAC,32); 839 pInstruction->nResult=pMessages[nNbMsg-1].nResult; 840 841 free(pMessages); 842 843 return S_SUCCESS; 844 } 845 #endif 846 /** 847 * This function executes the SET_SIZE instruction. 848 * 849 * @param nPartitionID: the partition identifier 850 * @param nNewSectorCount: the new sector count 851 **/ 852 static TEEC_Result partitionSetSize(uint32_t nPartitionID, uint32_t nNewSectorCount) 853 { 854 FILE* pFile; 855 uint32_t nCurrentSectorCount; 856 857 pFile = g_pPartitionFiles[nPartitionID]; 858 859 if (pFile==NULL) 860 { 861 /* The partition is not opened */ 862 return S_ERROR_BAD_STATE; 863 } 864 865 /* Determine the current size of the partition */ 866 if (fseek(pFile, 0, SEEK_END) != 0) 867 { 868 LogError("fseek error: %s", strerror(errno)); 869 return errno2serror(); 870 } 871 nCurrentSectorCount = ftell(pFile) / g_nSectorSize; 872 873 if (nNewSectorCount > nCurrentSectorCount) 874 { 875 uint32_t nAddedBytesCount; 876 /* Enlarge the partition file. Make sure we actually write 877 some non-zero data into the new sectors. Otherwise, some file-system 878 might not really reserve the storage space but use a 879 sparse representation. In this case, a subsequent write instruction 880 could fail due to out-of-space, which we want to avoid. */ 881 nAddedBytesCount = (nNewSectorCount-nCurrentSectorCount)*g_nSectorSize; 882 while (nAddedBytesCount) 883 { 884 if (fputc(0xA5, pFile)!=0xA5) 885 { 886 return errno2serror(); 887 } 888 nAddedBytesCount--; 889 } 890 } 891 else if (nNewSectorCount < nCurrentSectorCount) 892 { 893 int result = 0; 894 /* Truncate the partition file */ 895 #if defined(LINUX) || (defined ANDROID) 896 result = ftruncate(fileno(pFile),nNewSectorCount * g_nSectorSize); 897 #endif 898 #if defined (__SYMBIAN32__) 899 LogError("No truncate available in Symbian C API"); 900 #endif 901 #ifdef WIN32 902 result = _chsize(_fileno(pFile),nNewSectorCount * g_nSectorSize); 903 #endif 904 if (result) 905 { 906 return errno2serror(); 907 } 908 } 909 return S_SUCCESS; 910 } 911 912 /** 913 * This function executes the SYNC instruction. 914 * 915 * @param pPartitionID: the partition identifier 916 **/ 917 static TEEC_Result partitionSync(uint32_t nPartitionID) 918 { 919 TEEC_Result nError = S_SUCCESS; 920 int result; 921 922 FILE* pFile = g_pPartitionFiles[nPartitionID]; 923 924 if (pFile == NULL) 925 { 926 /* The partition is not currently opened */ 927 return S_ERROR_BAD_STATE; 928 } 929 930 /* First make sure that the data in the stdio buffers 931 is flushed to the file descriptor */ 932 result=fflush(pFile); 933 if (result) 934 { 935 nError=errno2serror(); 936 goto end; 937 } 938 /* Then synchronize the file descriptor with the file-system */ 939 940 #if defined(LINUX) || (defined ANDROID) 941 result=fdatasync(fileno(pFile)); 942 #endif 943 #if defined (__SYMBIAN32__) 944 result=fsync(fileno(pFile)); 945 #endif 946 #ifdef WIN32 947 result=_commit(_fileno(pFile)); 948 #endif 949 if (result) 950 { 951 nError=errno2serror(); 952 } 953 954 end: 955 return nError; 956 } 957 958 /** 959 * This function executes the NOTIFY instruction. 960 * 961 * @param pMessage the message string 962 * @param nMessageType the type of messages 963 **/ 964 static void notify(const wchar_t* pMessage, uint32_t nMessageType) 965 { 966 switch (nMessageType) 967 { 968 case DELEGATION_NOTIFY_TYPE_ERROR: 969 LogError("%ls", pMessage); 970 break; 971 case DELEGATION_NOTIFY_TYPE_WARNING: 972 LogWarning("%ls", pMessage); 973 break; 974 case DELEGATION_NOTIFY_TYPE_DEBUG: 975 LogInfo("DEBUG: %ls", pMessage); 976 break; 977 case DELEGATION_NOTIFY_TYPE_INFO: 978 default: 979 LogInfo("%ls", pMessage); 980 break; 981 } 982 } 983 984 /*---------------------------------------------------------------------------- 985 * Session main function 986 *----------------------------------------------------------------------------*/ 987 988 /* 989 * This function runs a session opened on the delegation service. It fetches 990 * instructions and execute them in a loop. It never returns, but may call 991 * exit when instructed to shutdown by the service 992 */ 993 static int runSession(TEEC_Context* pContext, TEEC_Session* pSession, TEEC_Operation* pOperation) 994 { 995 memset(&g_pExchangeBuffer->sAdministrativeData, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData)); 996 997 while (true) 998 { 999 S_RESULT nError; 1000 TEEC_Result nTeeError; 1001 uint32_t nInstructionsIndex; 1002 uint32_t nInstructionsBufferSize = sizeof(g_pExchangeBuffer->sInstructions); 1003 1004 pOperation->paramTypes = TEEC_PARAM_TYPES( 1005 TEEC_MEMREF_PARTIAL_INPUT, 1006 TEEC_MEMREF_PARTIAL_OUTPUT, 1007 TEEC_MEMREF_PARTIAL_INOUT, 1008 TEEC_NONE); 1009 pOperation->params[0].memref.parent = &sExchangeSharedMem; 1010 pOperation->params[0].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sAdministrativeData); 1011 pOperation->params[0].memref.size = sizeof(g_pExchangeBuffer->sAdministrativeData); 1012 1013 pOperation->params[1].memref.parent = &sExchangeSharedMem; 1014 pOperation->params[1].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sInstructions); 1015 pOperation->params[1].memref.size = sizeof(g_pExchangeBuffer->sInstructions); 1016 1017 pOperation->params[2].memref.parent = &sExchangeSharedMem; 1018 pOperation->params[2].memref.offset = offsetof(DELEGATION_EXCHANGE_BUFFER, sWorkspace); 1019 pOperation->params[2].memref.size = g_nWorkspaceSize; 1020 1021 nTeeError = TEEC_InvokeCommand(pSession, 1022 SERVICE_DELEGATION_GET_INSTRUCTIONS, /* commandID */ 1023 pOperation, /* IN OUT operation */ 1024 NULL /* OUT errorOrigin, optional */ 1025 ); 1026 1027 if (nTeeError != TEEC_SUCCESS) 1028 { 1029 LogError("TEEC_InvokeCommand error: 0x%08X", nTeeError); 1030 LogError("Daemon exits"); 1031 exit(2); 1032 } 1033 1034 if (pOperation->params[1].tmpref.size > nInstructionsBufferSize) 1035 { 1036 /* Should not happen, probably an error from the service */ 1037 pOperation->params[1].tmpref.size = 0; 1038 } 1039 1040 /* Reset the operation results */ 1041 nError = TEEC_SUCCESS; 1042 g_pExchangeBuffer->sAdministrativeData.nSyncExecuted = 0; 1043 memset(g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates)); 1044 memset(g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes, 0x00, sizeof(g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes)); 1045 1046 /* Execute the instructions */ 1047 nInstructionsIndex = 0; 1048 nInstructionsBufferSize = pOperation->params[1].tmpref.size; 1049 while (true) 1050 { 1051 DELEGATION_INSTRUCTION * pInstruction; 1052 uint32_t nInstructionID; 1053 pInstruction = (DELEGATION_INSTRUCTION *)(&g_pExchangeBuffer->sInstructions[nInstructionsIndex/4]); 1054 if (nInstructionsIndex + 4 <= nInstructionsBufferSize) 1055 { 1056 nInstructionID = pInstruction->sGeneric.nInstructionID; 1057 nInstructionsIndex+=4; 1058 } 1059 else 1060 { 1061 goto instruction_parse_end; 1062 } 1063 if ((nInstructionID & 0x0F) == 0) 1064 { 1065 /* Partition-independent instruction */ 1066 switch (nInstructionID) 1067 { 1068 case DELEGATION_INSTRUCTION_SHUTDOWN: 1069 { 1070 exit(0); 1071 /* The implementation of the TF Client API will automatically 1072 destroy the context and release any associated resource */ 1073 } 1074 case DELEGATION_INSTRUCTION_NOTIFY: 1075 { 1076 /* Parse the instruction parameters */ 1077 wchar_t pMessage[100]; 1078 uint32_t nMessageType; 1079 uint32_t nMessageSize; 1080 memset(pMessage, 0, 100*sizeof(wchar_t)); 1081 1082 if (nInstructionsIndex + 8 <= nInstructionsBufferSize) 1083 { 1084 nMessageType = pInstruction->sNotify.nMessageType; 1085 nMessageSize = pInstruction->sNotify.nMessageSize; 1086 nInstructionsIndex+=8; 1087 } 1088 else 1089 { 1090 goto instruction_parse_end; 1091 } 1092 if (nMessageSize > (99)*sizeof(wchar_t)) 1093 { 1094 /* How to handle the error correctly in this case ? */ 1095 goto instruction_parse_end; 1096 } 1097 if (nInstructionsIndex + nMessageSize <= nInstructionsBufferSize) 1098 { 1099 memcpy(pMessage, &pInstruction->sNotify.nMessage[0], nMessageSize); 1100 nInstructionsIndex+=nMessageSize; 1101 } 1102 else 1103 { 1104 goto instruction_parse_end; 1105 } 1106 /* Align the pInstructionsIndex on 4 bytes */ 1107 nInstructionsIndex = (nInstructionsIndex+3)&~3; 1108 notify(pMessage, nMessageType); 1109 break; 1110 } 1111 default: 1112 LogError("Unknown instruction identifier: %02X", nInstructionID); 1113 nError = S_ERROR_BAD_PARAMETERS; 1114 break; 1115 } 1116 } 1117 else 1118 { 1119 /* Partition-specific instruction */ 1120 uint32_t nPartitionID = (nInstructionID & 0xF0) >> 4; 1121 if (g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates[nPartitionID] == S_SUCCESS) 1122 { 1123 /* Execute the instruction only if there is currently no 1124 error on the partition */ 1125 switch (nInstructionID & 0x0F) 1126 { 1127 case DELEGATION_INSTRUCTION_PARTITION_CREATE: 1128 nError = partitionCreate(nPartitionID); 1129 #ifdef SUPPORT_RPMB_PARTITION 1130 if (nPartitionID == RPMB_PARTITION_ID) 1131 { 1132 /* TODO: get the Write counter */ 1133 pInstruction->sAuthRW.nMC = 0; 1134 } 1135 #endif 1136 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError); 1137 break; 1138 case DELEGATION_INSTRUCTION_PARTITION_OPEN: 1139 { 1140 uint32_t nPartitionSize = 0; 1141 nError = partitionOpen(nPartitionID, &nPartitionSize); 1142 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d pSize=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nPartitionSize, nError); 1143 if (nError == S_SUCCESS) 1144 { 1145 g_pExchangeBuffer->sAdministrativeData.nPartitionOpenSizes[nPartitionID] = nPartitionSize; 1146 } 1147 #ifdef SUPPORT_RPMB_PARTITION 1148 if (nPartitionID == RPMB_PARTITION_ID) 1149 { 1150 /* TODO: get the Write counter */ 1151 pInstruction->sAuthRW.nMC = 0; 1152 } 1153 #endif 1154 break; 1155 } 1156 case DELEGATION_INSTRUCTION_PARTITION_READ: 1157 #ifdef SUPPORT_RPMB_PARTITION 1158 if (nPartitionID == RPMB_PARTITION_ID) 1159 { 1160 if (nInstructionsIndex + sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t) <= nInstructionsBufferSize) 1161 { 1162 nInstructionsIndex+=sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t); 1163 } 1164 else 1165 { 1166 goto instruction_parse_end; 1167 } 1168 nError = rpmbRead(&pInstruction->sAuthRW); 1169 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError); 1170 break; 1171 } 1172 else 1173 #endif 1174 { 1175 /* Parse parameters */ 1176 uint32_t nSectorID; 1177 uint32_t nWorkspaceOffset; 1178 if (nInstructionsIndex + 8 <= nInstructionsBufferSize) 1179 { 1180 nSectorID = pInstruction->sReadWrite.nSectorID; 1181 nWorkspaceOffset = pInstruction->sReadWrite.nWorkspaceOffset; 1182 nInstructionsIndex+=8; 1183 } 1184 else 1185 { 1186 goto instruction_parse_end; 1187 } 1188 nError = partitionRead(nPartitionID, nSectorID, nWorkspaceOffset); 1189 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d sid=%d woff=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nSectorID, nWorkspaceOffset, nError); 1190 break; 1191 } 1192 case DELEGATION_INSTRUCTION_PARTITION_WRITE: 1193 #ifdef SUPPORT_RPMB_PARTITION 1194 if (nPartitionID == RPMB_PARTITION_ID) 1195 { 1196 if (nInstructionsIndex + sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t) <= nInstructionsBufferSize) 1197 { 1198 nInstructionsIndex+=sizeof(DELEGATION_RPMB_INSTRUCTION)-sizeof(uint32_t); 1199 } 1200 else 1201 { 1202 goto instruction_parse_end; 1203 } 1204 nError = rpmbWrite(&pInstruction->sAuthRW); 1205 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError); 1206 break; 1207 } 1208 else 1209 #endif 1210 { 1211 /* Parse parameters */ 1212 uint32_t nSectorID; 1213 uint32_t nWorkspaceOffset; 1214 if (nInstructionsIndex + 8 <= nInstructionsBufferSize) 1215 { 1216 nSectorID = pInstruction->sReadWrite.nSectorID; 1217 nWorkspaceOffset = pInstruction->sReadWrite.nWorkspaceOffset; 1218 nInstructionsIndex+=8; 1219 } 1220 else 1221 { 1222 goto instruction_parse_end; 1223 } 1224 nError = partitionWrite(nPartitionID, nSectorID, nWorkspaceOffset); 1225 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d sid=%d woff=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nSectorID, nWorkspaceOffset, nError); 1226 break; 1227 } 1228 case DELEGATION_INSTRUCTION_PARTITION_SYNC: 1229 nError = partitionSync(nPartitionID); 1230 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError); 1231 if (nError == S_SUCCESS) 1232 { 1233 g_pExchangeBuffer->sAdministrativeData.nSyncExecuted++; 1234 } 1235 break; 1236 case DELEGATION_INSTRUCTION_PARTITION_SET_SIZE: 1237 { 1238 uint32_t nNewSize; 1239 if (nInstructionsIndex + 4 <= nInstructionsBufferSize) 1240 { 1241 nNewSize = pInstruction->sSetSize.nNewSize; 1242 nInstructionsIndex+=4; 1243 } 1244 else 1245 { 1246 goto instruction_parse_end; 1247 } 1248 nError = partitionSetSize(nPartitionID, nNewSize); 1249 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d nNewSize=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nNewSize, nError); 1250 break; 1251 } 1252 case DELEGATION_INSTRUCTION_PARTITION_CLOSE: 1253 nError = partitionClose(nPartitionID); 1254 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError); 1255 break; 1256 case DELEGATION_INSTRUCTION_PARTITION_DESTROY: 1257 nError = partitionDestroy(nPartitionID); 1258 TRACE_INFO("INSTRUCTION: ID=0x%x pid=%d err=%d", (nInstructionID & 0x0F), nPartitionID, nError); 1259 break; 1260 } 1261 g_pExchangeBuffer->sAdministrativeData.nPartitionErrorStates[nPartitionID] = nError; 1262 } 1263 } 1264 } 1265 instruction_parse_end: 1266 memset(pOperation, 0, sizeof(TEEC_Operation)); 1267 } 1268 } 1269 1270 /** 1271 * This function opens a new session to the delegation service. 1272 **/ 1273 static int createSession(TEEC_Context* pContext, TEEC_Session* pSession, TEEC_Operation* pOperation) 1274 { 1275 TEEC_Result nError; 1276 uint32_t nExchangeBufferSize; 1277 1278 memset(pOperation, 0, sizeof(TEEC_Operation)); 1279 pOperation->paramTypes = TEEC_PARAM_TYPES( 1280 TEEC_VALUE_OUTPUT, TEEC_NONE, TEEC_NONE, TEEC_NONE); 1281 nError = TEEC_OpenSession(pContext, 1282 pSession, /* OUT session */ 1283 &g_sServiceId, /* destination UUID */ 1284 TEEC_LOGIN_PRIVILEGED, /* connectionMethod */ 1285 NULL, /* connectionData */ 1286 pOperation, /* IN OUT operation */ 1287 NULL /* OUT errorOrigin, optional */ 1288 ); 1289 if (nError != TEEC_SUCCESS) 1290 { 1291 LogError("Error on TEEC_OpenSession : 0x%x", nError); 1292 exit(2); 1293 } 1294 /* Read sector size */ 1295 g_nSectorSize = pOperation->params[0].value.a; 1296 LogInfo("Sector Size: %d bytes", g_nSectorSize); 1297 1298 /* Check sector size */ 1299 if (!(g_nSectorSize == 512 || g_nSectorSize == 1024 || g_nSectorSize == 2048 || g_nSectorSize == 4096)) 1300 { 1301 LogError("Incorrect sector size: terminating..."); 1302 exit(2); 1303 } 1304 1305 /* Check workspace size */ 1306 if (g_nWorkspaceSize < 8 * g_nSectorSize) 1307 { 1308 g_nWorkspaceSize = 8 * g_nSectorSize; 1309 LogWarning("Workspace size too small, automatically set to %d bytes", g_nWorkspaceSize); 1310 } 1311 /* Compute the size of the exchange buffer */ 1312 nExchangeBufferSize = sizeof(DELEGATION_EXCHANGE_BUFFER)-1+g_nWorkspaceSize; 1313 g_pExchangeBuffer = (DELEGATION_EXCHANGE_BUFFER*)malloc(nExchangeBufferSize); 1314 if (g_pExchangeBuffer == NULL) 1315 { 1316 LogError("Cannot allocate exchange buffer of %d bytes", nExchangeBufferSize); 1317 LogError("Now exiting..."); 1318 exit(2); 1319 } 1320 g_pWorkspaceBuffer = (uint8_t*)g_pExchangeBuffer->sWorkspace; 1321 memset(g_pExchangeBuffer, 0x00, nExchangeBufferSize); 1322 memset(g_pPartitionFiles,0,16*sizeof(FILE*)); 1323 1324 /* Register the exchange buffer as a shared memory block */ 1325 sExchangeSharedMem.buffer = g_pExchangeBuffer; 1326 sExchangeSharedMem.size = nExchangeBufferSize; 1327 sExchangeSharedMem.flags = TEEC_MEM_INPUT | TEEC_MEM_OUTPUT; 1328 nError = TEEC_RegisterSharedMemory(pContext, &sExchangeSharedMem); 1329 if (nError != TEEC_SUCCESS) 1330 { 1331 LogError("Error on TEEC_RegisterSharedMemory : 0x%x", nError); 1332 free(g_pExchangeBuffer); 1333 exit(2); 1334 } 1335 LogInfo("Daemon now connected"); 1336 return 0; 1337 } 1338 1339 1340 /*---------------------------------------------------------------------------- 1341 * Main 1342 *----------------------------------------------------------------------------*/ 1343 1344 #ifdef INCLUDE_CLIENT_DELEGATION 1345 int delegation_main(int argc, char* argv[]) 1346 #else 1347 int main(int argc, char* argv[]) 1348 #endif 1349 { 1350 TEEC_Result nError; 1351 TEEC_Context sContext; 1352 TEEC_Session sSession; 1353 TEEC_Operation sOperation; 1354 bool debug = false; 1355 1356 #ifndef SUPPORT_DELEGATION_EXTENSION 1357 char * baseDir = NULL; 1358 1359 LogInfo("TFSW Normal-World Daemon"); 1360 #else 1361 LogInfo("TFSW Normal-World Ext Daemon"); 1362 #endif 1363 LogInfo(S_VERSION_STRING); 1364 LogInfo(""); 1365 1366 /* Skip program name */ 1367 argv++; 1368 argc--; 1369 1370 while (argc != 0) 1371 { 1372 if (strcmp(argv[0], "-d") == 0) 1373 { 1374 debug = true; 1375 } 1376 #ifdef SUPPORT_DELEGATION_EXTENSION 1377 else if (strcmp(argv[0], "-c") == 0) 1378 { 1379 int error; 1380 argc--; 1381 argv++; 1382 if (argc == 0) 1383 { 1384 printUsage(); 1385 return 1; 1386 } 1387 /* Note that the function parseCommandLineExtension can modify the 1388 content of the g_partitionNames array */ 1389 error = parseCommandLineExtension(argv[0], g_pPartitionNames); 1390 if ( error != 0 ) 1391 { 1392 printUsage(); 1393 return error; 1394 } 1395 } 1396 #else 1397 else if (strcmp(argv[0], "-storageDir") == 0) 1398 { 1399 uint32_t i = 0; 1400 argc--; 1401 argv++; 1402 if (argc == 0) 1403 { 1404 printUsage(); 1405 return 1; 1406 } 1407 if (baseDir != NULL) 1408 { 1409 LogError("Only one storage directory may be specified"); 1410 return 1; 1411 } 1412 baseDir = malloc(strlen(argv[0])+1); /* Zero-terminated string */ 1413 if (baseDir == NULL) 1414 { 1415 LogError("Out of memory"); 1416 return 2; 1417 } 1418 1419 strcpy(baseDir, argv[0]); 1420 1421 /* Set default names to the partitions */ 1422 for ( i=0; i<16 ;i++ ) 1423 { 1424 g_pPartitionNames[i] = NULL; 1425 g_pPartitionNames[i] = malloc(strlen(baseDir) + 1 /* separator */ + sizeof("Store_X.tf")); 1426 if (g_pPartitionNames[i] != NULL) 1427 { 1428 sprintf(g_pPartitionNames[i], "%s%cStore_%1X.tf", baseDir, PATH_SEPARATOR, i); 1429 } 1430 else 1431 { 1432 free(baseDir); 1433 i=0; 1434 while(g_pPartitionNames[i] != NULL) free(g_pPartitionNames[i++]); 1435 LogError("Out of memory"); 1436 return 2; 1437 } 1438 } 1439 } 1440 else if (strcmp(argv[0], "-workspaceSize") == 0) 1441 { 1442 argc--; 1443 argv++; 1444 if (argc == 0) 1445 { 1446 printUsage(); 1447 return 1; 1448 } 1449 g_nWorkspaceSize=atol(argv[0]); 1450 } 1451 #endif /* ! SUPPORT_DELEGATION_EXTENSION */ 1452 /*****************************************/ 1453 else if (strcmp(argv[0], "--help") == 0 || strcmp(argv[0], "-h") == 0) 1454 { 1455 printUsage(); 1456 return 0; 1457 } 1458 else 1459 { 1460 printUsage(); 1461 return 1; 1462 } 1463 argc--; 1464 argv++; 1465 } 1466 1467 #ifndef SUPPORT_DELEGATION_EXTENSION 1468 if (baseDir == NULL) 1469 { 1470 LogError("-storageDir option is mandatory"); 1471 return 1; 1472 } 1473 else 1474 { 1475 if (static_checkStorageDirAndAccessRights(baseDir) != 0) 1476 { 1477 return 1; 1478 } 1479 } 1480 #endif /* #ifndef SUPPORT_DELEGATION_EXTENSION */ 1481 1482 /* 1483 * Detach the daemon from the console 1484 */ 1485 1486 #if defined(LINUX) || (defined ANDROID) 1487 { 1488 /* 1489 * Turns this application into a daemon => fork off parent process, setup logging, ... 1490 */ 1491 1492 /* Our process ID and Session ID */ 1493 pid_t pid, sid; 1494 1495 if (!debug) 1496 { 1497 LogInfo("tf_daemon is detaching from console... Further traces go to syslog"); 1498 /* Fork off the parent process */ 1499 pid = fork(); 1500 if (pid < 0) 1501 { 1502 LogError("daemon forking failed"); 1503 return 1; 1504 } 1505 1506 if (pid > 0) 1507 { 1508 /* parent */ 1509 return 0; 1510 } 1511 bDetached = true; 1512 } 1513 1514 /* Change the file mode mask */ 1515 umask(0077); 1516 1517 if (!debug) 1518 { 1519 /* Open any logs here */ 1520 openlog("tf_daemon", 0, LOG_DAEMON); 1521 1522 /* Detach from the console */ 1523 sid = setsid(); 1524 if (sid < 0) 1525 { 1526 /* Log the failure */ 1527 LogError("daemon group creation failed"); 1528 return 1; 1529 } 1530 /* Close out the standard file descriptors */ 1531 close(STDIN_FILENO); 1532 close(STDOUT_FILENO); 1533 close(STDERR_FILENO); 1534 } 1535 } 1536 /* Change priority so that tf_driver.ko with no polling thread is faster */ 1537 if (setpriority(PRIO_PROCESS, 0, 19)!=0) 1538 { 1539 LogError("Daemon cannot change priority"); 1540 return 1; 1541 } 1542 1543 #endif 1544 1545 TRACE_INFO("Sector size is %d", g_nSectorSize); 1546 1547 LogInfo("tf_daemon - started"); 1548 1549 nError = TEEC_InitializeContext(NULL, /* const char * name */ 1550 &sContext); /* TEEC_Context* context */ 1551 if (nError != TEEC_SUCCESS) 1552 { 1553 LogError("TEEC_InitializeContext error: 0x%08X", nError); 1554 LogError("Now exiting..."); 1555 exit(2); 1556 } 1557 1558 /* Open a session */ 1559 if(createSession(&sContext, &sSession, &sOperation) == 0) 1560 { 1561 /* Run the session. This should never return */ 1562 runSession(&sContext, &sSession, &sOperation); 1563 } 1564 TEEC_FinalizeContext(&sContext); 1565 1566 return 3; 1567 } 1568